@iotize/device-com-nfc.cordova 3.1.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.
- package/LICENSE +31 -0
- package/README.md +673 -0
- package/bundles/iotize-device-com-nfc.cordova.umd.js +469 -0
- package/bundles/iotize-device-com-nfc.cordova.umd.js.map +1 -0
- package/esm2015/iotize-device-com-nfc.cordova.js +5 -0
- package/esm2015/iotize-device-com-nfc.cordova.js.map +1 -0
- package/esm2015/iotize-device-com-nfc.cordova.metadata.json +1 -0
- package/esm2015/iotize-device-com-nfc.cordova.ngsummary.json +1 -0
- package/esm2015/public_api.js +2 -0
- package/esm2015/public_api.js.map +1 -0
- package/esm2015/public_api.metadata.json +1 -0
- package/esm2015/public_api.ngsummary.json +1 -0
- package/esm2015/www/cordova-interface.js +2 -0
- package/esm2015/www/cordova-interface.js.map +1 -0
- package/esm2015/www/cordova-interface.metadata.json +1 -0
- package/esm2015/www/cordova-interface.ngsummary.json +1 -0
- package/esm2015/www/errors.js +28 -0
- package/esm2015/www/errors.js.map +1 -0
- package/esm2015/www/errors.metadata.json +1 -0
- package/esm2015/www/errors.ngsummary.json +1 -0
- package/esm2015/www/index.js +5 -0
- package/esm2015/www/index.js.map +1 -0
- package/esm2015/www/index.metadata.json +1 -0
- package/esm2015/www/index.ngsummary.json +1 -0
- package/esm2015/www/logger.js +3 -0
- package/esm2015/www/logger.js.map +1 -0
- package/esm2015/www/logger.metadata.json +1 -0
- package/esm2015/www/logger.ngsummary.json +1 -0
- package/esm2015/www/nfc-com-protocol.js +109 -0
- package/esm2015/www/nfc-com-protocol.js.map +1 -0
- package/esm2015/www/nfc-com-protocol.metadata.json +1 -0
- package/esm2015/www/nfc-com-protocol.ngsummary.json +1 -0
- package/esm2015/www/tap-ndef/definitions.js +2 -0
- package/esm2015/www/tap-ndef/definitions.js.map +1 -0
- package/esm2015/www/tap-ndef/definitions.metadata.json +1 -0
- package/esm2015/www/tap-ndef/definitions.ngsummary.json +1 -0
- package/esm2015/www/tap-ndef/index.js +3 -0
- package/esm2015/www/tap-ndef/index.js.map +1 -0
- package/esm2015/www/tap-ndef/index.metadata.json +1 -0
- package/esm2015/www/tap-ndef/index.ngsummary.json +1 -0
- package/esm2015/www/tap-ndef/parse-ndef-message.js +57 -0
- package/esm2015/www/tap-ndef/parse-ndef-message.js.map +1 -0
- package/esm2015/www/tap-ndef/parse-ndef-message.metadata.json +1 -0
- package/esm2015/www/tap-ndef/parse-ndef-message.ngsummary.json +1 -0
- package/fesm2015/iotize-device-com-nfc.cordova.js +196 -0
- package/fesm2015/iotize-device-com-nfc.cordova.js.map +1 -0
- package/iotize-device-com-nfc.cordova.d.ts +4 -0
- package/iotize-device-com-nfc.cordova.metadata.json +1 -0
- package/package.json +54 -0
- package/plugin.xml +97 -0
- package/public_api.d.ts +1 -0
- package/src/android/build.gradle +38 -0
- package/src/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/src/android/gradle/wrapper/gradle-wrapper.properties +6 -0
- package/src/android/gradlew +172 -0
- package/src/android/gradlew.bat +84 -0
- package/src/android/local.properties +8 -0
- package/src/android/src/com/chariotsolutions/nfc/plugin/JSONBuilder.java +60 -0
- package/src/android/src/com/chariotsolutions/nfc/plugin/NfcPlugin.java +1192 -0
- package/src/android/src/com/chariotsolutions/nfc/plugin/NfcPluginError.java +15 -0
- package/src/android/src/com/chariotsolutions/nfc/plugin/PluginResponse.java +85 -0
- package/src/android/src/com/chariotsolutions/nfc/plugin/Util.java +140 -0
- package/src/ios/AppDelegate+NFC.swift +51 -0
- package/src/ios/ISO15Reader.swift +376 -0
- package/src/ios/NFCNDEFDelegate.swift +78 -0
- package/src/ios/NFCPlugin-Bridging-Header.h +7 -0
- package/src/ios/NFCTapPlugin.swift +251 -0
- package/www/cordova-interface.d.ts +18 -0
- package/www/errors.d.ts +16 -0
- package/www/index.d.ts +4 -0
- package/www/logger.d.ts +2 -0
- package/www/nfc-com-protocol.d.ts +14 -0
- package/www/phonegap-nfc.js +885 -0
- package/www/tap-ndef/definitions.d.ts +25 -0
- package/www/tap-ndef/index.d.ts +2 -0
- package/www/tap-ndef/parse-ndef-message.d.ts +6 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
package com.chariotsolutions.nfc.plugin;
|
|
2
|
+
|
|
3
|
+
class NfcPluginError extends Exception {
|
|
4
|
+
|
|
5
|
+
String code;
|
|
6
|
+
|
|
7
|
+
public String getCode() {
|
|
8
|
+
return code;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
public NfcPluginError(String code, String message, Throwable cause) {
|
|
12
|
+
super(message, cause);
|
|
13
|
+
this.code = code;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2018 IoTize SAS Inc. Licensed under the MIT license.
|
|
3
|
+
//
|
|
4
|
+
// PluginResponse.java
|
|
5
|
+
// device-com-ble.cordova BLE Cordova Plugin
|
|
6
|
+
//
|
|
7
|
+
package com.chariotsolutions.nfc.plugin;
|
|
8
|
+
|
|
9
|
+
import com.iotize.android.core.util.Helper;
|
|
10
|
+
|
|
11
|
+
import org.apache.cordova.CallbackContext;
|
|
12
|
+
import org.apache.cordova.PluginResult;
|
|
13
|
+
import org.json.JSONArray;
|
|
14
|
+
import org.json.JSONObject;
|
|
15
|
+
|
|
16
|
+
public class PluginResponse {
|
|
17
|
+
|
|
18
|
+
private static final String TAG = "PluginResponse";
|
|
19
|
+
private final CallbackContext callbackContext;
|
|
20
|
+
private final String action;
|
|
21
|
+
|
|
22
|
+
public PluginResponse(String action, JSONArray args, CallbackContext callbackContext) {
|
|
23
|
+
this.callbackContext = callbackContext;
|
|
24
|
+
this.action = action;
|
|
25
|
+
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
public void newResult(String data) {
|
|
29
|
+
PluginResult result = new PluginResult(
|
|
30
|
+
PluginResult.Status.OK,
|
|
31
|
+
data
|
|
32
|
+
);
|
|
33
|
+
result.setKeepCallback(true);
|
|
34
|
+
this.callbackContext.sendPluginResult(result);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
public void newResult(JSONObject data) {
|
|
38
|
+
PluginResult result = new PluginResult(
|
|
39
|
+
PluginResult.Status.OK,
|
|
40
|
+
data
|
|
41
|
+
);
|
|
42
|
+
result.setKeepCallback(true);
|
|
43
|
+
this.callbackContext.sendPluginResult(result);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
public void newResult(NfcPluginError error) {
|
|
47
|
+
this.callbackContext.sendPluginResult(new PluginResult(
|
|
48
|
+
PluginResult.Status.ERROR,
|
|
49
|
+
JSONBuilder.toJSONObject(error)
|
|
50
|
+
));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
public void success(JSONObject object) {
|
|
54
|
+
this.callbackContext.success(object);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
public void success(byte[] response) {
|
|
58
|
+
this.callbackContext.success(Helper.ByteArrayToHexString(response));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
public void error(NfcPluginError err) {
|
|
62
|
+
JSONObject object = JSONBuilder.toJSONObject(err);
|
|
63
|
+
this.callbackContext.error(object);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
public void success(boolean isConnected) {
|
|
67
|
+
this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, isConnected)); }
|
|
68
|
+
|
|
69
|
+
public void success() {
|
|
70
|
+
this.callbackContext.success();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
public void error(String message) {
|
|
74
|
+
this.callbackContext.success(message);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
public void success(String msg) {
|
|
78
|
+
this.callbackContext.success(msg);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
public CallbackContext getCallbackContext() {
|
|
82
|
+
return callbackContext;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
package com.chariotsolutions.nfc.plugin;
|
|
2
|
+
|
|
3
|
+
import android.nfc.NdefMessage;
|
|
4
|
+
import android.nfc.NdefRecord;
|
|
5
|
+
import android.nfc.Tag;
|
|
6
|
+
import android.nfc.tech.Ndef;
|
|
7
|
+
import android.util.Log;
|
|
8
|
+
import org.json.JSONArray;
|
|
9
|
+
import org.json.JSONException;
|
|
10
|
+
import org.json.JSONObject;
|
|
11
|
+
|
|
12
|
+
import java.util.ArrayList;
|
|
13
|
+
import java.util.Arrays;
|
|
14
|
+
import java.util.List;
|
|
15
|
+
|
|
16
|
+
public class Util {
|
|
17
|
+
|
|
18
|
+
static final String TAG = "NfcPlugin";
|
|
19
|
+
|
|
20
|
+
static JSONObject ndefToJSON(Ndef ndef) {
|
|
21
|
+
JSONObject json = new JSONObject();
|
|
22
|
+
|
|
23
|
+
if (ndef != null) {
|
|
24
|
+
try {
|
|
25
|
+
|
|
26
|
+
Tag tag = ndef.getTag();
|
|
27
|
+
// tag is going to be null for NDEF_FORMATABLE until NfcUtil.parseMessage is refactored
|
|
28
|
+
if (tag != null) {
|
|
29
|
+
json.put("id", byteArrayToJSON(tag.getId()));
|
|
30
|
+
json.put("techTypes", new JSONArray(Arrays.asList(tag.getTechList())));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
json.put("type", translateType(ndef.getType()));
|
|
34
|
+
json.put("maxSize", ndef.getMaxSize());
|
|
35
|
+
json.put("isWritable", ndef.isWritable());
|
|
36
|
+
json.put("ndefMessage", messageToJSON(ndef.getCachedNdefMessage()));
|
|
37
|
+
// Workaround for bug in ICS (Android 4.0 and 4.0.1) where
|
|
38
|
+
// mTag.getTagService(); of the Ndef object sometimes returns null
|
|
39
|
+
// see http://issues.mroland.at/index.php?do=details&task_id=47
|
|
40
|
+
try {
|
|
41
|
+
json.put("canMakeReadOnly", ndef.canMakeReadOnly());
|
|
42
|
+
} catch (NullPointerException e) {
|
|
43
|
+
json.put("canMakeReadOnly", JSONObject.NULL);
|
|
44
|
+
}
|
|
45
|
+
} catch (JSONException e) {
|
|
46
|
+
Log.e(TAG, "Failed to convert ndef into json: " + ndef.toString(), e);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return json;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
static JSONObject tagToJSON(Tag tag) {
|
|
53
|
+
JSONObject json = new JSONObject();
|
|
54
|
+
|
|
55
|
+
if (tag != null) {
|
|
56
|
+
try {
|
|
57
|
+
json.put("id", byteArrayToJSON(tag.getId()));
|
|
58
|
+
json.put("techTypes", new JSONArray(Arrays.asList(tag.getTechList())));
|
|
59
|
+
} catch (JSONException e) {
|
|
60
|
+
Log.e(TAG, "Failed to convert tag into json: " + tag.toString(), e);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return json;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
static String translateType(String type) {
|
|
67
|
+
String translation;
|
|
68
|
+
if (type.equals(Ndef.NFC_FORUM_TYPE_1)) {
|
|
69
|
+
translation = "NFC Forum Type 1";
|
|
70
|
+
} else if (type.equals(Ndef.NFC_FORUM_TYPE_2)) {
|
|
71
|
+
translation = "NFC Forum Type 2";
|
|
72
|
+
} else if (type.equals(Ndef.NFC_FORUM_TYPE_3)) {
|
|
73
|
+
translation = "NFC Forum Type 3";
|
|
74
|
+
} else if (type.equals(Ndef.NFC_FORUM_TYPE_4)) {
|
|
75
|
+
translation = "NFC Forum Type 4";
|
|
76
|
+
} else {
|
|
77
|
+
translation = type;
|
|
78
|
+
}
|
|
79
|
+
return translation;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
static NdefRecord[] jsonToNdefRecords(String ndefMessageAsJSON) throws JSONException {
|
|
83
|
+
JSONArray jsonRecords = new JSONArray(ndefMessageAsJSON);
|
|
84
|
+
NdefRecord[] records = new NdefRecord[jsonRecords.length()];
|
|
85
|
+
for (int i = 0; i < jsonRecords.length(); i++) {
|
|
86
|
+
JSONObject record = jsonRecords.getJSONObject(i);
|
|
87
|
+
byte tnf = (byte) record.getInt("tnf");
|
|
88
|
+
byte[] type = jsonToByteArray(record.getJSONArray("type"));
|
|
89
|
+
byte[] id = jsonToByteArray(record.getJSONArray("id"));
|
|
90
|
+
byte[] payload = jsonToByteArray(record.getJSONArray("payload"));
|
|
91
|
+
records[i] = new NdefRecord(tnf, type, id, payload);
|
|
92
|
+
}
|
|
93
|
+
return records;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
static JSONArray byteArrayToJSON(byte[] bytes) {
|
|
97
|
+
JSONArray json = new JSONArray();
|
|
98
|
+
for (byte aByte : bytes) {
|
|
99
|
+
json.put(aByte);
|
|
100
|
+
}
|
|
101
|
+
return json;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
static byte[] jsonToByteArray(JSONArray json) throws JSONException {
|
|
105
|
+
byte[] b = new byte[json.length()];
|
|
106
|
+
for (int i = 0; i < json.length(); i++) {
|
|
107
|
+
b[i] = (byte) json.getInt(i);
|
|
108
|
+
}
|
|
109
|
+
return b;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
static JSONArray messageToJSON(NdefMessage message) {
|
|
113
|
+
if (message == null) {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
List<JSONObject> list = new ArrayList<JSONObject>();
|
|
118
|
+
|
|
119
|
+
for (NdefRecord ndefRecord : message.getRecords()) {
|
|
120
|
+
list.add(recordToJSON(ndefRecord));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return new JSONArray(list);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
static JSONObject recordToJSON(NdefRecord record) {
|
|
127
|
+
JSONObject json = new JSONObject();
|
|
128
|
+
try {
|
|
129
|
+
json.put("tnf", record.getTnf());
|
|
130
|
+
json.put("type", byteArrayToJSON(record.getType()));
|
|
131
|
+
json.put("id", byteArrayToJSON(record.getId()));
|
|
132
|
+
json.put("payload", byteArrayToJSON(record.getPayload()));
|
|
133
|
+
} catch (JSONException e) {
|
|
134
|
+
//Not sure why this would happen, documentation is unclear.
|
|
135
|
+
Log.e(TAG, "Failed to convert ndef record into json: " + record.toString(), e);
|
|
136
|
+
}
|
|
137
|
+
return json;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
//
|
|
2
|
+
// AppDelegate+NFC.swift
|
|
3
|
+
// PhoneGap NFC - Cordova Plugin
|
|
4
|
+
//
|
|
5
|
+
// Copyright © 2019 dev@iotize.com. All rights reserved.
|
|
6
|
+
|
|
7
|
+
import CoreNFC
|
|
8
|
+
|
|
9
|
+
extension AppDelegate {
|
|
10
|
+
|
|
11
|
+
override open func application(_ application: UIApplication,
|
|
12
|
+
continue userActivity: NSUserActivity,
|
|
13
|
+
restorationHandler: @escaping ([Any]?) -> Void) -> Bool {
|
|
14
|
+
|
|
15
|
+
NSLog("Extending UIApplicationDelegate")
|
|
16
|
+
|
|
17
|
+
guard userActivity.activityType == NSUserActivityTypeBrowsingWeb else {
|
|
18
|
+
return false
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Confirm that the NSUserActivity object contains a valid NDEF message.
|
|
22
|
+
if #available(iOS 12.0, *) {
|
|
23
|
+
let ndefMessage = userActivity.ndefMessagePayload
|
|
24
|
+
guard ndefMessage.records.count > 0,
|
|
25
|
+
ndefMessage.records[0].typeNameFormat != .empty else {
|
|
26
|
+
return false
|
|
27
|
+
}
|
|
28
|
+
let nfcPluginInstance: NfcPlugin = self.viewController.getCommandInstance("NfcPlugin") as! NfcPlugin
|
|
29
|
+
var resolved: Bool = false;
|
|
30
|
+
NSLog(nfcPluginInstance.debugDescription);
|
|
31
|
+
|
|
32
|
+
DispatchQueue.global().async {
|
|
33
|
+
let waitingTimeInterval: Double = 0.1;
|
|
34
|
+
print("<NFC> Did start timeout")
|
|
35
|
+
for _ in 1...2000 { // 5?s timeout
|
|
36
|
+
if ( !nfcPluginInstance.isListeningNDEF ) {
|
|
37
|
+
Thread.sleep(forTimeInterval: waitingTimeInterval)
|
|
38
|
+
} else {
|
|
39
|
+
let jsonDictionary = ndefMessage.ndefMessageToJSON()
|
|
40
|
+
nfcPluginInstance.sendThroughChannel(jsonDictionary: jsonDictionary)
|
|
41
|
+
resolved = true
|
|
42
|
+
return
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return resolved
|
|
47
|
+
} else {
|
|
48
|
+
return false
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
//
|
|
2
|
+
// IOS15Reader.swift
|
|
3
|
+
// NFC
|
|
4
|
+
//
|
|
5
|
+
// Created by dev@iotize.com on 23/07/2019.
|
|
6
|
+
// Copyright © 2019 dev@iotize.com. All rights reserved.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
import UIKit
|
|
10
|
+
import CoreNFC
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
public extension String {
|
|
14
|
+
|
|
15
|
+
func dataFromHexString() -> Data {
|
|
16
|
+
var bytes = [UInt8]()
|
|
17
|
+
for i in 0..<(count/2) {
|
|
18
|
+
let range = index(self.startIndex, offsetBy: 2*i)..<index(self.startIndex, offsetBy: 2*i+2)
|
|
19
|
+
let stringBytes = self[range]
|
|
20
|
+
let byte = strtol((stringBytes as NSString).utf8String, nil, 16)
|
|
21
|
+
bytes.append(UInt8(byte))
|
|
22
|
+
}
|
|
23
|
+
return Data(bytes: UnsafePointer<UInt8>(bytes), count:bytes.count)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
extension Data {
|
|
29
|
+
|
|
30
|
+
func hexEncodedString() -> String {
|
|
31
|
+
let format = "%02hhX"
|
|
32
|
+
return map { String(format: format, $0) }.joined()
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@available(iOS 13.0, *)
|
|
37
|
+
class ST25DVReader : NSObject {
|
|
38
|
+
|
|
39
|
+
typealias Completion = (Error?) -> ()
|
|
40
|
+
|
|
41
|
+
private var comSession: NFCTagReaderSession?
|
|
42
|
+
private var tag: NFCISO15693Tag?
|
|
43
|
+
|
|
44
|
+
static var MB_CTRL_DYN : UInt8 = 0x0D
|
|
45
|
+
|
|
46
|
+
private var connectionCompleted : Completion?
|
|
47
|
+
|
|
48
|
+
/*ST25 commands*/
|
|
49
|
+
static var ISO15693_CUSTOM_ST25DV_CMD_WRITE_MB_MSG : UInt8 = 0xAA;
|
|
50
|
+
static var ISO15693_CUSTOM_ST25DV_CMD_READ_MB_MSG_LENGTH : Int = 0xAB;
|
|
51
|
+
static var ISO15693_CUSTOM_ST25DV_CMD_READ_MB_MSG = 0xAC;
|
|
52
|
+
|
|
53
|
+
static var ISO15693_CUSTOM_ST_CMD_READ_DYN_CONFIG : Int = 0xAD;
|
|
54
|
+
static var ISO15693_CUSTOM_ST_CMD_WRITE_DYN_CONFIG : Int = 0xAE;
|
|
55
|
+
|
|
56
|
+
static var DELAY : UInt32 = 1000; // timeout resolution in millionths of second
|
|
57
|
+
static var NB_MAX_RETRY : Int = 50;
|
|
58
|
+
|
|
59
|
+
override init() {
|
|
60
|
+
super.init()
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
func initSession( alertMessage: String, completed: @escaping (Error?)->() ) {
|
|
64
|
+
|
|
65
|
+
guard NFCNDEFReaderSession.readingAvailable else {
|
|
66
|
+
completed( NFCReaderError( NFCReaderError.readerErrorUnsupportedFeature ))
|
|
67
|
+
return
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
connectionCompleted = completed
|
|
71
|
+
|
|
72
|
+
if NFCNDEFReaderSession.readingAvailable {
|
|
73
|
+
comSession = NFCTagReaderSession(pollingOption: [.iso15693], delegate: self, queue: nil)
|
|
74
|
+
comSession?.alertMessage = alertMessage
|
|
75
|
+
comSession?.begin()
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
func invalidateSession( message :String) {
|
|
80
|
+
comSession?.alertMessage = message
|
|
81
|
+
comSession?.invalidate()
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
func send( request: String, completed: @escaping (Data?,Error?)->() ) {
|
|
85
|
+
|
|
86
|
+
guard NFCNDEFReaderSession.readingAvailable else {
|
|
87
|
+
let error = NFCReaderError( NFCReaderError.readerErrorUnsupportedFeature )
|
|
88
|
+
invalidateSession( message: error.localizedDescription )
|
|
89
|
+
completed( nil, error )
|
|
90
|
+
return
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
guard comSession != nil && comSession!.isReady else {
|
|
94
|
+
let error = NFCReaderError( NFCReaderError.readerTransceiveErrorTagNotConnected )
|
|
95
|
+
invalidateSession( message: error.localizedDescription )
|
|
96
|
+
completed( nil, error )
|
|
97
|
+
return
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
let requestData : Data = request.dataFromHexString()
|
|
101
|
+
print( "Transceive - \(requestData.hexEncodedString())" )
|
|
102
|
+
transceive(request: requestData,
|
|
103
|
+
completed: { ( response: Data?, error: Error?) in
|
|
104
|
+
if nil != error {
|
|
105
|
+
self.invalidateSession( message: error?.localizedDescription ?? "Error" )
|
|
106
|
+
completed( nil, error )
|
|
107
|
+
return
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
completed( response, nil)
|
|
111
|
+
return
|
|
112
|
+
}
|
|
113
|
+
})
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
@available(iOS 13.0, *)
|
|
120
|
+
extension ST25DVReader : NFCTagReaderSessionDelegate {
|
|
121
|
+
// MARK: - NFCTagReaderSessionDelegate
|
|
122
|
+
func tagReaderSessionDidBecomeActive(_ session: NFCTagReaderSession) {
|
|
123
|
+
// If necessary, you may perform additional operations on session start.
|
|
124
|
+
// At this point RF polling is enabled.
|
|
125
|
+
print( "tagReaderSessionDidBecomeActive" )
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
func tagReaderSession(_ session: NFCTagReaderSession, didInvalidateWithError error: Error) {
|
|
129
|
+
// If necessary, you may handle the error. Note session is no longer valid.
|
|
130
|
+
// You must create a new session to restart RF polling.
|
|
131
|
+
print( "tagReaderSession:didInvalidateWithError - \(error)" )
|
|
132
|
+
connectionCompleted?(error)
|
|
133
|
+
self.comSession = nil
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
func tagReaderSession(_ session: NFCTagReaderSession, didDetect tags: [NFCTag]) {
|
|
137
|
+
print( "tagReaderSession:didDectectTag" )
|
|
138
|
+
guard let session = self.comSession else {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
if tags.count > 1 {
|
|
142
|
+
// Restart polling in 500 milliseconds.
|
|
143
|
+
let retryInterval = DispatchTimeInterval.milliseconds(500)
|
|
144
|
+
session.alertMessage = "More than 1 Tap is detected. Please remove all tags and try again."
|
|
145
|
+
DispatchQueue.global().asyncAfter(deadline: .now() + retryInterval, execute: {
|
|
146
|
+
session.restartPolling()
|
|
147
|
+
})
|
|
148
|
+
return
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
guard let tag = tags.first else {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
switch tag {
|
|
156
|
+
case .iso15693(let iso15tag):
|
|
157
|
+
self.tag = iso15tag
|
|
158
|
+
default:
|
|
159
|
+
let error = NFCReaderError( NFCReaderError.ndefReaderSessionErrorTagNotWritable )
|
|
160
|
+
invalidateSession( message: error.localizedDescription )
|
|
161
|
+
connectionCompleted?(error)
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Connect to tag
|
|
166
|
+
session.connect(to: tag) { [weak self] (error: Error?) in
|
|
167
|
+
guard let strongSelf = self else {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if error != nil {
|
|
172
|
+
let error = NFCReaderError( NFCReaderError.readerTransceiveErrorTagNotConnected )
|
|
173
|
+
strongSelf.invalidateSession( message: error.localizedDescription )
|
|
174
|
+
strongSelf.connectionCompleted?(error)
|
|
175
|
+
return
|
|
176
|
+
}
|
|
177
|
+
print( "connected to tag" )
|
|
178
|
+
strongSelf.connectionCompleted?(nil)
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
@available(iOS 13.0, *)
|
|
184
|
+
extension ST25DVReader {
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
func transceive(request: Data, completed: @escaping (Data?, Error?)->()){
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
checkMBEnabled( completed: { ( error: Error?) in
|
|
192
|
+
if nil != error {
|
|
193
|
+
self.invalidateSession( message: error?.localizedDescription ?? "Error" )
|
|
194
|
+
completed( nil, error )
|
|
195
|
+
return
|
|
196
|
+
}
|
|
197
|
+
print( "Com enabled" )
|
|
198
|
+
self.sendRequest( request: request,
|
|
199
|
+
nbTry: ST25DVReader.NB_MAX_RETRY,
|
|
200
|
+
completed: { ( response: Data?, error: Error?) in
|
|
201
|
+
if nil != error {
|
|
202
|
+
self.invalidateSession( message: error?.localizedDescription ?? "Error" )
|
|
203
|
+
completed( nil, error )
|
|
204
|
+
return
|
|
205
|
+
}
|
|
206
|
+
completed(response, nil)
|
|
207
|
+
})
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
func sendRequest(request: Data, nbTry: Int, completed: @escaping (Data?, Error?)->() ) {
|
|
213
|
+
guard let tag = self.tag else {
|
|
214
|
+
let error = NFCReaderError( NFCReaderError.readerTransceiveErrorTagNotConnected )
|
|
215
|
+
invalidateSession( message: error.localizedDescription )
|
|
216
|
+
completed(nil, error )
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (nbTry <= 0){
|
|
221
|
+
let error = NFCReaderError( NFCReaderError.readerTransceiveErrorRetryExceeded )
|
|
222
|
+
invalidateSession( message: error.localizedDescription )
|
|
223
|
+
completed(nil, error )
|
|
224
|
+
return
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
var parameters = Data( bytes:[request.count - 1], count: 1 )
|
|
228
|
+
parameters.append(request)
|
|
229
|
+
print( "Send - \(parameters.hexEncodedString())" )
|
|
230
|
+
tag.customCommand(requestFlags: [.highDataRate],
|
|
231
|
+
customCommandCode: 0xAA,
|
|
232
|
+
customRequestParameters: parameters,
|
|
233
|
+
completionHandler: { (response: Data?, error: Error?) in
|
|
234
|
+
if nil != error {
|
|
235
|
+
usleep(ST25DVReader.DELAY)
|
|
236
|
+
self.sendRequest( request: request, nbTry: nbTry - 1, completed: completed )
|
|
237
|
+
return
|
|
238
|
+
}
|
|
239
|
+
usleep(ST25DVReader.DELAY * 10) // free ST25DV for SPI
|
|
240
|
+
self.readResponse( nbTry: nbTry , completed: completed)
|
|
241
|
+
})
|
|
242
|
+
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
func readResponse( nbTry: Int, completed: @escaping (Data?, Error?)->() ) {
|
|
246
|
+
|
|
247
|
+
guard let tag = self.tag else {
|
|
248
|
+
let error = NFCReaderError( NFCReaderError.readerTransceiveErrorTagNotConnected )
|
|
249
|
+
invalidateSession( message: error.localizedDescription )
|
|
250
|
+
completed( nil, error )
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
//We have tried enough timeout and return
|
|
255
|
+
if (nbTry <= 0){
|
|
256
|
+
print( "Read Abandonned" )
|
|
257
|
+
let error = NFCReaderError( NFCReaderError.readerTransceiveErrorRetryExceeded )
|
|
258
|
+
invalidateSession( message: error.localizedDescription )
|
|
259
|
+
completed( nil, error )
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
print( "Read \(nbTry)" )
|
|
264
|
+
|
|
265
|
+
//check Mailbox
|
|
266
|
+
tag.customCommand(requestFlags: [.highDataRate],
|
|
267
|
+
customCommandCode: 0xAD,
|
|
268
|
+
customRequestParameters: Data(bytes: [UInt8(0x0D)], count: 1),
|
|
269
|
+
completionHandler: { (response: Data, error: Error?) in
|
|
270
|
+
if nil != error {
|
|
271
|
+
usleep(ST25DVReader.DELAY)
|
|
272
|
+
self.readResponse( nbTry: nbTry - 1, completed: completed )
|
|
273
|
+
return
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
print( "Read resonse" )
|
|
277
|
+
|
|
278
|
+
if ( (response.count >= 1) && ( (response[0]&0x1) != 0 ) && ( (response[0]&0x2) != 0 )){
|
|
279
|
+
|
|
280
|
+
print( "Read Value - \(Data(response).hexEncodedString())" )
|
|
281
|
+
tag.customCommand(requestFlags: [.highDataRate],
|
|
282
|
+
customCommandCode: 0xAC,
|
|
283
|
+
customRequestParameters: Data(bytes: [UInt8(0), UInt8(0)], count: 2),
|
|
284
|
+
completionHandler: { (response: Data, error: Error?) in
|
|
285
|
+
if nil != error {
|
|
286
|
+
self.invalidateSession( message: error?.localizedDescription ?? "Error" )
|
|
287
|
+
completed( nil, error )
|
|
288
|
+
return
|
|
289
|
+
}
|
|
290
|
+
print( "got Value - \(Data(response).hexEncodedString())" )
|
|
291
|
+
completed(response,nil)
|
|
292
|
+
return
|
|
293
|
+
})
|
|
294
|
+
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
usleep(ST25DVReader.DELAY)
|
|
298
|
+
self.readResponse( nbTry: nbTry - 1, completed: completed )
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
})
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
func checkMBEnabled(completed: @escaping (Error?)->()) {
|
|
307
|
+
guard let tag = self.tag else {
|
|
308
|
+
let error = NFCReaderError( NFCReaderError.readerTransceiveErrorTagNotConnected )
|
|
309
|
+
invalidateSession( message: error.localizedDescription )
|
|
310
|
+
completed( error )
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
//Read Config
|
|
315
|
+
tag.customCommand(requestFlags: [.highDataRate],
|
|
316
|
+
customCommandCode: 0xAD,
|
|
317
|
+
customRequestParameters: Data(bytes: [UInt8(0x0D)], count: 1),
|
|
318
|
+
completionHandler: { (response: Data, error: Error?) in
|
|
319
|
+
if nil != error {
|
|
320
|
+
self.invalidateSession( message: error?.localizedDescription ?? "Error" )
|
|
321
|
+
completed(error)
|
|
322
|
+
return
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if ( response.count == 0) {
|
|
326
|
+
let error = NFCReaderError( NFCReaderError.readerTransceiveErrorTagResponseError )
|
|
327
|
+
self.invalidateSession( message: error.localizedDescription )
|
|
328
|
+
completed( error )
|
|
329
|
+
return
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
let current = response[0];
|
|
334
|
+
|
|
335
|
+
//We should reset mailbox
|
|
336
|
+
if ( (current != 0x41) && (current != 0x81) ) {
|
|
337
|
+
|
|
338
|
+
//disable
|
|
339
|
+
tag.customCommand(requestFlags: [.highDataRate],
|
|
340
|
+
customCommandCode: 0xAE,
|
|
341
|
+
customRequestParameters: Data(bytes: [UInt8(0x0D), UInt8(0x00)], count: 2),
|
|
342
|
+
completionHandler: { (response: Data, error: Error?) in
|
|
343
|
+
if nil != error {
|
|
344
|
+
self.invalidateSession( message: error?.localizedDescription ?? "Error" )
|
|
345
|
+
completed( error )
|
|
346
|
+
return
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
//enable
|
|
350
|
+
tag.customCommand(requestFlags: [.highDataRate],
|
|
351
|
+
customCommandCode: 0xAE,
|
|
352
|
+
customRequestParameters: Data(bytes: [UInt8(0x0D), UInt8(0x01)], count: 2),
|
|
353
|
+
completionHandler: { (response: Data, error: Error?) in
|
|
354
|
+
if nil != error {
|
|
355
|
+
self.invalidateSession( message: error?.localizedDescription ?? "Error" )
|
|
356
|
+
completed( error )
|
|
357
|
+
return
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
completed(nil)
|
|
361
|
+
return
|
|
362
|
+
|
|
363
|
+
})
|
|
364
|
+
})
|
|
365
|
+
}
|
|
366
|
+
//We are ok to go
|
|
367
|
+
else
|
|
368
|
+
{
|
|
369
|
+
completed(nil)
|
|
370
|
+
return
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
})
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|