|
@@ -0,0 +1,333 @@
|
|
|
|
+package serialporttest.utils;
|
|
|
|
+
|
|
|
|
+import android.os.SystemClock;
|
|
|
|
+import android.util.Log;
|
|
|
|
+
|
|
|
|
+import java.io.File;
|
|
|
|
+import java.io.IOException;
|
|
|
|
+import java.io.InputStream;
|
|
|
|
+import java.io.OutputStream;
|
|
|
|
+import java.util.Arrays;
|
|
|
|
+import java.util.Locale;
|
|
|
|
+import java.util.concurrent.TimeoutException;
|
|
|
|
+
|
|
|
|
+import android_serialport_api.SerialPort;
|
|
|
|
+
|
|
|
|
+public class SerialPortNfcUtil {
|
|
|
|
+ private String TAG = "SerialPortNfcUtil";
|
|
|
|
+
|
|
|
|
+ public SerialPort serialPort = null;
|
|
|
|
+ public InputStream inputStream = null;
|
|
|
|
+ public OutputStream outputStream = null;
|
|
|
|
+
|
|
|
|
+ private ISerialPortNfcListener serialPortNfcListener = null;
|
|
|
|
+ public boolean isOpenSerialPortUtil = false;
|
|
|
|
+
|
|
|
|
+ public Thread receiveThread = null;
|
|
|
|
+
|
|
|
|
+ public static SerialPortNfcUtil instance = null;
|
|
|
|
+
|
|
|
|
+ public SerialPortNfcUtil() {
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static SerialPortNfcUtil getInstance() {
|
|
|
|
+ if (instance == null) {
|
|
|
|
+ synchronized (SerialPortNfcUtil.class) {
|
|
|
|
+ if (instance == null) {
|
|
|
|
+ instance = new SerialPortNfcUtil();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return instance;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 打开串口的方法
|
|
|
|
+ */
|
|
|
|
+ public void openSerialPort() {
|
|
|
|
+
|
|
|
|
+ Log.i(TAG, "打开NFC串口7");
|
|
|
|
+ try {
|
|
|
|
+ serialPort = new SerialPort();
|
|
|
|
+ serialPort.setCallback(new SerialPort.Callback() {
|
|
|
|
+ @Override
|
|
|
|
+ public void onOpen(boolean success) {
|
|
|
|
+ //获取打开的串口中的输入输出流,以便于串口数据的收发
|
|
|
|
+ inputStream = serialPort.getInputStream();
|
|
|
|
+ outputStream = serialPort.getOutputStream();
|
|
|
|
+ isOpenSerialPortUtil = true;
|
|
|
|
+ Log.i(TAG, "open nfc serialPort7 success...");
|
|
|
|
+ receiveSerialPort();
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ serialPort.open(new File("/dev/ttyS7"), 115200, 0);
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ e.printStackTrace();
|
|
|
|
+ Log.e(TAG, "open nfc serialPort7 failed...");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 接收串口数据的方法
|
|
|
|
+ */
|
|
|
|
+ public void receiveSerialPort() {
|
|
|
|
+ if (receiveThread != null)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ Log.e(TAG, "NFC接收数据线程...");
|
|
|
|
+
|
|
|
|
+ receiveThread = new Thread() {
|
|
|
|
+ @Override
|
|
|
|
+ public void run() {
|
|
|
|
+ while (isOpenSerialPortUtil) {
|
|
|
|
+ /*try {
|
|
|
|
+ Thread.sleep(150);
|
|
|
|
+ } catch (InterruptedException e) {
|
|
|
|
+ e.printStackTrace();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ int size;
|
|
|
|
+ try {
|
|
|
|
+ byte[] buffer = new byte[64];
|
|
|
|
+ if (inputStream == null) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if(inputStream.available()>0) {
|
|
|
|
+ size = inputStream.read(buffer);
|
|
|
|
+ Log.e(TAG, "nfc data byte: " + Arrays.toString(buffer) + ", size: " + size);
|
|
|
|
+ if (size > 0) {
|
|
|
|
+ if (serialPortNfcListener != null) {
|
|
|
|
+ serialPortNfcListener.onNfcData(buffer, size);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ } catch (IOException e) {
|
|
|
|
+ e.printStackTrace();
|
|
|
|
+ return;
|
|
|
|
+ }*/
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ while (!Thread.currentThread().isInterrupted()) {
|
|
|
|
+ try {
|
|
|
|
+ //如果可读取消息为0,就不继续。防止InputStream.read阻塞
|
|
|
|
+ if (inputStream.available() == 0) {
|
|
|
|
+ SystemClock.sleep(10);
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ byte[] bytes = readTime(inputStream, 1, 1000).getBytes();
|
|
|
|
+ //无数据不返回
|
|
|
|
+ if (bytes.length != 0) {
|
|
|
|
+ if (serialPortNfcListener != null) {
|
|
|
|
+ serialPortNfcListener.onNfcData(bytes, bytes.length);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ String receiveData = StringUtils.bytesToHex(bytes).toUpperCase(Locale.ROOT);
|
|
|
|
+ Log.e(TAG, "received nfc data: " + receiveData);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ } catch (Throwable e) {
|
|
|
|
+ Log.e(TAG, "读取线程异常", e);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+ //启动接收线程
|
|
|
|
+ receiveThread.start();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 只读一次,读取到就返回,读取不到就一直等
|
|
|
|
+ *
|
|
|
|
+ * @param inputStream inputStream
|
|
|
|
+ * @return byte[]
|
|
|
|
+ * @throws Exception Exception
|
|
|
|
+ */
|
|
|
|
+ @Deprecated
|
|
|
|
+ public static byte[] readOnce(InputStream inputStream) throws Exception {
|
|
|
|
+ return readOnce(inputStream, Long.MAX_VALUE);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 只读一次,读取到就返回。读取不到,一直等直到超时,如果超时则向上抛异常
|
|
|
|
+ *
|
|
|
|
+ * @param inputStream inputStream
|
|
|
|
+ * @param timeOut 超时毫秒
|
|
|
|
+ * @return byte[]
|
|
|
|
+ * @throws Exception Exception
|
|
|
|
+ */
|
|
|
|
+ public static byte[] readOnce(InputStream inputStream, long timeOut) throws Exception {
|
|
|
|
+ long startTime = System.currentTimeMillis();
|
|
|
|
+ int count = 0;
|
|
|
|
+ while (count == 0 && System.currentTimeMillis() - startTime < timeOut)
|
|
|
|
+ count = inputStream.available();//获取真正长度
|
|
|
|
+ if (System.currentTimeMillis() - startTime >= timeOut) {
|
|
|
|
+ throw new TimeoutException("读取超时");
|
|
|
|
+ }
|
|
|
|
+ byte[] bytes = new byte[count];
|
|
|
|
+ // 一定要读取count个数据,如果inputStream.read(bytes);可能读不完
|
|
|
|
+ int readCount = 0; // 已经成功读取的字节的个数
|
|
|
|
+ while (readCount < count)
|
|
|
|
+ readCount += inputStream.read(bytes, readCount, count - readCount);
|
|
|
|
+ return bytes;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 读取inputStream数据到YBytes,一直不停组包,每次组包时间maxGroupTime,如果maxGroupTime内没数据,就返回。
|
|
|
|
+ *
|
|
|
|
+ * @param inputStream inputStream
|
|
|
|
+ * @param maxGroupTime 最大组包时间,如果这个时间内有数据,就一直组包。如果这个时间都没数据,就返回。
|
|
|
|
+ * @return YBytes
|
|
|
|
+ * @throws Exception Exception
|
|
|
|
+ */
|
|
|
|
+ @Deprecated
|
|
|
|
+ public static YBytes readTime(InputStream inputStream, int maxGroupTime) throws Exception {
|
|
|
|
+ return readTime(inputStream, maxGroupTime, Integer.MAX_VALUE);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 读取inputStream数据到YBytes,一直不停组包,每次组包时间maxGroupTime,如果一直有数据,不超过maxTime。
|
|
|
|
+ *
|
|
|
|
+ * @param inputStream inputStream
|
|
|
|
+ * @param maxGroupTime 最大组包时间,如果这个时间内有数据,就一直组包。如果这个时间都没数据,就返回。
|
|
|
|
+ * @param maxTime 最多读取这么长时间
|
|
|
|
+ * @return YBytes
|
|
|
|
+ * @throws Exception Exception
|
|
|
|
+ */
|
|
|
|
+ public static YBytes readTime(InputStream inputStream, int maxGroupTime, int maxTime) throws Exception {
|
|
|
|
+ final YBytes bytes = new YBytes();
|
|
|
|
+ long startTime = System.currentTimeMillis();//开始时间
|
|
|
|
+ long groupTime;//运行时间
|
|
|
|
+ int i = 0;//第几次组包
|
|
|
|
+ int count = inputStream.available();//可读取多少字节内容
|
|
|
|
+ do {
|
|
|
|
+ byte[] newBytes = new byte[1024];
|
|
|
|
+ int newSize = inputStream.read(newBytes, 0, count);
|
|
|
|
+ if (newSize > 0) {
|
|
|
|
+ bytes.addByte(newBytes, newSize);
|
|
|
|
+ log("第" + (++i) + "次组包后长度:" + bytes.getBytes().length + ",\t已耗时:" + (System.currentTimeMillis() - startTime));
|
|
|
|
+ }
|
|
|
|
+ SystemClock.sleep(1);
|
|
|
|
+ count = inputStream.available();
|
|
|
|
+ groupTime = System.currentTimeMillis();
|
|
|
|
+ //如果读取长度为0,那么休息1毫秒继续读取,如果在maxGroupTime时间内都没有数据,那么就退出循环,或者超过maxTime
|
|
|
|
+ while (count == 0 && System.currentTimeMillis() - groupTime <= maxGroupTime && System.currentTimeMillis() - startTime <= maxTime) {
|
|
|
|
+ SystemClock.sleep(1);
|
|
|
|
+ count = inputStream.available();
|
|
|
|
+ }
|
|
|
|
+ } while (System.currentTimeMillis() - groupTime <= maxGroupTime && System.currentTimeMillis() - startTime <= maxTime);
|
|
|
|
+ return bytes;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 读取inputStream数据到YBytes,一直不停组包,至少读取时间:leastTime。但是期间读取长度达到minReadLength,立即返回。
|
|
|
|
+ *
|
|
|
|
+ * @param inputStream inputStream
|
|
|
|
+ * @param maxTime 最多读取这么长时间
|
|
|
|
+ * @param minLength 至少读取长度,只要读取长度大于等于minLength,直接返回,最多读取maxTime时间
|
|
|
|
+ * @return YBytes
|
|
|
|
+ * @throws Exception Exception
|
|
|
|
+ */
|
|
|
|
+ public static YBytes readLength(final InputStream inputStream, final int minLength, final int maxTime) throws Exception {
|
|
|
|
+ final YBytes bytes = new YBytes();
|
|
|
|
+ long startTime = System.currentTimeMillis();
|
|
|
|
+ int i = 0;
|
|
|
|
+ while (bytes.getBytes().length < minLength && System.currentTimeMillis() - startTime < maxTime) {
|
|
|
|
+ //如果可读取消息为0,就不继续。防止InputStream.read阻塞
|
|
|
|
+ if (inputStream.available() == 0) {
|
|
|
|
+ SystemClock.sleep(1);
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ byte[] newBytes = new byte[Math.max(minLength, 1024)];
|
|
|
|
+ int newSize = inputStream.read(newBytes, 0, inputStream.available());
|
|
|
|
+ if (newSize > 0) {
|
|
|
|
+ bytes.addByte(newBytes, newSize);
|
|
|
|
+ log("第" + (++i) + "次组包后长度:" + bytes.getBytes().length + ",\t目标长度:" + minLength + ",\t已耗时:" + (System.currentTimeMillis() - startTime) + "ms,\t超时时间:" + maxTime + "ms");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (System.currentTimeMillis() - startTime >= maxTime)
|
|
|
|
+ log("超时返回,超时时间:" + maxTime + "ms");
|
|
|
|
+ return bytes;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private static void log(String string) {
|
|
|
|
+ Log.i("Serial", string);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 关闭串口的方法
|
|
|
|
+ * 关闭串口中的输入输出流
|
|
|
|
+ * 然后将flag的值设为flag,终止接收数据线程
|
|
|
|
+ */
|
|
|
|
+ public void closeSerialPort() {
|
|
|
|
+ Log.i(TAG, "关闭串口");
|
|
|
|
+ try {
|
|
|
|
+ if (inputStream != null) {
|
|
|
|
+ inputStream.close();
|
|
|
|
+ }
|
|
|
|
+ if (outputStream != null) {
|
|
|
|
+ outputStream.close();
|
|
|
|
+ }
|
|
|
|
+ if (receiveThread != null && receiveThread.isAlive()) {
|
|
|
|
+ receiveThread.interrupt();
|
|
|
|
+ receiveThread = null;
|
|
|
|
+ }
|
|
|
|
+ isOpenSerialPortUtil = false;
|
|
|
|
+ } catch (IOException e) {
|
|
|
|
+ e.printStackTrace();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //MF1卡读块(待验证)
|
|
|
|
+ public void readTag() {
|
|
|
|
+ byte[] cmd = {(byte)0x00, (byte)0x00, (byte)0x0A, (byte)0x04, (byte)0x02, (byte)0x01,
|
|
|
|
+ (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0x0D};
|
|
|
|
+
|
|
|
|
+ sendBytes(cmd);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 发送串口数据的方法
|
|
|
|
+ *
|
|
|
|
+ * @param command 要发送的数据
|
|
|
|
+ */
|
|
|
|
+ private void send(String command) {
|
|
|
|
+ try {
|
|
|
|
+ if (isOpenSerialPortUtil) {
|
|
|
|
+ byte[] sendData = command.getBytes();
|
|
|
|
+ outputStream.write(sendData);
|
|
|
|
+ Log.i(TAG, "NFC串口数据发送成功: " + command);
|
|
|
|
+ }
|
|
|
|
+ } catch (IOException e) {
|
|
|
|
+ e.printStackTrace();
|
|
|
|
+ Log.i(TAG, "NFC串口数据发送失败");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void sendBytes(byte[] cmd) {
|
|
|
|
+ try {
|
|
|
|
+ if (isOpenSerialPortUtil) {
|
|
|
|
+ outputStream.write(cmd);
|
|
|
|
+ Log.i(TAG, "NFC串口数据发送成功");
|
|
|
|
+ }
|
|
|
|
+ } catch (IOException e) {
|
|
|
|
+ e.printStackTrace();
|
|
|
|
+ Log.i(TAG, "NFC串口数据发送失败");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public void setOnDataReceiveStringListener(ISerialPortNfcListener listener) {
|
|
|
|
+ serialPortNfcListener = listener;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public interface ISerialPortNfcListener {
|
|
|
|
+ void onNfcData(final byte[] buffer, final int size);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+}
|