package com.hdl.sdk.ttl.Utils.HDLUtlis;
|
|
import android.os.SystemClock;
|
import android.util.Log;
|
|
import com.hdl.sdk.ttl.Config.Global;
|
import com.hdl.sdk.ttl.HDLDeviceManger.Bean.ReceiveData;
|
import com.hdl.sdk.ttl.HDLDeviceManger.Bean.SendDatas;
|
import com.hdl.sdk.ttl.HDLDeviceManger.Bean.UdpDataBean;
|
import com.hdl.sdk.ttl.HDLDeviceManger.Core.Crc;
|
import com.hdl.sdk.ttl.HDLDeviceManger.Core.HDLSerialPortCore;
|
|
import java.net.InetAddress;
|
import java.nio.ByteBuffer;
|
import java.util.Calendar;
|
|
/**
|
* Created by hxb on 2023/10/18.
|
*/
|
public class SerialPortSendAndReceiveUtil {
|
private static volatile SerialPortSendAndReceiveUtil instance = null;
|
|
/**
|
* 发送线程
|
*/
|
private Thread sendThread;
|
|
/**
|
* 接收线程
|
*/
|
private Thread receiveThread;
|
|
|
private SerialPortSendAndReceiveUtil() {
|
sendThread = new Thread(new SendRunnable());
|
receiveThread = new Thread(new ReceiveRunnable());
|
}
|
|
public static SerialPortSendAndReceiveUtil getInstance() {
|
if (instance == null) {
|
synchronized (SerialPortSendAndReceiveUtil.class) {
|
if (instance == null) {
|
instance = new SerialPortSendAndReceiveUtil();
|
}
|
}
|
}
|
return instance;
|
}
|
|
public void start() {
|
sendThread.start();
|
receiveThread.start();
|
|
Global.mReceiveData = data;
|
}
|
|
/**
|
* 获取封装数据
|
*
|
* @param body 发送数据内容
|
* @param writeOrRead 读写标识,1表示写,2表示读取
|
* @return
|
*/
|
private static byte[] getSendByte(byte[] body, int writeOrRead) {
|
byte[] crcBytes = new byte[2 + 1 + 1 + body.length + 2];
|
crcBytes[0] = (byte) 0XFE;
|
crcBytes[1] = (byte) 0xFE;
|
crcBytes[2] = (byte) writeOrRead;
|
crcBytes[3] = (byte) body.length;
|
System.arraycopy(body, 0, crcBytes, 4, body.length);
|
|
//Check CRC
|
Crc.CRC16_MODBUS(crcBytes, crcBytes.length);
|
|
return crcBytes;
|
}
|
|
|
static class SendRunnable implements Runnable {
|
/**
|
* 发送一条后休眠时间
|
*/
|
private int sleepTime = 30;
|
/**
|
* 重发间隔时间
|
*/
|
private int intervalTime = 500;
|
|
/**
|
* 重发次数
|
*/
|
private int reSendCount = 3;
|
|
/**
|
* 线程运行状态
|
*/
|
private boolean run = true;
|
|
@Override
|
public void run() {
|
while (run) {
|
try {
|
SystemClock.sleep(sleepTime);
|
if (HDLSerialPortCore.mSerialPort == null) {
|
Log.i("串口-发送->", "串口没有初始化");
|
continue;
|
}
|
|
for (int i = 0; i < SendDatas.sendDataArrayList.size(); i++) {
|
SendDatas sendDatas = SendDatas.sendDataArrayList.get(i);
|
|
//第一次发送,时间先初始化
|
if (sendDatas.StartCalendar == null) {
|
sendDatas.StartCalendar = Calendar.getInstance();
|
} else {
|
//距离上次发送的时间如还在重发时间内,先不发
|
if (Calendar.getInstance().getTimeInMillis() - sendDatas.StartCalendar.getTimeInMillis() < intervalTime) {
|
continue;
|
}
|
}
|
//超出特重发数次就不发送,并移除出列表
|
if (sendDatas.SendCount >= reSendCount) {
|
synchronized (SendDatas.sendDataArrayList) {
|
SendDatas.sendDataArrayList.remove(i--);
|
}
|
continue;
|
}
|
|
sendDatas.StartCalendar = Calendar.getInstance();//重置发送时间
|
sendDatas.SendCount++;
|
|
byte[] sendBytes = SerialPortSendAndReceiveUtil.getSendByte(sendDatas.GetSerialPortSendBytes(), 1);
|
|
HDLSerialPortCore.mSerialPort.getOutputStream().write(sendBytes);
|
HDLSerialPortCore.mSerialPort.getOutputStream().flush();
|
SystemClock.sleep(sleepTime);
|
}
|
|
//发送完成后通知读取缓存数据
|
read();
|
|
} catch (Exception e) {
|
e.printStackTrace();
|
}
|
}
|
|
|
}
|
|
/**
|
* 通知读取总线缓存数据
|
*/
|
void read() {
|
try {
|
byte[] body = new byte[]{(byte) 0xFE, (byte) 0xFE, 0x02, 0x01, 0x00, (byte) 0x9C, 0x6C};
|
// 发送Data
|
HDLSerialPortCore.mSerialPort.getOutputStream().write(body);
|
HDLSerialPortCore.mSerialPort.getOutputStream().flush();
|
Log.d("串口-发送->", "发送读取");
|
} catch (Exception ignored) {
|
}
|
}
|
}
|
|
private static ReceiveData data = new ReceiveData() {
|
|
@Override
|
public void receiveData(int command, int desSubnetID, int desDeviceID, int subnetID, int deviceID, byte[] usefulBytes) {
|
// 更新发送是否成功的信息
|
SendDatas.ReceiveBytes(command, subnetID, deviceID, usefulBytes);
|
//2019-8-20 增加目标子网号设备号判断
|
if ((desSubnetID == 0xFF && desSubnetID == 0xFF)
|
|| (desSubnetID == Crc.localSubnetID && desSubnetID == Crc.localDeviceID)) {
|
//参数
|
UdpDataBean udpDataBean = new UdpDataBean();
|
udpDataBean.sourceSubnetID = subnetID;
|
udpDataBean.sourceDeviceID = deviceID;
|
udpDataBean.desSubnetID = desSubnetID;
|
udpDataBean.desDeviceID = desDeviceID;
|
udpDataBean.command = command;
|
|
udpDataBean.addBytes = usefulBytes;
|
HDLSerialPortCore.HandleInsideData(udpDataBean);
|
|
}
|
|
}
|
};
|
|
static class ReceiveRunnable implements Runnable {
|
/**
|
* 线程运行状态
|
*/
|
private boolean run = true;
|
|
private byte[] head = new byte[]{(byte) 0xFE, (byte) 0xFE};
|
|
/**
|
* 缓存区
|
*/
|
private final ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
|
|
@Override
|
public void run() {
|
while (run) {
|
try {
|
if (HDLSerialPortCore.mSerialPort == null) {
|
Log.i("串口-读取->", "串口没有初始化");
|
continue;
|
}
|
byte[] data = new byte[1024];
|
int size = HDLSerialPortCore.mSerialPort.getInputStream().read(data);
|
if (size <= 0) {
|
continue;
|
}
|
|
try {
|
byteBuffer.put(data, 0, size);
|
Log.d("串口->回复", byteToHex(data, 0, size) + " position:" + byteBuffer.position());
|
} catch (Exception e) {
|
byteBuffer.flip();
|
byteBuffer.clear();
|
}
|
|
while (true) {
|
removeInVoidBytes();
|
|
//没有新的数据,返回
|
if (!haveData()) {
|
break;
|
}
|
|
|
int bodyIndex = 2 + 1 + 1;
|
int lenght = byteBuffer.get(3) & 0xFF;
|
|
byte[] packet = getBody(0, bodyIndex + lenght + 2);
|
//是否已经获取完整所有的数据
|
byte[] tempBytes = getBody(bodyIndex, lenght);
|
remove(bodyIndex + lenght + 2);
|
|
if (!Crc.CRC16_MODBUS_MATCH(packet, packet.length)) {
|
Log.d("串口->回复", "CRC不对");
|
continue;
|
}
|
if (tempBytes == null) {
|
Log.d("串口->回复", "当前数据还没有接收完成");
|
//当前数据还没有接收完成
|
continue;
|
}
|
|
if (lenght <= 1) {
|
//设备回复的协议数据
|
continue;
|
}
|
|
int command = (tempBytes[7] & 0xFF) * 256 + (tempBytes[8] & 0xFF);
|
|
int subnetID = tempBytes[3] & 0xFF;
|
int deviceID = tempBytes[4] & 0xFF;
|
int desSubnetID = tempBytes[9] & 0xFF;
|
int desDeviceID = tempBytes[10] & 0xFF;
|
//如果不是发给自己的数据或者不是广播的数据,不处理
|
if (desSubnetID != Global.subnetID || desDeviceID != Global.deviceID) {
|
if (desSubnetID != 0xFF || desDeviceID != 0xFF) {
|
Log.d("串口->回复", "过滤掉=={目标子网:" + desSubnetID + ",目标设备:" + desDeviceID + "}");
|
continue;
|
}
|
}
|
|
byte[] usefulBytes = new byte[(tempBytes[2] & 0xFF) - 11];
|
// 复制附加数据
|
System.arraycopy(tempBytes, 11, usefulBytes, 0, usefulBytes.length);
|
if (Global.mReceiveData != null) {
|
Global.mReceiveData.receiveData(command, desSubnetID, desDeviceID, subnetID, deviceID, usefulBytes);
|
}
|
}
|
|
} catch (Exception e) {
|
e.printStackTrace();
|
}
|
}
|
}
|
|
private String byteToHex(byte[] bytes, int index, int length) {
|
StringBuilder sb = new StringBuilder();
|
for (int i = index; i < length; i++) {
|
sb.append(String.format(" %02X", bytes[i]));
|
}
|
return sb.toString();
|
}
|
|
/**
|
* 获取头部数据
|
*
|
* @return
|
*/
|
boolean haveData() {
|
|
int length = 2 + 1 + 1 + (byteBuffer.get(3) & 0xFF) + 2;
|
|
//数据还没有接收全
|
if (byteBuffer.position() < length) {
|
return false;
|
}
|
|
return true;
|
}
|
|
/**
|
* 获取数据内容
|
*
|
* @param lenght
|
* @return
|
*/
|
byte[] getBody(int index, int lenght) {
|
//是否已经获取完整所有的数据
|
byte[] bodyBytes = new byte[lenght];
|
if (index < 0 || byteBuffer.position() < index + lenght) {
|
//当前数据还没有接收完成
|
return null;
|
}
|
|
for (int i = 0; i < bodyBytes.length; i++) {
|
bodyBytes[i] = byteBuffer.get(index + i);
|
}
|
return bodyBytes;
|
}
|
|
/**
|
* 移除可能存在的无效数据
|
*/
|
void removeInVoidBytes() {
|
for (int i = 0; i < dddd.length; i++) {
|
dddd[i] = byteBuffer.get(i);
|
}
|
// Log.d("串口->回复", "position:"+byteBuffer.position()+" 处理前的数据"+byteToHex(dddd, 0, 100));
|
int index = 0;
|
boolean isMatch = false;
|
for (; index < byteBuffer.position() - head.length; index++) {
|
isMatch = true;
|
for (int j = 0; j < head.length; j++) {
|
if (head[j] != byteBuffer.get(index + j)) {
|
isMatch = false;
|
break;
|
}
|
}
|
if (isMatch) {
|
break;
|
}
|
}
|
int endIndex = 0;
|
if (0 < index && isMatch) {
|
endIndex = byteBuffer.position();
|
byteBuffer.clear();
|
for (int i = index; i < endIndex; i++) {
|
byteBuffer.put(byteBuffer.get(i));
|
}
|
}
|
|
for (int i = 0; i < dddd.length; i++) {
|
dddd[i] = byteBuffer.get(i);
|
}
|
}
|
|
byte[] dddd = new byte[100];
|
|
/**
|
* 移除到指定位置前面的数据
|
*
|
* @param position 指定位置
|
*/
|
void remove(int position) {
|
int endIndex = byteBuffer.position();
|
byteBuffer.clear();
|
//TODO 清空之前的数据
|
for (int i = position; i < endIndex; i++) {
|
byteBuffer.put(byteBuffer.get(i));
|
}
|
|
for (int i = 0; i < dddd.length; i++) {
|
dddd[i] = byteBuffer.get(i);
|
}
|
|
// Log.d("串口->回复", "position:"+byteBuffer.position()+" 移除后的数据"+byteToHex(dddd, 0, 100));
|
}
|
}
|
|
}
|