ios: Update WiiMote code using newer features from BTstack. Probably some bugs, so I recommend sticking with the nobtstack builds for now.

This commit is contained in:
meancoot 2013-02-28 18:38:49 -05:00
parent bd088a3332
commit f73511baa0
20 changed files with 1695 additions and 1288 deletions

View File

@ -8,10 +8,11 @@
/* Begin PBXBuildFile section */
96096DD816D1ABAF00BF4499 /* RAModuleInfoList.m in Sources */ = {isa = PBXBuildFile; fileRef = 96096DD716D1ABAF00BF4499 /* RAModuleInfoList.m */; };
960DB2C416E0193D00F977E3 /* BTstackManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 960DB2C216E0193D00F977E3 /* BTstackManager.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
960DB2C716E0197600F977E3 /* BTDiscoveryViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 960DB2C616E0197600F977E3 /* BTDiscoveryViewController.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
9614C6BB16DD7C00000B36EF /* BTDevice.m in Sources */ = {isa = PBXBuildFile; fileRef = 9614C6AE16DD7C00000B36EF /* BTDevice.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
9614C6BC16DD7C00000B36EF /* BTInquiryViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9614C6B016DD7C00000B36EF /* BTInquiryViewController.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
9614C6BD16DD7C00000B36EF /* libBTstack.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 9614C6B816DD7C00000B36EF /* libBTstack.dylib */; };
9614C6BE16DD7C00000B36EF /* WiiMoteHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 9614C6BA16DD7C00000B36EF /* WiiMoteHelper.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
9614C6BE16DD7C00000B36EF /* WiiMoteHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 9614C6BA16DD7C00000B36EF /* WiiMoteHelper.m */; };
9614C6C116DD7D54000B36EF /* wiimote.c in Sources */ = {isa = PBXBuildFile; fileRef = 9614C6BF16DD7D54000B36EF /* wiimote.c */; };
9614C6C416DDC018000B36EF /* autosave.c in Sources */ = {isa = PBXBuildFile; fileRef = 96AFAE9D16C1D9A9009DE44C /* autosave.c */; };
9614C6C516DDC018000B36EF /* cheats.c in Sources */ = {isa = PBXBuildFile; fileRef = 96AFAEA016C1D9A9009DE44C /* cheats.c */; };
@ -176,10 +177,12 @@
/* Begin PBXFileReference section */
96096DD716D1ABAF00BF4499 /* RAModuleInfoList.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RAModuleInfoList.m; sourceTree = "<group>"; };
960DB2C216E0193D00F977E3 /* BTstackManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BTstackManager.m; sourceTree = "<group>"; };
960DB2C316E0193D00F977E3 /* BTstackManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BTstackManager.h; sourceTree = "<group>"; };
960DB2C516E0197500F977E3 /* BTDiscoveryViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BTDiscoveryViewController.h; sourceTree = "<group>"; };
960DB2C616E0197600F977E3 /* BTDiscoveryViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BTDiscoveryViewController.m; sourceTree = "<group>"; };
9614C6AD16DD7C00000B36EF /* BTDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BTDevice.h; sourceTree = "<group>"; };
9614C6AE16DD7C00000B36EF /* BTDevice.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BTDevice.m; sourceTree = "<group>"; };
9614C6AF16DD7C00000B36EF /* BTInquiryViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BTInquiryViewController.h; sourceTree = "<group>"; };
9614C6B016DD7C00000B36EF /* BTInquiryViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BTInquiryViewController.m; sourceTree = "<group>"; };
9614C6B216DD7C00000B36EF /* btstack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = btstack.h; sourceTree = "<group>"; };
9614C6B316DD7C00000B36EF /* hci_cmds.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hci_cmds.h; sourceTree = "<group>"; };
9614C6B416DD7C00000B36EF /* linked_list.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = linked_list.h; sourceTree = "<group>"; };
@ -382,8 +385,10 @@
9614C6B116DD7C00000B36EF /* btstack */,
9614C6AD16DD7C00000B36EF /* BTDevice.h */,
9614C6AE16DD7C00000B36EF /* BTDevice.m */,
9614C6AF16DD7C00000B36EF /* BTInquiryViewController.h */,
9614C6B016DD7C00000B36EF /* BTInquiryViewController.m */,
960DB2C516E0197500F977E3 /* BTDiscoveryViewController.h */,
960DB2C616E0197600F977E3 /* BTDiscoveryViewController.m */,
960DB2C216E0193D00F977E3 /* BTstackManager.m */,
960DB2C316E0193D00F977E3 /* BTstackManager.h */,
9614C6B816DD7C00000B36EF /* libBTstack.dylib */,
9614C6B916DD7C00000B36EF /* WiiMoteHelper.h */,
9614C6BA16DD7C00000B36EF /* WiiMoteHelper.m */,
@ -957,9 +962,10 @@
96C19C3016D7045700FE8D5A /* RAConfig.m in Sources */,
965AE29E16D9BF94001D7667 /* ios_input.m in Sources */,
9614C6BB16DD7C00000B36EF /* BTDevice.m in Sources */,
9614C6BC16DD7C00000B36EF /* BTInquiryViewController.m in Sources */,
9614C6BE16DD7C00000B36EF /* WiiMoteHelper.m in Sources */,
9614C6C116DD7D54000B36EF /* wiimote.c in Sources */,
960DB2C416E0193D00F977E3 /* BTstackManager.m in Sources */,
960DB2C716E0197600F977E3 /* BTDiscoveryViewController.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@ -31,7 +31,6 @@
//
// BTDevice.h
// BT-Keyboard
//
// Created by Matthias Ringwald on 3/30/09.
//
@ -59,25 +58,35 @@ typedef enum {
} BluetoothConnectionState;
@interface BTDevice : NSObject {
bd_addr_t address;
bd_addr_t _address;
NSString * name;
uint32_t classOfDevice;
uint8_t pageScanRepetitionMode;
uint16_t clockOffset;
uint32_t classOfDevice;
BluetoothConnectionState connectionState;
uint8_t rssi;
// deprecated
BluetoothConnectionState connectionState;
}
- (void) setAddress:(bd_addr_t *)addr;
- (bd_addr_t *) address;
- (void) setAddress:(bd_addr_t*)addr;
- (BOOL) setAddressFromString:(NSString *) addressString;
- (bd_addr_t*) address;
- (NSString *) toString;
+ (NSString *) stringForAddress:(bd_addr_t *) address;
- (NSString *) addressString;
+ (NSString *) stringForAddress:(bd_addr_t*) address;
+ (BOOL) address:(bd_addr_t *) address fromString:(NSString *) addressString;
@property (readonly) BluetoothDeviceType deviceType;
@property (readonly) NSString * nameOrAddress;
@property (nonatomic, copy) NSString * name;
@property (nonatomic, assign) uint32_t classOfDevice;
@property (nonatomic, assign) uint16_t clockOffset;
@property (nonatomic, assign) uint8_t pageScanRepetitionMode;
@property (nonatomic, assign) uint8_t rssi;
@property (nonatomic, assign) BluetoothConnectionState connectionState;
@end

View File

@ -44,32 +44,67 @@
@synthesize connectionState;
@synthesize pageScanRepetitionMode;
@synthesize clockOffset;
@synthesize rssi;
- (BTDevice *)init {
name = NULL;
bzero(&address, 6);
memset(&_address, 0, 6);
classOfDevice = kCODInvalid;
connectionState = kBluetoothConnectionNotConnected;
return self;
}
- (void) setAddress:(bd_addr_t *)newAddr{
BD_ADDR_COPY( &address, newAddr);
- (void) setAddress:(bd_addr_t*)newAddr{
BD_ADDR_COPY( &_address, newAddr);
}
- (bd_addr_t *) address{
return &address;
- (BOOL) setAddressFromString:(NSString *) addressString{
return [BTDevice address:&_address fromString:addressString];
}
+ (NSString *) stringForAddress:(bd_addr_t *) address {
uint8_t * addr = (uint8_t*) address;
- (bd_addr_t*) address{
return &_address;
}
+ (NSString *) stringForAddress:(bd_addr_t*) address {
uint8_t *addr = (uint8_t*) *address;
return [NSString stringWithFormat:@"%02x:%02x:%02x:%02x:%02x:%02x", addr[0], addr[1], addr[2],
addr[3], addr[4], addr[5]];
}
+ (BOOL) address:(bd_addr_t *)address fromString:(NSString *) addressString{
// support both : and - or NOTHING as separator
addressString = [addressString stringByReplacingOccurrencesOfString:@":" withString:@""];
addressString = [addressString stringByReplacingOccurrencesOfString:@"-" withString:@""];
if ([addressString length] != 12) return NO;
unsigned int bd_addr_buffer[BD_ADDR_LEN]; //for sscanf, integer needed
// reset result buffer
int i;
for (i = 0; i < BD_ADDR_LEN; i++) {
bd_addr_buffer[i] = 0;
}
// parse
int result = sscanf([addressString UTF8String], "%2x%2x%2x%2x%2x%2x", &bd_addr_buffer[0], &bd_addr_buffer[1], &bd_addr_buffer[2],
&bd_addr_buffer[3], &bd_addr_buffer[4], &bd_addr_buffer[5]);
// store
if (result == 6){
for (i = 0; i < BD_ADDR_LEN; i++) {
(*address)[i] = (uint8_t) bd_addr_buffer[i];
}
return YES;
}
return NO;
}
- (NSString *) nameOrAddress{
if (name) return name;
return [BTDevice stringForAddress:&address];
return [self addressString];
}
- (NSString *) addressString{
return [BTDevice stringForAddress:&_address];
}
- (BluetoothDeviceType) deviceType{
@ -83,7 +118,7 @@
}
}
- (NSString *) toString{
return [NSString stringWithFormat:@"Device addr %@ name %@ COD %x", [BTDevice stringForAddress:&address], name, classOfDevice];
return [NSString stringWithFormat:@"Device addr %@ name %@ COD %x", [BTDevice stringForAddress:&_address], name, classOfDevice];
}
- (void)dealloc {

View File

@ -28,20 +28,11 @@
* SUCH DAMAGE.
*
*/
//
// BTInquiryViewController.h
//
// Created by Matthias Ringwald on 10/8/09.
//
#import <UIKit/UIKit.h>
#import "BTstackManager.h"
#include "btstack/hci_cmds.h" // for HCI_STATE
#include "btstack/utils.h"
@class BTDevice;
@protocol BTInquiryDelegate;
@class BTstackManager;
@protocol BTDiscoveryDelegate;
typedef enum {
kInquiryInactive,
@ -49,46 +40,28 @@ typedef enum {
kInquiryRemoteName
} InquiryState;
@interface BTInquiryViewController : UITableViewController
@interface BTDiscoveryViewController : UITableViewController<BTstackManagerListener>
{
NSMutableArray *devices;
HCI_STATE bluetoothState;
InquiryState inquiryState;
BTstackManager *bt;
NSObject<BTDiscoveryDelegate> * _delegate;
UIActivityIndicatorView *deviceActivity;
UIActivityIndicatorView *bluetoothActivity;
UIFont * deviceNameFont;
UIFont * macAddressFont;
id<BTInquiryDelegate> delegate;
bool allowSelection;
bool showIcons;
// hacks
bool stopRemoteNameGathering;
bool restartInquiry;
BTDevice *remoteNameDevice; // device for which remote name request is pending
BTDevice *remoteDevice; // device for which connection is pending
BTDevice *connectedDevice; // device to which we're connected
bool notifyDelegateOnInquiryStopped;
InquiryState inquiryState;
int remoteNameIndex;
BOOL showIcons;
int connectingIndex;
NSString *customActivityText;
}
- (void) startInquiry;
- (void) stopInquiry;
- (void) showConnecting:(BTDevice *) device;
- (void) showConnected:(BTDevice *) device;
- (void) removeDeviceForAddress:(bd_addr_t *)addr;
@property (nonatomic, assign) bool allowSelection;
@property (nonatomic, assign) bool showIcons;
@property (nonatomic, retain) NSMutableArray *devices;
@property (nonatomic, retain) id<BTInquiryDelegate> delegate;
-(void) markConnecting:(int)index; // use -1 for no connection active
@property (nonatomic, assign) NSObject<BTDiscoveryDelegate> * delegate;
@property (nonatomic, assign) BOOL showIcons;
@property (nonatomic, retain) NSString *customActivityText;
@end
@protocol BTInquiryDelegate
+ (void) deviceChoosen:(BTInquiryViewController *) inqView device:(BTDevice*) device;
+ (void) deviceDetected:(BTInquiryViewController *) inqView device:(BTDevice*) device;
+ (void) disconnectDevice:(BTInquiryViewController *) inqView device:(BTDevice*) device;
+ (void) inquiryStopped;
@protocol BTDiscoveryDelegate
@optional
-(BOOL) discoveryView:(BTDiscoveryViewController*)discoveryView willSelectDeviceAtIndex:(int)deviceIndex; // returns NO to ignore selection
-(void) statusCellSelectedDiscoveryView:(BTDiscoveryViewController*)discoveryView;
@end

View File

@ -0,0 +1,351 @@
/*
* 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.
*
*/
#import "BTDiscoveryViewController.h"
#import "BTDevice.h"
// fix compare for 3.0
#ifndef __IPHONE_3_0
#define __IPHONE_3_0 30000
#endif
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_3_0
// SDK 30 defines missing in SDK 20
@interface UITableViewCell (NewIn30)
- (id)initWithStyle:(int)style reuseIdentifier:(NSString *)reuseIdentifier;
@end
#endif
@interface UIDevice (privateAPI)
-(BOOL) isWildcat;
@end
@implementation BTDiscoveryViewController
@synthesize showIcons;
@synthesize delegate = _delegate;
@synthesize customActivityText;
- (id) init {
self = [super initWithStyle:UITableViewStyleGrouped];
macAddressFont = [UIFont fontWithName:@"Courier New" size:[UIFont labelFontSize]];
deviceNameFont = [UIFont boldSystemFontOfSize:[UIFont labelFontSize]];
inquiryState = kInquiryInactive;
connectingIndex = -1;
deviceActivity = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[deviceActivity startAnimating];
bluetoothActivity = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[bluetoothActivity startAnimating];
bt = [BTstackManager sharedInstance];
_delegate = nil;
return self;
}
-(void) reload{
[[self tableView] reloadData];
}
/*
- (id)initWithStyle:(UITableViewStyle)style {
// Override initWithStyle: if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
if (self = [super initWithStyle:style]) {
}
return self;
}
*/
/*
- (void)viewDidLoad {
[super viewDidLoad];
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
*/
/*
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
}
*/
/*
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
}
*/
/*
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
}
*/
/*
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
}
*/
/*
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
*/
// BTstackManagerListenerDelegate
-(void) activatedBTstackManager:(BTstackManager*) manager{
[self reload];
}
-(void) btstackManager:(BTstackManager*)manager activationFailed:(BTstackError)error {
[self reload];
}
-(void) discoveryInquiryBTstackManager:(BTstackManager*) manager {
inquiryState = kInquiryActive;
[self reload];
}
-(void) btstackManager:(BTstackManager*)manager discoveryQueryRemoteName:(int)deviceIndex {
inquiryState = kInquiryRemoteName;
remoteNameIndex = deviceIndex;
[self reload];
}
-(void) discoveryStoppedBTstackManager:(BTstackManager*) manager {
inquiryState = kInquiryInactive;
[self reload];
}
-(void) btstackManager:(BTstackManager*)manager deviceInfo:(BTDevice*)device {
[self reload];
}
-(void) markConnecting:(int)index; {
connectingIndex = index;
[self reload];
}
-(void) setCustomActivityText:(NSString*) text{
[text retain];
[customActivityText release];
customActivityText = text;
[self reload];
}
// MARK: Table view methods
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
return @"Devices";
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 1 + [bt numberOfDevicesFound];
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_3_0
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
#else
cell = [[[UITableViewCell alloc] initWithFrame:CGRectNull reuseIdentifier:(NSString *)CellIdentifier] autorelease];
#endif
}
// Set up the cell...
NSString *theLabel = nil;
UIImage *theImage = nil;
UIFont *theFont = nil;
int idx = [indexPath indexAtPosition:1];
if (idx >= [bt numberOfDevicesFound]) {
if (customActivityText) {
theLabel = customActivityText;
cell.accessoryView = bluetoothActivity;
} else if ([bt isActivating]){
theLabel = @"Activating BTstack...";
cell.accessoryView = bluetoothActivity;
} else if (![bt isActive]){
theLabel = @"Bluetooth not accessible!";
cell.accessoryView = nil;
} else {
#if 0
if (connectedDevice) {
theLabel = @"Disconnect";
cell.accessoryView = nil;
}
#endif
if (connectingIndex >= 0) {
theLabel = @"Connecting...";
cell.accessoryView = bluetoothActivity;
} else {
switch (inquiryState){
case kInquiryInactive:
if ([bt numberOfDevicesFound] > 0){
theLabel = @"Find more devices...";
} else {
theLabel = @"Find devices...";
}
cell.accessoryView = nil;
break;
case kInquiryActive:
theLabel = @"Searching...";
cell.accessoryView = bluetoothActivity;
break;
case kInquiryRemoteName:
theLabel = @"Query device names...";
cell.accessoryView = bluetoothActivity;
break;
}
}
}
} else {
BTDevice *dev = [bt deviceAtIndex:idx];
// pick font
theLabel = [dev nameOrAddress];
if ([dev name]){
theFont = deviceNameFont;
} else {
theFont = macAddressFont;
}
// pick an icon for the devices
if (showIcons) {
NSString *imageName = @"bluetooth.png";
// check major device class
switch (([dev classOfDevice] & 0x1f00) >> 8) {
case 0x01:
imageName = @"computer.png";
break;
case 0x02:
imageName = @"smartphone.png";
break;
case 0x05:
switch ([dev classOfDevice] & 0xff){
case 0x40:
imageName = @"keyboard.png";
break;
case 0x80:
imageName = @"mouse.png";
break;
case 0xc0:
imageName = @"keyboard.png";
break;
default:
imageName = @"HID.png";
break;
}
}
#ifdef LASER_KB
if ([dev name] && [[dev name] isEqualToString:@"CL800BT"]){
imageName = @"keyboard.png";
}
if ([dev name] && [[dev name] isEqualToString:@"CL850"]){
imageName = @"keyboard.png";
}
// Celluon CL800BT, CL850 have 00-0b-24-aa-bb-cc, COD 0x400210
uint8_t *addr = (uint8_t *) [dev address];
if (addr[0] == 0x00 && addr[1] == 0x0b && addr[2] == 0x24){
imageName = @"keyboard.png";
}
#endif
theImage = [UIImage imageNamed:imageName];
}
// set accessory view
if (idx == connectingIndex){
cell.accessoryView = deviceActivity;
} else {
cell.accessoryView = nil;
}
}
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_3_0
if (theLabel) cell.textLabel.text = theLabel;
if (theFont) cell.textLabel.font = theFont;
if (theImage) cell.imageView.image = theImage;
#else
if (theLabel) cell.text = theLabel;
if (theFont) cell.font = theFont;
if (theImage) cell.image = theImage;
#endif
return cell;
}
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (!_delegate) return nil;
int index = [indexPath indexAtPosition:1];
if (index >= [bt numberOfDevicesFound]){
if ([_delegate respondsToSelector:@selector(statusCellSelectedDiscoveryView:)]){
[_delegate statusCellSelectedDiscoveryView:self];
return nil;
}
}
if ([_delegate respondsToSelector:@selector(discoveryView:willSelectDeviceAtIndex:)] && [_delegate discoveryView:self willSelectDeviceAtIndex:index]){
return indexPath;
}
return nil;
}
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
UIDevice * uiDevice = [UIDevice currentDevice];
return [uiDevice respondsToSelector:@selector(isWildcat)] && [uiDevice isWildcat];
}
- (void)dealloc {
[super dealloc];
}
@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.
*
*/
//
// BTInquiryViewController.m
//
// Created by Matthias Ringwald on 10/8/09.
//
#import "BTInquiryViewController.h"
#import "BTDevice.h"
#import <UIKit/UIToolbar.h>
#include "btstack/btstack.h"
//#include "wiimote.h"
#define INQUIRY_INTERVAL 3
unsigned myosd_num_of_joys = 0;
static BTInquiryViewController *inqView;
static btstack_packet_handler_t clientHandler;
static uint8_t remoteNameIndex;
@interface BTInquiryViewController (Private)
- (void) handlePacket:(uint8_t) packet_type channel:(uint16_t) channel packet:(uint8_t*) packet size:(uint16_t) size;
- (BTDevice *) getDeviceForAddress:(bd_addr_t *)addr;
- (void) getNextRemoteName;
- (void) startInquiry;
@end
static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
if (inqView) {
[inqView handlePacket:packet_type channel:channel packet:packet size:size];
}
}
@implementation BTInquiryViewController
@synthesize devices;
@synthesize delegate;
@synthesize allowSelection;
@synthesize showIcons;
- (id) init {
self = [super initWithStyle:UITableViewStyleGrouped];
bluetoothState = HCI_STATE_OFF;
inquiryState = kInquiryInactive;
allowSelection = false;
showIcons = false;
remoteDevice = nil;
restartInquiry = true;
notifyDelegateOnInquiryStopped = false;
macAddressFont = [UIFont fontWithName:@"Courier New" size:[UIFont labelFontSize]];
deviceNameFont = [UIFont boldSystemFontOfSize:[UIFont labelFontSize]];
deviceActivity = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[deviceActivity startAnimating];
bluetoothActivity = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[bluetoothActivity startAnimating];
devices = [[NSMutableArray alloc] init];
inqView = self;
return self;
}
- (void) myStartInquiry{
if (inquiryState != kInquiryInactive) {
NSLog(@"Inquiry already active");
return;
}
NSLog(@"Inquiry started");
stopRemoteNameGathering = false;
restartInquiry = true;
inquiryState = kInquiryActive;
[[self tableView] reloadData];
bt_send_cmd(&hci_inquiry, HCI_INQUIRY_LAP, INQUIRY_INTERVAL, 0);
}
- (void) handlePacket:(uint8_t) packet_type channel:(uint16_t) channel packet:(uint8_t*) packet size:(uint16_t) size {
bd_addr_t event_addr;
switch (packet_type) {
case HCI_EVENT_PACKET:
switch (packet[0]){
case BTSTACK_EVENT_STATE:
{
// bt stack activated
bluetoothState = (HCI_STATE)packet[2];
[[self tableView] reloadData];
// set BT state
/*
if (bluetoothState == HCI_STATE_WORKING) {
[self myStartInquiry];
}
*/
break;
}
case BTSTACK_EVENT_POWERON_FAILED:
{
bluetoothState = HCI_STATE_OFF;
[[self tableView] reloadData];
UIAlertView* alertView = [[UIAlertView alloc] init];
alertView.title = @"Bluetooth not accessible!";
alertView.message = @"Hardware initialization failed!\n"
"Make sure you have turned off Bluetooth in the System Settings.";
NSLog(@"Alert: %@ - %@", alertView.title, alertView.message);
[alertView addButtonWithTitle:@"Dismiss"];
[alertView show];
break;
}
case HCI_EVENT_INQUIRY_RESULT:
case HCI_EVENT_INQUIRY_RESULT_WITH_RSSI:
{
int numResponses = packet[2];
int i;
for (i=0; i<numResponses;i++){
bd_addr_t addr;
bt_flip_addr(addr, &packet[3+i*6]);
if ([inqView getDeviceForAddress:&addr]) {
NSLog(@"Device %@ already in list", [BTDevice stringForAddress:&addr]);
continue;
}
BTDevice *dev = [[BTDevice alloc] init];
[dev setAddress:&addr];
[dev setPageScanRepetitionMode:packet[3 + numResponses*6 + i]];
[dev setClassOfDevice:READ_BT_24(packet, 3 + numResponses*(6+1+1+1) + i*3)];
[dev setClockOffset:(READ_BT_16(packet, 3 + numResponses*(6+1+1+1+3) + i*2) & 0x7fff)];
// hexdump(packet, size);
NSLog(@"--> adding %@", [dev toString] );
[devices addObject:dev];
if (delegate) {
[delegate deviceDetected:self device:dev];
}
}
[[inqView tableView] reloadData];
NSLog(@"bye" );
break;
}
case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE:
{
bt_flip_addr(event_addr, &packet[3]);
BTDevice *dev = [inqView getDeviceForAddress:&event_addr];
if (!dev) break;
[dev setConnectionState:kBluetoothConnectionNotConnected];
if (packet[2] == 0) {
[dev setName:[NSString stringWithUTF8String:(const char *) &packet[9]]];
if (delegate) {
[delegate deviceDetected:self device:dev];
}
}
[[self tableView] reloadData];
remoteNameIndex++;
[self getNextRemoteName];
break;
}
case HCI_EVENT_COMMAND_COMPLETE:
{
if (COMMAND_COMPLETE_EVENT(packet, hci_inquiry_cancel)){
// inquiry canceled
NSLog(@"Inquiry cancelled successfully");
inquiryState = kInquiryInactive;
[[self tableView] reloadData];
if (notifyDelegateOnInquiryStopped){
notifyDelegateOnInquiryStopped = false;
if (delegate) {
[delegate inquiryStopped];
}
}
}
if (COMMAND_COMPLETE_EVENT(packet, hci_remote_name_request_cancel)){
// inquiry canceled
NSLog(@"Remote name request cancelled successfully");
inquiryState = kInquiryInactive;
[[self tableView] reloadData];
if (notifyDelegateOnInquiryStopped){
notifyDelegateOnInquiryStopped = false;
if (delegate) {
[delegate inquiryStopped];
}
}
}
break;
}
case HCI_EVENT_INQUIRY_COMPLETE:
{
NSLog(@"Inquiry complete");
// reset name check
remoteNameIndex = 0;
[self getNextRemoteName];
break;
}
default:
break;
// hexdump(packet, size);
//break;
}
default:
break;
}
// forward to client app
(*clientHandler)(packet_type, channel, packet, size);
}
- (BTDevice *) getDeviceForAddress:(bd_addr_t *)addr {
uint8_t j;
for (j=0; j<[devices count]; j++){
BTDevice *dev = [devices objectAtIndex:j];
if (BD_ADDR_CMP(addr, [dev address]) == 0){
return dev;
}
}
return nil;
}
- (void) removeDeviceForAddress:(bd_addr_t *)addr {
uint8_t j;
for (j=0; j<[devices count]; j++){
BTDevice *dev = [devices objectAtIndex:j];
if (BD_ADDR_CMP(addr, [dev address]) == 0){
NSLog(@"--> removed %@", [dev toString] );
[devices removeObject:dev];
[[self tableView] reloadData];
return;
}
}
}
- (void) getNextRemoteName{
// stopped?
if (stopRemoteNameGathering) {
inquiryState = kInquiryInactive;
[[self tableView] reloadData];
if (notifyDelegateOnInquiryStopped){
notifyDelegateOnInquiryStopped = false;
if (delegate) {
[delegate inquiryStopped];
}
}
return;
}
remoteNameDevice = nil;
for (remoteNameIndex = 0; remoteNameIndex < [devices count]; remoteNameIndex++){
BTDevice *dev = [devices objectAtIndex:remoteNameIndex];
if (![dev name]){
remoteNameDevice = dev;
break;
}
}
if (remoteNameDevice) {
inquiryState = kInquiryRemoteName;
[remoteNameDevice setConnectionState:kBluetoothConnectionRemoteName];
bt_send_cmd(&hci_remote_name_request, [remoteNameDevice address], [remoteNameDevice pageScanRepetitionMode], 0, [remoteNameDevice clockOffset] | 0x8000);
} else {
inquiryState = kInquiryInactive;
// inquiry done.
if (restartInquiry) {
[self myStartInquiry];
}
}
[[self tableView] reloadData];
}
- (void) startInquiry {
//static int b = 0;
//if(!b)
//{
//b=1;
// put into loop
// @TODO: cannot be called a second time!
clientHandler = bt_register_packet_handler(packet_handler);
bluetoothState = HCI_STATE_INITIALIZING;
[[self tableView] reloadData];
stopRemoteNameGathering = false;
restartInquiry = true;
bt_send_cmd(&btstack_set_power_mode, HCI_POWER_ON );
//}
}
- (void) stopInquiry {
NSLog(@"stop inquiry called, state %u", inquiryState);
restartInquiry = false;
stopRemoteNameGathering = true;
bool immediateNotify = true;
switch (inquiryState) {
case kInquiryActive:
// just stop inquiry
immediateNotify = false;
bt_send_cmd(&hci_inquiry_cancel);
break;
case kInquiryInactive:
NSLog(@"stop inquiry called although inquiry inactive?");
break;
case kInquiryRemoteName:
if (remoteNameDevice) {
// just stop remote name request
immediateNotify = false;
bt_send_cmd(&hci_remote_name_request_cancel, [remoteNameDevice address]);
}
break;
default:
break;
}
if (immediateNotify && delegate){
[delegate inquiryStopped];
} else {
notifyDelegateOnInquiryStopped = true;
}
}
- (void) showConnecting:(BTDevice *) device {
remoteDevice = device;
[[self tableView] reloadData];
}
- (void) showConnected:(BTDevice *) device {
connectedDevice = device;
[[self tableView] reloadData];
}
/*
- (void)loadView {
[super loadView];
}
*/
/*
- (void)viewDidLoad {
[super viewDidLoad];
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
//self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
*/
/*
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
}
*/
/*
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
}
*/
/*
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
}
*/
/*
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
}
*/
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
//return NO;
//return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
// unregister self
bt_register_packet_handler(clientHandler);
// done
[super dealloc];
}
#pragma mark Table view methods
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
return @"Devices";
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
int rows = 1; // 1 for status line
if (bluetoothState == HCI_STATE_WORKING) {
rows += [devices count];
}
return rows;
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:/* UITableViewCellStyleDefault = */(UITableViewCellStyle)0 reuseIdentifier:CellIdentifier] autorelease];
// cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
// Set up the cell...
NSString *label = nil;
int idx = [indexPath indexAtPosition:1];
if (bluetoothState != HCI_STATE_WORKING || idx >= [devices count]) {
if (bluetoothState == HCI_STATE_INITIALIZING){
label = @"Activating BTstack...";
cell.accessoryView = bluetoothActivity;
} else if (bluetoothState == HCI_STATE_OFF){
label = @"Bluetooth not accessible!";
cell.accessoryView = nil;
} else {
if (connectedDevice) {
label = @"Disconnect";
cell.accessoryView = nil;
} else if (remoteDevice) {
label = @"Connecting...";
cell.accessoryView = bluetoothActivity;
} else {
switch (inquiryState){
case kInquiryInactive:
if (myosd_num_of_joys==4)
{
label = @"Maximun devices connected!";
}
else if ([devices count] > 0){
label = @"Press here to find more devices...";
} else {
label = @"Press here to find first device...";
}
cell.accessoryView = nil;
break;
case kInquiryActive:
//label = @"Searching...";
label = @"Press 1 and 2 on the WiiMote to sync";
cell.accessoryView = bluetoothActivity;
break;
case kInquiryRemoteName:
label = @"Query device names...";
cell.accessoryView = bluetoothActivity;
break;
}
}
}
} else {
BTDevice *dev = [devices objectAtIndex:idx];
label = [dev nameOrAddress];
if ([dev name]){
cell.font = deviceNameFont;
} else {
cell.font = macAddressFont;
}
// pick an icon for the devices
if (showIcons) {
int major = ([dev classOfDevice] & 0x1f00) >> 8;
if (major == 0x01) {
cell.image = [UIImage imageNamed:@"computer.png"];
} else if (major == 0x02) {
cell.image = [UIImage imageNamed:@"smartphone.png"];
} else if ( major == 0x05 && ([dev classOfDevice] & 0xff) == 0x40){
cell.image = [UIImage imageNamed:@"keyboard.png"];
} else {
cell.image = [UIImage imageNamed:@"bluetooth.png"];
}
}
switch ([dev connectionState]) {
case kBluetoothConnectionNotConnected:
case kBluetoothConnectionConnected:
cell.accessoryView = nil;
break;
case kBluetoothConnectionConnecting:
case kBluetoothConnectionRemoteName:
cell.accessoryView = deviceActivity;
break;
}
}
cell.text = label;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(@"didSelectRowAtIndexPath %@", indexPath);
// Navigation logic may go here. Create and push another view controller.
// AnotherViewController *anotherViewController = [[AnotherViewController alloc] initWithNibName:@"AnotherView" bundle:nil];
// [self.navigationController pushViewController:anotherViewController];
// [anotherViewController release];
// valid selection?
int idx = [indexPath indexAtPosition:1];
//printf("sleccion %d\n",idx);
if (bluetoothState == HCI_STATE_WORKING) {
if (delegate) {
if (idx < [devices count]){
[delegate deviceChoosen:self device:[devices objectAtIndex:idx]];
} else if (idx == [devices count]) {
//printf("seleccionado %d %d\n",idx,connectedDevice);
if (connectedDevice) {
// DISCONNECT button
[delegate disconnectDevice:self device:connectedDevice];
} else if (myosd_num_of_joys<4){
// Find more devices
[self myStartInquiry];
}
}
}
} else {
[tableView deselectRowAtIndexPath:indexPath animated:TRUE];
}
}
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (allowSelection) {
return indexPath;
}
return nil;
}
@end

