@iotize/device-com-nfc.cordova 3.9.0 → 3.9.2

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,506 +1,536 @@
1
- import CoreNFC
2
-
3
- @available(iOS 13.0, *)
4
- class NFCTagReader : NSObject, NFCTagReaderSessionDelegate {
5
-
6
- private var plugin: NfcPlugin
7
-
8
- typealias Completion = (Error?) -> ()
9
- typealias CompletionWithJSONResponse = ([AnyHashable: Any]?, Error?) -> ()
10
-
11
- internal var comSession: NFCTagReaderSession?
12
- internal var tag: NFCTag?
13
-
14
- static var MB_CTRL_DYN : UInt8 = 0x0D
15
-
16
- internal var connectionCompleted : Completion?
17
- internal var initSessionCompletion: Completion?
18
- internal var onDiscoverCompletion : CompletionWithJSONResponse?
19
-
20
-
21
- static var DELAY : UInt32 = 1000; // timeout resolution in millionths of second
22
- static var NB_MAX_RETRY : Int = 50;
23
-
24
- init(plugin: NfcPlugin) {
25
- self.plugin = plugin
26
- super.init()
27
- }
28
-
29
- func initSession( pollingOption: NFCTagReaderSession.PollingOption, alertMessage: String, completed: Completion? ) {
30
- return self.initSession(pollingOption: pollingOption, alertMessage: alertMessage, completed: completed, onDiscover: nil)
31
- }
32
-
33
- func initSession( pollingOption: NFCTagReaderSession.PollingOption, alertMessage: String, onDiscover: CompletionWithJSONResponse?) {
34
- return self.initSession(pollingOption: pollingOption, alertMessage: alertMessage, completed: nil, onDiscover: onDiscover)
35
- }
36
-
37
- func initSession( pollingOption: NFCTagReaderSession.PollingOption, alertMessage: String, completed: Completion?, onDiscover: CompletionWithJSONResponse? ) {
38
- connectionCompleted = completed
39
- onDiscoverCompletion = onDiscover
40
-
41
- if NFCNDEFReaderSession.readingAvailable {
42
- comSession = NFCTagReaderSession(pollingOption: pollingOption, delegate: self, queue: nil)
43
- comSession?.alertMessage = alertMessage
44
- comSession?.begin()
45
- } else {
46
- completed?(NFCReaderError.readerTransceiveErrorSessionInvalidated as? Error)
47
- }
48
- }
49
-
50
- func initSession( pollingOption: NFCTagReaderSession.PollingOption, alertMessage: String, initSessionCompletion: Completion?, onDiscover: CompletionWithJSONResponse? ) {
51
- self.initSessionCompletion = initSessionCompletion
52
- return self.initSession(pollingOption: pollingOption, alertMessage: alertMessage, completed: nil, onDiscover: onDiscover)
53
- }
54
-
55
- func invalidateSession( message :String) {
56
- comSession?.alertMessage = message
57
- comSession?.invalidate()
58
- tag = nil
59
- }
60
-
61
- func tagReaderSessionDidBecomeActive(_ session: NFCTagReaderSession) {
62
- // If necessary, you may perform additional operations on session start.
63
- // At this point RF polling is enabled.
64
- if let actualInitSessionCompletion = initSessionCompletion {
65
- actualInitSessionCompletion(nil)
66
- initSessionCompletion = nil //do not keep session completion
67
- }
68
- printNFC( "tagReaderSessionDidBecomeActive" )
69
- }
70
-
71
- func tagReaderSession(_ session: NFCTagReaderSession, didInvalidateWithError error: Error) {
72
- // If necessary, you may handle the error. Note session is no longer valid.
73
- // You must create a new session to restart RF polling.
74
- printNFC( "tagReaderSession:didInvalidateWithError - \(error)" )
75
- if let actualInitSessionCompletion = initSessionCompletion {
76
- actualInitSessionCompletion(error)
77
- initSessionCompletion = nil //do not keep session completion
78
- }
79
- connectionCompleted?(error)
80
- clear()
81
- self.comSession = nil
82
- }
83
-
84
- func tagReaderSession(_ session: NFCTagReaderSession, didDetect tags: [NFCTag]) {
85
- printNFC( "tagReaderSession:didDectectTag" )
86
- guard let session = self.comSession else {
87
- return;
88
- }
89
- if tags.count > 1 {
90
- // Restart polling in 500 milliseconds.
91
- let retryInterval = DispatchTimeInterval.milliseconds(500)
92
- session.alertMessage = "More than 1 Tap is detected. Please remove all tags and try again."
93
- DispatchQueue.global().asyncAfter(deadline: .now() + retryInterval, execute: {
94
- session.restartPolling()
95
- })
96
- return
97
-
98
- }
99
-
100
- guard let tag = tags.first else {
101
- return;
102
- }
103
-
104
- self.tag = tag
105
-
106
- if let onDiscover = self.onDiscoverCompletion {
107
-
108
- Task {
109
- self.onDiscoverCompletion?(await self.createJSON(tag: tag), nil)
110
- }
111
-
112
- }
113
-
114
- if let connectionCompletion = self.connectionCompleted {
115
- connect(tech: nil, connectionCompletion: connectionCompletion)
116
- }
117
-
118
- }
119
-
120
- //full transparent mode
121
-
122
- @available(iOS 14.0, *)
123
- func transceiveRaw(request: Data, completed: @escaping (Data?, Error?) -> (), nbTry: Int = NB_MAX_RETRY) {
124
- guard (request.count >= 2) else {
125
- completed(nil, NFCReaderError(NFCReaderError.readerErrorInvalidParameterLength))
126
- return
127
- }
128
-
129
- switch self.tag {
130
- case .iso15693(let iso15693Tag):
131
-
132
- let flags = Int(request[0])
133
- let commandCode = Int(request[1])
134
- let dataToSend = request.dropFirst(2)
135
-
136
- printNFC("TRANSCEIVE RAW SEND \(request.hexEncodedString())")
137
- printNFC("TRANSCEIVE RAW SEND ON ISO15TAG TRY \(nbTry), SESSION READY \(String(describing: comSession?.isReady))")
138
-
139
- iso15693Tag.sendRequest(requestFlags: flags, commandCode: commandCode, data: dataToSend, resultHandler: {(result: Result<(NFCISO15693ResponseFlag, Data?), any Error>) in
140
-
141
- printNFC("SEND_REQUEST_CALLBACK")
142
- switch result {
143
- case .success((let flag, let data)):
144
- let firstByteBuffer = withUnsafeBytes(of: flag.rawValue) { Data($0)}
145
- var resultData = Data(firstByteBuffer)
146
- if let nonNilData = data {
147
- resultData.append(nonNilData)
148
- }
149
-
150
- //Last delay to let ST25DV "breathe"
151
- //usleep(1000*NFCTagReader.DELAY)
152
-
153
- printNFC("TRANSCEIVE RAW RETURN \(resultData.hexEncodedString())")
154
- completed(resultData, nil)
155
- return
156
- case .failure(let error):
157
- printNFC("TRANSCEIVE RAW ERROR \(error.localizedDescription), TRY \(nbTry)")
158
- if (nbTry >= 0) {
159
- usleep(NFCTagReader.DELAY)
160
- return self.transceiveRaw(request: request, completed: completed, nbTry: nbTry - 1)
161
- }
162
-
163
- completed(nil, error)
164
- return
165
- }
166
- })
167
- break
168
- case .iso7816(let iso7816Tag):
169
- printNFC("TRANSCEIVE RAW SEND ON iso7816Tag TRY \(nbTry), SESSION READY \(String(describing: comSession?.isReady))")
170
-
171
- guard let requestAPDU = NFCISO7816APDU(data: request) else {
172
- completed(nil, NFCReaderError(NFCReaderError.readerErrorInvalidParameterLength) )
173
- return
174
- }
175
-
176
- iso7816Tag.sendCommand(apdu: requestAPDU, resultHandler: {(result: Result<NFCISO7816ResponseAPDU, any Error>) in
177
-
178
- printNFC("SEND_REQUEST_CALLBACK")
179
- switch result {
180
- case .success(let response):
181
- var resultData = Data()
182
-
183
- if let nonNilData = response.payload {
184
- resultData.append(nonNilData)
185
- }
186
-
187
- resultData.append(response.statusWord1)
188
- resultData.append(response.statusWord2)
189
-
190
-
191
- printNFC("TRANSCEIVE RAW RETURN \(resultData.hexEncodedString())")
192
- completed(resultData, nil)
193
- return
194
- case .failure(let error):
195
- printNFC("TRANSCEIVE RAW ERROR \(error.localizedDescription), TRY \(nbTry)")
196
- if (error is NFCReaderError) {
197
- if (!iso7816Tag.isAvailable) {
198
- completed(nil, error)
199
- return
200
- }
201
- }
202
- if (nbTry >= 0) {
203
- usleep(NFCTagReader.DELAY)
204
- return self.transceiveRaw(request: request, completed: completed, nbTry: nbTry - 1)
205
- }
206
- completed(nil, error)
207
- return
208
- }
209
- })
210
- default:
211
- completed(nil, NFCReaderError(NFCReaderError.readerTransceiveErrorTagConnectionLost))
212
- return
213
- }
214
-
215
-
216
- }
217
-
218
- func connect(tech: NfcTech?, connectionCompletion: Completion?) {
219
-
220
- // Check if a tag has been detected
221
- guard let tag = self.tag else {
222
- connectionCompletion?(NFCReaderError( NFCReaderError.readerTransceiveErrorTagNotConnected ))
223
- return
224
- }
225
- // Connect to tag
226
- if let actualTech = tech {
227
- switch actualTech {
228
- case NfcTech.NfcV:
229
- guard case .iso15693(_) = self.tag else {
230
- connectionCompletion?(NFCReaderError( NFCReaderError.readerErrorInvalidParameter ))
231
- return
232
- }
233
- break
234
- case NfcTech.IsoDep:
235
- fallthrough
236
- case NfcTech.NfcA:
237
- fallthrough
238
- case NfcTech.NfcB:
239
- guard case .iso7816(_) = self.tag else {
240
- connectionCompletion?(NFCReaderError( NFCReaderError.readerErrorInvalidParameter ))
241
- return
242
- }
243
- break
244
- default:
245
- connectionCompletion?(NFCReaderError( NFCReaderError.readerErrorInvalidParameter ))
246
- return
247
- }
248
- }
249
- self.connectionCompleted = connectionCompletion
250
-
251
- self.comSession?.connect(to: tag) { [weak self] (error: Error?) in
252
- guard let strongSelf = self else {
253
- return;
254
- }
255
-
256
- if error != nil {
257
- let error = NFCReaderError( NFCReaderError.readerTransceiveErrorTagNotConnected )
258
- strongSelf.invalidateSession( message: error.localizedDescription )
259
- strongSelf.connectionCompleted?(error)
260
- strongSelf.connectionCompleted = nil
261
- return
262
- }
263
- printNFC( "connected to tag" )
264
- strongSelf.tag = tag
265
- strongSelf.connectionCompleted?(nil)
266
- }
267
- }
268
-
269
- func clear() {
270
- self.tag = nil
271
- self.connectionCompleted = nil
272
- }
273
- }
274
-
275
- @available(iOS 13.0, *)
276
- extension NFCTagReader {
277
-
278
-
279
-
280
- func transceiveTap(request: Data, completed: @escaping (Data?, Error?)->()){
281
-
282
-
283
- checkMBEnabled( completed: { ( error: Error?) in
284
- if nil != error {
285
- self.invalidateSession( message: error?.localizedDescription ?? "Error" )
286
- completed( nil, error )
287
- return
288
- }
289
- printNFC( "Com enabled" )
290
- self.sendRequest( request: request,
291
- nbTry: NFCTagReader.NB_MAX_RETRY,
292
- completed: { ( response: Data?, error: Error?) in
293
- if nil != error {
294
- self.invalidateSession( message: error?.localizedDescription ?? "Error" )
295
- completed( nil, error )
296
- return
297
- }
298
- completed(response, nil)
299
- })
300
- })
301
-
302
- }
303
-
304
- func sendRequest(request: Data, nbTry: Int, completed: @escaping (Data?, Error?)->() ) {
305
- guard case let .iso15693(iso15693tag) = self.tag else {
306
- let error = NFCReaderError( NFCReaderError.readerTransceiveErrorTagNotConnected )
307
- invalidateSession( message: error.localizedDescription )
308
- completed(nil, error )
309
- return;
310
- }
311
-
312
- if (nbTry <= 0){
313
- let error = NFCReaderError( NFCReaderError.readerTransceiveErrorRetryExceeded )
314
- invalidateSession( message: error.localizedDescription )
315
- completed(nil, error )
316
- return
317
- }
318
-
319
- var parameters = Data( bytes:[request.count - 1], count: 1 )
320
- parameters.append(request)
321
- printNFC( "Send - \(parameters.hexEncodedString())" )
322
-
323
- iso15693tag.customCommand(requestFlags: [.highDataRate],
324
- customCommandCode: 0xAA,
325
- customRequestParameters: parameters,
326
- completionHandler: { (response: Data?, error: Error?) in
327
- if nil != error {
328
- usleep(NFCTagReader.DELAY)
329
- self.sendRequest( request: request, nbTry: nbTry - 1, completed: completed )
330
- return
331
- }
332
- usleep(NFCTagReader.DELAY * 10) // free ST25DV for SPI
333
- self.readResponse( nbTry: nbTry , completed: completed)
334
- })
335
-
336
- }
337
-
338
- func readResponse( nbTry: Int, completed: @escaping (Data?, Error?)->() ) {
339
-
340
- guard case let .iso15693(iso15693tag) = self.tag else {
341
- let error = NFCReaderError( NFCReaderError.readerTransceiveErrorTagNotConnected )
342
- invalidateSession( message: error.localizedDescription )
343
- completed( nil, error )
344
- return;
345
- }
346
-
347
- //We have tried enough timeout and return
348
- if (nbTry <= 0){
349
- printNFC( "Read Abandonned" )
350
- let error = NFCReaderError( NFCReaderError.readerTransceiveErrorRetryExceeded )
351
- invalidateSession( message: error.localizedDescription )
352
- completed( nil, error )
353
- return;
354
- }
355
-
356
- printNFC( "Read \(nbTry)" )
357
-
358
- //check Mailbox
359
- iso15693tag.customCommand(requestFlags: [.highDataRate],
360
- customCommandCode: 0xAD,
361
- customRequestParameters: Data(bytes: [UInt8(0x0D)], count: 1),
362
- completionHandler: { (response: Data, error: Error?) in
363
- if nil != error {
364
- usleep(NFCTagReader.DELAY)
365
- self.readResponse( nbTry: nbTry - 1, completed: completed )
366
- return
367
- }
368
-
369
- printNFC( "Read response" )
370
-
371
- if ( (response.count >= 1) && ( (response[0]&0x1) != 0 ) && ( (response[0]&0x2) != 0 )){
372
-
373
- printNFC( "Read Value - \(Data(response).hexEncodedString())" )
374
- iso15693tag.customCommand(requestFlags: [.highDataRate],
375
- customCommandCode: 0xAC,
376
- customRequestParameters: Data(bytes: [UInt8(0), UInt8(0)], count: 2),
377
- completionHandler: { (response: Data, error: Error?) in
378
- if nil != error {
379
- self.invalidateSession( message: error?.localizedDescription ?? "Error" )
380
- completed( nil, error )
381
- return
382
- }
383
- printNFC( "got Value - \(Data(response).hexEncodedString())" )
384
- completed(response,nil)
385
- return
386
- })
387
-
388
- }
389
- else {
390
- usleep(NFCTagReader.DELAY)
391
- self.readResponse( nbTry: nbTry - 1, completed: completed )
392
- }
393
-
394
- })
395
-
396
-
397
- }
398
-
399
- func checkMBEnabled(completed: @escaping (Error?)->()) {
400
- guard case let .iso15693(iso15693tag) = self.tag else {
401
- let error = NFCReaderError( NFCReaderError.readerTransceiveErrorTagNotConnected )
402
- invalidateSession( message: error.localizedDescription )
403
- completed( error )
404
- return;
405
- }
406
-
407
- //Read Config
408
- iso15693tag.customCommand(requestFlags: [.highDataRate],
409
- customCommandCode: 0xAD,
410
- customRequestParameters: Data(bytes: [UInt8(0x0D)], count: 1),
411
- completionHandler: { (response: Data, error: Error?) in
412
- if nil != error {
413
- self.invalidateSession( message: error?.localizedDescription ?? "Error" )
414
- completed(error)
415
- return
416
- }
417
-
418
- if ( response.count == 0) {
419
- let error = NFCReaderError( NFCReaderError.readerTransceiveErrorTagResponseError )
420
- self.invalidateSession( message: error.localizedDescription )
421
- completed( error )
422
- return
423
- }
424
-
425
-
426
- let current = response[0];
427
-
428
- //We should reset mailbox
429
- if ( (current != 0x41) && (current != 0x81) ) {
430
-
431
- //disable
432
- iso15693tag.customCommand(requestFlags: [.highDataRate],
433
- customCommandCode: 0xAE,
434
- customRequestParameters: Data(bytes: [UInt8(0x0D), UInt8(0x00)], count: 2),
435
- completionHandler: { (response: Data, error: Error?) in
436
- if nil != error {
437
- self.invalidateSession( message: error?.localizedDescription ?? "Error" )
438
- completed( error )
439
- return
440
- }
441
-
442
- //enable
443
- iso15693tag.customCommand(requestFlags: [.highDataRate],
444
- customCommandCode: 0xAE,
445
- customRequestParameters: Data(bytes: [UInt8(0x0D), UInt8(0x01)], count: 2),
446
- completionHandler: { (response: Data, error: Error?) in
447
- if nil != error {
448
- self.invalidateSession( message: error?.localizedDescription ?? "Error" )
449
- completed( error )
450
- return
451
- }
452
-
453
- completed(nil)
454
- return
455
-
456
- })
457
- })
458
- }
459
- //We are ok to go
460
- else
461
- {
462
- completed(nil)
463
- return
464
- }
465
-
466
- })
467
- }
468
-
469
- func sendTap( request: String, completed: @escaping (Data?,Error?)->() ) {
470
-
471
- guard NFCNDEFReaderSession.readingAvailable else {
472
- let error = NFCReaderError( NFCReaderError.readerErrorUnsupportedFeature )
473
- invalidateSession( message: error.localizedDescription )
474
- completed( nil, error )
475
- return
476
- }
477
-
478
- guard comSession != nil && comSession!.isReady else {
479
- let error = NFCReaderError( NFCReaderError.readerTransceiveErrorTagNotConnected )
480
- invalidateSession( message: error.localizedDescription )
481
- completed( nil, error )
482
- return
483
- }
484
-
485
- let requestData : Data = request.dataFromHexString()
486
- printNFC( "Transceive - \(requestData.hexEncodedString())" )
487
- transceiveTap(request: requestData,
488
- completed: { ( response: Data?, error: Error?) in
489
- if nil != error {
490
- self.invalidateSession( message: error?.localizedDescription ?? "Error" )
491
- completed( nil, error )
492
- return
493
- }
494
- else {
495
- completed( response, nil)
496
- return
497
- }
498
- })
499
- }
500
-
501
- func createJSON(tag: NFCTag) async -> [AnyHashable: Any] {
502
- try? await self.comSession?.connect(to: tag)
503
- return await tag.toJSON(isTapDiscoveryEnabled: self.plugin.isTapDiscoveryEnabled())
504
- }
505
- }
506
-
1
+ import CoreNFC
2
+
3
+ @available(iOS 13.0, *)
4
+ class NFCTagReader : NSObject, NFCTagReaderSessionDelegate {
5
+
6
+ private var plugin: NfcPlugin
7
+
8
+ typealias Completion = (Error?) -> ()
9
+ typealias CompletionWithJSONResponse = ([AnyHashable: Any]?, Error?) -> ()
10
+
11
+ internal var comSession: NFCTagReaderSession?
12
+ internal var tag: NFCTag?
13
+
14
+ static var MB_CTRL_DYN : UInt8 = 0x0D
15
+
16
+ internal var connectionCompleted : Completion?
17
+ internal var initSessionCompletion: Completion?
18
+ internal var onDiscoverCompletion : CompletionWithJSONResponse?
19
+
20
+
21
+ static var DELAY : UInt32 = 1000; // timeout resolution in millionths of second
22
+ static var NB_MAX_RETRY : Int = 50;
23
+
24
+ init(plugin: NfcPlugin) {
25
+ self.plugin = plugin
26
+ super.init()
27
+ }
28
+
29
+ func initSession( pollingOption: NFCTagReaderSession.PollingOption, alertMessage: String, completed: Completion? ) {
30
+ return self.initSession(pollingOption: pollingOption, alertMessage: alertMessage, completed: completed, onDiscover: nil)
31
+ }
32
+
33
+ func initSession( pollingOption: NFCTagReaderSession.PollingOption, alertMessage: String, onDiscover: CompletionWithJSONResponse?) {
34
+ return self.initSession(pollingOption: pollingOption, alertMessage: alertMessage, completed: nil, onDiscover: onDiscover)
35
+ }
36
+
37
+ func initSession( pollingOption: NFCTagReaderSession.PollingOption, alertMessage: String, completed: Completion?, onDiscover: CompletionWithJSONResponse? ) {
38
+ connectionCompleted = completed
39
+ onDiscoverCompletion = onDiscover
40
+
41
+ if NFCNDEFReaderSession.readingAvailable {
42
+ comSession = NFCTagReaderSession(pollingOption: pollingOption, delegate: self, queue: nil)
43
+ comSession?.alertMessage = alertMessage
44
+ comSession?.begin()
45
+ } else {
46
+ completed?(NFCReaderError.readerTransceiveErrorSessionInvalidated as? Error)
47
+ }
48
+ }
49
+
50
+ func initSession( pollingOption: NFCTagReaderSession.PollingOption, alertMessage: String, initSessionCompletion: Completion?, onDiscover: CompletionWithJSONResponse? ) {
51
+ self.initSessionCompletion = initSessionCompletion
52
+ return self.initSession(pollingOption: pollingOption, alertMessage: alertMessage, completed: nil, onDiscover: onDiscover)
53
+ }
54
+
55
+ func invalidateSession( message :String) {
56
+ comSession?.alertMessage = message
57
+ comSession?.invalidate()
58
+ tag = nil
59
+ }
60
+
61
+ func tagReaderSessionDidBecomeActive(_ session: NFCTagReaderSession) {
62
+ // If necessary, you may perform additional operations on session start.
63
+ // At this point RF polling is enabled.
64
+ if let actualInitSessionCompletion = initSessionCompletion {
65
+ actualInitSessionCompletion(nil)
66
+ initSessionCompletion = nil //do not keep session completion
67
+ }
68
+ printNFC( "tagReaderSessionDidBecomeActive" )
69
+ if (self.comSession == nil) {
70
+ self.comSession = session
71
+ }
72
+ }
73
+
74
+ func tagReaderSession(_ session: NFCTagReaderSession, didInvalidateWithError error: Error) {
75
+ // If necessary, you may handle the error. Note session is no longer valid.
76
+ // You must create a new session to restart RF polling.
77
+ printNFC( "tagReaderSession:didInvalidateWithError - \(error)" )
78
+ if let actualInitSessionCompletion = initSessionCompletion {
79
+ actualInitSessionCompletion(error)
80
+ initSessionCompletion = nil //do not keep session completion
81
+ }
82
+ connectionCompleted?(error)
83
+ clear()
84
+ self.comSession = nil
85
+ }
86
+
87
+ func tagReaderSession(_ session: NFCTagReaderSession, didDetect tags: [NFCTag]) {
88
+ printNFC( "tagReaderSession:didDetectTag" )
89
+ guard let session = self.comSession else {
90
+ return;
91
+ }
92
+ if tags.count > 1 {
93
+ // Restart polling in 500 milliseconds.
94
+ let retryInterval = DispatchTimeInterval.milliseconds(500)
95
+ session.alertMessage = "More than 1 Tap is detected. Please remove all tags and try again."
96
+ DispatchQueue.global().asyncAfter(deadline: .now() + retryInterval, execute: {
97
+ session.restartPolling()
98
+ })
99
+ return
100
+
101
+ }
102
+
103
+ guard let tag = tags.first else {
104
+ return;
105
+ }
106
+
107
+ self.tag = tag
108
+
109
+ if self.onDiscoverCompletion != nil {
110
+
111
+ Task {
112
+ self.onDiscoverCompletion?(await self.createJSON(tag: tag), nil)
113
+ }
114
+
115
+ }
116
+
117
+ if let connectionCompletion = self.connectionCompleted {
118
+ connect(tech: nil, connectionCompletion: connectionCompletion)
119
+ }
120
+
121
+ }
122
+
123
+ //full transparent mode
124
+
125
+ @available(iOS 14.0, *)
126
+ func transceiveRaw(request: Data, completed: @escaping (Data?, Error?) -> (), nbTry: Int = NB_MAX_RETRY) {
127
+ guard (request.count >= 2) else {
128
+ completed(nil, NFCReaderError(NFCReaderError.readerErrorInvalidParameterLength))
129
+ return
130
+ }
131
+
132
+ switch self.tag {
133
+ case .iso15693(let iso15693Tag):
134
+
135
+ let flags = Int(request[0])
136
+ let commandCode = Int(request[1])
137
+ let dataToSend = request.dropFirst(2)
138
+
139
+ printNFC("TRANSCEIVE RAW SEND \(request.hexEncodedString())")
140
+ printNFC("TRANSCEIVE RAW SEND ON ISO15TAG TRY \(nbTry), SESSION READY \(String(describing: comSession?.isReady))")
141
+
142
+ iso15693Tag.sendRequest(requestFlags: flags, commandCode: commandCode, data: dataToSend, resultHandler: {(result: Result<(NFCISO15693ResponseFlag, Data?), any Error>) in
143
+
144
+ printNFC("SEND_REQUEST_CALLBACK")
145
+ switch result {
146
+ case .success((let flag, let data)):
147
+ let firstByteBuffer = withUnsafeBytes(of: flag.rawValue) { Data($0)}
148
+ var resultData = Data(firstByteBuffer)
149
+ if let nonNilData = data {
150
+ resultData.append(nonNilData)
151
+ }
152
+
153
+ //Last delay to let ST25DV "breathe"
154
+ //usleep(1000*NFCTagReader.DELAY)
155
+
156
+ printNFC("TRANSCEIVE RAW RETURN \(resultData.hexEncodedString())")
157
+ completed(resultData, nil)
158
+ return
159
+ case .failure(let error):
160
+ printNFC("TRANSCEIVE RAW ERROR \(error.localizedDescription), TRY \(nbTry)")
161
+ if (nbTry >= 0) {
162
+ usleep(NFCTagReader.DELAY)
163
+ return self.transceiveRaw(request: request, completed: completed, nbTry: nbTry - 1)
164
+ }
165
+
166
+ completed(nil, error)
167
+ return
168
+ }
169
+ })
170
+ break
171
+ case .iso7816(let iso7816Tag):
172
+ printNFC("TRANSCEIVE RAW SEND ON iso7816Tag TRY \(nbTry), SESSION READY \(String(describing: comSession?.isReady))")
173
+
174
+ guard let requestAPDU = NFCISO7816APDU(data: request) else {
175
+ completed(nil, NFCReaderError(NFCReaderError.readerErrorInvalidParameterLength) )
176
+ return
177
+ }
178
+
179
+ iso7816Tag.sendCommand(apdu: requestAPDU, resultHandler: {(result: Result<NFCISO7816ResponseAPDU, any Error>) in
180
+
181
+ printNFC("SEND_REQUEST_CALLBACK")
182
+ switch result {
183
+ case .success(let response):
184
+ var resultData = Data()
185
+
186
+ if let nonNilData = response.payload {
187
+ resultData.append(nonNilData)
188
+ }
189
+
190
+ resultData.append(response.statusWord1)
191
+ resultData.append(response.statusWord2)
192
+
193
+
194
+ printNFC("TRANSCEIVE RAW RETURN \(resultData.hexEncodedString())")
195
+ completed(resultData, nil)
196
+ return
197
+ case .failure(let error):
198
+ printNFC("TRANSCEIVE RAW ERROR \(error.localizedDescription), TRY \(nbTry)")
199
+ if (error is NFCReaderError) {
200
+ if (!iso7816Tag.isAvailable) {
201
+ completed(nil, error)
202
+ return
203
+ }
204
+ }
205
+ if (nbTry >= 0) {
206
+ usleep(NFCTagReader.DELAY)
207
+ return self.transceiveRaw(request: request, completed: completed, nbTry: nbTry - 1)
208
+ }
209
+ completed(nil, error)
210
+ return
211
+ }
212
+ })
213
+ default:
214
+ completed(nil, NFCReaderError(NFCReaderError.readerTransceiveErrorTagConnectionLost))
215
+ return
216
+ }
217
+
218
+
219
+ }
220
+
221
+ func connect(tech: NfcTech?, connectionCompletion: Completion?) {
222
+
223
+ // Check if a tag has been detected
224
+ guard let tag = self.tag else {
225
+ connectionCompletion?(NFCReaderError( NFCReaderError.readerTransceiveErrorTagNotConnected ))
226
+ return
227
+ }
228
+ // Connect to tag
229
+ if let actualTech = tech {
230
+ switch actualTech {
231
+ case NfcTech.NfcV:
232
+ guard case .iso15693(_) = self.tag else {
233
+ connectionCompletion?(NFCReaderError( NFCReaderError.readerErrorInvalidParameter ))
234
+ return
235
+ }
236
+ break
237
+ case NfcTech.IsoDep:
238
+ fallthrough
239
+ case NfcTech.NfcA:
240
+ fallthrough
241
+ case NfcTech.NfcB:
242
+ guard case .iso7816(_) = self.tag else {
243
+ connectionCompletion?(NFCReaderError( NFCReaderError.readerErrorInvalidParameter ))
244
+ return
245
+ }
246
+ break
247
+ default:
248
+ connectionCompletion?(NFCReaderError( NFCReaderError.readerErrorInvalidParameter ))
249
+ return
250
+ }
251
+ }
252
+ self.connectionCompleted = connectionCompletion
253
+
254
+ self.comSession?.connect(to: tag) { [weak self] (error: Error?) in
255
+ guard let strongSelf = self else {
256
+ return;
257
+ }
258
+
259
+ if error != nil {
260
+ let error = NFCReaderError( NFCReaderError.readerTransceiveErrorTagNotConnected )
261
+ strongSelf.invalidateSession( message: error.localizedDescription )
262
+ strongSelf.connectionCompleted?(error)
263
+ strongSelf.connectionCompleted = nil
264
+ return
265
+ }
266
+ printNFC( "connected to tag" )
267
+ strongSelf.tag = tag
268
+ strongSelf.connectionCompleted?(nil)
269
+ }
270
+ }
271
+
272
+ func clear() {
273
+ self.tag = nil
274
+ self.connectionCompleted = nil
275
+ }
276
+ }
277
+
278
+ @available(iOS 13.0, *)
279
+ extension NFCTagReader {
280
+
281
+
282
+
283
+ func transceiveTap(request: Data, completed: @escaping (Data?, Error?)->()){
284
+
285
+
286
+ checkMBEnabled( completed: { ( error: Error?) in
287
+ if nil != error {
288
+ self.invalidateSession( message: error?.localizedDescription ?? "Error" )
289
+ completed( nil, error )
290
+ return
291
+ }
292
+ printNFC( "Com enabled" )
293
+ self.sendRequest( request: request,
294
+ nbTry: NFCTagReader.NB_MAX_RETRY,
295
+ completed: { ( response: Data?, error: Error?) in
296
+ if nil != error {
297
+ self.invalidateSession( message: error?.localizedDescription ?? "Error" )
298
+ completed( nil, error )
299
+ return
300
+ }
301
+ completed(response, nil)
302
+ })
303
+ })
304
+
305
+ }
306
+
307
+ func sendRequest(request: Data, nbTry: Int, completed: @escaping (Data?, Error?)->() ) {
308
+ guard case let .iso15693(iso15693tag) = self.tag else {
309
+ let error = NFCReaderError( NFCReaderError.readerTransceiveErrorTagNotConnected )
310
+ invalidateSession( message: error.localizedDescription )
311
+ completed(nil, error )
312
+ return;
313
+ }
314
+
315
+ if (nbTry <= 0){
316
+ let error = NFCReaderError( NFCReaderError.readerTransceiveErrorRetryExceeded )
317
+ invalidateSession( message: error.localizedDescription )
318
+ completed(nil, error )
319
+ return
320
+ }
321
+
322
+ var parameters = Data( bytes:[request.count - 1], count: 1 )
323
+ parameters.append(request)
324
+ printNFC( "Send - \(parameters.hexEncodedString())" )
325
+
326
+ iso15693tag.customCommand(requestFlags: [.highDataRate],
327
+ customCommandCode: 0xAA,
328
+ customRequestParameters: parameters,
329
+ completionHandler: { (response: Data?, error: Error?) in
330
+ if nil != error {
331
+ usleep(NFCTagReader.DELAY)
332
+ self.sendRequest( request: request, nbTry: nbTry - 1, completed: completed )
333
+ return
334
+ }
335
+ usleep(NFCTagReader.DELAY * 10) // free ST25DV for SPI
336
+ self.readResponse( nbTry: nbTry , completed: completed)
337
+ })
338
+
339
+ }
340
+
341
+ func readResponse( nbTry: Int, completed: @escaping (Data?, Error?)->() ) {
342
+
343
+ guard case let .iso15693(iso15693tag) = self.tag else {
344
+ let error = NFCReaderError( NFCReaderError.readerTransceiveErrorTagNotConnected )
345
+ invalidateSession( message: error.localizedDescription )
346
+ completed( nil, error )
347
+ return;
348
+ }
349
+
350
+ //We have tried enough timeout and return
351
+ if (nbTry <= 0){
352
+ printNFC( "Read Abandonned" )
353
+ let error = NFCReaderError( NFCReaderError.readerTransceiveErrorRetryExceeded )
354
+ invalidateSession( message: error.localizedDescription )
355
+ completed( nil, error )
356
+ return;
357
+ }
358
+
359
+ printNFC( "Read \(nbTry)" )
360
+
361
+ //check Mailbox
362
+ iso15693tag.customCommand(requestFlags: [.highDataRate],
363
+ customCommandCode: 0xAD,
364
+ customRequestParameters: Data(bytes: [UInt8(0x0D)], count: 1),
365
+ completionHandler: { (response: Data, error: Error?) in
366
+ if nil != error {
367
+ usleep(NFCTagReader.DELAY)
368
+ self.readResponse( nbTry: nbTry - 1, completed: completed )
369
+ return
370
+ }
371
+
372
+ printNFC( "Read response" )
373
+
374
+ if ( (response.count >= 1) && ( (response[0]&0x1) != 0 ) && ( (response[0]&0x2) != 0 )){
375
+
376
+ printNFC( "Read Value - \(Data(response).hexEncodedString())" )
377
+ iso15693tag.customCommand(requestFlags: [.highDataRate],
378
+ customCommandCode: 0xAC,
379
+ customRequestParameters: Data(bytes: [UInt8(0), UInt8(0)], count: 2),
380
+ completionHandler: { (response: Data, error: Error?) in
381
+ if nil != error {
382
+ self.invalidateSession( message: error?.localizedDescription ?? "Error" )
383
+ completed( nil, error )
384
+ return
385
+ }
386
+ printNFC( "got Value - \(Data(response).hexEncodedString())" )
387
+ completed(response,nil)
388
+ return
389
+ })
390
+
391
+ }
392
+ else {
393
+ usleep(NFCTagReader.DELAY)
394
+ self.readResponse( nbTry: nbTry - 1, completed: completed )
395
+ }
396
+
397
+ })
398
+
399
+
400
+ }
401
+
402
+ func checkMBEnabled(completed: @escaping (Error?)->()) {
403
+ guard case let .iso15693(iso15693tag) = self.tag else {
404
+ let error = NFCReaderError( NFCReaderError.readerTransceiveErrorTagNotConnected )
405
+ invalidateSession( message: error.localizedDescription )
406
+ completed( error )
407
+ return;
408
+ }
409
+
410
+ //Read Config
411
+ iso15693tag.customCommand(requestFlags: [.highDataRate],
412
+ customCommandCode: 0xAD,
413
+ customRequestParameters: Data(bytes: [UInt8(0x0D)], count: 1),
414
+ completionHandler: { (response: Data, error: Error?) in
415
+ if nil != error {
416
+ self.invalidateSession( message: error?.localizedDescription ?? "Error" )
417
+ completed(error)
418
+ return
419
+ }
420
+
421
+ if ( response.count == 0) {
422
+ let error = NFCReaderError( NFCReaderError.readerTransceiveErrorTagResponseError )
423
+ self.invalidateSession( message: error.localizedDescription )
424
+ completed( error )
425
+ return
426
+ }
427
+
428
+
429
+ let current = response[0];
430
+
431
+ //We should reset mailbox
432
+ if ( (current != 0x41) && (current != 0x81) ) {
433
+
434
+ //disable
435
+ iso15693tag.customCommand(requestFlags: [.highDataRate],
436
+ customCommandCode: 0xAE,
437
+ customRequestParameters: Data(bytes: [UInt8(0x0D), UInt8(0x00)], count: 2),
438
+ completionHandler: { (response: Data, error: Error?) in
439
+ if nil != error {
440
+ self.invalidateSession( message: error?.localizedDescription ?? "Error" )
441
+ completed( error )
442
+ return
443
+ }
444
+
445
+ //enable
446
+ iso15693tag.customCommand(requestFlags: [.highDataRate],
447
+ customCommandCode: 0xAE,
448
+ customRequestParameters: Data(bytes: [UInt8(0x0D), UInt8(0x01)], count: 2),
449
+ completionHandler: { (response: Data, error: Error?) in
450
+ if nil != error {
451
+ self.invalidateSession( message: error?.localizedDescription ?? "Error" )
452
+ completed( error )
453
+ return
454
+ }
455
+
456
+ completed(nil)
457
+ return
458
+
459
+ })
460
+ })
461
+ }
462
+ //We are ok to go
463
+ else
464
+ {
465
+ completed(nil)
466
+ return
467
+ }
468
+
469
+ })
470
+ }
471
+
472
+ func sendTap( request: String, completed: @escaping (Data?,Error?)->() ) {
473
+
474
+ guard NFCNDEFReaderSession.readingAvailable else {
475
+ let error = NFCReaderError( NFCReaderError.readerErrorUnsupportedFeature )
476
+ invalidateSession( message: error.localizedDescription )
477
+ completed( nil, error )
478
+ return
479
+ }
480
+
481
+ guard comSession != nil && comSession!.isReady else {
482
+ let error = NFCReaderError( NFCReaderError.readerTransceiveErrorTagNotConnected )
483
+ invalidateSession( message: error.localizedDescription )
484
+ completed( nil, error )
485
+ return
486
+ }
487
+
488
+ let requestData : Data = request.dataFromHexString()
489
+ printNFC( "Transceive - \(requestData.hexEncodedString())" )
490
+ transceiveTap(request: requestData,
491
+ completed: { ( response: Data?, error: Error?) in
492
+ if nil != error {
493
+ self.invalidateSession( message: error?.localizedDescription ?? "Error" )
494
+ completed( nil, error )
495
+ return
496
+ }
497
+ else {
498
+ completed( response, nil)
499
+ return
500
+ }
501
+ })
502
+ }
503
+
504
+ func createJSON(tag: NFCTag) async -> [AnyHashable: Any] {
505
+ try? await self.comSession?.connect(to: tag)
506
+ return await tag.toJSON(isTapDiscoveryEnabled: self.plugin.isTapDiscoveryEnabled())
507
+ }
508
+
509
+ func writeNDEF(message: NFCNDEFMessage, completed: @escaping (Error?)->()) {
510
+ guard let ndefTag = self.tag else {
511
+ completed(NFCReaderError(NFCReaderError.readerTransceiveErrorTagNotConnected))
512
+ return
513
+ }
514
+ var tag: NFCNDEFTag? = nil
515
+ switch(ndefTag) {
516
+ case .iso15693(let iso15693Tag):
517
+ tag = iso15693Tag
518
+ default:
519
+ completed(NFCReaderError(NFCReaderError.readerTransceiveErrorTagNotConnected))
520
+ return
521
+
522
+ }
523
+ if (tag != nil) {
524
+ tag?.writeNDEF(message, completionHandler: {
525
+ (error:Error?) in
526
+ if (error != nil) {
527
+ completed(error)
528
+ } else {
529
+ completed(nil)
530
+ }
531
+ })
532
+
533
+ }
534
+ }
535
+ }
536
+