Add files via upload
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
# 超高频(UHF) RFID 卡读写的 Cordova 插件
|
||||
|
||||
## 说明
|
||||
**使用UHF1_Com13_SDK_v1.5,针对k71v1_64_bsp型号设备**
|
||||
|
||||
## 安装
|
||||
使用 Cordova
|
||||
<pre>cordova plugin add https://github.com/shuto-cn/UHF#Com13_SDK_v1.5</pre>
|
||||
|
||||
使用 Ionic
|
||||
<pre>ionic cordova plugin add https://github.com/shuto-cn/UHF#Com13_SDK_v1.5</pre>
|
||||
|
||||
## 示例程序
|
||||
https://github.com/shuto-cn/uhf-demo/tree/Com13_SDK_v1.5
|
||||
|
||||
## 目前提供的功能
|
||||
### 单次询卡 - 读取卡的 EPC
|
||||
* 调用:
|
||||
<pre>cordova.plugins.uhf.searchCard(successCallBack, errorCallback);</pre>
|
||||
* 参数:
|
||||
* 返回值:
|
||||
EPC数组,因为可能读到多个。<pre>["30396062C3AE88C00021E2BC"]</pre>
|
||||
* 多次巡卡方法已取消,如有需求请用js实现。
|
||||
|
||||
### 写卡
|
||||
* 调用:
|
||||
<pre>cordova.plugins.uhf.writeCard(message, successCallBack, errorCallback);</pre>
|
||||
* 参数:
|
||||
<pre>
|
||||
{
|
||||
data: "内容"
|
||||
}
|
||||
</pre>
|
||||
* 内容为需要写入user区的数据,支持中英文,上限为128位16进制
|
||||
* 返回值:“写入成功”或“写入失败”
|
||||
|
||||
### 读卡
|
||||
* 仅读取user区的内容
|
||||
* 调用:
|
||||
<pre>cordova.plugins.uhf.readCard(successCallBack, errorCallback);</pre>
|
||||
* 返回值:
|
||||
<pre>"内容"</pre>
|
||||
|
||||
### 设置功率
|
||||
* 调用:
|
||||
<pre>cordova.plugins.uhf.setPower(power, successCallBack, errorCallback);</pre>
|
||||
* 参数:
|
||||
<pre>
|
||||
目前支持的功率值为 16 至 26,超出范围会按最大或最小值处理。
|
||||
</pre>
|
||||
* 返回值:“设置成功”或“设置失败”
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "cordova-plugin-uhf",
|
||||
"version": "0.0.1",
|
||||
"description": "",
|
||||
"cordova": {
|
||||
"id": "cordova-plugin-uhf",
|
||||
"platforms": [
|
||||
"android"
|
||||
]
|
||||
},
|
||||
"keywords": [
|
||||
"ecosystem:cordova",
|
||||
"cordova-android"
|
||||
],
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<plugin id="cordova-plugin-uhf" version="0.0.2"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android" xmlns="http://apache.org/cordova/ns/plugins/1.0">
|
||||
<name>Cordova UHF Plugin</name>
|
||||
<js-module name="cordova-plugin-uhf" src="www/cordova-plugin-uhf.js">
|
||||
<clobbers target="cordova.plugin.uhf"/>
|
||||
</js-module>
|
||||
<platform name="android">
|
||||
<config-file parent="/*" target="res/xml/config.xml">
|
||||
<feature name="UHF">
|
||||
<param name="android-package" value="cordova.plugin.uhf.UHF"/>
|
||||
</feature>
|
||||
</config-file>
|
||||
<source-file src="src/android/cordova/plugin/uhf/UHF.java"
|
||||
target-dir="src/cordova/plugin/uhf"/>
|
||||
<source-file src="src/android/cordova/plugin/uhf/Util.java"
|
||||
target-dir="src/cordova/plugin/uhf"/>
|
||||
<source-file src="src/android/uhfcom13_v15.jar" target-dir="libs"/>
|
||||
<source-file src="src/android/SerialPort.jar" target-dir="libs"/>
|
||||
|
||||
|
||||
<resource-file src="src/android/libs/armeabi/libdevapi.so"
|
||||
target="jniLibs/armeabi/libdevapi.so"/>
|
||||
<resource-file src="src/android/libs/armeabi/libirdaSerialPort.so"
|
||||
target="jniLibs/armeabi/libirdaSerialPort.so"/>
|
||||
<resource-file src="src/android/libs/armeabi/libuhf.so"
|
||||
target="jniLibs/armeabi/libuhf.so"/>
|
||||
|
||||
<resource-file src="src/android/libs/armeabi-v7a/libdevapi.so"
|
||||
target="jniLibs/armeabi-v7a/libdevapi.so"/>
|
||||
<resource-file src="src/android/libs/armeabi-v7a/libirdaSerialPort.so"
|
||||
target="jniLibs/armeabi-v7a/libirdaSerialPort.so"/>
|
||||
<resource-file src="src/android/libs/armeabi-v7a/libuhf.so"
|
||||
target="jniLibs/armeabi-v7a/libuhf.so"/>
|
||||
|
||||
<resource-file src="src/android/libs/arm64-v8a/libdevapi.so"
|
||||
target="jniLibs/arm64-v8a/libdevapi.so"/>
|
||||
<resource-file src="src/android/libs/arm64-v8a/libirdaSerialPort.so"
|
||||
target="jniLibs/arm64-v8a/libirdaSerialPort.so"/>
|
||||
<resource-file src="src/android/libs/arm64-v8a/libuhf.so"
|
||||
target="jniLibs/arm64-v8a/libuhf.so"/>
|
||||
|
||||
</platform>
|
||||
</plugin>
|
||||
Binary file not shown.
@@ -0,0 +1,256 @@
|
||||
package cordova.plugin.uhf;
|
||||
|
||||
import android.util.Log;
|
||||
import cn.pda.serialport.Tools;
|
||||
import com.android.hdhe.uhf.reader.UhfReader;
|
||||
import com.android.hdhe.uhf.readerInterface.TagModel;
|
||||
import org.apache.cordova.CallbackContext;
|
||||
import org.apache.cordova.CordovaPlugin;
|
||||
import org.apache.cordova.PluginResult;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 超高频(UHF)读写卡插件。
|
||||
* 因不同的机型使用的so库不同,故无法适配所有机型。
|
||||
*/
|
||||
public class UHF extends CordovaPlugin {
|
||||
private UhfReader manager;
|
||||
private String selectedEpc = "";
|
||||
private byte[] password = Tools.HexString2Bytes("00000000");
|
||||
private boolean threadFlag;
|
||||
|
||||
@Override
|
||||
protected void pluginInitialize() {
|
||||
super.pluginInitialize();
|
||||
manager = UhfReader.getInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
|
||||
switch (action) {
|
||||
case "readCard":
|
||||
this.readCard(callbackContext);
|
||||
return true;
|
||||
case "searchCard":
|
||||
this.searchCard(callbackContext);
|
||||
return true;
|
||||
case "writeCard":
|
||||
this.writeCard(args, callbackContext);
|
||||
return true;
|
||||
case "setPower":
|
||||
this.setPower(args, callbackContext);
|
||||
return true;
|
||||
case "startWork":
|
||||
this.startWork(callbackContext);
|
||||
return true;
|
||||
case "endWork":
|
||||
this.endWork(callbackContext);
|
||||
return true;
|
||||
case "selectCard":
|
||||
this.selectCard(args, callbackContext);
|
||||
return true;
|
||||
case "inventoryCard":
|
||||
this.inventoryCard(callbackContext);
|
||||
return true;
|
||||
case "stopInventoryCard":
|
||||
this.stopInventoryCard(callbackContext);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void startWork(CallbackContext callbackContext) {
|
||||
if (this.manager == null) {
|
||||
manager = UhfReader.getInstance();
|
||||
}
|
||||
callbackContext.success();
|
||||
}
|
||||
|
||||
private void endWork(CallbackContext callbackContext) {
|
||||
if (this.manager != null) {
|
||||
this.manager.close();
|
||||
this.manager = null;
|
||||
}
|
||||
callbackContext.success();
|
||||
}
|
||||
|
||||
|
||||
private void stopInventoryCard(CallbackContext callbackContext) {
|
||||
threadFlag = false;
|
||||
callbackContext.success("停止");
|
||||
}
|
||||
|
||||
private void searchCard(CallbackContext callbackContext) {
|
||||
try {
|
||||
JSONArray ja = onceSearchCard();
|
||||
callbackContext.success(ja);
|
||||
} catch (JSONException e) {
|
||||
callbackContext.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void inventoryCard(CallbackContext callbackContext) {
|
||||
threadFlag = true;
|
||||
Thread thread = new InventoryThread(callbackContext);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
private class InventoryThread extends Thread {
|
||||
|
||||
private CallbackContext cb;
|
||||
|
||||
public InventoryThread(CallbackContext cb) {
|
||||
super();
|
||||
this.cb = cb;
|
||||
}
|
||||
|
||||
public InventoryThread() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
super.run();
|
||||
try {
|
||||
while (threadFlag) {
|
||||
JSONArray ja = onceSearchCard();
|
||||
PluginResult pr = new PluginResult(PluginResult.Status.OK, ja);
|
||||
pr.setKeepCallback(true);
|
||||
cb.sendPluginResult(pr);
|
||||
Thread.sleep(100);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
cb.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 单次巡卡,每执行一次,就扫描一次范围内的卡片,将巡到的卡片信息以json数组的形式返回。
|
||||
*/
|
||||
private JSONArray onceSearchCard() throws JSONException {
|
||||
List<TagModel> tagList;
|
||||
tagList = manager.inventoryRealTime(); //实时盘存
|
||||
JSONArray ja = new JSONArray();
|
||||
JSONObject jo;
|
||||
String epcStr;
|
||||
if (tagList != null && !tagList.isEmpty()) {
|
||||
for (TagModel tag : tagList) {
|
||||
if (tag == null) {
|
||||
break;
|
||||
} else {
|
||||
epcStr = Tools.Bytes2HexString(tag.getmEpcBytes(), tag.getmEpcBytes().length);
|
||||
}
|
||||
jo = new JSONObject();
|
||||
jo.put("mEpcBytes", epcStr);
|
||||
jo.put("mRssi", tag.getmRssi());
|
||||
ja.put(jo);
|
||||
}
|
||||
}
|
||||
return ja;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读卡,将USER区的hex字符串转换为ascii读取,因EPC区与TID区不能写入,故暂时只读取USER区,注释掉的部分为适应EPC区与TID区读取的代码
|
||||
* 将注释解开后应抛出JSONException
|
||||
*/
|
||||
private void readCard(CallbackContext callbackContext) {
|
||||
// JSONObject obj = message.getJSONObject(0);
|
||||
// int site = obj.getInt("site");
|
||||
// int addr = obj.getInt("addr");
|
||||
// if (site == 1) {
|
||||
// addr = 2;
|
||||
// length = 6;
|
||||
// } else if (site == 3) {
|
||||
// addr = 0;
|
||||
// length = 32;
|
||||
// } else if (site == 2) {
|
||||
// addr = 0;
|
||||
// length = 12;
|
||||
// }
|
||||
manager.selectEPC(Tools.HexString2Bytes(this.selectedEpc));
|
||||
int length = 32;
|
||||
byte[] data = manager.readFrom6C(3, 0, length, password);
|
||||
if (data != null && data.length >= 1) {
|
||||
String msg;
|
||||
// if (site == 3) { // 读取User区的时候,将16进制字符串转换为ascii
|
||||
msg = Util.bytes2Str(data);
|
||||
// } else { // 因EPC区与TID区不能写入,故读取时不转码
|
||||
// msg = Tools.Bytes2HexString(data, data.length);
|
||||
// }
|
||||
callbackContext.success(msg);
|
||||
} else {
|
||||
callbackContext.error("读取失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 选卡,将选到的卡储存在this.selectedEpc中
|
||||
*/
|
||||
private void selectCard(JSONArray message, CallbackContext callbackContext) throws JSONException {
|
||||
JSONObject obj = message.getJSONObject(0);
|
||||
String epc = obj.getString("epc");
|
||||
manager.selectEPC(Tools.HexString2Bytes(epc));
|
||||
this.selectedEpc = epc;
|
||||
callbackContext.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 写卡,将ascii转换为bytes并写入
|
||||
*/
|
||||
private void writeCard(JSONArray message, CallbackContext callbackContext) {
|
||||
manager.selectEPC(Tools.HexString2Bytes(this.selectedEpc));
|
||||
String _data = null;
|
||||
try {
|
||||
JSONObject obj = message.getJSONObject(0);
|
||||
_data = Util.str2HexStr(obj.getString("data"));
|
||||
} catch (JSONException e) {
|
||||
callbackContext.error("JSON解析失败");
|
||||
}
|
||||
// 处理_data,将ascii转换为16进制字符串,超过32 * 4位的16进制字符串报错,小于32 * 4时在16进制字符串末位补0x00作为完结标记,再转换为bytes
|
||||
if (_data != null && _data.length() > 32 * 4) {
|
||||
callbackContext.error("数据过长");
|
||||
return;
|
||||
}
|
||||
if (_data.length() < 32 * 4) {
|
||||
_data += "00";
|
||||
}
|
||||
byte[] dataBytes = Util.hexStringToBytes(_data);
|
||||
boolean writeFlag = false;
|
||||
if (dataBytes != null) {
|
||||
writeFlag = manager.writeTo6C(password, 3, 0, dataBytes.length / 2, dataBytes);
|
||||
}
|
||||
if (writeFlag) {
|
||||
callbackContext.success("写入成功");
|
||||
} else {
|
||||
callbackContext.error("写入失败");
|
||||
}
|
||||
}
|
||||
|
||||
private void setPower(JSONArray message, CallbackContext callbackContext) throws JSONException {
|
||||
int power = message.getInt(0);
|
||||
if (power > 26) {
|
||||
power = 26;
|
||||
} else if (power < 16) {
|
||||
power = 16;
|
||||
}
|
||||
if (manager.setOutputPower(power)) {
|
||||
callbackContext.success("设置成功");
|
||||
} else {
|
||||
callbackContext.error("设置失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
if (this.manager != null) {
|
||||
this.manager.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package cordova.plugin.uhf;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import android.content.Context;
|
||||
import android.media.AudioManager;
|
||||
import android.media.SoundPool;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* 工具类,主要用于实现各类字符串之间的转换
|
||||
*/
|
||||
public class Util {
|
||||
|
||||
public static String str2HexStr(String origin) {
|
||||
byte[] bytes = origin.getBytes();
|
||||
String hex = bytesToHexString(bytes, bytes.length);
|
||||
return hex;
|
||||
}
|
||||
|
||||
public static String hexStr2Str(String hex) {
|
||||
byte[] bb = hexStringToBytes(hex);
|
||||
String rr = new String(bb);
|
||||
return rr;
|
||||
}
|
||||
|
||||
public static String bytes2Str(byte[] src) {
|
||||
String rr = bytesToHexString(src, src.length);
|
||||
String str = new String(hexStr2Str(rr));
|
||||
return str;
|
||||
}
|
||||
|
||||
private static String bytesToHexString(byte[] src, int size) {
|
||||
StringBuilder stringBuilder = new StringBuilder("");
|
||||
if (src == null || size <= 0) {
|
||||
return null;
|
||||
}
|
||||
for (int i = 0; i < size; i++) {
|
||||
int v = src[i] & 0xFF;
|
||||
String hv = Integer.toHexString(v);
|
||||
if (hv.length() < 2) {
|
||||
stringBuilder.append(0);
|
||||
}
|
||||
stringBuilder.append(hv);
|
||||
}
|
||||
String str = stringBuilder.toString();
|
||||
if (str.length() < 128) {
|
||||
str += "00";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
public static byte[] hexStringToBytes(String hexString) {
|
||||
if (hexString == null || hexString.equals("")) {
|
||||
return null;
|
||||
}
|
||||
hexString = hexString.toUpperCase();
|
||||
int length = hexString.length() / 2;
|
||||
char[] hexChars = hexString.toCharArray();
|
||||
byte[] d = new byte[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
int pos = i * 2;
|
||||
// 以0x00为分界线,不读取后面的数据
|
||||
if ((byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1])) == 00) {
|
||||
break;
|
||||
}
|
||||
d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
private static byte charToByte(char c) {
|
||||
return (byte) "0123456789ABCDEF".indexOf(c);
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Vendored
+41
@@ -0,0 +1,41 @@
|
||||
var exec = require('cordova/exec');
|
||||
|
||||
var coolMethod = function () {};
|
||||
|
||||
coolMethod.readCard = function (success, error) {
|
||||
exec(success, error, 'UHF', 'readCard', []);
|
||||
}
|
||||
|
||||
coolMethod.inventoryCard = function (success, error) {
|
||||
exec(success, error, 'UHF', 'inventoryCard', []);
|
||||
}
|
||||
|
||||
coolMethod.stopInventoryCard = function (success, error) {
|
||||
exec(success, error, 'UHF', 'stopInventoryCard', []);
|
||||
}
|
||||
|
||||
coolMethod.searchCard = function (success, error) {
|
||||
exec(success, error, 'UHF', 'searchCard', []);
|
||||
}
|
||||
|
||||
coolMethod.writeCard = function (arg, success, error) {
|
||||
exec(success, error, 'UHF', 'writeCard', [arg]);
|
||||
}
|
||||
|
||||
coolMethod.setPower = function (arg, success, error) {
|
||||
exec(success, error, 'UHF', 'setPower', [arg]);
|
||||
}
|
||||
|
||||
coolMethod.startWork = function (success, error) {
|
||||
exec(success, error, 'UHF', 'startWork', []);
|
||||
}
|
||||
|
||||
coolMethod.endWork = function (success, error) {
|
||||
exec(success, error, 'UHF', 'endWork', []);
|
||||
}
|
||||
|
||||
coolMethod.selectCard = function (arg, success, error) {
|
||||
exec(success, error, 'UHF', 'selectCard', [arg]);
|
||||
}
|
||||
|
||||
module.exports = coolMethod;
|
||||
Reference in New Issue
Block a user