|
@@ -12,6 +12,7 @@ import java.io.FileNotFoundException;
|
|
|
import java.io.FileOutputStream;
|
|
|
import java.io.IOException;
|
|
|
import java.io.Serializable;
|
|
|
+import java.util.Arrays;
|
|
|
import java.util.Timer;
|
|
|
import java.util.TimerTask;
|
|
|
|
|
@@ -25,6 +26,8 @@ import cn.minbb.serialport.listener.OnDataProgressListener;
|
|
|
import cn.minbb.serialport.listener.OnOpenSerialPortListener;
|
|
|
import cn.minbb.serialport.listener.OnSerialPortDataListener;
|
|
|
import cn.minbb.serialport.thread.SerialPortReadThread;
|
|
|
+import cn.minbb.serialport.utils.ByteUtil;
|
|
|
+import cn.minbb.serialport.utils.LogUtil;
|
|
|
|
|
|
/**
|
|
|
* 串口管理器 - 单例模式 防止 反射 克隆 序列化 破坏
|
|
@@ -43,6 +46,13 @@ public class SerialPortManager extends SerialPort implements Serializable, Clone
|
|
|
private Handler mSendingHandler;
|
|
|
private SerialPortReadThread mSerialPortReadThread;
|
|
|
|
|
|
+ private SerialPortStatus serialPortStatus = SerialPortStatus.CLOSE;
|
|
|
+
|
|
|
+ // 报文长度
|
|
|
+ private static int LENGTH = 64;
|
|
|
+ // 超时时间
|
|
|
+ private static int TIMEOUT = 5000;
|
|
|
+
|
|
|
// 默认是第一次创建
|
|
|
private static volatile boolean isCreate = false;
|
|
|
// 单例对象
|
|
@@ -69,6 +79,22 @@ public class SerialPortManager extends SerialPort implements Serializable, Clone
|
|
|
return serialPortManager;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 获取当前串口状态
|
|
|
+ */
|
|
|
+ public SerialPortStatus getSerialPortStatus() {
|
|
|
+ return serialPortStatus;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 设置接收数据超时时间
|
|
|
+ *
|
|
|
+ * @param timeout 毫秒
|
|
|
+ */
|
|
|
+ public static void setTimeout(int timeout) {
|
|
|
+ SerialPortManager.TIMEOUT = timeout;
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 打开串口
|
|
|
* <p>
|
|
@@ -107,6 +133,7 @@ public class SerialPortManager extends SerialPort implements Serializable, Clone
|
|
|
startSendThread();
|
|
|
// 开启接收消息的线程
|
|
|
startReadThread();
|
|
|
+ serialPortStatus = SerialPortStatus.OPEN;
|
|
|
return true;
|
|
|
} catch (Exception e) {
|
|
|
e.printStackTrace();
|
|
@@ -150,6 +177,7 @@ public class SerialPortManager extends SerialPort implements Serializable, Clone
|
|
|
|
|
|
mOnOpenSerialPortListener = null;
|
|
|
mOnSerialPortDataListener = null;
|
|
|
+ serialPortStatus = SerialPortStatus.CLOSE;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -190,18 +218,18 @@ public class SerialPortManager extends SerialPort implements Serializable, Clone
|
|
|
Data data = (Data) msg.obj;
|
|
|
switch (data.getDataType()) {
|
|
|
case BYTES:
|
|
|
- SendDataBytesImpl sendDataBytes = new SendDataBytesImpl();
|
|
|
- SendDataContext<byte[]> contextBytes = new SendDataContext<>(mFileInputStream, mFileOutputStream, onDataProgressListener, sendDataBytes);
|
|
|
+ SendDataBytesImpl sendDataBytesImpl = new SendDataBytesImpl();
|
|
|
+ SendDataContext<byte[]> contextBytes = new SendDataContext<>(mFileInputStream, mFileOutputStream, onDataProgressListener, sendDataBytesImpl);
|
|
|
contextBytes.doSend((byte[]) data.getData());
|
|
|
break;
|
|
|
case STRING:
|
|
|
- SendDataStringImpl sendDataString = new SendDataStringImpl();
|
|
|
- SendDataContext<String> contextString = new SendDataContext<>(mFileInputStream, mFileOutputStream, onDataProgressListener, sendDataString);
|
|
|
+ SendDataStringImpl sendDataStringImpl = new SendDataStringImpl();
|
|
|
+ SendDataContext<String> contextString = new SendDataContext<>(mFileInputStream, mFileOutputStream, onDataProgressListener, sendDataStringImpl);
|
|
|
contextString.doSend((String) data.getData());
|
|
|
break;
|
|
|
case FILE:
|
|
|
- SendDataFileImpl sendDataFile = new SendDataFileImpl();
|
|
|
- SendDataContext<File> contextFile = new SendDataContext<>(mFileInputStream, mFileOutputStream, onDataProgressListener, sendDataFile);
|
|
|
+ SendDataFileImpl sendDataFileImpl = new SendDataFileImpl();
|
|
|
+ SendDataContext<File> contextFile = new SendDataContext<>(mFileInputStream, mFileOutputStream, onDataProgressListener, sendDataFileImpl);
|
|
|
contextFile.doSend((File) data.getData());
|
|
|
break;
|
|
|
}
|
|
@@ -216,9 +244,9 @@ public class SerialPortManager extends SerialPort implements Serializable, Clone
|
|
|
// }
|
|
|
// }
|
|
|
} catch (IOException e) {
|
|
|
- e.printStackTrace();
|
|
|
+ throw new RuntimeException(e);
|
|
|
} catch (Exception e) {
|
|
|
- e.printStackTrace();
|
|
|
+ throw new RuntimeException(e);
|
|
|
}
|
|
|
}
|
|
|
};
|
|
@@ -239,47 +267,48 @@ public class SerialPortManager extends SerialPort implements Serializable, Clone
|
|
|
/**
|
|
|
* 开启接收消息的线程
|
|
|
*/
|
|
|
- private static String data = "";
|
|
|
- private static boolean over = false;
|
|
|
- private final long TIMEOUT = 500; // 超时时间
|
|
|
+ private static byte[] dataBytes = new byte[0];
|
|
|
|
|
|
private void startReadThread() {
|
|
|
mSerialPortReadThread = new SerialPortReadThread(mFileInputStream) {
|
|
|
@Override
|
|
|
public void onDataReceived(final byte[] bytes) {
|
|
|
- // if (null != mOnSerialPortDataListener) {
|
|
|
- // mOnSerialPortDataListener.onDataReceived(bytes);
|
|
|
- // }
|
|
|
- // 收到数据,计时开始
|
|
|
- if (data.trim().isEmpty()) {
|
|
|
+ // 收到 EOF(-1) 或者超时则认为数据包接收完毕
|
|
|
+ // 串口空闲状态下收到数据,启动超时计时器,并修改串口状态为数据输入状态
|
|
|
+ if (SerialPortStatus.OPEN == serialPortStatus) {
|
|
|
+ serialPortStatus = SerialPortStatus.DATA_IN;
|
|
|
new Timer().schedule(new TimerTask() {
|
|
|
@Override
|
|
|
public void run() {
|
|
|
- String s = data.trim();
|
|
|
- if (!s.isEmpty()) {
|
|
|
- over = false;
|
|
|
- mOnSerialPortDataListener.onDataReceived(bytes, s);
|
|
|
- data = "";
|
|
|
+ // 超时执行
|
|
|
+ if (SerialPortStatus.DATA_IN == serialPortStatus) {
|
|
|
+ // 解包收到的数据
|
|
|
+ LogUtil.setAppendFile("接收超时");
|
|
|
+ dataNotify();
|
|
|
}
|
|
|
}
|
|
|
}, TIMEOUT);
|
|
|
}
|
|
|
+ // 遍历数据块,检测到报文结束符 EOF(-1) 则终止报文接收
|
|
|
+ int eofIndex = -1;
|
|
|
int blockSize = bytes.length;
|
|
|
byte[] byteBlock = new byte[blockSize];
|
|
|
for (int i = 0; i < blockSize; i++) {
|
|
|
- if (bytes[i] == '\n') {
|
|
|
- over = true;
|
|
|
+ if (bytes[i] == -1) {
|
|
|
+ eofIndex = i;
|
|
|
break;
|
|
|
+ } else {
|
|
|
+ byteBlock[i] = bytes[i];
|
|
|
}
|
|
|
- byteBlock[i] = bytes[i];
|
|
|
}
|
|
|
- String block = new String(byteBlock);
|
|
|
- data += block;
|
|
|
- // 收到数据结束符
|
|
|
- if (over && !data.isEmpty()) {
|
|
|
- over = false;
|
|
|
- mOnSerialPortDataListener.onDataReceived(bytes, data.trim());
|
|
|
- data = "";
|
|
|
+ if (eofIndex != -1) {
|
|
|
+ // 收到包尾,拼接包尾数据后通知
|
|
|
+ byte[] tailBytes = new byte[eofIndex];
|
|
|
+ System.arraycopy(byteBlock, 0, tailBytes, 0, eofIndex);
|
|
|
+ dataBytesReceived(tailBytes);
|
|
|
+ dataNotify();
|
|
|
+ } else {
|
|
|
+ dataBytesReceived(byteBlock);
|
|
|
}
|
|
|
}
|
|
|
};
|
|
@@ -341,11 +370,38 @@ public class SerialPortManager extends SerialPort implements Serializable, Clone
|
|
|
message.obj = data;
|
|
|
return mSendingHandler.sendMessage(message);
|
|
|
}
|
|
|
+ LogUtil.setAppendFile("缺失发送处理器");
|
|
|
throw new RuntimeException("缺失发送处理器");
|
|
|
}
|
|
|
+ LogUtil.setAppendFile("数据流为空");
|
|
|
throw new RuntimeException("数据流为空");
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 数据回调方法,当串口接收数据超时或者收到数据结束符时候调用,用于通知应用程序收到的数据
|
|
|
+ */
|
|
|
+ private void dataNotify() {
|
|
|
+ // 串口状态设置为空闲
|
|
|
+ serialPortStatus = SerialPortStatus.OPEN;
|
|
|
+ if (null != mOnSerialPortDataListener) {
|
|
|
+ mOnSerialPortDataListener.onDataReceived(dataBytes, new String(dataBytes));
|
|
|
+ LogUtil.setAppendFile(Arrays.toString(dataBytes));
|
|
|
+ dataBytes = new byte[0];
|
|
|
+ } else {
|
|
|
+ LogUtil.setAppendFile("串口数据监听器未定义");
|
|
|
+ throw new RuntimeException("串口数据监听器未定义");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 收到串口数据调用,同步锁
|
|
|
+ *
|
|
|
+ * @param bytes 收到的 Byte 数组
|
|
|
+ */
|
|
|
+ private synchronized void dataBytesReceived(byte[] bytes) {
|
|
|
+ dataBytes = ByteUtil.addBytes(dataBytes, bytes);
|
|
|
+ }
|
|
|
+
|
|
|
@Override
|
|
|
protected Object clone() throws CloneNotSupportedException {
|
|
|
return serialPortManager;
|