@capacitor-community/bluetooth-le 8.0.0-0 → 8.0.0

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.
@@ -1,423 +1,423 @@
1
- // swiftlint:disable type_body_length
2
- import Foundation
3
- import CoreBluetooth
4
-
5
- class Device: NSObject, CBPeripheralDelegate {
6
- typealias Callback = (_ success: Bool, _ value: String) -> Void
7
-
8
- private var peripheral: CBPeripheral!
9
- private var callbackMap = ThreadSafeDictionary<String, Callback>()
10
- private var timeoutMap = [String: DispatchWorkItem]()
11
- private var servicesCount = 0
12
- private var servicesDiscovered = 0
13
- private var characteristicsCount = 0
14
- private var characteristicsDiscovered = 0
15
-
16
- init(
17
- _ peripheral: CBPeripheral
18
- ) {
19
- super.init()
20
- self.peripheral = peripheral
21
- self.peripheral.delegate = self
22
- }
23
-
24
- func getName() -> String? {
25
- return self.peripheral.name
26
- }
27
-
28
- func getId() -> String {
29
- return self.peripheral.identifier.uuidString
30
- }
31
-
32
- func isConnected() -> Bool {
33
- return self.peripheral.state == CBPeripheralState.connected
34
- }
35
-
36
- func getPeripheral() -> CBPeripheral {
37
- return self.peripheral
38
- }
39
-
40
- func setOnConnected(
41
- _ connectionTimeout: Double,
42
- _ callback: @escaping Callback
43
- ) {
44
- let key = "connect"
45
- self.callbackMap[key] = callback
46
- self.setTimeout(key, "Connection timeout", connectionTimeout)
47
- }
48
-
49
- func peripheral(
50
- _ peripheral: CBPeripheral,
51
- didDiscoverServices error: Error?
52
- ) {
53
- log("didDiscoverServices")
54
- if error != nil {
55
- log("Error", error!.localizedDescription)
56
- return
57
- }
58
- self.servicesCount = peripheral.services?.count ?? 0
59
- self.servicesDiscovered = 0
60
- self.characteristicsCount = 0
61
- self.characteristicsDiscovered = 0
62
- for service in peripheral.services ?? [] {
63
- peripheral.discoverCharacteristics(nil, for: service)
64
- }
65
- }
66
-
67
- func peripheral(
68
- _ peripheral: CBPeripheral,
69
- didDiscoverCharacteristicsFor service: CBService,
70
- error: Error?
71
- ) {
72
- self.servicesDiscovered += 1
73
- log("didDiscoverCharacteristicsFor", self.servicesDiscovered, self.servicesCount)
74
- self.characteristicsCount += service.characteristics?.count ?? 0
75
- for characteristic in service.characteristics ?? [] {
76
- peripheral.discoverDescriptors(for: characteristic)
77
- }
78
- // if the last service does not have characteristics, resolve the connect call now
79
- if self.servicesDiscovered >= self.servicesCount && self.characteristicsDiscovered >= self.characteristicsCount {
80
- self.resolve("connect", "Connection successful.")
81
- self.resolve("discoverServices", "Services discovered.")
82
- }
83
- }
84
-
85
- func peripheral(
86
- _ peripheral: CBPeripheral,
87
- didDiscoverDescriptorsFor characteristic: CBCharacteristic,
88
- error: Error?
89
- ) {
90
- self.characteristicsDiscovered += 1
91
- if self.servicesDiscovered >= self.servicesCount && self.characteristicsDiscovered >= self.characteristicsCount {
92
- self.resolve("connect", "Connection successful.")
93
- self.resolve("discoverServices", "Services discovered.")
94
- }
95
- }
96
-
97
- func getServices() -> [CBService] {
98
- return self.peripheral.services ?? []
99
- }
100
-
101
- func discoverServices(
102
- _ timeout: Double,
103
- _ callback: @escaping Callback
104
- ) {
105
- let key = "discoverServices"
106
- self.callbackMap[key] = callback
107
- self.peripheral.discoverServices(nil)
108
- self.setTimeout(key, "Service discovery timeout.", timeout)
109
- }
110
-
111
- func getMtu() -> Int {
112
- // maximumWriteValueLength is 3 bytes less than ATT MTU
113
- return self.peripheral.maximumWriteValueLength(for: .withoutResponse) + 3
114
- }
115
-
116
- func readRssi(
117
- _ timeout: Double,
118
- _ callback: @escaping Callback
119
- ) {
120
- let key = "readRssi"
121
- self.callbackMap[key] = callback
122
- log("Reading RSSI value")
123
- self.peripheral.readRSSI()
124
- self.setTimeout(key, "Reading RSSI timeout.", timeout)
125
- }
126
-
127
- func peripheral(
128
- _ peripheral: CBPeripheral,
129
- didReadRSSI RSSI: NSNumber,
130
- error: Error?
131
- ) {
132
- let key = "readRssi"
133
- if error != nil {
134
- self.reject(key, error!.localizedDescription)
135
- return
136
- }
137
- self.resolve(key, RSSI.stringValue)
138
- }
139
-
140
- private func getCharacteristic(
141
- _ serviceUUID: CBUUID,
142
- _ characteristicUUID: CBUUID
143
- ) -> CBCharacteristic? {
144
- for service in peripheral.services ?? [] {
145
- if service.uuid == serviceUUID {
146
- for characteristic in service.characteristics ?? [] {
147
- if characteristic.uuid == characteristicUUID {
148
- return characteristic
149
- }
150
- }
151
- }
152
- }
153
- return nil
154
- }
155
-
156
- private func getDescriptor(
157
- _ serviceUUID: CBUUID,
158
- _ characteristicUUID: CBUUID,
159
- _ descriptorUUID: CBUUID
160
- ) -> CBDescriptor? {
161
- guard let characteristic = self.getCharacteristic(serviceUUID, characteristicUUID) else {
162
- return nil
163
- }
164
- for descriptor in characteristic.descriptors ?? [] {
165
- if descriptor.uuid == descriptorUUID {
166
- return descriptor
167
- }
168
- }
169
- return nil
170
- }
171
-
172
- func read(
173
- _ serviceUUID: CBUUID,
174
- _ characteristicUUID: CBUUID,
175
- _ timeout: Double,
176
- _ callback: @escaping Callback
177
- ) {
178
- let key = "read|\(serviceUUID.uuidString)|\(characteristicUUID.uuidString)"
179
- self.callbackMap[key] = callback
180
- guard let characteristic = self.getCharacteristic(serviceUUID, characteristicUUID) else {
181
- self.reject(key, "Characteristic not found.")
182
- return
183
- }
184
- log("Reading value")
185
- self.peripheral.readValue(for: characteristic)
186
- self.setTimeout(key, "Read timeout.", timeout)
187
- }
188
-
189
- func peripheral(
190
- _ peripheral: CBPeripheral,
191
- didUpdateValueFor characteristic: CBCharacteristic,
192
- error: Error?
193
- ) {
194
- let key = self.getKey("read", characteristic)
195
- let notifyKey = self.getKey("notification", characteristic)
196
- if error != nil {
197
- self.reject(key, error!.localizedDescription)
198
- return
199
- }
200
- if characteristic.value == nil {
201
- self.reject(key, "Characteristic contains no value.")
202
- return
203
- }
204
- // reading
205
- let valueString = dataToString(characteristic.value!)
206
- self.resolve(key, valueString)
207
-
208
- // notifications
209
- let callback = self.callbackMap[notifyKey]
210
- if callback != nil {
211
- callback!(true, valueString)
212
- }
213
- }
214
-
215
- func readDescriptor(
216
- _ serviceUUID: CBUUID,
217
- _ characteristicUUID: CBUUID,
218
- _ descriptorUUID: CBUUID,
219
- _ timeout: Double,
220
- _ callback: @escaping Callback
221
- ) {
222
- let key = "readDescriptor|\(serviceUUID.uuidString)|\(characteristicUUID.uuidString)|\(descriptorUUID.uuidString)"
223
- self.callbackMap[key] = callback
224
- guard let descriptor = self.getDescriptor(serviceUUID, characteristicUUID, descriptorUUID) else {
225
- self.reject(key, "Descriptor not found.")
226
- return
227
- }
228
- log("Reading descriptor value")
229
- self.peripheral.readValue(for: descriptor)
230
- self.setTimeout(key, "Read descriptor timeout.", timeout)
231
- }
232
-
233
- func peripheral(
234
- _ peripheral: CBPeripheral,
235
- didUpdateValueFor descriptor: CBDescriptor,
236
- error: Error?
237
- ) {
238
- let key = self.getKey("readDescriptor", descriptor)
239
- if error != nil {
240
- self.reject(key, error!.localizedDescription)
241
- return
242
- }
243
- if descriptor.value == nil {
244
- self.reject(key, "Descriptor contains no value.")
245
- return
246
- }
247
- let valueString = descriptorValueToString(descriptor.value!)
248
- self.resolve(key, valueString)
249
- }
250
-
251
- func write(
252
- _ serviceUUID: CBUUID,
253
- _ characteristicUUID: CBUUID,
254
- _ value: String,
255
- _ writeType: CBCharacteristicWriteType,
256
- _ timeout: Double,
257
- _ callback: @escaping Callback
258
- ) {
259
- let key = "write|\(serviceUUID.uuidString)|\(characteristicUUID.uuidString)"
260
- self.callbackMap[key] = callback
261
- guard let characteristic = self.getCharacteristic(serviceUUID, characteristicUUID) else {
262
- self.reject(key, "Characteristic not found.")
263
- return
264
- }
265
- let data: Data = stringToData(value)
266
- self.peripheral.writeValue(data, for: characteristic, type: writeType)
267
- if writeType == CBCharacteristicWriteType.withResponse {
268
- self.setTimeout(key, "Write timeout.", timeout)
269
- } else {
270
- self.resolve(key, "Successfully written value.")
271
- }
272
- }
273
-
274
- func peripheral(
275
- _ peripheral: CBPeripheral,
276
- didWriteValueFor characteristic: CBCharacteristic,
277
- error: Error?
278
- ) {
279
- let key = self.getKey("write", characteristic)
280
- if error != nil {
281
- self.reject(key, error!.localizedDescription)
282
- return
283
- }
284
- self.resolve(key, "Successfully written value.")
285
- }
286
-
287
- func writeDescriptor(
288
- _ serviceUUID: CBUUID,
289
- _ characteristicUUID: CBUUID,
290
- _ descriptorUUID: CBUUID,
291
- _ value: String,
292
- _ timeout: Double,
293
- _ callback: @escaping Callback
294
- ) {
295
- let key = "writeDescriptor|\(serviceUUID.uuidString)|\(characteristicUUID.uuidString)|\(descriptorUUID.uuidString)"
296
- self.callbackMap[key] = callback
297
- guard let descriptor = self.getDescriptor(serviceUUID, characteristicUUID, descriptorUUID) else {
298
- self.reject(key, "Descriptor not found.")
299
- return
300
- }
301
- let data: Data = stringToData(value)
302
- self.peripheral.writeValue(data, for: descriptor)
303
- self.setTimeout(key, "Write descriptor timeout.", timeout)
304
- }
305
-
306
- func peripheral(
307
- _ peripheral: CBPeripheral,
308
- didWriteValueFor descriptor: CBDescriptor,
309
- error: Error?
310
- ) {
311
- let key = self.getKey("writeDescriptor", descriptor)
312
- if error != nil {
313
- self.reject(key, error!.localizedDescription)
314
- return
315
- }
316
- self.resolve(key, "Successfully written descriptor value.")
317
- }
318
-
319
- func setNotifications(
320
- _ serviceUUID: CBUUID,
321
- _ characteristicUUID: CBUUID,
322
- _ enable: Bool,
323
- _ notifyCallback: Callback?,
324
- _ timeout: Double,
325
- _ callback: @escaping Callback
326
- ) {
327
- let key = "setNotifications|\(serviceUUID.uuidString)|\(characteristicUUID.uuidString)"
328
- let notifyKey = "notification|\(serviceUUID.uuidString)|\(characteristicUUID.uuidString)"
329
- self.callbackMap[key] = callback
330
- if notifyCallback != nil {
331
- self.callbackMap[notifyKey] = notifyCallback
332
- }
333
- guard let characteristic = self.getCharacteristic(serviceUUID, characteristicUUID) else {
334
- self.reject(key, "Characteristic not found.")
335
- return
336
- }
337
- log("Set notifications", enable)
338
- self.peripheral.setNotifyValue(enable, for: characteristic)
339
- self.setTimeout(key, "Set notifications timeout.", timeout)
340
- }
341
-
342
- func peripheral(
343
- _ peripheral: CBPeripheral,
344
- didUpdateNotificationStateFor characteristic: CBCharacteristic,
345
- error: Error?
346
- ) {
347
- let key = self.getKey("setNotifications", characteristic)
348
- if error != nil {
349
- self.reject(key, error!.localizedDescription)
350
- return
351
- }
352
- self.resolve(key, "Successfully set notifications.")
353
- }
354
-
355
- private func getKey(
356
- _ prefix: String,
357
- _ characteristic: CBCharacteristic?
358
- ) -> String {
359
- let serviceUUIDString: String
360
- let service: CBService? = characteristic?.service
361
- if service != nil {
362
- serviceUUIDString = cbuuidToStringUppercase(service!.uuid)
363
- } else {
364
- serviceUUIDString = "UNKNOWN-SERVICE"
365
- }
366
- let characteristicUUIDString: String
367
- if characteristic != nil {
368
- characteristicUUIDString = cbuuidToStringUppercase(characteristic!.uuid)
369
- } else {
370
- characteristicUUIDString = "UNKNOWN-CHARACTERISTIC"
371
- }
372
- return "\(prefix)|\(serviceUUIDString)|\(characteristicUUIDString)"
373
- }
374
-
375
- private func getKey(
376
- _ prefix: String,
377
- _ descriptor: CBDescriptor
378
- ) -> String {
379
- let baseKey = self.getKey(prefix, descriptor.characteristic)
380
- let descriptorUUIDString = cbuuidToStringUppercase(descriptor.uuid)
381
- return "\(baseKey)|\(descriptorUUIDString)"
382
- }
383
-
384
- private func resolve(
385
- _ key: String,
386
- _ value: String
387
- ) {
388
- let callback = self.callbackMap[key]
389
- if callback != nil {
390
- log("Resolve", key, value)
391
- callback!(true, value)
392
- self.callbackMap[key] = nil
393
- self.timeoutMap[key]?.cancel()
394
- self.timeoutMap[key] = nil
395
- }
396
- }
397
-
398
- private func reject(
399
- _ key: String,
400
- _ value: String
401
- ) {
402
- let callback = self.callbackMap[key]
403
- if callback != nil {
404
- log("Reject", key, value)
405
- callback!(false, value)
406
- self.callbackMap[key] = nil
407
- self.timeoutMap[key]?.cancel()
408
- self.timeoutMap[key] = nil
409
- }
410
- }
411
-
412
- private func setTimeout(
413
- _ key: String,
414
- _ message: String,
415
- _ timeout: Double
416
- ) {
417
- let workItem = DispatchWorkItem {
418
- self.reject(key, message)
419
- }
420
- self.timeoutMap[key] = workItem
421
- DispatchQueue.main.asyncAfter(deadline: .now() + timeout, execute: workItem)
422
- }
423
- }
1
+ // swiftlint:disable type_body_length
2
+ import Foundation
3
+ import CoreBluetooth
4
+
5
+ class Device: NSObject, CBPeripheralDelegate {
6
+ typealias Callback = (_ success: Bool, _ value: String) -> Void
7
+
8
+ private var peripheral: CBPeripheral!
9
+ private var callbackMap = ThreadSafeDictionary<String, Callback>()
10
+ private var timeoutMap = [String: DispatchWorkItem]()
11
+ private var servicesCount = 0
12
+ private var servicesDiscovered = 0
13
+ private var characteristicsCount = 0
14
+ private var characteristicsDiscovered = 0
15
+
16
+ init(
17
+ _ peripheral: CBPeripheral
18
+ ) {
19
+ super.init()
20
+ self.peripheral = peripheral
21
+ self.peripheral.delegate = self
22
+ }
23
+
24
+ func getName() -> String? {
25
+ return self.peripheral.name
26
+ }
27
+
28
+ func getId() -> String {
29
+ return self.peripheral.identifier.uuidString
30
+ }
31
+
32
+ func isConnected() -> Bool {
33
+ return self.peripheral.state == CBPeripheralState.connected
34
+ }
35
+
36
+ func getPeripheral() -> CBPeripheral {
37
+ return self.peripheral
38
+ }
39
+
40
+ func setOnConnected(
41
+ _ connectionTimeout: Double,
42
+ _ callback: @escaping Callback
43
+ ) {
44
+ let key = "connect"
45
+ self.callbackMap[key] = callback
46
+ self.setTimeout(key, "Connection timeout", connectionTimeout)
47
+ }
48
+
49
+ func peripheral(
50
+ _ peripheral: CBPeripheral,
51
+ didDiscoverServices error: Error?
52
+ ) {
53
+ log("didDiscoverServices")
54
+ if error != nil {
55
+ log("Error", error!.localizedDescription)
56
+ return
57
+ }
58
+ self.servicesCount = peripheral.services?.count ?? 0
59
+ self.servicesDiscovered = 0
60
+ self.characteristicsCount = 0
61
+ self.characteristicsDiscovered = 0
62
+ for service in peripheral.services ?? [] {
63
+ peripheral.discoverCharacteristics(nil, for: service)
64
+ }
65
+ }
66
+
67
+ func peripheral(
68
+ _ peripheral: CBPeripheral,
69
+ didDiscoverCharacteristicsFor service: CBService,
70
+ error: Error?
71
+ ) {
72
+ self.servicesDiscovered += 1
73
+ log("didDiscoverCharacteristicsFor", self.servicesDiscovered, self.servicesCount)
74
+ self.characteristicsCount += service.characteristics?.count ?? 0
75
+ for characteristic in service.characteristics ?? [] {
76
+ peripheral.discoverDescriptors(for: characteristic)
77
+ }
78
+ // if the last service does not have characteristics, resolve the connect call now
79
+ if self.servicesDiscovered >= self.servicesCount && self.characteristicsDiscovered >= self.characteristicsCount {
80
+ self.resolve("connect", "Connection successful.")
81
+ self.resolve("discoverServices", "Services discovered.")
82
+ }
83
+ }
84
+
85
+ func peripheral(
86
+ _ peripheral: CBPeripheral,
87
+ didDiscoverDescriptorsFor characteristic: CBCharacteristic,
88
+ error: Error?
89
+ ) {
90
+ self.characteristicsDiscovered += 1
91
+ if self.servicesDiscovered >= self.servicesCount && self.characteristicsDiscovered >= self.characteristicsCount {
92
+ self.resolve("connect", "Connection successful.")
93
+ self.resolve("discoverServices", "Services discovered.")
94
+ }
95
+ }
96
+
97
+ func getServices() -> [CBService] {
98
+ return self.peripheral.services ?? []
99
+ }
100
+
101
+ func discoverServices(
102
+ _ timeout: Double,
103
+ _ callback: @escaping Callback
104
+ ) {
105
+ let key = "discoverServices"
106
+ self.callbackMap[key] = callback
107
+ self.peripheral.discoverServices(nil)
108
+ self.setTimeout(key, "Service discovery timeout.", timeout)
109
+ }
110
+
111
+ func getMtu() -> Int {
112
+ // maximumWriteValueLength is 3 bytes less than ATT MTU
113
+ return self.peripheral.maximumWriteValueLength(for: .withoutResponse) + 3
114
+ }
115
+
116
+ func readRssi(
117
+ _ timeout: Double,
118
+ _ callback: @escaping Callback
119
+ ) {
120
+ let key = "readRssi"
121
+ self.callbackMap[key] = callback
122
+ log("Reading RSSI value")
123
+ self.peripheral.readRSSI()
124
+ self.setTimeout(key, "Reading RSSI timeout.", timeout)
125
+ }
126
+
127
+ func peripheral(
128
+ _ peripheral: CBPeripheral,
129
+ didReadRSSI RSSI: NSNumber,
130
+ error: Error?
131
+ ) {
132
+ let key = "readRssi"
133
+ if error != nil {
134
+ self.reject(key, error!.localizedDescription)
135
+ return
136
+ }
137
+ self.resolve(key, RSSI.stringValue)
138
+ }
139
+
140
+ private func getCharacteristic(
141
+ _ serviceUUID: CBUUID,
142
+ _ characteristicUUID: CBUUID
143
+ ) -> CBCharacteristic? {
144
+ for service in peripheral.services ?? [] {
145
+ if service.uuid == serviceUUID {
146
+ for characteristic in service.characteristics ?? [] {
147
+ if characteristic.uuid == characteristicUUID {
148
+ return characteristic
149
+ }
150
+ }
151
+ }
152
+ }
153
+ return nil
154
+ }
155
+
156
+ private func getDescriptor(
157
+ _ serviceUUID: CBUUID,
158
+ _ characteristicUUID: CBUUID,
159
+ _ descriptorUUID: CBUUID
160
+ ) -> CBDescriptor? {
161
+ guard let characteristic = self.getCharacteristic(serviceUUID, characteristicUUID) else {
162
+ return nil
163
+ }
164
+ for descriptor in characteristic.descriptors ?? [] {
165
+ if descriptor.uuid == descriptorUUID {
166
+ return descriptor
167
+ }
168
+ }
169
+ return nil
170
+ }
171
+
172
+ func read(
173
+ _ serviceUUID: CBUUID,
174
+ _ characteristicUUID: CBUUID,
175
+ _ timeout: Double,
176
+ _ callback: @escaping Callback
177
+ ) {
178
+ let key = "read|\(serviceUUID.uuidString)|\(characteristicUUID.uuidString)"
179
+ self.callbackMap[key] = callback
180
+ guard let characteristic = self.getCharacteristic(serviceUUID, characteristicUUID) else {
181
+ self.reject(key, "Characteristic not found.")
182
+ return
183
+ }
184
+ log("Reading value")
185
+ self.peripheral.readValue(for: characteristic)
186
+ self.setTimeout(key, "Read timeout.", timeout)
187
+ }
188
+
189
+ func peripheral(
190
+ _ peripheral: CBPeripheral,
191
+ didUpdateValueFor characteristic: CBCharacteristic,
192
+ error: Error?
193
+ ) {
194
+ let key = self.getKey("read", characteristic)
195
+ let notifyKey = self.getKey("notification", characteristic)
196
+ if error != nil {
197
+ self.reject(key, error!.localizedDescription)
198
+ return
199
+ }
200
+ if characteristic.value == nil {
201
+ self.reject(key, "Characteristic contains no value.")
202
+ return
203
+ }
204
+ // reading
205
+ let valueString = dataToString(characteristic.value!)
206
+ self.resolve(key, valueString)
207
+
208
+ // notifications
209
+ let callback = self.callbackMap[notifyKey]
210
+ if callback != nil {
211
+ callback!(true, valueString)
212
+ }
213
+ }
214
+
215
+ func readDescriptor(
216
+ _ serviceUUID: CBUUID,
217
+ _ characteristicUUID: CBUUID,
218
+ _ descriptorUUID: CBUUID,
219
+ _ timeout: Double,
220
+ _ callback: @escaping Callback
221
+ ) {
222
+ let key = "readDescriptor|\(serviceUUID.uuidString)|\(characteristicUUID.uuidString)|\(descriptorUUID.uuidString)"
223
+ self.callbackMap[key] = callback
224
+ guard let descriptor = self.getDescriptor(serviceUUID, characteristicUUID, descriptorUUID) else {
225
+ self.reject(key, "Descriptor not found.")
226
+ return
227
+ }
228
+ log("Reading descriptor value")
229
+ self.peripheral.readValue(for: descriptor)
230
+ self.setTimeout(key, "Read descriptor timeout.", timeout)
231
+ }
232
+
233
+ func peripheral(
234
+ _ peripheral: CBPeripheral,
235
+ didUpdateValueFor descriptor: CBDescriptor,
236
+ error: Error?
237
+ ) {
238
+ let key = self.getKey("readDescriptor", descriptor)
239
+ if error != nil {
240
+ self.reject(key, error!.localizedDescription)
241
+ return
242
+ }
243
+ if descriptor.value == nil {
244
+ self.reject(key, "Descriptor contains no value.")
245
+ return
246
+ }
247
+ let valueString = descriptorValueToString(descriptor.value!)
248
+ self.resolve(key, valueString)
249
+ }
250
+
251
+ func write(
252
+ _ serviceUUID: CBUUID,
253
+ _ characteristicUUID: CBUUID,
254
+ _ value: String,
255
+ _ writeType: CBCharacteristicWriteType,
256
+ _ timeout: Double,
257
+ _ callback: @escaping Callback
258
+ ) {
259
+ let key = "write|\(serviceUUID.uuidString)|\(characteristicUUID.uuidString)"
260
+ self.callbackMap[key] = callback
261
+ guard let characteristic = self.getCharacteristic(serviceUUID, characteristicUUID) else {
262
+ self.reject(key, "Characteristic not found.")
263
+ return
264
+ }
265
+ let data: Data = stringToData(value)
266
+ self.peripheral.writeValue(data, for: characteristic, type: writeType)
267
+ if writeType == CBCharacteristicWriteType.withResponse {
268
+ self.setTimeout(key, "Write timeout.", timeout)
269
+ } else {
270
+ self.resolve(key, "Successfully written value.")
271
+ }
272
+ }
273
+
274
+ func peripheral(
275
+ _ peripheral: CBPeripheral,
276
+ didWriteValueFor characteristic: CBCharacteristic,
277
+ error: Error?
278
+ ) {
279
+ let key = self.getKey("write", characteristic)
280
+ if error != nil {
281
+ self.reject(key, error!.localizedDescription)
282
+ return
283
+ }
284
+ self.resolve(key, "Successfully written value.")
285
+ }
286
+
287
+ func writeDescriptor(
288
+ _ serviceUUID: CBUUID,
289
+ _ characteristicUUID: CBUUID,
290
+ _ descriptorUUID: CBUUID,
291
+ _ value: String,
292
+ _ timeout: Double,
293
+ _ callback: @escaping Callback
294
+ ) {
295
+ let key = "writeDescriptor|\(serviceUUID.uuidString)|\(characteristicUUID.uuidString)|\(descriptorUUID.uuidString)"
296
+ self.callbackMap[key] = callback
297
+ guard let descriptor = self.getDescriptor(serviceUUID, characteristicUUID, descriptorUUID) else {
298
+ self.reject(key, "Descriptor not found.")
299
+ return
300
+ }
301
+ let data: Data = stringToData(value)
302
+ self.peripheral.writeValue(data, for: descriptor)
303
+ self.setTimeout(key, "Write descriptor timeout.", timeout)
304
+ }
305
+
306
+ func peripheral(
307
+ _ peripheral: CBPeripheral,
308
+ didWriteValueFor descriptor: CBDescriptor,
309
+ error: Error?
310
+ ) {
311
+ let key = self.getKey("writeDescriptor", descriptor)
312
+ if error != nil {
313
+ self.reject(key, error!.localizedDescription)
314
+ return
315
+ }
316
+ self.resolve(key, "Successfully written descriptor value.")
317
+ }
318
+
319
+ func setNotifications(
320
+ _ serviceUUID: CBUUID,
321
+ _ characteristicUUID: CBUUID,
322
+ _ enable: Bool,
323
+ _ notifyCallback: Callback?,
324
+ _ timeout: Double,
325
+ _ callback: @escaping Callback
326
+ ) {
327
+ let key = "setNotifications|\(serviceUUID.uuidString)|\(characteristicUUID.uuidString)"
328
+ let notifyKey = "notification|\(serviceUUID.uuidString)|\(characteristicUUID.uuidString)"
329
+ self.callbackMap[key] = callback
330
+ if notifyCallback != nil {
331
+ self.callbackMap[notifyKey] = notifyCallback
332
+ }
333
+ guard let characteristic = self.getCharacteristic(serviceUUID, characteristicUUID) else {
334
+ self.reject(key, "Characteristic not found.")
335
+ return
336
+ }
337
+ log("Set notifications", enable)
338
+ self.peripheral.setNotifyValue(enable, for: characteristic)
339
+ self.setTimeout(key, "Set notifications timeout.", timeout)
340
+ }
341
+
342
+ func peripheral(
343
+ _ peripheral: CBPeripheral,
344
+ didUpdateNotificationStateFor characteristic: CBCharacteristic,
345
+ error: Error?
346
+ ) {
347
+ let key = self.getKey("setNotifications", characteristic)
348
+ if error != nil {
349
+ self.reject(key, error!.localizedDescription)
350
+ return
351
+ }
352
+ self.resolve(key, "Successfully set notifications.")
353
+ }
354
+
355
+ private func getKey(
356
+ _ prefix: String,
357
+ _ characteristic: CBCharacteristic?
358
+ ) -> String {
359
+ let serviceUUIDString: String
360
+ let service: CBService? = characteristic?.service
361
+ if service != nil {
362
+ serviceUUIDString = cbuuidToStringUppercase(service!.uuid)
363
+ } else {
364
+ serviceUUIDString = "UNKNOWN-SERVICE"
365
+ }
366
+ let characteristicUUIDString: String
367
+ if characteristic != nil {
368
+ characteristicUUIDString = cbuuidToStringUppercase(characteristic!.uuid)
369
+ } else {
370
+ characteristicUUIDString = "UNKNOWN-CHARACTERISTIC"
371
+ }
372
+ return "\(prefix)|\(serviceUUIDString)|\(characteristicUUIDString)"
373
+ }
374
+
375
+ private func getKey(
376
+ _ prefix: String,
377
+ _ descriptor: CBDescriptor
378
+ ) -> String {
379
+ let baseKey = self.getKey(prefix, descriptor.characteristic)
380
+ let descriptorUUIDString = cbuuidToStringUppercase(descriptor.uuid)
381
+ return "\(baseKey)|\(descriptorUUIDString)"
382
+ }
383
+
384
+ private func resolve(
385
+ _ key: String,
386
+ _ value: String
387
+ ) {
388
+ let callback = self.callbackMap[key]
389
+ if callback != nil {
390
+ log("Resolve", key, value)
391
+ callback!(true, value)
392
+ self.callbackMap[key] = nil
393
+ self.timeoutMap[key]?.cancel()
394
+ self.timeoutMap[key] = nil
395
+ }
396
+ }
397
+
398
+ private func reject(
399
+ _ key: String,
400
+ _ value: String
401
+ ) {
402
+ let callback = self.callbackMap[key]
403
+ if callback != nil {
404
+ log("Reject", key, value)
405
+ callback!(false, value)
406
+ self.callbackMap[key] = nil
407
+ self.timeoutMap[key]?.cancel()
408
+ self.timeoutMap[key] = nil
409
+ }
410
+ }
411
+
412
+ private func setTimeout(
413
+ _ key: String,
414
+ _ message: String,
415
+ _ timeout: Double
416
+ ) {
417
+ let workItem = DispatchWorkItem {
418
+ self.reject(key, message)
419
+ }
420
+ self.timeoutMap[key] = workItem
421
+ DispatchQueue.main.asyncAfter(deadline: .now() + timeout, execute: workItem)
422
+ }
423
+ }