-
Notifications
You must be signed in to change notification settings - Fork 0
/
LXCBPeripheralServer.m
executable file
·222 lines (178 loc) · 6.49 KB
/
LXCBPeripheralServer.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
#import <CoreBluetooth/CoreBluetooth.h>
#import "LXCBPeripheralServer.h"
#ifndef LXCBLog
# define LXCBLog NSLog
#endif
@interface LXCBPeripheralServer () <CBPeripheralManagerDelegate,UIAlertViewDelegate>
@property(nonatomic, strong) CBPeripheralManager *peripheral;
@property(nonatomic, strong) CBMutableCharacteristic *characteristic;
@property(nonatomic, assign) BOOL serviceRequiresRegistration;
@property(nonatomic, strong) CBMutableService *service;
@property(nonatomic, strong) NSData *pendingData;
@end
@implementation LXCBPeripheralServer
+ (BOOL)isBluetoothSupported {
// Only for iOS 6.0
if (NSClassFromString(@"CBPeripheralManager") == nil) {
return NO;
}
// TODO: Make a check to see if the CBPeripheralManager is in unsupported state.
return YES;
}
- (id)init {
return [self initWithDelegate:nil];
}
- (id)initWithDelegate:(id<LXCBPeripheralServerDelegate>)delegate {
self = [super init];
if (self) {
self.peripheral =
[[CBPeripheralManager alloc] initWithDelegate:self queue:nil];
self.delegate = delegate;
}
return self;
}
#pragma mark -
- (void)enableService {
// If the service is already registered, we need to re-register it again.
if (self.service) {
[self.peripheral removeService:self.service];
}
// Create a BTLE Peripheral Service and set it to be the primary. If it
// is not set to the primary, it will not be found when the app is in the
// background.
self.service = [[CBMutableService alloc]
initWithType:self.serviceUUID primary:YES];
// Set up the characteristic in the service. This characteristic is only
// readable through subscription (CBCharacteristicsPropertyNotify) and has
// no default value set.
//
// There is no need to set the permission on characteristic.
self.characteristic =
[[CBMutableCharacteristic alloc]
initWithType:self.characteristicUUID
properties:CBCharacteristicPropertyNotify
value:nil
permissions:0];
// Assign the characteristic.
self.service.characteristics =
[NSArray arrayWithObject:self.characteristic];
// Add the service to the peripheral manager.
[self.peripheral addService:self.service];
}
- (void)disableService {
[self.peripheral removeService:self.service];
self.service = nil;
[self stopAdvertising];
}
// Called when the BTLE advertisments should start. We don't take down
// the advertisments unless the user switches us off.
- (void)startAdvertising {
if (self.peripheral.isAdvertising) {
[self.peripheral stopAdvertising];
}
NSDictionary *advertisment = @{
CBAdvertisementDataServiceUUIDsKey : @[self.serviceUUID, [CBUUID UUIDWithString:@"1234"]],
CBAdvertisementDataIsConnectable : @"0",
CBAdvertisementDataLocalNameKey: self.serviceName,
CBAdvertisementDataSolicitedServiceUUIDsKey : @[self.serviceUUID, [CBUUID UUIDWithString:@"1234"]]
};
[self.peripheral startAdvertising:advertisment];
}
- (void)stopAdvertising {
[self.peripheral stopAdvertising];
}
- (BOOL)isAdvertising {
return [self.peripheral isAdvertising];
}
#pragma mark -
- (void)sendToSubscribers:(NSData *)data {
if (self.peripheral.state != CBPeripheralManagerStatePoweredOn) {
LXCBLog(@"sendToSubscribers: peripheral not ready for sending state: %d", self.peripheral.state);
return;
}
BOOL success = [self.peripheral updateValue:data
forCharacteristic:self.characteristic
onSubscribedCentrals:nil];
if (!success) {
LXCBLog(@"Failed to send data, buffering data for retry once ready.");
self.pendingData = data;
return;
}
}
- (void)applicationDidEnterBackground {
// Deliberately continue advertising so that it still remains discoverable.
}
- (void)applicationWillEnterForeground {
NSLog(@"applicationWillEnterForeground.");
}
#pragma mark - CBPeripheralManagerDelegate
- (void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(NSError *)error {
// As soon as the service is added, we should start advertising.
[self startAdvertising];
}
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral {
switch (peripheral.state) {
case CBPeripheralManagerStatePoweredOn:
NSLog(@"peripheralStateChange: Powered On");
// As soon as the peripheral/bluetooth is turned on, start initializing
// the service.
[self enableService];
break;
case CBPeripheralManagerStatePoweredOff: {
NSLog(@"peripheralStateChange: Powered Off");
[self disableService];
self.serviceRequiresRegistration = YES;
break;
}
case CBPeripheralManagerStateResetting: {
NSLog(@"peripheralStateChange: Resetting");
self.serviceRequiresRegistration = YES;
break;
}
case CBPeripheralManagerStateUnauthorized: {
NSLog(@"peripheralStateChange: Deauthorized");
[self disableService];
self.serviceRequiresRegistration = YES;
break;
}
case CBPeripheralManagerStateUnsupported: {
NSLog(@"peripheralStateChange: Unsupported");
self.serviceRequiresRegistration = YES;
// TODO: Give user feedback that Bluetooth is not supported.
break;
}
case CBPeripheralManagerStateUnknown:
NSLog(@"peripheralStateChange: Unknown");
break;
default:
break;
}
}
- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic {
NSLog(@"did subscribe to char");
LXCBLog(@"didSubscribe: %@", characteristic.UUID);
LXCBLog(@"didSubscribe: - Central: %@", central.UUID);
[self.delegate peripheralServer:self centralDidSubscribe:central];
}
- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central
didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic {
LXCBLog(@"didUnsubscribe: %@", central.UUID);
[self.delegate peripheralServer:self centralDidUnsubscribe:central];
}
- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral
error:(NSError *)error {
if (error) {
LXCBLog(@"didStartAdvertising: Error: %@", error);
return;
}
LXCBLog(@"didStartAdvertising");
}
- (void)peripheralManagerIsReadyToUpdateSubscribers:(CBPeripheralManager *)peripheral {
LXCBLog(@"isReadyToUpdateSubscribers");
if (self.pendingData) {
NSData *data = [self.pendingData copy];
self.pendingData = nil;
[self sendToSubscribers:data];
}
}
@end