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)); } } }