View File

@ -0,0 +1,188 @@
/*
* 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

@ -0,0 +1,590 @@
/*
* 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.
*
*/
#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(RUN_LOOP_COCOA);
// our packet handler
bt_register_packet_handler(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();
if (err) return BTSTACK_CONNECTION_TO_BTDAEMON_FAILED;
}
connectedToDaemon = YES;
// check system BT
state = kW4SysBTState;
bt_send_cmd(&btstack_get_system_bluetooth_enabled);
return err;
}
-(BTstackError) deactivate {
if (!connectedToDaemon) return BTSTACK_CONNECTION_TO_BTDAEMON_FAILED;
state = kW4Deactivated;
bt_send_cmd(&btstack_set_power_mode, 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(&hci_write_inquiry_mode, 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(&hci_inquiry_cancel);
break;
case kRemoteName: {
discoveryState = kW4RemoteNameBeforeStop;
BTDevice *device = [discoveredDevices objectAtIndex:discoveryDeviceIndex];
bt_send_cmd(&hci_remote_name_request_cancel, [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(&btstack_set_system_bluetooth_enabled, 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(&btstack_set_power_mode, 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(&hci_remote_name_request, [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(&hci_inquiry, 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(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(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) ) {
discoveryState = kInquiry;
bt_send_cmd(&hci_inquiry, 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(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(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) ) {
discoveryState = kInactive;
[self sendDiscoveryStoppedEvent];
}
break;
case kW4InquiryStop:
if (packet[0] == HCI_EVENT_INQUIRY_COMPLETE
|| COMMAND_COMPLETE_EVENT(packet, hci_inquiry_cancel)) {
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)){
discoveryState = kInactive;
[self sendDiscoveryStoppedEvent];
}
break;
default:
break;
}
}
-(void) dropLinkKeyForAddress:(bd_addr_t*) address {
bt_send_cmd(&hci_delete_stored_link_key, 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(&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,19 +31,10 @@
#import <UIKit/UIKit.h>
#import "BTInquiryViewController.h"
@interface WiiMoteHelper : NSObject<BTInquiryDelegate>
{
}
+ (void)startwiimote:(UIViewController *)controller;
+ (void)endwiimote;
+ (void)cancelWiiMoteSearch;
#import "BTDiscoveryViewController.h"
@interface WiiMoteHelper : NSObject<BTDiscoveryDelegate, BTstackManagerDelegate, BTstackManagerListener>
+ (WiiMoteHelper*)get;
- (void)showDiscovery;
@end

View File

@ -37,391 +37,241 @@
#import "WiiMoteHelper.h"
#import "BTDevice.h"
#import "BTInquiryViewController.h"
#import "BTstackManager.h"
#import "BTDiscoveryViewController.h"
#import "btstack/btstack.h"
#import "btstack/run_loop.h"
#import "btstack/hci_cmds.h"
bool btOK = false;
bool initLoop = false;
BTDevice *device;
uint16_t wiiMoteConHandle = 0;
bool conected = false;
bool activated = false;
BTInquiryViewController *inqViewControl;
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 = NULL;
wm = wiimote_get_by_source_cid(channel);
if(wm!=NULL)
{
byte* msg = packet + 2;
byte event = packet[1];
switch (event) {
case WM_RPT_BTN:
{
/* button */
wiimote_pressed_buttons(wm, msg);
break;
}
case WM_RPT_READ:
{
/* data read */
if(WIIMOTE_DBG)printf("WM_RPT_READ data arrive!\n");
wiimote_pressed_buttons(wm, msg);
byte err = msg[2] & 0x0F;
if (err == 0x08)
printf("Unable to read data - address does not exist.\n");
else if (err == 0x07)
printf("Unable to read data - address is for write-only registers.\n");
else if (err)
printf("Unable to read data - unknown error code %x.\n", err);
unsigned short offset = BIG_ENDIAN_SHORT(*(unsigned short*)(msg + 3));
byte len = ((msg[2] & 0xF0) >> 4) + 1;
byte *data = (msg + 5);
if(WIIMOTE_DBG)
{
int i = 0;
printf("Read: 0x%04x ; ",offset);
for (; i < len; ++i)
printf("%x ", data[i]);
printf("\n");
}
if(wiimote_handshake(wm,WM_RPT_READ,data,len))
{
//btUsed = 1;
[inqViewControl showConnected:nil];
[inqViewControl showConnecting:nil];
//Create UIAlertView alert
[inqViewControl showConnecting:nil];
UIAlertView* alert =
[[UIAlertView alloc] initWithTitle:@"Connection detected!"
message: [NSString stringWithFormat:@"%@ '%@' connection sucessfully completed!",
(wm->exp.type != EXP_NONE ? @"Classic Controller" : @"WiiMote"),
[NSNumber numberWithInt:(wm->unid)+1]]
delegate:nil cancelButtonTitle:@"Dismiss" otherButtonTitles: nil];
[alert show];
//[alert dismissWithClickedButtonIndex:0 animated:TRUE];
[alert release];
if(device!=nil)
{
[device setConnectionState:kBluetoothConnectionConnected];
device = nil;
}
}
return;
}
case WM_RPT_CTRL_STATUS:
{
wiimote_pressed_buttons(wm, msg);
/* find the battery level and normalize between 0 and 1 */
if(WIIMOTE_DBG)
{
wm->battery_level = (msg[5] / (float)WM_MAX_BATTERY_CODE);
printf("BATTERY LEVEL %f\n", wm->battery_level);
}
//handshake stuff!
if(wiimote_handshake(wm,WM_RPT_CTRL_STATUS,msg,-1))
{
//btUsed = 1;
[inqViewControl showConnected:nil];
[inqViewControl showConnecting:nil];
UIAlertView* alert =
[[UIAlertView alloc] initWithTitle:@"Connection detected!"
message: [NSString stringWithFormat:@"WiiMote '%@' connection sucessfully completed!",[NSNumber numberWithInt:(wm->unid)+1]]
delegate:nil cancelButtonTitle:@"Dismiss" otherButtonTitles: nil];
[alert show];
//[alert dismissWithClickedButtonIndex:0 animated:TRUE];
[alert release];
[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
{
switch (packet[0]){
case L2CAP_EVENT_CHANNEL_OPENED:
// data: event (8), len(8), status (8), address(48), handle (16), psm (16), local_cid(16), remote_cid (16)
if (packet[2] == 0) {
// inform about new l2cap connection
bt_flip_addr(event_addr, &packet[3]);
uint16_t psm = READ_BT_16(packet, 11);
uint16_t source_cid = READ_BT_16(packet, 13);
wiiMoteConHandle = READ_BT_16(packet, 9);
NSLog(@"Channel successfully opened: handle 0x%02x, psm 0x%02x, source cid 0x%02x, dest cid 0x%02x",
wiiMoteConHandle, psm, source_cid, READ_BT_16(packet, 15));
if (psm == 0x13) {
// interupt channel openedn succesfully, now open control channel, too.
if(WIIMOTE_DBG)printf("open control channel\n");
bt_send_cmd(&l2cap_create_channel, event_addr, 0x11);
struct wiimote_t *wm = NULL;
wm = &joys[myosd_num_of_joys];
memset(wm, 0, sizeof(struct wiimote_t));
wm->unid = myosd_num_of_joys;
wm->i_source_cid = source_cid;
memcpy(&wm->addr,&event_addr,BD_ADDR_LEN);
if(WIIMOTE_DBG)printf("addr %02x:%02x:%02x:%02x:%02x:%02x\n", wm->addr[0], wm->addr[1], wm->addr[2],wm->addr[3], wm->addr[4], wm->addr[5]);
if(WIIMOTE_DBG)printf("saved 0x%02x 0x%02x\n",source_cid,wm->i_source_cid);
wm->exp.type = EXP_NONE;
} else {
//inicializamos el wiimote!
struct wiimote_t *wm = NULL;
wm = &joys[myosd_num_of_joys];
wm->wiiMoteConHandle = wiiMoteConHandle;
wm->c_source_cid = source_cid;
wm->state = WIIMOTE_STATE_CONNECTED;
myosd_num_of_joys++;
if(WIIMOTE_DBG)printf("Devices Number: %d\n",myosd_num_of_joys);
wiimote_handshake(wm,-1,NULL,-1);
}
}
break;
case L2CAP_EVENT_CHANNEL_CLOSED:
{
// data: event (8), len(8), channel (16)
uint16_t source_cid = READ_BT_16(packet, 2);
NSLog(@"Channel successfully closed: cid 0x%02x",source_cid);
bd_addr_t addr;
int unid = wiimote_remove(source_cid,&addr);
if(unid!=-1)
{
[inqViewControl removeDeviceForAddress:&addr];
UIAlertView* alert =
[[UIAlertView alloc] initWithTitle:@"Disconnection!"
message:[NSString stringWithFormat:@"WiiMote '%@' disconnection detected.\nIs battery drainned?",[NSNumber numberWithInt:(unid+1)]]
delegate:nil cancelButtonTitle:@"Dismiss" otherButtonTitles: nil];
[alert show];
[alert release];
}
}
break;
default:
break;
}
break;
}
default:
break;
}
}
static BTDevice *device;
static uint16_t wiiMoteConHandle = 0;
static bool btOK;
static WiiMoteHelper* instance;
@implementation WiiMoteHelper
+(void) startwiimote:(UIViewController *)controller{
if(!initLoop)
{
run_loop_init(RUN_LOOP_COCOA);
initLoop = true;
}
if(!btOK )
{
if (bt_open() ){
// Alert user?
} else {
bt_register_packet_handler(packet_handler);
btOK = true;
}
}
if (btOK)
{
// create inq controller
if(inqViewControl==nil)
{
inqViewControl = [[BTInquiryViewController alloc] init];
struct CGRect rect = controller.view.frame;
CGFloat navBarWidht = rect.size.width;
CGFloat navBarHeight = 45;
UINavigationBar *navBar = [ [ UINavigationBar alloc ] initWithFrame: CGRectMake(0, 0, navBarWidht , navBarHeight)];
[navBar autorelease];
[navBar setDelegate: inqViewControl ];
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button setFrame:CGRectMake(rect.size.width-70,5,60,35)];
[button setTitle:@"Done" forState:UIControlStateNormal];
button.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
[button addTarget:self action:@selector(cancelWiiMoteSearch) forControlEvents:UIControlEventTouchUpInside];
[navBar addSubview:button];
UILabel *navLabel = [[UILabel alloc] initWithFrame:CGRectMake(40,0,300, navBarHeight)];
navLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth;
navLabel.text = @"WiiMote Sync";
navLabel.backgroundColor = [UIColor clearColor];
navLabel.textColor = [UIColor blackColor];
navLabel.font = [UIFont systemFontOfSize: 18];
navLabel.textAlignment = UITextAlignmentLeft;
[navBar addSubview:navLabel];
[navLabel release];
[[inqViewControl tableView] setTableHeaderView:navBar];
[navBar release];
}
if(!activated)
{
UIAlertView* alertView=[[UIAlertView alloc] initWithTitle:nil
message:@"are you sure you to activate BTstack?"
delegate:self cancelButtonTitle:nil
otherButtonTitles:@"Yes",@"No",nil];
[alertView show];
[alertView release];
}
[controller presentModalViewController:inqViewControl animated:YES];
}
}
+ (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
+ (WiiMoteHelper*)get
{
if(buttonIndex == 0 )
{
[inqViewControl setDelegate:self];
[inqViewControl setAllowSelection:true];
activated = true;
[inqViewControl startInquiry];
}
else
{
[inqViewControl dismissModalViewControllerAnimated:YES];
}
if (!instance)
{
instance = [WiiMoteHelper new];
}
return instance;
}
+(void) cancelWiiMoteSearch {
[inqViewControl stopInquiry];
[inqViewControl dismissModalViewControllerAnimated:YES];
}
+(void) deviceChoosen:(BTInquiryViewController *) inqView device:(BTDevice*) deviceChoosen;
- (id)init
{
NSLog(@"deviceChoosen %@", [device toString]);
if (!btOK)
{
BTstackManager* bt = [BTstackManager sharedInstance];
[bt setDelegate:self];
[bt addListener:self];
btOK = [bt activate] == 0;
}
return self;
}
+ (void) deviceDetected:(BTInquiryViewController *) inqView device:(BTDevice*) selectedDevice {
- (void)dealloc
{
// TODO: Any other cleanup needed
[[BTstackManager sharedInstance] deactivate];
}
NSLog(@"deviceDetected %@", [device toString]);
if ([selectedDevice name] && [[selectedDevice name] caseInsensitiveCompare:@"Nintendo RVL-CNT-01"] == NSOrderedSame){
NSLog(@"WiiMote found with address %@", [BTDevice stringForAddress:[selectedDevice address]]);
device = selectedDevice;
- (void)showDiscovery
{
BTDiscoveryViewController* vc = [BTDiscoveryViewController new];
[vc setDelegate:self];
[[BTstackManager sharedInstance] addListener:vc];
[[RetroArch_iOS get] pushViewController:vc isGame:NO];
}
// 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(&hci_write_authentication_enable, 0);
}
// BTStackManagerDelegate
-(void) btstackManager:(BTstackManager*) manager
handlePacketWithType:(uint8_t) packet_type
forChannel:(uint16_t) channel
andData:(uint8_t *)packet
withLen:(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);
[inqViewControl stopInquiry];
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;
}
[inqViewControl showConnecting:device];
case WM_RPT_WRITE:
{
/* write feedback - safe to skip */
break;
}
// connect to device
[device setConnectionState:kBluetoothConnectionConnecting];
[[inqViewControl tableView] reloadData];
bt_send_cmd(&l2cap_create_channel, [device address], 0x13);
}
default:
{
printf("Unknown event, can not handle it [Code 0x%x].", event);
return;
}
}
}
break;
}
case HCI_EVENT_PACKET://0x04
{
switch (packet[0])
{
case HCI_EVENT_COMMAND_COMPLETE:
{
if (COMMAND_COMPLETE_EVENT(packet, hci_write_authentication_enable))
bt_send_cmd(&l2cap_create_channel, [device address], PSM_HID_INTERRUPT);
break;
}
case HCI_EVENT_PIN_CODE_REQUEST:
{
bt_flip_addr(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(&hci_pin_code_request_reply, event_addr, 6, &packet[2]); // use inverse bd_addr as PIN
break;
}
case L2CAP_EVENT_CHANNEL_OPENED:
{
// data: event (8), len(8), status (8), address(48), handle (16), psm (16), local_cid(16), remote_cid (16)
if (packet[2] == 0)
{
// inform about new l2cap connection
bt_flip_addr(event_addr, &packet[3]);
uint16_t psm = READ_BT_16(packet, 11);
uint16_t source_cid = READ_BT_16(packet, 13);
wiiMoteConHandle = READ_BT_16(packet, 9);
if (psm == 0x13)
{
// interupt channel openedn succesfully, now open control channel, too.
bt_send_cmd(&l2cap_create_channel, event_addr, 0x11);
struct wiimote_t *wm = &joys[myosd_num_of_joys];
memset(wm, 0, sizeof(struct wiimote_t));
wm->unid = myosd_num_of_joys;
wm->i_source_cid = source_cid;
memcpy(&wm->addr,&event_addr,BD_ADDR_LEN);
wm->exp.type = EXP_NONE;
}
else
{
//inicializamos el wiimote!
struct wiimote_t *wm = &joys[myosd_num_of_joys];
wm->wiiMoteConHandle = wiiMoteConHandle;
wm->c_source_cid = source_cid;
wm->state = WIIMOTE_STATE_CONNECTED;
myosd_num_of_joys++;
wiimote_handshake(wm,-1,NULL,-1);
}
}
break;
}
case L2CAP_EVENT_CHANNEL_CLOSED:
{
// data: event (8), len(8), channel (16)
uint16_t source_cid = READ_BT_16(packet, 2);
bd_addr_t addr;
wiimote_remove(source_cid,&addr);
break;
}
}
}
}
}
+ (void) inquiryStopped{
}
+ (void) disconnectDevice:(BTInquiryViewController *) inqView device:(BTDevice*) selectedDevice {
}
+ (void)endwiimote {
if(btOK)
{
int i=0;
while(i!=myosd_num_of_joys){
[inqViewControl removeDeviceForAddress:&joys[i].addr];
i++;
}
myosd_num_of_joys=0;
bt_send_cmd(&btstack_set_power_mode, HCI_POWER_OFF );
bt_close();
activated= false;
btOK = false;
}
}
@end

View File

@ -64,10 +64,10 @@ typedef void (*btstack_packet_handler_t) (uint8_t packet_type, uint16_t channel,
void bt_use_tcp(const char * address, uint16_t port);
// init BTstack library
int bt_open();
int bt_open(void);
// stop using BTstack library
int bt_close();
int bt_close(void);
// send hci cmd packet
int bt_send_cmd(const hci_cmd_t *cmd, ...);
@ -79,6 +79,7 @@ btstack_packet_handler_t bt_register_packet_handler(btstack_packet_handler_t han
void bt_send_acl(uint8_t * data, uint16_t len);
void bt_send_l2cap(uint16_t local_cid, uint8_t *data, uint16_t len);
void bt_send_rfcomm(uint16_t rfcom_cid, uint8_t *data, uint16_t len);
#if defined __cplusplus
}

View File

@ -53,13 +53,23 @@ extern "C" {
// extension for client/server communication
#define DAEMON_EVENT_PACKET 0x05
// L2CAP data
#define L2CAP_DATA_PACKET 0x06
// RFCOMM data
#define RFCOMM_DATA_PACKET 0x07
#define RFCOMM_DATA_PACKET 0x07
// Attribute protocol data
#define ATT_DATA_PACKET 0x08
// Security Manager protocol data
#define SM_DATA_PACKET 0x09
// debug log messages
#define LOG_MESSAGE_PACKET 0xfc
// Fixed PSM numbers
#define PSM_SDP 0x01
#define PSM_RFCOMM 0x03
@ -74,7 +84,7 @@ extern "C" {
#define HCI_EVENT_DISCONNECTION_COMPLETE 0x05
#define HCI_EVENT_AUTHENTICATION_COMPLETE_EVENT 0x06
#define HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE 0x07
#define HCI_EVENT_ENCRIPTION_CHANGE 0x08
#define HCI_EVENT_ENCRYPTION_CHANGE 0x08
#define HCI_EVENT_CHANGE_CONNECTION_LINK_KEY_COMPLETE 0x09
#define HCI_EVENT_MASTER_LINK_KEY_COMPLETE 0x0A
#define HCI_EVENT_READ_REMOTE_SUPPORTED_FEATURES_COMPLETE 0x0B
@ -97,12 +107,21 @@ extern "C" {
#define HCI_EVENT_PACKET_TYPE_CHANGED 0x1D
#define HCI_EVENT_INQUIRY_RESULT_WITH_RSSI 0x22
#define HCI_EVENT_EXTENDED_INQUIRY_RESPONSE 0x2F
#define HCI_EVENT_LE_META 0x3E
#define HCI_EVENT_VENDOR_SPECIFIC 0xFF
#define HCI_SUBEVENT_LE_CONNECTION_COMPLETE 0x01
#define HCI_SUBEVENT_LE_ADVERTISING_REPORT 0x02
#define HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE 0x03
#define HCI_SUBEVENT_LE_READ_REMOTE_USED_FEATURES_COMPLETE 0x04
#define HCI_SUBEVENT_LE_LONG_TERM_KEY_REQUEST 0x05
// last used HCI_EVENT in 2.1 is 0x3d
// events 0x50-0x5f are used internally
// BTSTACK DAEMON EVENTS
// events from BTstack for application/client lib
#define BTSTACK_EVENT_STATE 0x60
@ -118,25 +137,61 @@ extern "C" {
// data: system bluetooth on/off (bool)
#define BTSTACK_EVENT_SYSTEM_BLUETOOTH_ENABLED 0x64
// data: event (8), len(8), status (8), address(48), handle (16), psm (16), local_cid(16), remote_cid (16)
// data: event (8), len(8), status (8) == 0, address (48), name (1984 bits = 248 bytes)
#define BTSTACK_EVENT_REMOTE_NAME_CACHED 0x65
// data: discoverable enabled (bool)
#define BTSTACK_EVENT_DISCOVERABLE_ENABLED 0x66
// L2CAP EVENTS
// data: event (8), len(8), status (8), address(48), handle (16), psm (16), local_cid(16), remote_cid (16), local_mtu(16), remote_mtu(16)
#define L2CAP_EVENT_CHANNEL_OPENED 0x70
// data: event (8), len(8), channel (16)
#define L2CAP_EVENT_CHANNEL_CLOSED 0x71
// data: event (8), len(8), status (8), address(48), handle (16), psm (16), local_cid(16), remote_cid (16)
// data: event (8), len(8), address(48), handle (16), psm (16), local_cid(16), remote_cid (16)
#define L2CAP_EVENT_INCOMING_CONNECTION 0x72
// data: event(8), len(8), handle(16)
#define L2CAP_EVENT_TIMEOUT_CHECK 0x73
// data: event(8), len(8), handle(16)
// data: event(8), len(8), local_cid(16), credits(8)
#define L2CAP_EVENT_CREDITS 0x74
// data: event(8), len(8), service_record_handle(32)
#define SDP_SERVICE_REGISTERED 0x80
// data: event(8), len(8), status (8), psm (16)
#define L2CAP_EVENT_SERVICE_REGISTERED 0x75
// RFCOMM EVENTS
// data: event(8), len(8), status (8), address (48), handle (16), server channel(8), rfcomm_cid(16), max frame size(16)
#define RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE 0x80
// data: event(8), len(8), rfcomm_cid(16)
#define RFCOMM_EVENT_CHANNEL_CLOSED 0x81
// data: event (8), len(8), address(48), channel (8), rfcomm_cid (16)
#define RFCOMM_EVENT_INCOMING_CONNECTION 0x82
// data: event (8), len(8), rfcommid (16), ...
#define RFCOMM_EVENT_REMOTE_LINE_STATUS 0x83
// data: event(8), len(8), rfcomm_cid(16), credits(8)
#define RFCOMM_EVENT_CREDITS 0x84
// data: event(8), len(8), status (8), rfcomm server channel id (8)
#define RFCOMM_EVENT_SERVICE_REGISTERED 0x85
// data: event(8), len(8), status (8), rfcomm server channel id (8)
#define RFCOMM_EVENT_PERSISTENT_CHANNEL 0x86
// data: event(8), len(8), status(8), service_record_handle(32)
#define SDP_SERVICE_REGISTERED 0x90
// last error code in 2.1 is 0x38 - we start with 0x50 for BTstack errors
#define BTSTACK_CONNECTION_TO_BTDAEMON_FAILED 0x50
@ -145,6 +200,8 @@ extern "C" {
#define BTSTACK_ACTIVATION_FAILED_UNKNOWN 0x53
#define BTSTACK_NOT_ACTIVATED 0x54
#define BTSTACK_BUSY 0x55
#define BTSTACK_MEMORY_ALLOC_FAILED 0x56
#define BTSTACK_ACL_BUFFERS_FULL 0x57
// l2cap errors - enumeration by the command that created them
#define L2CAP_COMMAND_REJECT_REASON_COMMAND_NOT_UNDERSTOOD 0x60
@ -161,7 +218,14 @@ extern "C" {
#define L2CAP_CONFIG_RESPONSE_RESULT_UNACCEPTABLE_PARAMS 0x67
#define L2CAP_CONFIG_RESPONSE_RESULT_REJECTED 0x68
#define L2CAP_CONFIG_RESPONSE_RESULT_UNKNOWN_OPTIONS 0x69
#define L2CAP_SERVICE_ALREADY_REGISTERED 0x6a
#define RFCOMM_MULTIPLEXER_STOPPED 0x70
#define RFCOMM_CHANNEL_ALREADY_REGISTERED 0x71
#define RFCOMM_NO_OUTGOING_CREDITS 0x72
#define SDP_HANDLE_ALREADY_REGISTERED 0x80
/**
* Default INQ Mode
*/
@ -171,7 +235,8 @@ extern "C" {
*/
typedef enum {
HCI_POWER_OFF = 0,
HCI_POWER_ON
HCI_POWER_ON,
HCI_POWER_SLEEP
} HCI_POWER_MODE;
/**
@ -181,7 +246,9 @@ typedef enum {
HCI_STATE_OFF = 0,
HCI_STATE_INITIALIZING,
HCI_STATE_WORKING,
HCI_STATE_HALTING
HCI_STATE_HALTING,
HCI_STATE_SLEEPING,
HCI_STATE_FALLING_ASLEEP
} HCI_STATE;
/**
@ -200,9 +267,12 @@ extern const hci_cmd_t btstack_set_acl_capture_mode;
extern const hci_cmd_t btstack_get_version;
extern const hci_cmd_t btstack_get_system_bluetooth_enabled;
extern const hci_cmd_t btstack_set_system_bluetooth_enabled;
extern const hci_cmd_t btstack_set_discoverable;
extern const hci_cmd_t btstack_set_bluetooth_enabled; // only used by btstack config
extern const hci_cmd_t hci_accept_connection_request;
extern const hci_cmd_t hci_authentication_requested;
extern const hci_cmd_t hci_change_connection_link_key;
extern const hci_cmd_t hci_create_connection;
extern const hci_cmd_t hci_create_connection_cancel;
extern const hci_cmd_t hci_delete_stored_link_key;
@ -217,25 +287,64 @@ extern const hci_cmd_t hci_pin_code_request_negative_reply;
extern const hci_cmd_t hci_qos_setup;
extern const hci_cmd_t hci_read_bd_addr;
extern const hci_cmd_t hci_read_buffer_size;
extern const hci_cmd_t hci_read_le_host_supported;
extern const hci_cmd_t hci_read_link_policy_settings;
extern const hci_cmd_t hci_read_link_supervision_timeout;
extern const hci_cmd_t hci_read_local_supported_features;
extern const hci_cmd_t hci_read_num_broadcast_retransmissions;
extern const hci_cmd_t hci_reject_connection_request;
extern const hci_cmd_t hci_remote_name_request;
extern const hci_cmd_t hci_remote_name_request_cancel;
extern const hci_cmd_t hci_reset;
extern const hci_cmd_t hci_role_discovery;
extern const hci_cmd_t hci_set_event_mask;
extern const hci_cmd_t hci_set_connection_encryption;
extern const hci_cmd_t hci_sniff_mode;
extern const hci_cmd_t hci_switch_role_command;
extern const hci_cmd_t hci_write_authentication_enable;
extern const hci_cmd_t hci_write_class_of_device;
extern const hci_cmd_t hci_write_extended_inquiry_response;
extern const hci_cmd_t hci_write_inquiry_mode;
extern const hci_cmd_t hci_write_le_host_supported;
extern const hci_cmd_t hci_write_link_policy_settings;
extern const hci_cmd_t hci_write_link_supervision_timeout;
extern const hci_cmd_t hci_write_local_name;
extern const hci_cmd_t hci_write_num_broadcast_retransmissions;
extern const hci_cmd_t hci_write_page_timeout;
extern const hci_cmd_t hci_write_scan_enable;
extern const hci_cmd_t hci_write_simple_pairing_mode;
extern const hci_cmd_t hci_le_add_device_to_whitelist;
extern const hci_cmd_t hci_le_clear_white_list;
extern const hci_cmd_t hci_le_connection_update;
extern const hci_cmd_t hci_le_create_connection;
extern const hci_cmd_t hci_le_create_connection_cancel;
extern const hci_cmd_t hci_le_encrypt;
extern const hci_cmd_t hci_le_long_term_key_negative_reply;
extern const hci_cmd_t hci_le_long_term_key_request_reply;
extern const hci_cmd_t hci_le_rand;
extern const hci_cmd_t hci_le_read_advertising_channel_tx_power;
extern const hci_cmd_t hci_le_read_buffer_size ;
extern const hci_cmd_t hci_le_read_channel_map;
extern const hci_cmd_t hci_le_read_remote_used_features;
extern const hci_cmd_t hci_le_read_supported_features;
extern const hci_cmd_t hci_le_read_supported_states;
extern const hci_cmd_t hci_le_read_white_list_size;
extern const hci_cmd_t hci_le_receiver_test;
extern const hci_cmd_t hci_le_remove_device_from_whitelist;
extern const hci_cmd_t hci_le_set_advertise_enable;
extern const hci_cmd_t hci_le_set_advertising_data;
extern const hci_cmd_t hci_le_set_advertising_parameters;
extern const hci_cmd_t hci_le_set_event_mask;
extern const hci_cmd_t hci_le_set_host_channel_classification;
extern const hci_cmd_t hci_le_set_random_address;
extern const hci_cmd_t hci_le_set_scan_enable;
extern const hci_cmd_t hci_le_set_scan_parameters;
extern const hci_cmd_t hci_le_set_scan_response_data;
extern const hci_cmd_t hci_le_start_encryption;
extern const hci_cmd_t hci_le_test_end;
extern const hci_cmd_t hci_le_transmitter_test;
extern const hci_cmd_t l2cap_accept_connection;
extern const hci_cmd_t l2cap_create_channel;
extern const hci_cmd_t l2cap_create_channel_mtu;
@ -247,7 +356,25 @@ extern const hci_cmd_t l2cap_unregister_service;
extern const hci_cmd_t sdp_register_service_record;
extern const hci_cmd_t sdp_unregister_service_record;
// accept connection @param bd_addr(48), rfcomm_cid (16)
extern const hci_cmd_t rfcomm_accept_connection;
// create rfcomm channel: @param bd_addr(48), channel (8)
extern const hci_cmd_t rfcomm_create_channel;
// create rfcomm channel: @param bd_addr(48), channel (8), mtu (16), credits (8)
extern const hci_cmd_t rfcomm_create_channel_with_initial_credits;
// decline rfcomm disconnect,@param bd_addr(48), rfcomm cid (16), reason(8)
extern const hci_cmd_t rfcomm_decline_connection;
// disconnect rfcomm disconnect, @param rfcomm_cid(8), reason(8)
extern const hci_cmd_t rfcomm_disconnect;
// register rfcomm service: @param channel(8), mtu (16)
extern const hci_cmd_t rfcomm_register_service;
// register rfcomm service: @param channel(8), mtu (16), initial credits (8)
extern const hci_cmd_t rfcomm_register_service_with_initial_credits;
// unregister rfcomm service, @param service_channel(16)
extern const hci_cmd_t rfcomm_unregister_service;
// request persisten rfcomm channel for service name: serive name (char*)
extern const hci_cmd_t rfcomm_persistent_channel_for_service;
#if defined __cplusplus
}
#endif

View File

@ -54,8 +54,9 @@ int linked_list_empty(linked_list_t * list);
void linked_list_add(linked_list_t * list, linked_item_t *item); // <-- add item to list as first element
void linked_list_add_tail(linked_list_t * list, linked_item_t *item); // <-- add item to list as last element
int linked_list_remove(linked_list_t * list, linked_item_t *item); // <-- remove item from list
linked_item_t * linked_list_get_last_item(linked_list_t * list); // <-- find the last item in the list
void test_linked_list();
void test_linked_list(void);
#if defined __cplusplus
}

View File

@ -37,9 +37,16 @@
#pragma once
//#include "config.h"
#define HAVE_TIME
#include "linked_list.h"
#include <stdint.h>
#ifdef HAVE_TIME
#include <sys/time.h>
#endif
#if defined __cplusplus
extern "C" {
@ -59,27 +66,56 @@ typedef struct data_source {
typedef struct timer {
linked_item_t item;
#ifdef HAVE_TIME
struct timeval timeout; // <-- next timeout
#endif
#ifdef HAVE_TICK
uint32_t timeout; // timeout in system ticks
#endif
void (*process)(struct timer *ts); // <-- do processing
} timer_source_t;
// init must be called before any other run_loop call
void run_loop_init(RUN_LOOP_TYPE type);
// add/remove data_source
void run_loop_add_data_source(data_source_t *dataSource);
int run_loop_remove_data_source(data_source_t *dataSource);
// Set timer based on current time in milliseconds.
void run_loop_set_timer(timer_source_t *a, uint32_t timeout_in_ms);
// set timer based on current time
void run_loop_set_timer(timer_source_t *a, int timeout_in_ms);
// Set callback that will be executed when timer expires.
void run_loop_set_timer_handler(timer_source_t *ts, void (*process)(timer_source_t *_ts));
// add/remove timer_source
// Add/Remove timer source.
void run_loop_add_timer(timer_source_t *timer);
int run_loop_remove_timer(timer_source_t *timer);
// execute configured run_loop
void run_loop_execute();
// Init must be called before any other run_loop call.
// Use RUN_LOOP_EMBEDDED for embedded devices.
void run_loop_init(RUN_LOOP_TYPE type);
// Set data source callback.
void run_loop_set_data_source_handler(data_source_t *ds, int (*process)(data_source_t *_ds));
// Add/Remove data source.
void run_loop_add_data_source(data_source_t *dataSource);
int run_loop_remove_data_source(data_source_t *dataSource);
// Execute configured run loop. This function does not return.
void run_loop_execute(void);
// hack to fix HCI timer handling
#ifdef HAVE_TICK
// Sets how many miliseconds has one tick.
uint32_t embedded_ticks_for_ms(uint32_t time_in_ms);
// Queries the current time in ticks.
uint32_t embedded_get_ticks(void);
#endif
#ifdef EMBEDDED
// Sets an internal flag that is checked in the critical section
// just before entering sleep mode. Has to be called by the interupt
// handler of a data source to signal the run loop that a new data
// is available.
void embedded_trigger(void);
#endif
#if defined __cplusplus
}
#endif

View File

@ -79,30 +79,59 @@ typedef enum {
#define SDP_ClientExecutableURL 0x000b
#define SDP_IconURL 0x000c
#define SDP_AdditionalProtocolDescriptorList 0x000d
#define SDP_SupportedFormatsList 0x0303
// SERVICE CLASSES
#define SDP_OBEXObjectPush 0x1105
#define SDP_OBEXFileTransfer 0x1106
#define SDP_PublicBrowseGroup 0x1002
// PROTOCOLS
#define SDP_SDPProtocol 0x0001
#define SDP_UDPProtocol 0x0002
#define SDP_RFCOMMProtocol 0x0003
#define SDP_OBEXProtocol 0x0008
#define SDP_L2CAPProtocol 0x0100
// OFFSETS FOR LOCALIZED ATTRIBUTES - SDP_LanguageBaseAttributeIDList
#define SDP_Offest_ServiceName 0x0000
#define SDP_Offest_ServiceDescription 0x0001
#define SDP_Offest_ProviderName 0x0002
// OBEX
#define SDP_vCard_2_1 0x01
#define SDP_vCard_3_0 0x02
#define SDP_vCal_1_0 0x03
#define SDP_iCal_2_0 0x04
#define SDP_vNote 0x05
#define SDP_vMessage 0x06
#define SDP_OBEXFileTypeAny 0xFF
#pragma mark DateElement
// MARK: DateElement
void de_dump_data_element(uint8_t * record);
int de_get_len(uint8_t *header);
de_size_t de_get_size_type(uint8_t *header);
de_type_t de_get_element_type(uint8_t *header);
int de_get_header_size(uint8_t * header);
void de_create_sequence(uint8_t *header);
void de_store_descriptor_with_len(uint8_t * header, de_type_t type, de_size_t size, uint32_t len);
uint8_t * de_push_sequence(uint8_t *header);
void de_pop_sequence(uint8_t * parent, uint8_t * child);
void de_add_number(uint8_t *seq, de_type_t type, de_size_t size, uint32_t value);
void de_add_data( uint8_t *seq, de_type_t type, uint16_t size, uint8_t *data);
int de_get_data_size(uint8_t * header);
void de_add_uuid128(uint8_t * seq, uint8_t * uuid);
#pragma mark SDP
int sdp_append_attributes_in_attributeIDList(uint8_t *record, uint8_t *attributeIDList, uint16_t startIndex, uint16_t maxBytes, uint8_t *buffer);
// MARK: SDP
uint16_t sdp_append_attributes_in_attributeIDList(uint8_t *record, uint8_t *attributeIDList, uint16_t startOffset, uint16_t maxBytes, uint8_t *buffer);
uint8_t * sdp_get_attribute_value_for_attribute_id(uint8_t * record, uint16_t attributeID);
int sdp_record_matches_service_search_pattern(uint8_t *record, uint8_t *serviceSearchPattern);
uint8_t sdp_set_attribute_value_for_attribute_id(uint8_t * record, uint16_t attributeID, uint32_t value);
int sdp_record_matches_service_search_pattern(uint8_t *record, uint8_t *serviceSearchPattern);
int spd_get_filtered_size(uint8_t *record, uint8_t *attributeIDList);
int sdp_filter_attributes_in_attributeIDList(uint8_t *record, uint8_t *attributeIDList, uint16_t startOffset, uint16_t maxBytes, uint16_t *usedBytes, uint8_t *buffer);
void sdp_create_spp_service(uint8_t *service, int service_id, const char *name);
#if defined __cplusplus
}

View File

@ -39,12 +39,13 @@
#pragma once
#include <stdint.h>
#if defined __cplusplus
extern "C" {
#endif
#include <stdint.h>
/**
* @brief hci connection handle type
*/
@ -62,6 +63,13 @@ typedef uint8_t bd_addr_t[BD_ADDR_LEN];
#define LINK_KEY_LEN 16
typedef uint8_t link_key_t[LINK_KEY_LEN];
/**
* @brief The device name type
*/
#define DEVICE_NAME_LEN 248
typedef uint8_t device_name_t[DEVICE_NAME_LEN+1];
// helper for BT little endian format
#define READ_BT_16( buffer, pos) ( ((uint16_t) buffer[pos]) | (((uint16_t)buffer[pos+1]) << 8))
#define READ_BT_24( buffer, pos) ( ((uint32_t) buffer[pos]) | (((uint32_t)buffer[pos+1]) << 8) | (((uint32_t)buffer[pos+2]) << 16))
@ -77,6 +85,10 @@ typedef uint8_t link_key_t[LINK_KEY_LEN];
// check if command complete event for given command
#define COMMAND_COMPLETE_EVENT(event,cmd) ( event[0] == HCI_EVENT_COMMAND_COMPLETE && READ_BT_16(event,3) == cmd.opcode)
#define COMMAND_STATUS_EVENT(event,cmd) ( event[0] == HCI_EVENT_COMMAND_STATUS && READ_BT_16(event,4) == cmd.opcode)
// Code+Len=2, Pkts+Opcode=3; total=5
#define OFFSET_OF_DATA_IN_COMMAND_COMPLETE 5
// ACL Packet
#define READ_ACL_CONNECTION_HANDLE( buffer ) ( READ_BT_16(buffer,0) & 0x0fff)
@ -96,19 +108,19 @@ void net_store_32(uint8_t *buffer, uint16_t pos, uint32_t value);
void hexdump(void *data, int size);
void printUUID(uint8_t *uuid);
void print_bd_addr(bd_addr_t addr);
int sscan_bd_addr(uint8_t * addr_string, bd_addr_t addr);
// @deprecated please use more convenient bd_addr_to_str
void print_bd_addr( bd_addr_t addr);
char * bd_addr_to_str(bd_addr_t addr);
int sscan_bd_addr(uint8_t * addr_string, bd_addr_t addr);
uint8_t crc8_check(uint8_t *data, uint16_t len, uint8_t check_sum);
uint8_t crc8_calc(uint8_t *data, uint16_t len);
#define BD_ADDR_CMP(a,b) memcmp(a,b, BD_ADDR_LEN)
#define BD_ADDR_COPY(dest,src) memcpy(dest,src,BD_ADDR_LEN)
#ifdef EMBEDDED
void bzero(void *s, uint32_t n);
#endif
#if defined __cplusplus
}
#endif

View File

@ -47,7 +47,7 @@
#include "btstack/btstack.h"
#include "wiimote.h"
//int num_of_joys = 0;
int myosd_num_of_joys = 0;
struct wiimote_t joys[4];
extern int g_pref_wii_DZ_value;
#define STICK4WAY (myosd_waysStick == 4 && myosd_inGame)
@ -506,7 +506,6 @@ void calc_joystick_state(struct joystick_t* js, float x, float y);
* @return Returns 1 if handshake was successful, 0 if not.
*/
int classic_ctrl_handshake(struct wiimote_t* wm, struct classic_ctrl_t* cc, byte* data, unsigned short len) {
int i;
int offset = 0;
cc->btns = 0;
@ -581,7 +580,7 @@ int classic_ctrl_handshake(struct wiimote_t* wm, struct classic_ctrl_t* cc, byte
* @param msg The message specified in the event packet.
*/
void classic_ctrl_event(struct classic_ctrl_t* cc, byte* msg) {
int i, lx, ly, rx, ry;
int lx, ly, rx, ry;
byte l, r;
/* decrypt data */
@ -691,200 +690,3 @@ void calc_joystick_state(struct joystick_t* js, float x, float y) {
js->ry = ry;
}
////////////////////////////////////////////////////////////
extern float joy_analog_x[4];
extern float joy_analog_y[4];
int iOS_wiimote_check (struct wiimote_t *wm)
{
return wm->btns;
}
#if 0
joy_analog_x[wm->unid]=0.0f;
joy_analog_y[wm->unid]=0.0f;
if (1) {
if (wm->exp.type == EXP_CLASSIC) {
float deadZone;
switch(g_pref_wii_DZ_value)
{
case 0: deadZone = 0.12f;break;
case 1: deadZone = 0.15f;break;
case 2: deadZone = 0.17f;break;
case 3: deadZone = 0.2f;break;
case 4: deadZone = 0.3f;break;
case 5: deadZone = 0.4f;break;
}
//printf("deadzone %f\n",deadZone);
struct classic_ctrl_t* cc = (classic_ctrl_t*)&wm->exp.classic;
if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_ZL)) joyExKey |= MYOSD_R1;
if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_B)) joyExKey |= MYOSD_X;
if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_Y)) joyExKey |= MYOSD_A;
if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_A)) joyExKey |= MYOSD_B;
if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_X)) joyExKey |= MYOSD_Y;
if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_ZR)) joyExKey |= MYOSD_L1;
if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_UP)){
if(!STICK2WAY &&
!(STICK4WAY && (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_LEFT) ||
(IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_RIGHT)))))
joyExKey |= MYOSD_UP;
}
if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_DOWN)){
if(!STICK2WAY &&
!(STICK4WAY && (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_LEFT) ||
(IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_RIGHT)))))
joyExKey |= MYOSD_DOWN;
}
if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_LEFT)) joyExKey |= MYOSD_LEFT;
if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_RIGHT)) joyExKey |= MYOSD_RIGHT;
if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_FULL_L)) joyExKey |= MYOSD_L1;
if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_MINUS)) joyExKey |= MYOSD_SELECT;
if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_HOME)) {//myosd_exitGame = 0;usleep(50000);
myosd_exitGame = 1;}
if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_PLUS)) joyExKey |= MYOSD_START;
if (IS_PRESSED(cc, CLASSIC_CTRL_BUTTON_FULL_R)) joyExKey |= MYOSD_R1;
if(cc->ljs.mag >= deadZone)
{
joy_analog_x[wm->unid] = ( cc->ljs.rx > 1.0 ) ? 1.0 : ( cc->ljs.rx < -1.0 ) ? -1.0 : cc->ljs.rx;
joy_analog_y[wm->unid] = ( cc->ljs.ry > 1.0 ) ? 1.0 : ( cc->ljs.ry < -1.0 ) ? -1.0 : cc->ljs.ry;
float v = cc->ljs.ang;
if(STICK2WAY)
{
if( v < 180){
joyExKey |= MYOSD_RIGHT;
//printf("Right\n");
}
else if ( v >= 180){
joyExKey |= MYOSD_LEFT;
//printf("Left\n");
}
}
else if(STICK4WAY)
{
if(v >= 315 || v < 45){
joyExKey |= MYOSD_UP;
//printf("Up\n");
}
else if (v >= 45 && v < 135){
joyExKey |= MYOSD_RIGHT;
//printf("Right\n");
}
else if (v >= 135 && v < 225){
joyExKey |= MYOSD_DOWN;
//printf("Down\n");
}
else if (v >= 225 && v < 315){
joyExKey |= MYOSD_LEFT;
//printf("Left\n");
}
}
else
{
if( v >= 330 || v < 30){
joyExKey |= MYOSD_UP;
//printf("Up\n");
}
else if ( v >= 30 && v <60 ) {
joyExKey |= MYOSD_UP;joyExKey |= MYOSD_RIGHT;
//printf("UpRight\n");
}
else if ( v >= 60 && v < 120 ){
joyExKey |= MYOSD_RIGHT;
//printf("Right\n");
}
else if ( v >= 120 && v < 150 ){
joyExKey |= MYOSD_RIGHT;joyExKey |= MYOSD_DOWN;
//printf("RightDown\n");
}
else if ( v >= 150 && v < 210 ){
joyExKey |= MYOSD_DOWN;
//printf("Down\n");
}
else if ( v >= 210 && v < 240 ){
joyExKey |= MYOSD_DOWN;joyExKey |= MYOSD_LEFT;
//printf("DownLeft\n");
}
else if ( v >= 240 && v < 300 ){
joyExKey |= MYOSD_LEFT;
//printf("Left\n");
}
else if ( v >= 300 && v < 330 ){
joyExKey |= MYOSD_LEFT;
joyExKey |= MYOSD_UP;
//printf("LeftUp\n");
}
}
}
if(cc->rjs.mag >= deadZone)
{
float v = cc->rjs.ang;
if( v >= 330 || v < 30){
joyExKey |= MYOSD_Y;
//printf("Y\n");
}
else if ( v >= 30 && v <60 ) {
joyExKey |= MYOSD_Y;joyExKey |= MYOSD_B;
//printf("Y B\n");
}
else if ( v >= 60 && v < 120 ){
joyExKey |= MYOSD_B;
//printf("B\n");
}
else if ( v >= 120 && v < 150 ){
joyExKey |= MYOSD_B;joyExKey |= MYOSD_X;
//printf("B X\n");
}
else if ( v >= 150 && v < 210 ){
joyExKey |= MYOSD_X;
//printf("X\n");
}
else if ( v >= 210 && v < 240 ){
joyExKey |= MYOSD_X;joyExKey |= MYOSD_A;
//printf("X A\n");
}
else if ( v >= 240 && v < 300 ){
joyExKey |= MYOSD_A;
//printf("A\n");
}
else if ( v >= 300 && v < 330 ){
joyExKey |= MYOSD_A;joyExKey |= MYOSD_Y;
//printf("A Y\n");
}
}
/*
printf("classic L button pressed: %f\n", cc->l_shoulder);
printf("classic R button pressed: %f\n", cc->r_shoulder);
printf("classic left joystick angle: %f\n", cc->ljs.ang);
printf("classic left joystick magnitude: %f\n", cc->ljs.mag);
printf("classic left joystick rx: %f\n", cc->ljs.rx);
printf("classic left joystick ry: %f\n", cc->ljs.ry);
printf("classic right joystick angle: %f\n", cc->rjs.ang);
printf("classic right joystick magnitude: %f\n", cc->rjs.mag);
printf("classic right rx: %f\n", cc->rjs.rx);
printf("classic right ry: %f\n", cc->rjs.ry);
*/
}
return joyExKey;
} else {
joyExKey = 0;
return joyExKey;
}
}
#endif

