-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathWiiRemoteDiscovery.m
197 lines (158 loc) · 5.12 KB
/
WiiRemoteDiscovery.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
//
// WiiRemoteDiscovery.m
// DarwiinRemote
//
// Created by Ian Rickard on 12/9/06.
// Copyright 2006 __MyCompanyName__. All rights reserved.
//
#import <IOBluetooth/objc/IOBluetoothDevice.h>
#import "WiiRemoteDiscovery.h"
@implementation WiiRemoteDiscovery
- (id) init
{
self = [super init];
if (self != nil) {
// cam: calling IOBluetoothLocalDeviceAvailable has two advantages:
// 1. it sets up a event source in the run loop (bug for C version of the bluetooth api )
// 2. it checks for the availability of the BT hardware
if (IOBluetoothLocalDeviceAvailable () == FALSE)
{
[self release];
self = nil;
[NSException raise:NSGenericException format:@"Bluetooth hardware not available"];
}
}
return self;
}
+ (WiiRemoteDiscovery*) discoveryWithDelegate:(id) delegate
{
// cam: when using this convention, we must autorelease the returned object
return [[[WiiRemoteDiscovery alloc] initWithDelegate:delegate] autorelease];
}
- (void) dealloc
{
NSLogDebug (@"Wiimote Discovery released");
[super dealloc];
}
- (id) delegate
{
return _delegate;
}
- (void) setDelegate:(id) delegate
{
// only retain a shallow reference to the delegate, could be problematic if the delegate went to be
// dealloced, but in the most general case, the delegate 'owns' the WiiRemoteDiscovery
_delegate = delegate;
}
- (IOReturn) start
{
// cam: check everytime the presence of the bluetooth hardware,
// we don't know if the user has not turned it off meanwhile
if (IOBluetoothLocalDeviceAvailable () == FALSE)
return kIOReturnNotAttached;
// if we are currently discovering, we can't start a new discovery right now.
if ([self isDiscovering])
return kIOReturnSuccess;
if (!_delegate) {
NSLog (@"Warning: starting WiiRemoteDiscovery without delegate set");
}
// to start all over again, first stop the discovery
[self close];
// setup the inquiry for best performance and results, ie:
// limit the serach in time
// limit the serach in quality
// don't update the name of the devices, this is useless
// the returned inquiry is autoreleased, we will have to retain it if we decide to keep it
_inquiry = [IOBluetoothDeviceInquiry inquiryWithDelegate:self];
[_inquiry setInquiryLength:20];
[_inquiry setSearchCriteria:kBluetoothServiceClassMajorAny majorDeviceClass:0x05 minorDeviceClass:0x01];
[_inquiry setUpdateNewDeviceNames:NO];
IOReturn status = [_inquiry start];
if (status == kIOReturnSuccess) {
[_inquiry retain];
} else {
// not likely to happen, but we handle it anyway
NSLog (@"Error: Inquiry did not start, error %d", status);
[_inquiry setDelegate:nil];
_inquiry = nil;
}
return status;
}
- (IOReturn) stop
{
return [_inquiry stop];
}
- (IOReturn) close
{
IOReturn ret = kIOReturnSuccess;
ret = [_inquiry stop];
if (ret != kIOReturnNotPermitted)
LogIOReturn (ret);
[_inquiry setDelegate:nil];
[_inquiry release];
_inquiry = nil;
NSLogDebug (@"Discovery closed");
return ret;
}
- (BOOL) isDiscovering
{
return _isDiscovering;
}
- (void) setIsDiscovering:(BOOL) flag
{
[self willChangeValueForKey:@"isDiscovering"];
_isDiscovering = flag;
[self didChangeValueForKey:@"isDiscovering"];
}
#pragma mark -
#pragma mark IOBluetoothDeviceInquiry delegates
- (void) deviceInquiryStarted:(IOBluetoothDeviceInquiry*) sender
{
// this delegate method is called only when the search actually started
// it is important not to start another inquiry at the same time, cf apple docs
[self setIsDiscovering:YES];
}
- (void) deviceInquiryDeviceFound:(IOBluetoothDeviceInquiry *) sender
device:(IOBluetoothDevice *) device
{
// here we limit the search to only one device, we could search for more, but it is not necessary.
// note: never try to connect to the wiimote while the inquiry is still running! (cf apple docs)
[_inquiry stop];
}
- (void) deviceInquiryComplete:(IOBluetoothDeviceInquiry*) sender
error:(IOReturn) error
aborted:(BOOL) aborted
{
// the inquiry has completed, we can now process what we have found
[self setIsDiscovering:NO];
// unlikely to be called, but handle it anyway
if ((error != kIOReturnSuccess) && !aborted) {
[_delegate WiiRemoteDiscoveryError:error];
return;
}
// tell our delegate that we are going to connect to the found devices.
// as it takes some time to do it, the delegate could for example display a
// animated hourglass cursor during the connection process.
if ([[_inquiry foundDevices] count])
[_delegate willStartWiimoteConnections];
[self connectToFoundDevices];
}
#pragma mark -
- (void) connectToFoundDevices
{
// use the inquiry foundDevices array to query the found devices
// as we limited the bluetooth search, we can be sure all the items are actually wiimotes.
NSEnumerator * en = [[_inquiry foundDevices] objectEnumerator];
id device = nil;
while ((device = [en nextObject]) != nil) {
WiiRemote * wii = [[[WiiRemote alloc] init] autorelease];
IOReturn ret = [wii connectTo:device];
if (ret == kIOReturnSuccess)
[_delegate WiiRemoteDiscovered:wii];
else
[_delegate WiiRemoteDiscoveryError:ret];
}
// we passed through all devices, clear the search for now
[_inquiry clearFoundDevices];
}
@end