Skip to content

Commit 8893380

Browse files
committed
1. Revised the BLE command queue to use one queue per BLE device
2. This allows parallel use of BLE devices in an app
1 parent ae8fac7 commit 8893380

File tree

2 files changed

+147
-58
lines changed

2 files changed

+147
-58
lines changed

src/ios/BLECentralPlugin.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@
3434
NSMutableDictionary *stopNotificationCallbacks;
3535
NSMutableDictionary *connectCallbackLatches;
3636
NSMutableDictionary *readRSSICallbacks;
37+
NSMutableArray *commandQueue;
38+
NSMutableDictionary * commandQueueDict;
39+
NSMutableDictionary *bleProcessing;
40+
3741
}
3842

3943
@property (strong, nonatomic) NSMutableSet *peripherals;

src/ios/BLECentralPlugin.m

Lines changed: 143 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,9 @@ @implementation BLECentralPlugin
5454
}
5555
*/
5656

57-
NSMutableArray *commandQueue;
58-
Boolean bleProcessing = false;
57+
58+
59+
5960

6061

6162
- (void)pluginInitialize {
@@ -65,7 +66,9 @@ - (void)pluginInitialize {
6566

6667
[super pluginInitialize];
6768

68-
commandQueue = [NSMutableArray array];
69+
// Important note: The key to the commandQueueDict and bleProcessing is the peripheral UUID
70+
commandQueueDict = [NSMutableDictionary new];
71+
bleProcessing = [NSMutableDictionary new];
6972
peripherals = [NSMutableSet set];
7073
manager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
7174

@@ -93,40 +96,68 @@ - (void)pluginInitialize {
9396
#pragma mark - Cordova Plugin Methods
9497

9598

96-
-(CDVInvokedUrlCommand*)commandQueuePop {
97-
@synchronized(commandQueue)
98-
{
99-
if ([commandQueue count] == 0) {
100-
return nil;
99+
-(CDVInvokedUrlCommand*)commandQueuePop:(CDVInvokedUrlCommand*)anObject {
100+
NSString *key = [self getKeyFromCommand:anObject];
101+
return [self commandQueuePopKey:key];
102+
}
103+
-(CDVInvokedUrlCommand*)commandQueuePopKey:(NSString *)key {
104+
@synchronized(commandQueueDict)
105+
{
106+
[self setCurrentCommandQueueByKey: key];
107+
108+
@synchronized(commandQueue)
109+
{
110+
if ([commandQueue count] == 0) {
111+
return nil;
112+
}
113+
114+
id queueObject = [commandQueue objectAtIndex:0];
115+
116+
[commandQueue removeObjectAtIndex:0];
117+
118+
return queueObject;
119+
}
101120
}
102-
103-
id queueObject = [commandQueue objectAtIndex:0];
104-
105-
[commandQueue removeObjectAtIndex:0];
106-
107-
return queueObject;
108-
}
109121
}
110-
111-
-(CDVInvokedUrlCommand*)commandQueuePoll{
112-
@synchronized(commandQueue)
113-
{
114-
if ([commandQueue count] == 0) {
115-
return nil;
122+
-(CDVInvokedUrlCommand*)commandQueuePollKey:(NSString *)key {
123+
124+
@synchronized(commandQueueDict)
125+
{
126+
[self setCurrentCommandQueueByKey: key];
127+
128+
@synchronized(commandQueue)
129+
{
130+
131+
if ([commandQueue count] == 0) {
132+
return nil;
133+
}
134+
135+
id queueObject =[commandQueue objectAtIndex:0];
136+
137+
return queueObject;
138+
}
116139
}
140+
}
117141

118-
id queueObject =[commandQueue objectAtIndex:0];
119-
120-
return queueObject;
121-
}
142+
-(CDVInvokedUrlCommand*)commandQueuePoll:(CDVInvokedUrlCommand*)anObject {
143+
144+
NSString *key = [self getKeyFromCommand:anObject];
145+
return [self commandQueuePollKey:key];
122146
}
123147

124148
// Add to the tail of the queue
125149
-(void)commandQueuePush:(CDVInvokedUrlCommand*)anObject {
126-
@synchronized(commandQueue)
127-
{
128-
[commandQueue addObject:anObject];
129-
}
150+
151+
@synchronized(commandQueueDict)
152+
{
153+
[self setCurrentCommandQueue: anObject];
154+
155+
@synchronized(commandQueue)
156+
{
157+
158+
[commandQueue addObject:anObject];
159+
}
160+
}
130161
}
131162

132163

@@ -332,13 +363,36 @@ void dispatch_after_delay_on_background_queue(float delayInSeconds, dispatch_blo
332363
dispatch_after_delay(delayInSeconds, queue, block);
333364
}
334365

366+
- (NSString *)getKeyFromCommand:(CDVInvokedUrlCommand*) command {
367+
BLECommandContext *context = [self getData:command prop:CBCharacteristicPropertyWrite];
368+
CBPeripheral *peripheral = [context peripheral];
369+
NSString *key = [self keyForPeripheral: peripheral ];
370+
371+
return key;
372+
}
373+
374+
- (void)setCurrentCommandQueue: (CDVInvokedUrlCommand*)command {
375+
376+
NSString *key = [self getKeyFromCommand:command];
377+
[self setCurrentCommandQueueByKey:key];
378+
379+
}
380+
381+
- (void)setCurrentCommandQueueByKey: (NSString *) key{
382+
383+
commandQueue = [commandQueueDict objectForKey: key];
384+
if (!commandQueue) {
385+
[commandQueueDict setObject: [NSMutableArray array] forKey: key];
386+
commandQueue = [commandQueueDict objectForKey: key];
387+
}
388+
389+
}
390+
335391
- (void)queueCommand:(CDVInvokedUrlCommand*)command {
336392

337393
[self commandQueuePush: command];
394+
[self processCommands: command];
338395

339-
if (!bleProcessing) {
340-
[self processCommands];
341-
}
342396
}
343397

344398
- (void)read:(CDVInvokedUrlCommand*)command {
@@ -359,42 +413,61 @@ - (void)stopNotification:(CDVInvokedUrlCommand*)command {
359413
[self queueCommand:command];
360414
}
361415

362-
- (void)processCommands {
363-
364-
if (bleProcessing) { return; }
365-
366-
367-
CDVInvokedUrlCommand* command = [self commandQueuePoll];
368-
416+
- (void)processCommandsKey:(NSString *)key {
417+
418+
[self setCurrentCommandQueueByKey: key];
419+
420+
421+
422+
if ( [[bleProcessing objectForKey: key] isEqualToString: @"true"]) { return; }
423+
424+
CDVInvokedUrlCommand* command = [self commandQueuePollKey: key];
425+
369426
if (command != nil) {
370-
371-
bleProcessing = true;
427+
428+
429+
[bleProcessing setObject: @"true" forKey: key];
430+
372431
if ([command.methodName isEqualToString: @"read"]) {
373-
[self readEx: command];
432+
[self readEx: command];
374433
} else if ([command.methodName isEqualToString: @"write"]) {
375-
[self writeEx: command];
434+
[self writeEx: command];
376435
} else if ([command.methodName isEqualToString: @"writeWithoutResponse"]) {
377-
[self writeWithoutResponseEx: command];
436+
[self writeWithoutResponseEx: command];
378437
} else if ([command.methodName isEqualToString: @"startNotification"]) {
379438
[self startNotificationEx: command];
380439
} else if ([command.methodName isEqualToString: @"stopNotification"]) {
381440
[self stopNotificationEx: command];
382441
} else {
383-
// this shouldn't happen
384-
bleProcessing = false;
442+
// this shouldn't happen
443+
444+
[bleProcessing setObject: @"false" forKey: key];
385445
NSLog(@"Skipping unknown command in process commands");
386446
}
387447
}
448+
449+
}
450+
451+
- (void)processCommands:(CDVInvokedUrlCommand*)commandKey {
388452

453+
NSString *key = [self getKeyFromCommand:commandKey];
454+
[self processCommandsKey: key];
455+
389456
}
390457

391-
- (void )commandCompleted {
392-
NSLog(@"Processing Complete");
393-
CDVInvokedUrlCommand* command = [self commandQueuePop] ; // Pop the last command and process the next one.
394-
bleProcessing = false;
395-
[self processCommands];
458+
- (void )commandCompleted: (CDVInvokedUrlCommand*)commandKey {
459+
NSString *key = [self getKeyFromCommand:commandKey];
460+
[self commandCompletedKey:key];
396461
}
397462

463+
- (void )commandCompletedKey: (NSString *)key {
464+
NSLog(@"Processing Complete");
465+
CDVInvokedUrlCommand* command = [self commandQueuePopKey: key ]; // Pop the last command and process the next one.
466+
[bleProcessing setObject: @"false" forKey: key];
467+
[self processCommandsKey: key];
468+
}
469+
470+
398471

399472
#ifndef ADD_DELAYS
400473

@@ -591,7 +664,7 @@ - (void)writeWithoutResponseEx:(CDVInvokedUrlCommand*)command {
591664
}
592665
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
593666
}
594-
[self commandCompleted]; // Done in onWrite
667+
[self commandCompleted: command]; // Done in onWrite
595668

596669
});
597670
// dispatch_release(queue); // release the thread if its one of ours
@@ -614,7 +687,7 @@ - (void)writeWithoutResponseEx:(CDVInvokedUrlCommand*)command {
614687
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"message was null"];
615688
}
616689
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
617-
[self commandCompleted];
690+
[self commandCompleted: command];
618691
}
619692

620693
}
@@ -1074,14 +1147,14 @@ - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(C
10741147
NSString *key = [self keyForPeripheral: peripheral andCharacteristic:characteristic];
10751148
NSString *notifyCallbackId = [notificationCallbacks objectForKey:key];
10761149

1150+
//This is for async notifies
10771151
if (notifyCallbackId) {
10781152
NSData *data = characteristic.value; // send RAW data to Javascript
10791153

10801154
CDVPluginResult *pluginResult = nil;
10811155
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArrayBuffer:data];
10821156
[pluginResult setKeepCallbackAsBool:TRUE]; // keep for notification
10831157
[self.commandDelegate sendPluginResult:pluginResult callbackId:notifyCallbackId];
1084-
// [self commandCompleted]; This is for async notifies
10851158
}
10861159

10871160
NSString *readCallbackId = [readCallbacks objectForKey:key];
@@ -1092,7 +1165,7 @@ - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(C
10921165
CDVPluginResult *pluginResult = nil;
10931166
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArrayBuffer:data];
10941167
[self.commandDelegate sendPluginResult:pluginResult callbackId:readCallbackId];
1095-
// [self commandCompleted];
1168+
10961169

10971170
[readCallbacks removeObjectForKey:key];
10981171
}
@@ -1128,7 +1201,7 @@ - (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForChara
11281201
[self.commandDelegate sendPluginResult:pluginResult callbackId:notificationCallbackId];
11291202

11301203
}
1131-
[self commandCompleted];
1204+
[self commandCompletedKey: [self keyForPeripheral: peripheral] ];
11321205

11331206
}
11341207

@@ -1154,7 +1227,7 @@ - (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CB
11541227
[writeCallbacks removeObjectForKey:key];
11551228

11561229
}
1157-
[self commandCompleted];
1230+
[self commandCompletedKey: [self keyForPeripheral: peripheral] ];
11581231
}
11591232

11601233
- (void)peripheralDidUpdateRSSI:(CBPeripheral*)peripheral error:(NSError*)error {
@@ -1178,7 +1251,7 @@ - (void)peripheral:(CBPeripheral*)peripheral didReadRSSI:(NSNumber*)rssi error:(
11781251
}
11791252
[self.commandDelegate sendPluginResult:pluginResult callbackId: readRSSICallbackId];
11801253
[readRSSICallbacks removeObjectForKey:readRSSICallbackId];
1181-
[self commandCompleted];
1254+
[self commandCompletedKey: [self keyForPeripheral: peripheral] ];
11821255
}
11831256
}
11841257

@@ -1417,6 +1490,18 @@ -(NSString *) keyForPeripheral: (CBPeripheral *)peripheral andCharacteristic:(CB
14171490
return [NSString stringWithFormat:@"%@|%@", [peripheral uuidAsString], [characteristic UUID]];
14181491
}
14191492

1493+
-(NSString *) keyForPeripheral: (CBPeripheral *)peripheral {
1494+
return [NSString stringWithFormat:@"%@", [peripheral uuidAsString]];
1495+
}
1496+
1497+
// Return just the peripheralKey from a key with peripheral UUID and characteristic
1498+
-(NSString *) keyFromComplexKey: (NSString *)inKey {
1499+
NSArray *parts = [inKey componentsSeparatedByString: @"|"];
1500+
1501+
return parts[0];
1502+
1503+
}
1504+
14201505
#pragma mark - util
14211506

14221507
- (NSString*) centralManagerStateToString: (int)state

0 commit comments

Comments
 (0)