刚开始接到这个这个任务的时候,看了一下这款读卡器设备的参数(res232协议读卡器技术参数)
初步尝试,利用串口接收 :
1.依赖接入:
//串口检测
implementation 'com.github.licheedev:Android-SerialPort-API:2.0.0'
2.设置串口参数,打开串口接收:
private SerialPort mSerialPort;
protected OutputStream mOutputStream;
private InputStream mInputStream;
private void init_readuserid() {
try {
mSerialPort = SerialPort
.newBuilder(new File("/dev/ttyS3"), 9600) // 串口地址地址,波特率
.dataBits(8) // 数据位,默认8;可选值为5~8
.parity(0) // 校验位;0:无校验位(NONE,默认);1:奇校验位(ODD);2:偶校验位(EVEN)
.stopBits(1) // 停止位,默认1;1:1位停止位;2:2位停止位
.build();
mOutputStream = mSerialPort.getOutputStream();
mInputStream = mSerialPort.getInputStream();
//开启接收线程
new ReadThread().start();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private class ReadThread extends Thread {
@Override
public void run() {
super.run();
while (!isInterrupted()) {
int size;
try {
byte[] buffer = new byte[64];
if (mInputStream == null) {
Log.i(TAG, "run: 输入为空");
System.out.println("+strData+strData入为空");
return;
}
size = mInputStream.read(buffer);
if (size > 0) {
String strData = ByteUtil.byteToStr(buffer, size);
Log.i(TAG, "run: 输入的=" + strData);
System.out.println("run: 输入为=" + strData);
// onDataReceived(buffer, size);
}
} catch (IOException e) {
e.printStackTrace();
return;
}
}
}
}
到这里,不管我这边怎么用卡片去刷,数据是始终反馈,一开始找了很多方式来接收串口的测试方法,都不行,刚开始,还以为是usb 权限问题,我这边把文件清单添加了usb权限:
<!--USB权限-->
<uses-feature android:name="android.hardware.usb.host" />
调用: openUsbDevice() ,来检测usb 权限问题;
/**
* 获得 usb 权限
*/
private void openUsbDevice() {
//before open usb device
//should try to get usb permission
tryGetUsbPermission();
}
UsbManager mUsbManager;
private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";
private void tryGetUsbPermission() {
mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
registerReceiver(mUsbPermissionActionReceiver, filter);
PendingIntent mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
//here do emulation to ask all connected usb device for permission
for (final UsbDevice usbDevice : mUsbManager.getDeviceList().values()) {
//add some conditional check if necessary
//if(isWeCaredUsbDevice(usbDevice)){
if (mUsbManager.hasPermission(usbDevice)) {
//if has already got permission, just goto connect it
//that means: user has choose yes for your previously popup window asking for grant perssion for this usb device
//and also choose option: not ask again
afterGetUsbPermission(usbDevice);
} else {
//this line will let android popup window, ask user whether to allow this app to have permission to operate this usb device
mUsbManager.requestPermission(usbDevice, mPermissionIntent);
}
//}
}
}
private void afterGetUsbPermission(UsbDevice usbDevice) {
//call method to set up device communication
//Toast.makeText(this, String.valueOf("Got permission for usb device: " + usbDevice), Toast.LENGTH_LONG).show();
//Toast.makeText(this, String.valueOf("Found USB device: VID=" + usbDevice.getVendorId() + " PID=" + usbDevice.getProductId()), Toast.LENGTH_LONG).show();
doYourOpenUsbDevice(usbDevice);
}
private void doYourOpenUsbDevice(UsbDevice usbDevice) {
//now follow line will NOT show: User has not given permission to device UsbDevice
UsbDeviceConnection connection = mUsbManager.openDevice(usbDevice);
//add your operation code here
}
private final BroadcastReceiver mUsbPermissionActionReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (ACTION_USB_PERMISSION.equals(action)) {
synchronized (this) {
UsbDevice usbDevice = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
//user choose YES for your previously popup window asking for grant perssion for this usb device
if (null != usbDevice) {
afterGetUsbPermission(usbDevice);
}
} else {
//user choose NO for your previously popup window asking for grant perssion for this usb device
Toast.makeText(context, String.valueOf("Permission denied for device" + usbDevice), Toast.LENGTH_LONG).show();
}
}
}
}
};
还是没有数据接收到,我这边找了很多的usb调试工具,最多都只是检测能否正常打开指定的usb 串口名有没有权限,能正常打开也是收不到任何的数据,我就想,这样的方式是不行的,然后我这边找到一个强大的测试串口工具,这边做一下分享推荐
https://blog.csdn.net/xlazydog/article/details/99458381
我这边就下载了这位大佬写的测试串口调试工具,没想到,我这边可以正常读取到卡片数据回来,然后就改成了他推荐的一个开源的Android 驱动库:
https://github.com/mik3y/usb-serial-for-android
接下来就是,第二次测试,用这个驱动库来测试行不行了:
我这边as工具用的版本是(androidx):
compileSdkVersion 29
buildToolsVersion "29.0.2"
直接用依赖到我的项目是,报错的,集成不进去:
implementation 'com.github.mik3y:usb-serial-for-android:Tag'
只能去下载他提供的android测试模块了,再手动导进去了:
https://blog.csdn.net/helloworld19870427/article/details/93221649(参考手动导入过程)
这边就不做分享导入的过程了。直接上码:
1.还是坚持usb权限问题,不然的话,就算可以找到设备,也有可能打开失败(connection 为 null),用 //usb权限开启
openUsbDevice() 是可以避免失败的问题。
UsbDeviceConnection connection = manager.openDevice(driver.getDevice());
private SerialInputOutputManager mSerialIoManager;
private ExecutorService mExecutor;
private UsbSerialPort port;
private StringBuffer sBuffer;
//usb-rs232
// Find all available drivers from attached devices.
//usb权限开启
openUsbDevice();
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
List<UsbSerialDriver> availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(manager);
if (availableDrivers.isEmpty()) {
return;
}
// Open a connection to the first available driver.
UsbSerialDriver driver = availableDrivers.get(0);
UsbDeviceConnection connection = manager.openDevice(driver.getDevice());
if (connection == null) {
// You probably need to call UsbManager.requestPermission(driver.getDevice(), ..)
return;
}
// Read some data! Most have just one port (port 0).
port = driver.getPorts().get(0);
try {
port.open(connection);
port.setParameters(9600, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
byte buffer[] = new byte[16];
int numBytesRead = port.read(buffer, 1000);
Log.i(TAG, "Read= " + numBytesRead + " bytes.");
} catch (IOException e) {
// Deal with error.
}
sBuffer=new StringBuffer();
mExecutor = Executors.newSingleThreadExecutor();
mSerialIoManager = new SerialInputOutputManager(port, mListener);//添加监听
// 在新的线程中监听串口的数据变化
mExecutor.submit(mSerialIoManager);
收到读卡器返回的字节数据,这里有个问题是,这个依赖库的问题,他不是一次性完整的返回一整串数据,他的文档有使用说明是这样说的;
https://github.com/mik3y/usb-serial-for-android/wiki/Troubleshooting
SerialInputOutputManager.Listener mListener = new SerialInputOutputManager.Listener() {
@Override
public void onRunError(Exception e) {
Log.i(TAG, "Runner stopped.");
}
@Override
public void onNewData(final byte[] data) {
//TODO 新的数据
String usbid2 = bytesToHexString(data);
Log.i(TAG, "新的数据data4=" + usbid2);
Message message=handler.obtainMessage();
message.what=3;
message.obj=usbid2;
handler.sendMessage(message);
}
};
我这边就处理方式也是死规定的,如果你那边的数据不一可以参考我下面的数据,处理方式(把字节数据 转 字符串拼接,每次的字符串的长度去清空,再次方便接收保存数据):
public static String bytesToHexString(byte[] bytes) {
String result = "";
for (int i = 0; i < bytes.length; i++) {
String hexString = Integer.toHexString(bytes[i] & 0xFF);
if (hexString.length() == 1) {
hexString = '0' + hexString;
}
result += hexString.toUpperCase();
}
return result;
}
最后关闭
@Override
protected void onDestroy() {
super.onDestroy();
handler.removeCallbacksAndMessages(null);
try {
port.close();
} catch (IOException e) {
e.printStackTrace();
}
}
到这里就基本实现了一个读卡器正常接收卡片的信息,做个简单的记录,简单集成usb-serial-for-android驱动库,就测试好了,当然我这边是用的一个设备来测试,如果多个设备接收,我这边暂时没有实现,但关键是找到设备数,找到设备名,来相互确认名字,暂时是这样的思路,里面的文章还是有很多方式没有一一列举出来,可以自己尝试,如果你有更好的看法和实现方式,可以底部评论留下思路,可以一起交流学习。