package yaokong; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Objects; public abstract class WaitForAck { protected final InputStream inputStream; protected final OutputStream outputStream; protected WaitForAck(InputStream inputStream, OutputStream outputStream) { this.inputStream = Objects.requireNonNull(inputStream, "inputStream"); this.outputStream = Objects.requireNonNull(outputStream, "outputStream"); } // 在超时内等待下位机返回指定指令的确认帧 protected boolean waitForAck(byte expectedCommand) throws IOException { long deadline = System.currentTimeMillis() + 1000L; while (System.currentTimeMillis() < deadline) { if (inputStream.available() > 0) { byte[] response = readResponse(); if (response != null && parseResponse(response, expectedCommand)) { return true; } } try { Thread.sleep(10L); } catch (InterruptedException interruptedException) { Thread.currentThread().interrupt(); break; } } return false; } // 从输入流读取完整响应帧并校验帧头帧尾 private byte[] readResponse() throws IOException { ByteArrayOutputStream buffer = new ByteArrayOutputStream(); while (true) { int value = inputStream.read(); if (value == -1) { return buffer.size() == 0 ? null : buffer.toByteArray(); } buffer.write(value); if (buffer.size() == 1 && buffer.toByteArray()[0] != BluetoothProtocol.FRAME_HEADER[0]) { buffer.reset(); continue; } if (buffer.size() == 2) { byte[] header = buffer.toByteArray(); if (header[0] != BluetoothProtocol.FRAME_HEADER[0] || header[1] != BluetoothProtocol.FRAME_HEADER[1]) { buffer.reset(); continue; } } if ((byte) value == BluetoothProtocol.FRAME_FOOTER) { return buffer.toByteArray(); } } } // 解析确认帧并校验CRC与指令号 private boolean parseResponse(byte[] response, byte expectedCommand) { if (response.length < 7) { return false; } if (response[0] != BluetoothProtocol.FRAME_HEADER[0] || response[1] != BluetoothProtocol.FRAME_HEADER[1]) { return false; } if (response[2] != BluetoothProtocol.CMD_RESPONSE) { return false; } ByteBuffer wrapper = ByteBuffer.wrap(response).order(ByteOrder.LITTLE_ENDIAN); wrapper.position(3); int payloadLength = wrapper.getShort() & 0xFFFF; int frameLength = 2 + 1 + 2 + payloadLength + 2 + 1; if (response.length < frameLength) { return false; } if (payloadLength < 2) { return false; } int crcOffset = 2 + 1 + 2 + payloadLength; int calculatedCrc = CRC16.calculateCRC16(response, 2, 1 + 2 + payloadLength); int receivedCrc = ByteBuffer.wrap(response, crcOffset, 2).order(ByteOrder.LITTLE_ENDIAN).getShort() & 0xFFFF; if (calculatedCrc != receivedCrc) { return false; } byte ackCommand = response[2 + 1 + 2]; byte status = response[2 + 1 + 2 + 1]; if (ackCommand != expectedCommand) { return false; } return status == BluetoothProtocol.ERROR_SUCCESS; } }