@iotize/device-com-ble.cordova 3.6.2-alpha.2 → 3.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/README.md +174 -174
  2. package/bundles/iotize-device-com-ble.cordova.umd.js.map +1 -1
  3. package/bundles/iotize-device-com-ble.cordova.umd.min.js.map +1 -1
  4. package/esm2015/lib/ble-com-protocol.js.map +1 -1
  5. package/esm2015/lib/cordova-ble-error.js.map +1 -1
  6. package/esm2015/lib/cordova-interface.js.map +1 -1
  7. package/esm2015/lib/cordova-service-adapter.js.map +1 -1
  8. package/esm2015/lib/definitions.js.map +1 -1
  9. package/esm2015/lib/iotize-ble-cordova-plugin.js.map +1 -1
  10. package/esm2015/lib/logger.js.map +1 -1
  11. package/esm2015/lib/scanner.js.map +1 -1
  12. package/esm2015/lib/utility.js.map +1 -1
  13. package/esm2015/public_api.js.map +1 -1
  14. package/fesm2015/iotize-device-com-ble.cordova.js.map +1 -1
  15. package/package.json +1 -1
  16. package/plugin.xml +68 -68
  17. package/src/android/.gradle/6.8.2/fileHashes/fileHashes.lock +0 -0
  18. package/src/android/.gradle/6.8.2/gc.properties +0 -0
  19. package/src/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  20. package/src/android/.gradle/buildOutputCleanup/cache.properties +2 -0
  21. package/src/android/.gradle/checksums/checksums.lock +0 -0
  22. package/src/android/.gradle/configuration-cache/gc.properties +0 -0
  23. package/src/android/.gradle/vcs-1/gc.properties +0 -0
  24. package/src/android/.gradle/vcsWorkingDirs/gc.properties +0 -0
  25. package/src/android/.idea/android.iml +9 -0
  26. package/src/android/.idea/gradle.xml +16 -0
  27. package/src/android/.idea/modules.xml +8 -0
  28. package/src/android/.idea/vcs.xml +6 -0
  29. package/src/android/build.gradle +30 -27
  30. package/src/android/src/ble/BLECom.java +5 -3
  31. package/src/android/src/ble/BLEComError.java +119 -119
  32. package/src/android/src/ble/BLEProtocol.java +874 -874
  33. package/src/android/src/ble/BLEScanner.java +283 -283
  34. package/src/android/src/ble/JSONBuilder.java +83 -83
  35. package/src/android/src/ble/PluginResponse.java +129 -129
  36. package/src/android/src/ble/TapUtility.java +26 -26
  37. package/src/android/src/ble/characteristics/AbstractLwM2MRequestCharacteristic.java +48 -48
  38. package/src/android/src/ble/characteristics/CharacteristicAdapter.java +221 -221
  39. package/src/android/src/ble/characteristics/CharacteristicAdapterCallbacks.java +21 -21
  40. package/src/android/src/ble/characteristics/LwM2M20BytesRequestCharacteristicAdapter.java +161 -161
  41. package/src/android/src/ble/characteristics/LwM2MMTURequestCharacteristicAdapter.java +134 -134
  42. package/src/android/src/ble/commands/BLECommand.java +18 -18
  43. package/src/android/src/ble/commands/CharacteristicOperationCompletedNotifier.java +37 -37
  44. package/src/android/src/ble/commands/CommandCompletedNotifier.java +10 -10
  45. package/src/android/src/ble/commands/DescriptorOperationCompletedNotifier.java +36 -36
  46. package/src/android/src/ble/commands/GattOperationCompletedNotifier.java +28 -28
  47. package/src/ios/BLECom.swift +744 -732
  48. package/src/ios/BLEManager.swift +41 -23
  49. package/src/ios/BLETapPeripheral.swift +5 -10
  50. package/src/ios/CBPeripheralConverter.swift +164 -139
  51. package/src/ios/Queue.swift +114 -108
  52. package/src/windows/IoTizeBLE.pdb +0 -0
  53. package/src/windows/IoTizeBLE.pri +0 -0
  54. package/src/windows/iotize-ble-com.js +159 -159
  55. package/www/plugin.js +1 -1
  56. package/src/android/.gradle/4.8.1/fileHashes/fileHashes.bin +0 -0
  57. package/src/android/.gradle/4.8.1/fileHashes/fileHashes.lock +0 -0
  58. /package/src/android/.gradle/{4.8.1 → 6.8.2}/fileChanges/last-build.bin +0 -0
