|
|
@ -9,25 +9,27 @@ import com.iflytop.profilometer.core.migration.type.protocol.TPMIBasicReport; |
|
|
|
import com.iflytop.profilometer.core.migration.type.protocol.TPMIPacket; |
|
|
|
import com.iflytop.profilometer.core.migration.type.protocol.TPMIPosReport; |
|
|
|
|
|
|
|
import java.util.concurrent.ArrayBlockingQueue; |
|
|
|
import java.util.concurrent.BlockingQueue; |
|
|
|
import java.util.concurrent.Semaphore; |
|
|
|
import java.util.concurrent.TimeUnit; |
|
|
|
import java.nio.ByteBuffer; |
|
|
|
import java.util.concurrent.*; |
|
|
|
|
|
|
|
public class BleDeviceUartChannel { |
|
|
|
|
|
|
|
public interface OnBleReportListener { |
|
|
|
void onReportReceived(TPMIPacket packet); |
|
|
|
} |
|
|
|
|
|
|
|
private OnBleReportListener reportListener; |
|
|
|
private BleDeviceOnReportListener deviceOnReportListener; |
|
|
|
private final byte[] buffer = new byte[1024]; |
|
|
|
private int bufferLen = 0; |
|
|
|
|
|
|
|
private final ByteBuffer receiveBuffer = ByteBuffer.allocate(10240); |
|
|
|
private final CommandTransactionContext ctCxt = new CommandTransactionContext(); |
|
|
|
private final BlockingQueue<TPMIPacket> reportPacketList = new ArrayBlockingQueue<>(100); |
|
|
|
|
|
|
|
private BlockingQueue<TPMIPacket> reportPacketList = new ArrayBlockingQueue<>(100); |
|
|
|
private final ExecutorService bleExecutor = Executors.newSingleThreadExecutor(r -> { |
|
|
|
Thread t = new Thread(r); |
|
|
|
t.setName("ble-handler-thread"); |
|
|
|
t.setPriority(Thread.MAX_PRIORITY); |
|
|
|
return t; |
|
|
|
}); |
|
|
|
|
|
|
|
public static class CommandTransactionContext { |
|
|
|
private TPMIPacket txPacket; |
|
|
@ -42,7 +44,7 @@ public class BleDeviceUartChannel { |
|
|
|
} |
|
|
|
|
|
|
|
synchronized TPMIPacket clearCtCxt() { |
|
|
|
var packet = this.rxPacket; |
|
|
|
TPMIPacket packet = this.rxPacket; |
|
|
|
this.rxPacket = null; |
|
|
|
this.txPacket = null; |
|
|
|
this.semaphore = null; |
|
|
@ -50,19 +52,12 @@ public class BleDeviceUartChannel { |
|
|
|
return packet; |
|
|
|
} |
|
|
|
|
|
|
|
void waitCxt(Integer overtime) throws InterruptedException { |
|
|
|
this.semaphore.tryAcquire(overtime, TimeUnit.MILLISECONDS); |
|
|
|
void waitCxt(Integer timeoutMs) throws InterruptedException { |
|
|
|
this.semaphore.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS); |
|
|
|
} |
|
|
|
|
|
|
|
synchronized void trySetReceiptPacket(TPMIPacket packet) { |
|
|
|
if (this.txPacket == null) { |
|
|
|
// log.warn("rx receipt but no tx packet, ignore"); |
|
|
|
return; |
|
|
|
} |
|
|
|
if (this.waitIndex != packet.getIndex()) { |
|
|
|
// log.warn("rx receipt but index not match, expect {}, but {}", this.waitIndex, packet.getIndex()); |
|
|
|
return; |
|
|
|
} |
|
|
|
if (txPacket == null || waitIndex != packet.getIndex()) return; |
|
|
|
this.rxPacket = packet; |
|
|
|
this.semaphore.release(); |
|
|
|
} |
|
|
@ -80,56 +75,54 @@ public class BleDeviceUartChannel { |
|
|
|
this.deviceOnReportListener = listener; |
|
|
|
} |
|
|
|
|
|
|
|
public synchronized TPMIPacket sendCommand(TPMIPacket tx, Integer overtime) { |
|
|
|
public synchronized TPMIPacket sendCommand(TPMIPacket tx, Integer timeoutMs) { |
|
|
|
Log.i("BLE", "TX PACKET: " + tx); |
|
|
|
ctCxt.newCtCxt(tx); |
|
|
|
|
|
|
|
BleManager.getInstance().sendMessage(tx.rawpacket); |
|
|
|
|
|
|
|
try { |
|
|
|
ctCxt.waitCxt(overtime); |
|
|
|
} catch (InterruptedException ignored) { |
|
|
|
ctCxt.waitCxt(timeoutMs); |
|
|
|
} catch (InterruptedException e) { |
|
|
|
Thread.currentThread().interrupt(); |
|
|
|
} |
|
|
|
return ctCxt.clearCtCxt(); |
|
|
|
} |
|
|
|
|
|
|
|
private void handleReceivedData(byte[] data) { |
|
|
|
// Log.d("BLE", "收到原始数据: " + Arrays.toString(data)); |
|
|
|
bleExecutor.execute(() -> processIncomingData(data)); |
|
|
|
} |
|
|
|
|
|
|
|
// 追加到缓冲区 |
|
|
|
if (bufferLen + data.length > buffer.length) { |
|
|
|
private void processIncomingData(byte[] data) { |
|
|
|
synchronized (receiveBuffer) { |
|
|
|
if (receiveBuffer.remaining() < data.length) { |
|
|
|
Log.w("BLE", "BLE缓冲区溢出,已清空"); |
|
|
|
bufferLen = 0; |
|
|
|
} |
|
|
|
System.arraycopy(data, 0, buffer, bufferLen, data.length); |
|
|
|
bufferLen += data.length; |
|
|
|
|
|
|
|
int offset = 0; |
|
|
|
while (offset < bufferLen) { |
|
|
|
var report = TPMIPacketFactory.analysisRawRxData(buffer, bufferLen, offset); |
|
|
|
if (report.result.equals(TPMIPacketFactory.PacketAnalysisResult.SUC)) { |
|
|
|
// Log.d("BLE", "BLE协议包解析成功: " + report.packet); |
|
|
|
// if (reportListener != null) { |
|
|
|
// reportListener.onReportReceived(report.packet); |
|
|
|
// } |
|
|
|
if (deviceOnReportListener != null) { |
|
|
|
dispatchTypedPacket(report.packet); |
|
|
|
} |
|
|
|
offset += report.packet.getPacketLen(); |
|
|
|
} else if (report.result.equals(TPMIPacketFactory.PacketAnalysisResult.CHECKSUM_ERROR)) { |
|
|
|
Log.w("BLE", "BLE数据包校验失败,跳过 1 字节"); |
|
|
|
offset += 1; |
|
|
|
} else if (report.result.equals(TPMIPacketFactory.PacketAnalysisResult.PACKE_NOT_FULLY_RECEIVED)) { |
|
|
|
receiveBuffer.clear(); |
|
|
|
} |
|
|
|
receiveBuffer.put(data); |
|
|
|
receiveBuffer.flip(); // 切换为读模式 |
|
|
|
|
|
|
|
while (receiveBuffer.remaining() > 0) { |
|
|
|
int offset = receiveBuffer.position(); |
|
|
|
var report = TPMIPacketFactory.analysisRawRxData( |
|
|
|
receiveBuffer.array(), |
|
|
|
receiveBuffer.limit(), |
|
|
|
offset |
|
|
|
); |
|
|
|
|
|
|
|
if (report.result == TPMIPacketFactory.PacketAnalysisResult.SUC) { |
|
|
|
if (reportListener != null) reportListener.onReportReceived(report.packet); |
|
|
|
if (deviceOnReportListener != null) dispatchTypedPacket(report.packet); |
|
|
|
receiveBuffer.position(offset + report.packet.getPacketLen()); |
|
|
|
Log.i("BLE","SUC : " + report.packet.getPacketLen()); |
|
|
|
} else if (report.result == TPMIPacketFactory.PacketAnalysisResult.PACKE_NOT_FULLY_RECEIVED) { |
|
|
|
// Log.i("BLE","PACKE_NOT_FULLY_RECEIVED : " + data.length); |
|
|
|
break; |
|
|
|
} else { |
|
|
|
offset += 1; |
|
|
|
receiveBuffer.position(offset + 1); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 移除已处理部分数据 |
|
|
|
if (offset > 0 && offset <= bufferLen) { |
|
|
|
System.arraycopy(buffer, offset, buffer, 0, bufferLen - offset); |
|
|
|
bufferLen -= offset; |
|
|
|
// 保留未解析部分 |
|
|
|
receiveBuffer.compact(); // 相当于 left shift:将未读部分移到开头 |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -146,12 +139,9 @@ public class BleDeviceUartChannel { |
|
|
|
} |
|
|
|
|
|
|
|
private void processRXPacket(TPMIPacket rx) { |
|
|
|
if (rx.getPacketType().equals(TPMIPacket.PacketType.RESPONSE)) { |
|
|
|
if (rx.getPacketType() == TPMIPacket.PacketType.RESPONSE) { |
|
|
|
ctCxt.trySetReceiptPacket(rx); |
|
|
|
} else if (rx.getPacketType().equals(TPMIPacket.PacketType.REPORT)) { |
|
|
|
/* |
|
|
|
* 处理上报包 |
|
|
|
*/ |
|
|
|
} else if (rx.getPacketType() == TPMIPacket.PacketType.REPORT) { |
|
|
|
reportPacketList.offer(rx); |
|
|
|
} |
|
|
|
} |
|
|
|