View File

@ -276,8 +276,6 @@ extern "C" {
extern int myosd_num_of_joys;
//devuelve un int haciendo polling de lo guardado en el wiimote
int iOS_wiimote_check (struct wiimote_t *wm);
int wiimote_remove(uint16_t source_cid, bd_addr_t *addr);
struct wiimote_t* wiimote_get_by_source_cid(uint16_t source_cid);
int wiimote_handshake(struct wiimote_t* wm, byte event, byte* data, unsigned short len);

View File

@ -353,7 +353,7 @@
- (IBAction)showWiiRemoteConfig
{
#ifdef WIIMOTE
[WiiMoteHelper startwiimote:_navigator];
[[WiiMoteHelper get] showDiscovery];
#endif
}

View File

@ -165,10 +165,10 @@ static int16_t ios_input_state(void *data, const struct retro_keybind **binds, u
case RETRO_DEVICE_ID_JOYPAD_B: return IS_PRESSED(wm, WIIMOTE_BUTTON_ONE);
case RETRO_DEVICE_ID_JOYPAD_START: return IS_PRESSED(wm, WIIMOTE_BUTTON_PLUS);
case RETRO_DEVICE_ID_JOYPAD_SELECT: return IS_PRESSED(wm, WIIMOTE_BUTTON_MINUS);
case RETRO_DEVICE_ID_JOYPAD_UP: return IS_PRESSED(wm, WIIMOTE_BUTTON_UP);
case RETRO_DEVICE_ID_JOYPAD_DOWN: return IS_PRESSED(wm, WIIMOTE_BUTTON_DOWN);
case RETRO_DEVICE_ID_JOYPAD_LEFT: return IS_PRESSED(wm, WIIMOTE_BUTTON_LEFT);
case RETRO_DEVICE_ID_JOYPAD_RIGHT: return IS_PRESSED(wm, WIIMOTE_BUTTON_RIGHT);
case RETRO_DEVICE_ID_JOYPAD_UP: return IS_PRESSED(wm, WIIMOTE_BUTTON_RIGHT);
case RETRO_DEVICE_ID_JOYPAD_DOWN: return IS_PRESSED(wm, WIIMOTE_BUTTON_LEFT);
case RETRO_DEVICE_ID_JOYPAD_LEFT: return IS_PRESSED(wm, WIIMOTE_BUTTON_UP);
case RETRO_DEVICE_ID_JOYPAD_RIGHT: return IS_PRESSED(wm, WIIMOTE_BUTTON_DOWN);
}
}
#endif