@@ -1,732 +1,744 @@
1
- //
2
- // Copyright 2018 IoTize SAS Inc. Licensed under the MIT license.
3
- //
4
- // BLECom.swift
5
- // device-com-ble.cordova BLE Cordova Plugin
6
- //
7
-
8
- import Foundation
9
- import CoreBluetooth
10
-
11
- // Custom debug print functions
12
-
13
- public func printBLE(_ object: Any...) {
14
- #if true
15
- for item in object {
16
- Swift.print("BLE:", item)
17
- }
18
- #endif
19
- }
20
-
21
- public func printBLE(_ object: Any) {
22
- #if true
23
- Swift.print("BLE:", object)
24
- #endif
25
- }
26
-
27
-
28
- struct IoTizeBleError: Error {
29
-
30
- let code: Int
31
- let message: String
32
-
33
- init(code: Int, message: String) {
34
- self.code = code
35
- self.message = message
36
- }
37
-
38
- static func BleUnsupported() -> IoTizeBleError { return IoTizeBleError(code:100, message:"Bluetooth is not supported")}
39
- static func BleUnauthorized() -> IoTizeBleError { return IoTizeBleError(code:101, message:"Bluetooth is not authorized")}
40
- static func BlePoweredOff() -> IoTizeBleError { return IoTizeBleError(code:102, message:"Bluetooth is powered off")}
41
- static func BleResetting() -> IoTizeBleError { return IoTizeBleError(code:103, message:"Bluetooth is resetting")}
42
- static func BleUnknown() -> IoTizeBleError { return IoTizeBleError(code:104, message:"Bluetooth is in an unknown state")}
43
-
44
- static func PeripheralConnectionFailed(peripheral: CBPeripheral, error: Error?) -> IoTizeBleError { return IoTizeBleError(code:200, message:"Connection to \(peripheral.name ?? "unknown peripheral") failed: \(error?.localizedDescription ?? "unknown")" )}
45
- static func NoDeviceConnected() -> IoTizeBleError { return IoTizeBleError(code:201, message:"No Device Connected")}
46
-
47
- static func ServiceDiscoveryFailed(peripheral: CBPeripheral) -> IoTizeBleError { return IoTizeBleError(code:300, message:"Failed to discover services for \(peripheral.name ?? "unknown peripheral")" )}
48
- static func CharacteristicsDiscoveryFailed(peripheral: CBPeripheral) -> IoTizeBleError { return IoTizeBleError(code:301, message:"Failed to discover characteristics for \(peripheral.name ?? "unknown peripheral")" )}
49
- static func CharacteristicSPPNotFound(peripheral: CBPeripheral) -> IoTizeBleError { return IoTizeBleError(code:302, message:"Characteristic SPP not found for \(peripheral.name ?? "unknown peripheral")" )}
50
- static func CharacteristicNotifyChangeFailed() -> IoTizeBleError { return IoTizeBleError(code:304, message:"Failed to set notification for characteristic" )}
51
- static func BleVersionIsOld(version: String) -> IoTizeBleError { return IoTizeBleError(code:303, message:"BLE firmware version is too old: \(version)" )}
52
-
53
- static func InvalidWriteData(peripheral: CBPeripheral) -> IoTizeBleError { return IoTizeBleError(code:403, message:"Invalid write data for \(peripheral.name ?? "unknown peripheral")" )}
54
- static func TimedOutRequest(msg: String) -> IoTizeBleError { return IoTizeBleError(code:404, message:"Waiting for response timed out, txData: " + msg )}
55
-
56
- }
57
-
58
- enum CordovaBLEErrorCode: CustomStringConvertible {
59
- case InternalError
60
- case IllegalArgument
61
-
62
- var description: String {
63
- switch self {
64
- case .InternalError: return "CordovaBLEErrorInternalError"
65
- case .IllegalArgument: return "CordovaBLEErrorIllegalArgument"
66
- }
67
- }
68
- }
69
-
70
- struct CordovaBLEError: Error {
71
- var code: CordovaBLEErrorCode
72
- var message: String
73
-
74
- init(_ code: CordovaBLEErrorCode, _ message: String) {
75
- self.code = code
76
- self.message = message
77
- }
78
-
79
- func toJSON() -> [AnyHashable: Any] {
80
- return ["code": code.description, "message": message]
81
- }
82
-
83
- static func InternalError(_ message: String) -> CordovaBLEError {return CordovaBLEError(.InternalError, message)}
84
-
85
- static func IllegalArgument(_ message: String) -> CordovaBLEError {return CordovaBLEError(.IllegalArgument, message)}
86
- }
87
-
88
- struct BLEAction {
89
- var id: String
90
- var action: () -> Void
91
-
92
- init(_ id: String, _ action: @escaping () -> Void) {
93
- self.id = id
94
- self.action = action
95
- }
96
- }
97
-
98
- //Main class handling the plugin functionalities.
99
- @objc(BLECom) class BLECom : CDVPlugin {
100
-
101
- var bleActionQueue: Queue<BLEAction>!
102
-
103
- var isHandlingQueue = false
104
-
105
- var bleController: BLEManager!
106
- var lastError: IoTizeBleError?
107
-
108
- //
109
- override func pluginInitialize(){
110
- bleController = BLEManager()
111
- bleActionQueue = Queue<BLEAction>()
112
- }
113
-
114
- //helper to return an empty response
115
- func sendSuccessWithoutResponse(command: CDVInvokedUrlCommand) {
116
- let pluginResult = CDVPluginResult(status: CDVCommandStatus_OK)
117
-
118
- self.commandDelegate!.send(pluginResult, callbackId: command.callbackId)
119
- if (bleActionQueue.first?.id == command.callbackId) {
120
- removeFromQueue()
121
- }
122
- }
123
-
124
- //helper to return a string
125
- func sendSuccessWithSingleResponse(command: CDVInvokedUrlCommand, result: String){
126
- let pluginResult = CDVPluginResult(
127
- status: CDVCommandStatus_OK,
128
- messageAs: result
129
- )
130
- self.commandDelegate!.send( pluginResult, callbackId: command.callbackId)
131
- if (bleActionQueue.first?.id == command.callbackId) {
132
- removeFromQueue()
133
- }
134
- }
135
-
136
- //helper to return a boolean
137
- private func sendSuccessWithSingleResponse(command: CDVInvokedUrlCommand, result: Bool) {
138
- let pluginResult = CDVPluginResult(
139
- status: CDVCommandStatus_OK,
140
- messageAs: result
141
- )
142
- self.commandDelegate!.send(pluginResult, callbackId: command.callbackId)
143
- if (bleActionQueue.first?.id == command.callbackId) {
144
- removeFromQueue()
145
- }
146
- }
147
-
148
- //helper to return a JSon object
149
- func sendSuccessWithSingleResponse(command: CDVInvokedUrlCommand, result: DiscoveredDeviceType){
150
- let pluginResult = CDVPluginResult(
151
- status: CDVCommandStatus_OK,
152
- messageAs: result.ToJSON()
153
- )
154
- self.commandDelegate!.send( pluginResult, callbackId: command.callbackId)
155
- if (bleActionQueue.first?.id == command.callbackId) {
156
- removeFromQueue()
157
- }
158
- }
159
-
160
- //helper to return a String with keeping the callback
161
- func sendSuccessWithMultipleResponse(command: CDVInvokedUrlCommand, result: String){
162
- let pluginResult = CDVPluginResult(
163
- status: CDVCommandStatus_OK,
164
- messageAs: result
165
- )
166
- pluginResult!.setKeepCallbackAs(true);
167
- self.commandDelegate!.send( pluginResult, callbackId: command.callbackId )
168
- if (bleActionQueue.first?.id == command.callbackId) {
169
- removeFromQueue()
170
- }
171
- }
172
-
173
- //helper to return a JSon DiscoveredDeviceType object with keeping the callback
174
- func sendSuccessWithMultipleResponse(command: CDVInvokedUrlCommand, result: DiscoveredDeviceType){
175
- let pluginResult = CDVPluginResult(
176
- status: CDVCommandStatus_OK,
177
- messageAs: result.ToJSON()
178
- )
179
- pluginResult!.setKeepCallbackAs(true);
180
- self.commandDelegate!.send( pluginResult, callbackId: command.callbackId )
181
- if (bleActionQueue.first?.id == command.callbackId) {
182
- removeFromQueue()
183
- }
184
- }
185
- //helper to return a JSon Array object object
186
- func sendSuccessWithSingleResponse(command: CDVInvokedUrlCommand, result: [[AnyHashable: Any]]) {
187
- let pluginResult = CDVPluginResult(
188
- status: CDVCommandStatus_OK,
189
- messageAs: result
190
- )
191
- self.commandDelegate!.send( pluginResult, callbackId: command.callbackId )
192
- if (bleActionQueue.first?.id == command.callbackId) {
193
- removeFromQueue()
194
- } }
195
-
196
- //helper to send back an error
197
- func sendError(command: CDVInvokedUrlCommand, result: String){
198
- let pluginResult = CDVPluginResult(
199
- status: CDVCommandStatus_ERROR,
200
- messageAs: result
201
- )
202
- self.commandDelegate!.send( pluginResult, callbackId: command.callbackId)
203
- if (bleActionQueue.first?.id == command.callbackId) {
204
- removeFromQueue()
205
- } }
206
-
207
- func sendError(command: CDVInvokedUrlCommand, result: CordovaBLEError){
208
- let pluginResult = CDVPluginResult(
209
- status: CDVCommandStatus_ERROR,
210
- messageAs: result.toJSON()
211
- )
212
- self.commandDelegate!.send( pluginResult, callbackId: command.callbackId)
213
- if (bleActionQueue.first?.id == command.callbackId) {
214
- removeFromQueue()
215
- }
216
- }
217
-
218
-
219
- //Is BLE available
220
- @objc(checkAvailable:)
221
- func checkAvailable(command: CDVInvokedUrlCommand) {
222
- addToQueue(command: command, bleAction: {[self] in
223
- DispatchQueue.main.async {
224
-
225
- //from ios5
226
- if ( floor(NSFoundationVersionNumber) <= floor(NSFoundationVersionNumber_iOS_5_1) ){
227
- self.sendError(command: command, result: IoTizeBleError.BleUnsupported().message)
228
- }
229
-
230
- //check State
231
- self.bleController.checkState(completion: {
232
- (error: IoTizeBleError?) -> () in
233
-
234
- DispatchQueue.main.async {
235
-
236
- if (error != nil){
237
- self.lastError = error
238
- self.sendError(command: command, result: error!.message)
239
- }
240
- else {
241
- self.sendSuccessWithSingleResponse(command: command, result: true)
242
- }
243
-
244
- }
245
- })
246
- }
247
- })
248
- }
249
-
250
-
251
- //Start scanning IoTize devices
252
- @objc(startScan:)
253
- func startScan(command: CDVInvokedUrlCommand) {
254
- addToQueue(command: command, bleAction: {[self] in
255
- if (!self.isReady()){
256
-
257
- DispatchQueue.main.async {
258
- Thread.sleep(forTimeInterval: 0.01)
259
- self.startScan(command: command)
260
- }
261
- return
262
- }
263
-
264
- self.bleController.beginScan(completion: {
265
- (result: Any, error: IoTizeBleError?) -> () in
266
-
267
- DispatchQueue.main.async {
268
-
269
- if (error != nil){
270
- self.lastError = error
271
- self.sendError(command: command, result: error!.message)
272
- }
273
- else if let resultString = result as? String{
274
- self.sendSuccessWithMultipleResponse(command: command, result: resultString)
275
- } else if let resultDiscoveredDevice = result as? DiscoveredDeviceType {
276
- self.sendSuccessWithMultipleResponse(command: command, result: resultDiscoveredDevice)
277
- } else if let resultDevice = result as? CBPeripheral {
278
- self.sendSuccessWithMultipleResponse(command: command, result: CBPeripheralConverter.toDiscoveredDeviceType(device: resultDevice))
279
- } else {
280
- }
281
- }
282
- })
283
- })
284
- }
285
-
286
- //Stop scanning
287
- @objc(stopScan:)
288
- func stopScan(command: CDVInvokedUrlCommand) {
289
- addToQueue(command: command, bleAction: {[self] in
290
- bleController.stopScan();
291
- self.sendSuccessWithSingleResponse(command: command, result: "OK")
292
- })
293
- }
294
-
295
-
296
- //Connect to a device using its UUID
297
- @objc(connectAndDiscoverTapServices:)
298
- func connectAndDiscoverTapServices(command: CDVInvokedUrlCommand) {
299
- addToQueue(command: command, bleAction: {[self] in
300
- //we need the UUID of the device
301
- if (command.arguments.count == 0){
302
- let error = CordovaBLEError.IllegalArgument("Missing arguments")
303
- self.sendError(command: command, result: error)
304
- return
305
- }
306
-
307
- let deviceUUID = command.arguments[0] as? String ?? ""
308
-
309
- bleController.useBLETapPeripheral = true
310
-
311
- bleController.connectWithUUID(device: deviceUUID, completion: {
312
- (state: Any?, error: IoTizeBleError?) -> () in
313
-
314
- DispatchQueue.main.async {
315
-
316
- if (error != nil){
317
- self.lastError = error
318
- self.sendError(command: command, result: error!.message)
319
- }
320
- else {
321
- //printBLE("##> Sending Connected Ok")
322
- let _state = state as? String
323
-
324
- self.sendSuccessWithMultipleResponse(command: command, result: _state ?? "") // keep callback
325
- }
326
- }
327
- })
328
- })
329
- }
330
-
331
-
332
- @objc(connect:)
333
- func connect(command: CDVInvokedUrlCommand) {
334
- addToQueue(command: command, bleAction: {[self] in
335
- //we need the UUID of the device
336
- if (command.arguments.count == 0){
337
- self.sendError(command: command, result: CordovaBLEError.IllegalArgument("Missing arguments"))
338
- return
339
- }
340
-
341
- let deviceUUID = command.arguments[0] as? String ?? ""
342
-
343
- bleController.useBLETapPeripheral = false
344
-
345
- bleController.connectWithUUID(device: deviceUUID, completion: {
346
- (state: Any?, error: IoTizeBleError?) -> () in
347
-
348
- DispatchQueue.main.async {
349
-
350
- if (error != nil){
351
- self.lastError = error
352
- self.sendError(command: command, result: error!.message)
353
- }
354
- else {
355
- //printBLE("##> Sending Connected Ok")
356
- let _state = state as? String
357
-
358
- self.sendSuccessWithMultipleResponse(command: command, result: _state ?? "") // keep callback
359
- }
360
- }
361
- })
362
- })
363
- }
364
-
365
- //Disconnect from a device using its name
366
- @objc(disConnect:)
367
- func disConnect(command: CDVInvokedUrlCommand) {
368
- addToQueue(command: command, bleAction: { [self] in
369
- //we need the name of the device
370
- if (command.arguments.count == 0){
371
- self.sendError(command: command, result: CordovaBLEError.IllegalArgument("Missing arguments"))
372
- return
373
- }
374
-
375
- bleController.disconnect( completion: {
376
- (error: IoTizeBleError?) -> () in
377
-
378
- DispatchQueue.main.async {
379
-
380
- if (error != nil){
381
- self.lastError = error
382
- self.sendError(command: command, result: error!.message)
383
- }
384
- else {
385
- self.sendSuccessWithSingleResponse(command: command, result: "OK")
386
- }
387
- }
388
- })
389
- })
390
- }
391
-
392
- //Retrieve additional information
393
- @objc(getLastError:)
394
- func getLastError(command: CDVInvokedUrlCommand) {
395
- addToQueue(command: command, bleAction: {[self] in
396
- let msg: String = (lastError != nil) ? (lastError!.message) : ""
397
- self.sendSuccessWithSingleResponse(command: command, result: msg)
398
- })
399
- }
400
-
401
- //Send Data to device
402
- @objc(sendRequest:)
403
- func sendRequest(command: CDVInvokedUrlCommand) {
404
-
405
- addToQueue(command: command, bleAction: {[self] in
406
- printBLE("##> SendRequest")
407
- //we need data to send
408
- if (command.arguments.count == 1){
409
- self.sendError(command: command, result: CordovaBLEError.IllegalArgument("Missing arguments"))
410
- return
411
- }
412
-
413
- let data = command.arguments[1] as? String ?? ""
414
-
415
- bleController.sendRequest(data: data, completion: {
416
- (response: Any, error: IoTizeBleError?) -> () in
417
-
418
- DispatchQueue.main.async {
419
-
420
- if (error != nil){
421
- self.lastError = error
422
- self.sendError(command: command, result: error!.message)
423
- }
424
- else {
425
- if let responseString = response as? String {
426
- self.sendSuccessWithSingleResponse(command: command, result: responseString)
427
- }
428
- else if let responseDiscoveredDevice = response as? DiscoveredDeviceType {
429
- self.sendSuccessWithSingleResponse(command: command, result: responseDiscoveredDevice)
430
- } else if let responseDevice = response as? CBPeripheral {
431
- self.sendSuccessWithSingleResponse(command: command, result: CBPeripheralConverter.toDiscoveredDeviceType(device: responseDevice))
432
- }
433
- }
434
- }
435
- })
436
- })
437
- }
438
-
439
- @objc(isConnected:)
440
- func isConnected(command: CDVInvokedUrlCommand) {
441
- addToQueue(command: command, bleAction: { [self] in
442
- var status: Bool ;
443
-
444
- if (command.arguments.count < 1) {
445
- let error = CordovaBLEError.IllegalArgument("Missing arguments")
446
- self.sendError(command: command, result: error)
447
- }
448
-
449
- let deviceUUID = command.arguments[0] as? String ?? ""
450
- do {
451
- status = try bleController.isConnected(deviceUUID)
452
- self.sendSuccessWithSingleResponse(command: command, result: status)
453
- }
454
- catch {
455
- if (error is CordovaBLEError) {
456
- self.sendError(command: command, result: (error as! CordovaBLEError))
457
- } else {
458
- let cordovaError = CordovaBLEError.InternalError("Unkown error")
459
- self.sendError(command: command, result: cordovaError)
460
- }
461
- }
462
- })
463
-
464
- }
465
-
466
- func isReady() -> Bool {
467
- return bleController.isReady()
468
- }
469
-
470
- @objc(discoverServices:)
471
- func discoverServices(command: CDVInvokedUrlCommand) {
472
- addToQueue(command: command, bleAction: {[self] in
473
- printBLE("discoverServices called")
474
- if (command.arguments.count == 0){
475
- self.sendError(command: command, result: CordovaBLEError.IllegalArgument("Missing arguments"))
476
- return
477
- }
478
-
479
- let deviceUUID = command.arguments[0] as? String ?? ""
480
-
481
- bleController.discoverServices(forUUID: deviceUUID) { (anyPeripheral, error) in
482
- if (error != nil) {
483
- self.lastError = error
484
- self.sendError(command: command, result: error?.message ?? "discoverServicesError")
485
- } else {
486
- if let peripheral = anyPeripheral as? CBPeripheral {
487
- let result = CBPeripheralConverter.toServiceDescriptionsJSON(device: peripheral)
488
- self.sendSuccessWithSingleResponse(command: command, result: result)
489
- }
490
- }
491
- }
492
- })
493
- }
494
-
495
- @objc(characteristicWriteWithoutResponse:)
496
- func characteristicWriteWithoutResponse(command: CDVInvokedUrlCommand) {
497
-
498
- addToQueue(command: command, bleAction: {[self] in
499
- printBLE("characteristicWriteWithoutResponse called")
500
- if (command.arguments.count < 4){
501
- self.sendError(command: command, result: CordovaBLEError.IllegalArgument("Missing arguments"))
502
- return
503
- }
504
- let deviceID = command.arguments[0] as? String ?? ""
505
-
506
- guard let serviceUUID = CBUUIDHelper.fromString(command.arguments[1] as? String ?? "") else {
507
- let cordovaError = CordovaBLEError.IllegalArgument("\"\(command.arguments[1] as? String ?? "")\" is not a valid BLE UUID")
508
- self.sendError(command: command, result: cordovaError)
509
- return
510
- }
511
- guard let characteristicUUID = CBUUIDHelper.fromString(command.arguments[2] as? String ?? "") else {
512
- let cordovaError = CordovaBLEError.IllegalArgument("\"\(command.arguments[2] as? String ?? "")\" is not a valid BLE UUID")
513
- self.sendError(command: command, result: cordovaError)
514
- return
515
- }
516
-
517
- let dataToWrite = Data(Request.stringToHexArray(command.arguments[3] as? String ?? ""))
518
-
519
- bleController.characteristicWriteWithoutResponse(deviceID: deviceID, serviceUUID: serviceUUID, characteristicUUID: characteristicUUID, data: dataToWrite, completion: { (error) in
520
- if (error != nil) {
521
- self.sendError(command: command, result: error!.message)
522
- return
523
- }
524
- self.sendSuccessWithSingleResponse(command: command, result: "OK")
525
- })
526
- })
527
- }
528
-
529
- @objc(characteristicWrite:)
530
- func characteristicWrite(command: CDVInvokedUrlCommand) {
531
- addToQueue(command: command, bleAction: {[self] in
532
- printBLE("characteristicWrite called")
533
- if (command.arguments.count < 4){
534
- self.sendError(command: command, result: CordovaBLEError.IllegalArgument("Missing arguments"))
535
- return
536
- }
537
- let deviceID = command.arguments[0] as? String ?? ""
538
-
539
- guard let serviceUUID = CBUUIDHelper.fromString(command.arguments[1] as? String ?? "") else {
540
- let cordovaError = CordovaBLEError.IllegalArgument("\"\(command.arguments[1] as? String ?? "")\" is not a valid BLE UUID")
541
- self.sendError(command: command, result: cordovaError)
542
- return
543
- }
544
-
545
- guard let characteristicUUID = CBUUIDHelper.fromString(command.arguments[2] as? String ?? "") else {
546
- let cordovaError = CordovaBLEError.IllegalArgument("\"\(command.arguments[2] as? String ?? "")\" is not a valid BLE UUID")
547
-
548
- self.sendError(command: command, result: cordovaError)
549
- return
550
- }
551
-
552
- let dataToWrite = Data(Request.stringToHexArray(command.arguments[3] as? String ?? ""))
553
-
554
- bleController.characteristicWrite(deviceID: deviceID, serviceUUID: serviceUUID, characteristicUUID: characteristicUUID, data: dataToWrite, completion: { (error) in
555
- if (error != nil) {
556
- self.sendError(command: command, result: error!.message)
557
- return
558
- }
559
- self.sendSuccessWithSingleResponse(command: command, result: "OK")
560
- })
561
- })
562
- }
563
-
564
- @objc(characteristicRead:)
565
- func characteristicRead(command: CDVInvokedUrlCommand) {
566
-
567
- addToQueue(command: command, bleAction: {[self] in
568
- printBLE("characteristicRead called")
569
- if (command.arguments.count < 3){
570
- self.sendError(command: command, result: CordovaBLEError.IllegalArgument("Missing arguments"))
571
- return
572
- }
573
- let deviceID = command.arguments[0] as? String ?? ""
574
- guard let serviceUUID = CBUUIDHelper.fromString(command.arguments[1] as? String ?? "") else {
575
- let cordovaError = CordovaBLEError.IllegalArgument("\"\(command.arguments[1] as? String ?? "")\" is not a valid BLE UUID")
576
- self.sendError(command: command, result: cordovaError)
577
- return
578
- }
579
- guard let characteristicUUID = CBUUIDHelper.fromString(command.arguments[2] as? String ?? "") else {
580
- let cordovaError = CordovaBLEError.IllegalArgument("\"\(command.arguments[2] as? String ?? "")\" is not a valid BLE UUID")
581
- self.sendError(command: command, result: cordovaError)
582
- return
583
- }
584
-
585
- bleController.characteristicRead(deviceID: deviceID, serviceUUID: serviceUUID, characteristicUUID: characteristicUUID, completion: { (readData, error) in
586
- if (error != nil) {
587
- self.sendError(command: command, result: error!.message)
588
- return
589
- }
590
- let data = readData as! String
591
- self.sendSuccessWithSingleResponse(command: command, result: data)
592
- })
593
- })
594
-
595
-
596
- }
597
-
598
- @objc(characteristicStartNotification:)
599
- func characteristicStartNotification(command: CDVInvokedUrlCommand) {
600
-
601
- addToQueue(command: command, bleAction: {[self] () in
602
- printBLE("characteristicStartNotification called")
603
- if (command.arguments.count < 3){
604
- self.sendError(command: command, result: "characteristicStartNotification parameter error")
605
- return
606
- }
607
- let deviceID = command.arguments[0] as? String ?? ""
608
-
609
- guard let serviceUUID = CBUUIDHelper.fromString(command.arguments[1] as? String ?? "") else {
610
- let cordovaError = CordovaBLEError.IllegalArgument("\"\(command.arguments[1] as? String ?? "")\" is not a valid BLE UUID")
611
- self.sendError(command: command, result: cordovaError)
612
- return
613
- }
614
- guard let characteristicUUID = CBUUIDHelper.fromString(command.arguments[2] as? String ?? "") else {
615
- let cordovaError = CordovaBLEError.IllegalArgument("\"\(command.arguments[2] as? String ?? "")\" is not a valid BLE UUID")
616
- self.sendError(command: command, result: cordovaError)
617
- return
618
- }
619
-
620
- bleController.characteristicStartNotification(deviceID: deviceID, serviceUUID: serviceUUID, characteristicUUID: characteristicUUID, completion: { error in
621
- if (error != nil) {
622
- printBLE("characteristicStartNotification response error")
623
- self.sendError(command: command, result: error!.message)
624
- return
625
- }
626
- printBLE("characteristicStartNotification response OK")
627
- self.sendSuccessWithSingleResponse(command: command, result: "OK")
628
- })
629
- })
630
-
631
- }
632
-
633
- @objc(characteristicStopNotification:)
634
- func characteristicStopNotification(command: CDVInvokedUrlCommand) {
635
-
636
- addToQueue(command: command, bleAction: { [self] () in
637
- printBLE("characteristicStopNotification called")
638
- if (command.arguments.count < 3){
639
- self.sendError(command: command, result: "characteristicStopNotification parameter error")
640
- return
641
- }
642
- let deviceID = command.arguments[0] as? String ?? ""
643
-
644
- guard let serviceUUID = CBUUIDHelper.fromString(command.arguments[1] as? String ?? "") else {
645
- let cordovaError = CordovaBLEError.IllegalArgument("\"\(command.arguments[1] as? String ?? "")\" is not a valid BLE UUID")
646
- self.sendError(command: command, result: cordovaError)
647
- return
648
- }
649
- guard let characteristicUUID = CBUUIDHelper.fromString(command.arguments[2] as? String ?? "") else {
650
- let cordovaError = CordovaBLEError.IllegalArgument("\"\(command.arguments[2] as? String ?? "")\" is not a valid BLE UUID")
651
- self.sendError(command: command, result: cordovaError)
652
- return
653
- }
654
-
655
- bleController.characteristicStopNotification(deviceID: deviceID, serviceUUID: serviceUUID, characteristicUUID: characteristicUUID, completion: { error in
656
- if (error != nil) {
657
- printBLE("characteristicStopNotification response error")
658
- self.sendError(command: command, result: error!.message)
659
- return
660
- }
661
- printBLE("characteristicStopNotification response OK")
662
- self.sendSuccessWithSingleResponse(command: command, result: "OK")
663
- })
664
- })
665
-
666
- }
667
-
668
- @objc(characteristicChanged:)
669
- func characteristicChanged(command: CDVInvokedUrlCommand) {
670
-
671
- addToQueue(command: command, bleAction: { [self] () in
672
-
673
- printBLE("characteristicChanged called")
674
- if (command.arguments.count < 3){
675
- self.sendError(command: command, result: "SendRequest parameter error")
676
- return
677
- }
678
- let deviceID = command.arguments[0] as? String ?? ""
679
-
680
- guard let serviceUUID = CBUUIDHelper.fromString(command.arguments[1] as? String ?? "") else {
681
- let cordovaError = CordovaBLEError.IllegalArgument("\"\(command.arguments[1] as? String ?? "")\" is not a valid BLE UUID")
682
- self.sendError(command: command, result: cordovaError)
683
- return
684
- }
685
- guard let characteristicUUID = CBUUIDHelper.fromString(command.arguments[2] as? String ?? "") else {
686
- let cordovaError = CordovaBLEError.IllegalArgument("\"\(command.arguments[2] as? String ?? "")\" is not a valid BLE UUID")
687
- self.sendError(command: command, result: cordovaError)
688
- return
689
- }
690
-
691
- bleController.characteristicChanged(deviceID: deviceID, serviceUUID: serviceUUID, characteristicUUID: characteristicUUID, completion: { (result, error) in
692
- if (error != nil) {
693
- self.sendError(command: command, result: error!.message)
694
- return
695
- }
696
- self.sendSuccessWithMultipleResponse(command: command, result: result as! String)
697
- })
698
- if (bleActionQueue.first?.id == command.callbackId) {
699
- removeFromQueue()
700
- }
701
- })
702
- }
703
-
704
- func addToQueue(command: CDVInvokedUrlCommand, bleAction: @escaping () -> Void) {
705
- bleActionQueue.enqueue(BLEAction(command.callbackId, bleAction))
706
- if (!isHandlingQueue) {
707
- isHandlingQueue = true
708
- DispatchQueue.main.async {
709
- bleAction()
710
- }
711
- }
712
- }
713
-
714
- func removeFromQueue() {
715
- bleActionQueue.dequeue()
716
- if (isHandlingQueue) {
717
- if (bleActionQueue.first != nil) {
718
- DispatchQueue.main.async {
719
- self.bleActionQueue.first!.action()
720
- }
721
- } else {
722
- isHandlingQueue = false
723
- }
724
- }
725
- }
726
-
727
-
728
- @objc(close:)
729
- func close(command: CDVInvokedUrlCommand) {
730
- disConnect(command: command)
731
- }
732
- }
1
+ //
2
+ // Copyright 2018 IoTize SAS Inc. Licensed under the MIT license.
3
+ //
4
+ // BLECom.swift
5
+ // device-com-ble.cordova BLE Cordova Plugin
6
+ //
7
+
8
+ import Foundation
9
+ import CoreBluetooth
10
+
11
+ // Custom debug print functions
12
+
13
+ public func printBLE(_ object: Any...) {
14
+ #if DEBUG
15
+ for item in object {
16
+ Swift.print("BLE:", item)
17
+ }
18
+ #endif
19
+ }
20
+
21
+ public func printBLE(_ object: Any) {
22
+ #if DEBUG
23
+ Swift.print("BLE:", object)
24
+ #endif
25
+ }
26
+
27
+
28
+ struct IoTizeBleError: Error {
29
+
30
+ let code: Int
31
+ let message: String
32
+
33
+ init(code: Int, message: String) {
34
+ self.code = code
35
+ self.message = message
36
+ }
37
+
38
+ static func BleUnsupported() -> IoTizeBleError { return IoTizeBleError(code:100, message:"Bluetooth is not supported")}
39
+ static func BleUnauthorized() -> IoTizeBleError { return IoTizeBleError(code:101, message:"Bluetooth is not authorized")}
40
+ static func BlePoweredOff() -> IoTizeBleError { return IoTizeBleError(code:102, message:"Bluetooth is powered off")}
41
+ static func BleResetting() -> IoTizeBleError { return IoTizeBleError(code:103, message:"Bluetooth is resetting")}
42
+ static func BleUnknown() -> IoTizeBleError { return IoTizeBleError(code:104, message:"Bluetooth is in an unknown state")}
43
+
44
+ static func PeripheralConnectionFailed(peripheral: CBPeripheral, error: Error?) -> IoTizeBleError { return IoTizeBleError(code:200, message:"Connection to \(peripheral.name ?? "unknown peripheral") failed: \(error?.localizedDescription ?? "unknown")" )}
45
+ static func NoDeviceConnected() -> IoTizeBleError { return IoTizeBleError(code:201, message:"No Device Connected")}
46
+
47
+ static func ServiceDiscoveryFailed(peripheral: CBPeripheral) -> IoTizeBleError { return IoTizeBleError(code:300, message:"Failed to discover services for \(peripheral.name ?? "unknown peripheral")" )}
48
+ static func CharacteristicsDiscoveryFailed(peripheral: CBPeripheral) -> IoTizeBleError { return IoTizeBleError(code:301, message:"Failed to discover characteristics for \(peripheral.name ?? "unknown peripheral")" )}
49
+ static func CharacteristicSPPNotFound(peripheral: CBPeripheral) -> IoTizeBleError { return IoTizeBleError(code:302, message:"Characteristic SPP not found for \(peripheral.name ?? "unknown peripheral")" )}
50
+ static func CharacteristicNotifyChangeFailed() -> IoTizeBleError { return IoTizeBleError(code:304, message:"Failed to set notification for characteristic" )}
51
+ static func BleVersionIsOld(version: String) -> IoTizeBleError { return IoTizeBleError(code:303, message:"BLE firmware version is too old: \(version)" )}
52
+
53
+ static func InvalidWriteData(peripheral: CBPeripheral) -> IoTizeBleError { return IoTizeBleError(code:403, message:"Invalid write data for \(peripheral.name ?? "unknown peripheral")" )}
54
+ static func TimedOutRequest(msg: String) -> IoTizeBleError { return IoTizeBleError(code:404, message:"Waiting for response timed out, txData: " + msg )}
55
+
56
+ }
57
+
58
+ enum CordovaBLEErrorCode: CustomStringConvertible {
59
+ case InternalError
60
+ case IllegalArgument
61
+ case DeviceNotFound
62
+
63
+ var description: String {
64
+ switch self {
65
+ case .InternalError: return "CordovaBLEErrorInternalError"
66
+ case .IllegalArgument: return "CordovaBLEErrorIllegalArgument"
67
+ case .DeviceNotFound: return "CordovaBLEErrorDeviceNotFound"
68
+ }
69
+ }
70
+ }
71
+
72
+ struct CordovaBLEError: Error {
73
+ var code: CordovaBLEErrorCode
74
+ var message: String
75
+
76
+ init(_ code: CordovaBLEErrorCode, _ message: String) {
77
+ self.code = code
78
+ self.message = message
79
+ }
80
+
81
+ func toJSON() -> [AnyHashable: Any] {
82
+ return ["code": code.description, "message": message]
83
+ }
84
+
85
+ static func InternalError(_ message: String) -> CordovaBLEError {return CordovaBLEError(.InternalError, message)}
86
+
87
+ static func IllegalArgument(_ message: String) -> CordovaBLEError {return CordovaBLEError(.IllegalArgument, message)}
88
+ }
89
+
90
+ struct BLEAction {
91
+ var id: String
92
+ var action: () -> Void
93
+
94
+ init(_ id: String, _ action: @escaping () -> Void) {
95
+ self.id = id
96
+ self.action = action
97
+ }
98
+ }
99
+
100
+ //Main class handling the plugin functionalities.
101
+ @objc(BLECom) class BLECom : CDVPlugin {
102
+
103
+ var bleActionQueue: Queue<BLEAction>!
104
+
105
+ var isHandlingQueue = false
106
+
107
+ var bleController: BLEManager!
108
+ var lastError: IoTizeBleError?
109
+
110
+ //
111
+ override func pluginInitialize(){
112
+ bleController = BLEManager()
113
+ bleActionQueue = Queue<BLEAction>()
114
+ }
115
+
116
+ //helper to return an empty response
117
+ func sendSuccessWithoutResponse(command: CDVInvokedUrlCommand) {
118
+ let pluginResult = CDVPluginResult(status: CDVCommandStatus_OK)
119
+
120
+ self.commandDelegate!.send(pluginResult, callbackId: command.callbackId)
121
+ removeFromQueue(id: command.callbackId)
122
+
123
+ }
124
+
125
+ //helper to return a string
126
+ func sendSuccessWithSingleResponse(command: CDVInvokedUrlCommand, result: String){
127
+ let pluginResult = CDVPluginResult(
128
+ status: CDVCommandStatus_OK,
129
+ messageAs: result
130
+ )
131
+ self.commandDelegate!.send( pluginResult, callbackId: command.callbackId)
132
+ removeFromQueue(id: command.callbackId)
133
+ }
134
+
135
+ //helper to return a boolean
136
+ private func sendSuccessWithSingleResponse(command: CDVInvokedUrlCommand, result: Bool) {
137
+ let pluginResult = CDVPluginResult(
138
+ status: CDVCommandStatus_OK,
139
+ messageAs: result
140
+ )
141
+ self.commandDelegate!.send(pluginResult, callbackId: command.callbackId)
142
+ removeFromQueue(id: command.callbackId)
143
+ }
144
+
145
+ //helper to return a JSon object
146
+ func sendSuccessWithSingleResponse(command: CDVInvokedUrlCommand, result: DiscoveredDeviceType){
147
+ let pluginResult = CDVPluginResult(
148
+ status: CDVCommandStatus_OK,
149
+ messageAs: result.ToJSON()
150
+ )
151
+ self.commandDelegate!.send( pluginResult, callbackId: command.callbackId)
152
+ removeFromQueue(id: command.callbackId)
153
+ }
154
+
155
+ //helper to return a String with keeping the callback
156
+ func sendSuccessWithMultipleResponse(command: CDVInvokedUrlCommand, result: String){
157
+ let pluginResult = CDVPluginResult(
158
+ status: CDVCommandStatus_OK,
159
+ messageAs: result
160
+ )
161
+ pluginResult!.setKeepCallbackAs(true);
162
+ self.commandDelegate!.send( pluginResult, callbackId: command.callbackId )
163
+ removeFromQueue(id: command.callbackId)
164
+ }
165
+
166
+ //helper to return a JSon DiscoveredDeviceType object with keeping the callback
167
+ func sendSuccessWithMultipleResponse(command: CDVInvokedUrlCommand, result: DiscoveredDeviceType){
168
+ let pluginResult = CDVPluginResult(
169
+ status: CDVCommandStatus_OK,
170
+ messageAs: result.ToJSON()
171
+ )
172
+ pluginResult!.setKeepCallbackAs(true);
173
+ self.commandDelegate!.send( pluginResult, callbackId: command.callbackId )
174
+ removeFromQueue(id: command.callbackId)
175
+ }
176
+ //helper to return a JSon Array object object
177
+ func sendSuccessWithSingleResponse(command: CDVInvokedUrlCommand, result: [[AnyHashable: Any]]) {
178
+ let pluginResult = CDVPluginResult(
179
+ status: CDVCommandStatus_OK,
180
+ messageAs: result
181
+ )
182
+ self.commandDelegate!.send( pluginResult, callbackId: command.callbackId )
183
+ removeFromQueue(id: command.callbackId) }
184
+
185
+ //helper to send back an error
186
+ func sendError(command: CDVInvokedUrlCommand, result: String){
187
+ let pluginResult = CDVPluginResult(
188
+ status: CDVCommandStatus_ERROR,
189
+ messageAs: result
190
+ )
191
+ self.commandDelegate!.send( pluginResult, callbackId: command.callbackId)
192
+ removeFromQueue(id: command.callbackId) }
193
+
194
+ func sendError(command: CDVInvokedUrlCommand, result: CordovaBLEError){
195
+ let pluginResult = CDVPluginResult(
196
+ status: CDVCommandStatus_ERROR,
197
+ messageAs: result.toJSON()
198
+ )
199
+ self.commandDelegate!.send( pluginResult, callbackId: command.callbackId)
200
+ removeFromQueue(id: command.callbackId)
201
+ }
202
+
203
+
204
+ //Is BLE available
205
+ @objc(checkAvailable:)
206
+ func checkAvailable(command: CDVInvokedUrlCommand) {
207
+ addToQueue(command: command, bleAction: {[self] in
208
+ DispatchQueue.main.async {
209
+
210
+ //from ios5
211
+ if ( floor(NSFoundationVersionNumber) <= floor(NSFoundationVersionNumber_iOS_5_1) ){
212
+ self.sendError(command: command, result: IoTizeBleError.BleUnsupported().message)
213
+ }
214
+
215
+ //check State
216
+ self.bleController.checkState(completion: {
217
+ (error: IoTizeBleError?) -> () in
218
+
219
+ DispatchQueue.main.async {
220
+
221
+ if (error != nil){
222
+ self.lastError = error
223
+ self.sendError(command: command, result: error!.message)
224
+ }
225
+ else {
226
+ self.sendSuccessWithSingleResponse(command: command, result: true)
227
+ }
228
+
229
+ }
230
+ })
231
+ }
232
+ })
233
+ }
234
+
235
+
236
+ //Start scanning IoTize devices
237
+ @objc(startScan:)
238
+ func startScan(command: CDVInvokedUrlCommand) {
239
+ addToQueue(command: command, bleAction: {[self] in
240
+ if (!self.isReady()){
241
+
242
+ DispatchQueue.main.async {
243
+ Thread.sleep(forTimeInterval: 0.01)
244
+ self.startScan(command: command)
245
+ }
246
+ return
247
+ }
248
+
249
+ let scanOptionsJSON = command.arguments[0] as? String ?? nil
250
+
251
+ var serviceUUIDs: [CBUUID]? = nil
252
+
253
+ if let actualScanOptionsJSON = scanOptionsJSON {
254
+ if let scanOptionsJSONData = actualScanOptionsJSON.data(using: .utf8) {
255
+ if let scannerOptions = try? JSONDecoder().decode(ScannerOptions.self, from: scanOptionsJSONData) {
256
+ if let filters = scannerOptions.filters {
257
+ if (!filters.isEmpty) {
258
+ serviceUUIDs = []
259
+ for filter in filters {
260
+ serviceUUIDs?.append(CBUUID(string: filter))
261
+ }
262
+
263
+ }
264
+
265
+ }
266
+ }
267
+ }
268
+ }
269
+
270
+ self.bleController.beginScan(completion: {
271
+ (result: Any, error: IoTizeBleError?) -> () in
272
+
273
+ DispatchQueue.main.async {
274
+
275
+ if (error != nil){
276
+ self.lastError = error
277
+ self.sendError(command: command, result: error!.message)
278
+ }
279
+ else if let resultString = result as? String{
280
+ self.sendSuccessWithMultipleResponse(command: command, result: resultString)
281
+ } else if let resultDiscoveredDevice = result as? DiscoveredDeviceType {
282
+ self.sendSuccessWithMultipleResponse(command: command, result: resultDiscoveredDevice)
283
+ } else if let resultDevice = result as? CBPeripheral {
284
+ self.sendSuccessWithMultipleResponse(command: command, result: CBPeripheralConverter.toDiscoveredDeviceType(device: resultDevice))
285
+ } else {
286
+ }
287
+ }
288
+ }, serviceUUIDs: serviceUUIDs)
289
+ })
290
+ }
291
+
292
+ //Stop scanning
293
+ @objc(stopScan:)
294
+ func stopScan(command: CDVInvokedUrlCommand) {
295
+ addToQueue(command: command, bleAction: {[self] in
296
+ bleController.stopScan();
297
+ self.sendSuccessWithSingleResponse(command: command, result: "OK")
298
+ })
299
+ }
300
+
301
+
302
+ //Connect to a device using its UUID
303
+ @objc(connectAndDiscoverTapServices:)
304
+ func connectAndDiscoverTapServices(command: CDVInvokedUrlCommand) {
305
+ addToQueue(command: command, bleAction: {[self] in
306
+ //we need the UUID of the device
307
+ if (command.arguments.count == 0){
308
+ let error = CordovaBLEError.IllegalArgument("Missing arguments")
309
+ self.sendError(command: command, result: error)
310
+ return
311
+ }
312
+
313
+ let deviceUUID = command.arguments[0] as? String ?? ""
314
+
315
+ bleController.useBLETapPeripheral = true
316
+
317
+ bleController.connectWithUUID(device: deviceUUID, completion: {
318
+ (state: Any?, error: IoTizeBleError?) -> () in
319
+
320
+ DispatchQueue.main.async {
321
+
322
+ if (error != nil){
323
+ self.lastError = error
324
+ self.sendError(command: command, result: error!.message)
325
+ }
326
+ else {
327
+ //printBLE("##> Sending Connected Ok")
328
+ let _state = state as? String
329
+
330
+ self.sendSuccessWithMultipleResponse(command: command, result: _state ?? "") // keep callback
331
+ }
332
+ }
333
+ })
334
+ })
335
+ }
336
+
337
+
338
+ @objc(connect:)
339
+ func connect(command: CDVInvokedUrlCommand) {
340
+ addToQueue(command: command, bleAction: {[self] in
341
+
342
+ printBLE("connect called")
343
+ //we need the UUID of the device
344
+ if (command.arguments.count == 0){
345
+ self.sendError(command: command, result: CordovaBLEError.IllegalArgument("Missing arguments"))
346
+ return
347
+ }
348
+
349
+ let deviceUUID = command.arguments[0] as? String ?? ""
350
+
351
+ bleController.useBLETapPeripheral = false
352
+
353
+ bleController.connectWithUUID(device: deviceUUID, completion: {
354
+ (state: Any?, error: IoTizeBleError?) -> () in
355
+
356
+ DispatchQueue.main.async {
357
+
358
+ if (error != nil){
359
+ self.lastError = error
360
+ self.sendError(command: command, result: error!.message)
361
+ }
362
+ else {
363
+ //printBLE("##> Sending Connected Ok")
364
+ let _state = state as? String
365
+
366
+ self.sendSuccessWithMultipleResponse(command: command, result: _state ?? "") // keep callback
367
+ }
368
+ }
369
+ })
370
+ })
371
+ }
372
+
373
+ //Disconnect from a device using its name
374
+ @objc(disConnect:)
375
+ func disConnect(command: CDVInvokedUrlCommand) {
376
+ addToQueue(command: command, bleAction: { [self] in
377
+ printBLE("disconnect called")
378
+ //we need the name of the device
379
+ if (command.arguments.count == 0){
380
+ self.sendError(command: command, result: CordovaBLEError.IllegalArgument("Missing arguments"))
381
+ return
382
+ }
383
+
384
+ bleController.disconnect( completion: {
385
+ (error: IoTizeBleError?) -> () in
386
+
387
+ DispatchQueue.main.async {
388
+
389
+ if (error != nil){
390
+ self.lastError = error
391
+ self.sendError(command: command, result: error!.message)
392
+ }
393
+ else {
394
+ self.sendSuccessWithSingleResponse(command: command, result: "OK")
395
+ }
396
+ }
397
+ })
398
+ })
399
+ }
400
+
401
+ //Retrieve additional information
402
+ @objc(getLastError:)
403
+ func getLastError(command: CDVInvokedUrlCommand) {
404
+ addToQueue(command: command, bleAction: {[self] in
405
+ let msg: String = (lastError != nil) ? (lastError!.message) : ""
406
+ self.sendSuccessWithSingleResponse(command: command, result: msg)
407
+ })
408
+ }
409
+
410
+ //Send Data to device
411
+ @objc(sendRequest:)
412
+ func sendRequest(command: CDVInvokedUrlCommand) {
413
+
414
+ addToQueue(command: command, bleAction: {[self] in
415
+ printBLE("##> SendRequest")
416
+ //we need data to send
417
+ if (command.arguments.count == 1){
418
+ self.sendError(command: command, result: CordovaBLEError.IllegalArgument("Missing arguments"))
419
+ return
420
+ }
421
+
422
+ let data = command.arguments[1] as? String ?? ""
423
+
424
+ bleController.sendRequest(data: data, completion: {
425
+ (response: Any, error: IoTizeBleError?) -> () in
426
+
427
+ DispatchQueue.main.async {
428
+
429
+ if (error != nil){
430
+ self.lastError = error
431
+ self.sendError(command: command, result: error!.message)
432
+ }
433
+ else {
434
+ if let responseString = response as? String {
435
+ self.sendSuccessWithSingleResponse(command: command, result: responseString)
436
+ }
437
+ else if let responseDiscoveredDevice = response as? DiscoveredDeviceType {
438
+ self.sendSuccessWithSingleResponse(command: command, result: responseDiscoveredDevice)
439
+ } else if let responseDevice = response as? CBPeripheral {
440
+ self.sendSuccessWithSingleResponse(command: command, result: CBPeripheralConverter.toDiscoveredDeviceType(device: responseDevice))
441
+ }
442
+ }
443
+ }
444
+ })
445
+ })
446
+ }
447
+
448
+ @objc(isConnected:)
449
+ func isConnected(command: CDVInvokedUrlCommand) {
450
+ addToQueue(command: command, bleAction: { [self] in
451
+ var status: Bool ;
452
+
453
+ if (command.arguments.count < 1) {
454
+ let error = CordovaBLEError.IllegalArgument("Missing arguments")
455
+ self.sendError(command: command, result: error)
456
+ }
457
+
458
+ let deviceUUID = command.arguments[0] as? String ?? ""
459
+ do {
460
+ status = try bleController.isConnected(deviceUUID)
461
+ self.sendSuccessWithSingleResponse(command: command, result: status)
462
+ }
463
+ catch {
464
+ if (error is CordovaBLEError) {
465
+ self.sendError(command: command, result: (error as! CordovaBLEError))
466
+ } else {
467
+ let cordovaError = CordovaBLEError.InternalError("Unkown error")
468
+ self.sendError(command: command, result: cordovaError)
469
+ }
470
+ }
471
+ })
472
+
473
+ }
474
+
475
+ func isReady() -> Bool {
476
+ return bleController.isReady()
477
+ }
478
+
479
+ @objc(discoverServices:)
480
+ func discoverServices(command: CDVInvokedUrlCommand) {
481
+ addToQueue(command: command, bleAction: {[self] in
482
+ printBLE("discoverServices called")
483
+ if (command.arguments.count == 0){
484
+ self.sendError(command: command, result: CordovaBLEError.IllegalArgument("Missing arguments"))
485
+ return
486
+ }
487
+
488
+ let deviceUUID = command.arguments[0] as? String ?? ""
489
+
490
+ bleController.discoverServices(forUUID: deviceUUID) { (anyPeripheral, error) in
491
+ if (error != nil) {
492
+ self.lastError = error
493
+ self.sendError(command: command, result: error?.message ?? "discoverServicesError")
494
+ } else {
495
+ if let peripheral = anyPeripheral as? CBPeripheral {
496
+ let result = CBPeripheralConverter.toServiceDescriptionsJSON(device: peripheral)
497
+ self.sendSuccessWithSingleResponse(command: command, result: result)
498
+ }
499
+ }
500
+ }
501
+ })
502
+ }
503
+
504
+ @objc(characteristicWriteWithoutResponse:)
505
+ func characteristicWriteWithoutResponse(command: CDVInvokedUrlCommand) {
506
+
507
+ addToQueue(command: command, bleAction: {[self] in
508
+ printBLE("characteristicWriteWithoutResponse called")
509
+ if (command.arguments.count < 4){
510
+ self.sendError(command: command, result: CordovaBLEError.IllegalArgument("Missing arguments"))
511
+ return
512
+ }
513
+ let deviceID = command.arguments[0] as? String ?? ""
514
+
515
+ guard let serviceUUID = CBUUIDHelper.fromString(command.arguments[1] as? String ?? "") else {
516
+ let cordovaError = CordovaBLEError.IllegalArgument("\"\(command.arguments[1] as? String ?? "")\" is not a valid BLE UUID")
517
+ self.sendError(command: command, result: cordovaError)
518
+ return
519
+ }
520
+ guard let characteristicUUID = CBUUIDHelper.fromString(command.arguments[2] as? String ?? "") else {
521
+ let cordovaError = CordovaBLEError.IllegalArgument("\"\(command.arguments[2] as? String ?? "")\" is not a valid BLE UUID")
522
+ self.sendError(command: command, result: cordovaError)
523
+ return
524
+ }
525
+
526
+ let dataToWrite = Data(Request.stringToHexArray(command.arguments[3] as? String ?? ""))
527
+
528
+ bleController.characteristicWriteWithoutResponse(deviceID: deviceID, serviceUUID: serviceUUID, characteristicUUID: characteristicUUID, data: dataToWrite, completion: { (error) in
529
+ if (error != nil) {
530
+ self.sendError(command: command, result: error!.message)
531
+ return
532
+ }
533
+ self.sendSuccessWithSingleResponse(command: command, result: "OK")
534
+ })
535
+ })
536
+ }
537
+
538
+ @objc(characteristicWrite:)
539
+ func characteristicWrite(command: CDVInvokedUrlCommand) {
540
+ addToQueue(command: command, bleAction: {[self] in
541
+ printBLE("characteristicWrite called")
542
+ if (command.arguments.count < 4){
543
+ self.sendError(command: command, result: CordovaBLEError.IllegalArgument("Missing arguments"))
544
+ return
545
+ }
546
+ let deviceID = command.arguments[0] as? String ?? ""
547
+
548
+ guard let serviceUUID = CBUUIDHelper.fromString(command.arguments[1] as? String ?? "") else {
549
+ let cordovaError = CordovaBLEError.IllegalArgument("\"\(command.arguments[1] as? String ?? "")\" is not a valid BLE UUID")
550
+ self.sendError(command: command, result: cordovaError)
551
+ return
552
+ }
553
+
554
+ guard let characteristicUUID = CBUUIDHelper.fromString(command.arguments[2] as? String ?? "") else {
555
+ let cordovaError = CordovaBLEError.IllegalArgument("\"\(command.arguments[2] as? String ?? "")\" is not a valid BLE UUID")
556
+
557
+ self.sendError(command: command, result: cordovaError)
558
+ return
559
+ }
560
+
561
+ let dataToWrite = Data(Request.stringToHexArray(command.arguments[3] as? String ?? ""))
562
+
563
+ bleController.characteristicWrite(deviceID: deviceID, serviceUUID: serviceUUID, characteristicUUID: characteristicUUID, data: dataToWrite, completion: { (error) in
564
+ if (error != nil) {
565
+ self.sendError(command: command, result: error!.message)
566
+ return
567
+ }
568
+ self.sendSuccessWithSingleResponse(command: command, result: "OK")
569
+ })
570
+ })
571
+ }
572
+
573
+ @objc(characteristicRead:)
574
+ func characteristicRead(command: CDVInvokedUrlCommand) {
575
+
576
+ addToQueue(command: command, bleAction: {[self] in
577
+ printBLE("characteristicRead called")
578
+ if (command.arguments.count < 3){
579
+ self.sendError(command: command, result: CordovaBLEError.IllegalArgument("Missing arguments"))
580
+ return
581
+ }
582
+ let deviceID = command.arguments[0] as? String ?? ""
583
+ guard let serviceUUID = CBUUIDHelper.fromString(command.arguments[1] as? String ?? "") else {
584
+ let cordovaError = CordovaBLEError.IllegalArgument("\"\(command.arguments[1] as? String ?? "")\" is not a valid BLE UUID")
585
+ self.sendError(command: command, result: cordovaError)
586
+ return
587
+ }
588
+ guard let characteristicUUID = CBUUIDHelper.fromString(command.arguments[2] as? String ?? "") else {
589
+ let cordovaError = CordovaBLEError.IllegalArgument("\"\(command.arguments[2] as? String ?? "")\" is not a valid BLE UUID")
590
+ self.sendError(command: command, result: cordovaError)
591
+ return
592
+ }
593
+
594
+ bleController.characteristicRead(deviceID: deviceID, serviceUUID: serviceUUID, characteristicUUID: characteristicUUID, completion: { (readData, error) in
595
+ if (error != nil) {
596
+ self.sendError(command: command, result: error!.message)
597
+ return
598
+ }
599
+ let data = readData as! String
600
+ self.sendSuccessWithSingleResponse(command: command, result: data)
601
+ })
602
+ })
603
+
604
+
605
+ }
606
+
607
+ @objc(characteristicStartNotification:)
608
+ func characteristicStartNotification(command: CDVInvokedUrlCommand) {
609
+
610
+ addToQueue(command: command, bleAction: {[self] () in
611
+ printBLE("characteristicStartNotification called")
612
+ if (command.arguments.count < 3){
613
+ self.sendError(command: command, result: "characteristicStartNotification parameter error")
614
+ return
615
+ }
616
+ let deviceID = command.arguments[0] as? String ?? ""
617
+
618
+ guard let serviceUUID = CBUUIDHelper.fromString(command.arguments[1] as? String ?? "") else {
619
+ let cordovaError = CordovaBLEError.IllegalArgument("\"\(command.arguments[1] as? String ?? "")\" is not a valid BLE UUID")
620
+ self.sendError(command: command, result: cordovaError)
621
+ return
622
+ }
623
+ guard let characteristicUUID = CBUUIDHelper.fromString(command.arguments[2] as? String ?? "") else {
624
+ let cordovaError = CordovaBLEError.IllegalArgument("\"\(command.arguments[2] as? String ?? "")\" is not a valid BLE UUID")
625
+ self.sendError(command: command, result: cordovaError)
626
+ return
627
+ }
628
+
629
+ bleController.characteristicStartNotification(deviceID: deviceID, serviceUUID: serviceUUID, characteristicUUID: characteristicUUID, completion: { error in
630
+ if (error != nil) {
631
+ printBLE("characteristicStartNotification response error")
632
+ self.sendError(command: command, result: error!.message)
633
+ return
634
+ }
635
+ printBLE("characteristicStartNotification response OK")
636
+ self.sendSuccessWithSingleResponse(command: command, result: "OK")
637
+ })
638
+ })
639
+
640
+ }
641
+
642
+ @objc(characteristicStopNotification:)
643
+ func characteristicStopNotification(command: CDVInvokedUrlCommand) {
644
+
645
+ addToQueue(command: command, bleAction: { [self] () in
646
+ printBLE("characteristicStopNotification called")
647
+ if (command.arguments.count < 3){
648
+ self.sendError(command: command, result: "characteristicStopNotification parameter error")
649
+ return
650
+ }
651
+ let deviceID = command.arguments[0] as? String ?? ""
652
+
653
+ guard let serviceUUID = CBUUIDHelper.fromString(command.arguments[1] as? String ?? "") else {
654
+ let cordovaError = CordovaBLEError.IllegalArgument("\"\(command.arguments[1] as? String ?? "")\" is not a valid BLE UUID")
655
+ self.sendError(command: command, result: cordovaError)
656
+ return
657
+ }
658
+ guard let characteristicUUID = CBUUIDHelper.fromString(command.arguments[2] as? String ?? "") else {
659
+ let cordovaError = CordovaBLEError.IllegalArgument("\"\(command.arguments[2] as? String ?? "")\" is not a valid BLE UUID")
660
+ self.sendError(command: command, result: cordovaError)
661
+ return
662
+ }
663
+
664
+ bleController.characteristicStopNotification(deviceID: deviceID, serviceUUID: serviceUUID, characteristicUUID: characteristicUUID, completion: { error in
665
+ if (error != nil) {
666
+ printBLE("characteristicStopNotification response error")
667
+ self.sendError(command: command, result: error!.message)
668
+ return
669
+ }
670
+ printBLE("characteristicStopNotification response OK")
671
+ self.sendSuccessWithSingleResponse(command: command, result: "OK")
672
+ })
673
+ })
674
+
675
+ }
676
+
677
+ @objc(characteristicChanged:)
678
+ func characteristicChanged(command: CDVInvokedUrlCommand) {
679
+
680
+ addToQueue(command: command, bleAction: { [self] () in
681
+
682
+ printBLE("characteristicChanged called")
683
+ if (command.arguments.count < 3){
684
+ self.sendError(command: command, result: "SendRequest parameter error")
685
+ return
686
+ }
687
+ let deviceID = command.arguments[0] as? String ?? ""
688
+
689
+ guard let serviceUUID = CBUUIDHelper.fromString(command.arguments[1] as? String ?? "") else {
690
+ let cordovaError = CordovaBLEError.IllegalArgument("\"\(command.arguments[1] as? String ?? "")\" is not a valid BLE UUID")
691
+ self.sendError(command: command, result: cordovaError)
692
+ return
693
+ }
694
+ guard let characteristicUUID = CBUUIDHelper.fromString(command.arguments[2] as? String ?? "") else {
695
+ let cordovaError = CordovaBLEError.IllegalArgument("\"\(command.arguments[2] as? String ?? "")\" is not a valid BLE UUID")
696
+ self.sendError(command: command, result: cordovaError)
697
+ return
698
+ }
699
+
700
+ bleController.characteristicChanged(deviceID: deviceID, serviceUUID: serviceUUID, characteristicUUID: characteristicUUID, completion: { (result, error) in
701
+ if (error != nil) {
702
+ self.sendError(command: command, result: error!.message)
703
+ return
704
+ }
705
+ self.sendSuccessWithMultipleResponse(command: command, result: result as! String)
706
+ })
707
+ removeFromQueue(id: command.callbackId)
708
+ })
709
+ }
710
+
711
+ func addToQueue(command: CDVInvokedUrlCommand, bleAction: @escaping () -> Void) {
712
+ bleActionQueue.enqueue(BLEAction(command.callbackId, bleAction))
713
+ if (!isHandlingQueue) {
714
+ isHandlingQueue = true
715
+ DispatchQueue.main.async {
716
+ bleAction()
717
+ }
718
+ }
719
+ }
720
+
721
+ func removeFromQueue(id: String) {
722
+ bleActionQueue.dequeue(searchClosure: {$0.id == id})
723
+ if (isHandlingQueue) {
724
+ DispatchQueue.main.async {
725
+ self.bleActionQueue.first?.action()
726
+ if (self.bleActionQueue.isEmpty) {
727
+ self.isHandlingQueue = false
728
+ }
729
+ }
730
+ }
731
+ }
732
+
733
+
734
+ @objc(close:)
735
+ func close(command: CDVInvokedUrlCommand) {
736
+ disConnect(command: command)
737
+ }
738
+ }
739
+
740
+ struct ScannerOptions: Decodable {
741
+ let filters: [String]?
742
+ }
743
+
744
+