|
|
@ -14,14 +14,14 @@ import lombok.extern.slf4j.Slf4j; |
|
|
|
import org.java_websocket.client.WebSocketClient; |
|
|
|
import org.java_websocket.enums.ReadyState; |
|
|
|
import org.java_websocket.handshake.ServerHandshake; |
|
|
|
import org.springframework.beans.factory.annotation.Autowired; |
|
|
|
import org.springframework.scheduling.annotation.Scheduled; |
|
|
|
import org.springframework.stereotype.Component; |
|
|
|
|
|
|
|
import java.net.URI; |
|
|
|
import java.nio.ByteBuffer; |
|
|
|
import java.nio.ByteOrder; |
|
|
|
import java.util.HashMap; |
|
|
|
import java.util.List; |
|
|
|
import java.util.Map; |
|
|
|
import java.util.concurrent.BlockingQueue; |
|
|
|
import java.util.concurrent.LinkedBlockingQueue; |
|
|
|
import java.util.concurrent.TimeUnit; |
|
|
@ -32,13 +32,58 @@ public class A8kCanBusConnection extends WebSocketClient { |
|
|
|
@Resource |
|
|
|
AppEventBusService eventBus; |
|
|
|
|
|
|
|
private A8kPacket txPacketContext; |
|
|
|
// 接收回执上下文 |
|
|
|
public BlockingQueue<A8kPacket> receiptQueue = new LinkedBlockingQueue<>(); // |
|
|
|
boolean isWaitingReceipt = false; // |
|
|
|
int waitingReceiptIndex = 0;// |
|
|
|
int packetIndex = 0;//发送包的packetIndex |
|
|
|
boolean debugFlag = true;//调试标志位 |
|
|
|
|
|
|
|
static class ProcessContext { |
|
|
|
BlockingQueue<A8kPacket> receiptQueue = new LinkedBlockingQueue<>(); // |
|
|
|
int waitingReceiptIndex = 0;// |
|
|
|
Map<MId, CmdId> txcmdcache = new HashMap<>(); |
|
|
|
|
|
|
|
|
|
|
|
public A8kPacket getReceipt(int overtime) { |
|
|
|
long end = System.currentTimeMillis() + overtime; |
|
|
|
while (System.currentTimeMillis() < end) { |
|
|
|
int left = (int) (end - System.currentTimeMillis()); |
|
|
|
A8kPacket packet = null; |
|
|
|
try { |
|
|
|
packet = receiptQueue.poll(left, TimeUnit.MILLISECONDS); |
|
|
|
} catch (InterruptedException ignored) { |
|
|
|
} |
|
|
|
if (packet != null) { |
|
|
|
return packet; |
|
|
|
} |
|
|
|
} |
|
|
|
return null; |
|
|
|
} |
|
|
|
|
|
|
|
synchronized void pushReceipt(A8kPacket packet) { |
|
|
|
if (waitingReceiptIndex >= 0 && waitingReceiptIndex == packet.getPacketIndex()) { |
|
|
|
log.debug("pushReceipt:| {}", packet); |
|
|
|
receiptQueue.add(packet); |
|
|
|
waitingReceiptIndex = -1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
synchronized void setWaitingReceiptIndex(int index) { |
|
|
|
receiptQueue.clear(); |
|
|
|
waitingReceiptIndex = index; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
synchronized void storageTxLastCmd(A8kPacket pack) { |
|
|
|
MId mid = MId.valueOf(pack.getModuleId()); |
|
|
|
CmdId cmdId = CmdId.valueOf(pack.getCmdId()); |
|
|
|
if (cmdId != null && cmdId.isActionCmd()) |
|
|
|
txcmdcache.put(mid, cmdId); |
|
|
|
} |
|
|
|
|
|
|
|
synchronized CmdId getLastTxCmd(MId mid) { |
|
|
|
return txcmdcache.get(mid); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
ProcessContext context = new ProcessContext(); |
|
|
|
int packetIndex = 0;//发送包的packetIndex |
|
|
|
|
|
|
|
|
|
|
|
public A8kCanBusConnection(String url) { |
|
|
@ -146,39 +191,33 @@ public class A8kCanBusConnection extends WebSocketClient { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
AppException buildOvertimeError(A8kPacket pack) { |
|
|
|
return AppException.of(new AEHardwareError(A8kEcode.LOW_ERROR_OVERTIME, MId.valueOf(pack.getModuleId()), CmdId.valueOf(pack.getCmdId()))); |
|
|
|
} |
|
|
|
|
|
|
|
private A8kPacket _priSend(A8kPacket pack, int overtime) throws AppException { |
|
|
|
pack.setPacketIndex(packetIndex); |
|
|
|
waitingReceiptIndex = packetIndex; |
|
|
|
packetIndex = packetIndex + 1; |
|
|
|
// alloc new packetIndex |
|
|
|
packetIndex = packetIndex + 1; |
|
|
|
if (packetIndex > 10000) { |
|
|
|
packetIndex = 1; |
|
|
|
} |
|
|
|
receiptQueue.clear(); |
|
|
|
isWaitingReceipt = true; |
|
|
|
String txpacket = pack.toByteString(); |
|
|
|
|
|
|
|
CmdId cmdid = CmdId.valueOf(pack.getCmdId()); |
|
|
|
if (cmdid == null) { |
|
|
|
// throw new AppException(MId.valueOf(pack.getModuleId()), A8kEcode.CmdNotSupport.index); |
|
|
|
throw AppException.of(new AEHardwareError(A8kEcode.LOW_EXT_ERROR_CMD_NOT_SUPPORT, MId.valueOf(pack.getModuleId()), null)); |
|
|
|
} |
|
|
|
if (debugFlag && pack.isTrace()) { |
|
|
|
String packstr = pack.toString(); |
|
|
|
log.debug("Tx:|RAW:{}| {}", txpacket, packstr); |
|
|
|
} |
|
|
|
//set waiting receipt index |
|
|
|
pack.setPacketIndex(packetIndex); |
|
|
|
context.storageTxLastCmd(pack); |
|
|
|
context.setWaitingReceiptIndex(packetIndex); |
|
|
|
|
|
|
|
txPacketContext = pack; |
|
|
|
// TX packet |
|
|
|
String txpacket = pack.toByteString(); |
|
|
|
log.debug("Tx:|RAW:{}| {}", txpacket, pack); |
|
|
|
send(txpacket); |
|
|
|
|
|
|
|
|
|
|
|
A8kPacket receipt; |
|
|
|
try { |
|
|
|
receipt = receiptQueue.poll(overtime, TimeUnit.MILLISECONDS); |
|
|
|
} catch (InterruptedException e) { |
|
|
|
isWaitingReceipt = false; |
|
|
|
throw AppException.of(new AEHardwareError(A8kEcode.LOW_ERROR_OVERTIME, MId.valueOf(pack.getModuleId()), CmdId.valueOf(pack.getCmdId()))); |
|
|
|
} |
|
|
|
isWaitingReceipt = false; |
|
|
|
receipt = context.getReceipt(overtime); |
|
|
|
if (receipt == null) { |
|
|
|
throw AppException.of(new AEHardwareError(A8kEcode.LOW_ERROR_OVERTIME, MId.valueOf(pack.getModuleId()), CmdId.valueOf(pack.getCmdId()))); |
|
|
|
throw buildOvertimeError(pack); |
|
|
|
} |
|
|
|
|
|
|
|
if (receipt.getPacketType() == A8kPacket.PACKET_TYPE_ERROR_ACK) { |
|
|
@ -191,7 +230,7 @@ public class A8kCanBusConnection extends WebSocketClient { |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* |
|
|
|
* 处理接收到的消息 |
|
|
|
*/ |
|
|
|
private void processMessage(String s) { |
|
|
|
byte[] rx = ByteArray.hexStringToBytes(s); |
|
|
@ -212,32 +251,21 @@ public class A8kCanBusConnection extends WebSocketClient { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
A8kPacket tpCxt = this.txPacketContext; |
|
|
|
if (debugFlag) { |
|
|
|
if (packet.getPacketType() == A8kPacket.PACKET_TYPE_ACK) { |
|
|
|
if (tpCxt != null && tpCxt.getPacketIndex() == packet.getPacketIndex()) { |
|
|
|
if (tpCxt.isTrace()) { |
|
|
|
log.debug("RX-ACK |RAW:{}| {}", s, packet); |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
log.debug("RX-REPORT |RAW:{}| {}", s, packet); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (packet.getPacketType() == A8kPacket.PACKET_TYPE_ACK || packet.getPacketType() == A8kPacket.PACKET_TYPE_ERROR_ACK) { |
|
|
|
if (isWaitingReceipt) { |
|
|
|
if (waitingReceiptIndex == packet.getPacketIndex()) { |
|
|
|
receiptQueue.add(packet); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (packet.getPacketType() == A8kPacket.PACKET_TYPE_EVENT) { |
|
|
|
log.debug("RX-ACK |RAW:{}| {}", s, packet); |
|
|
|
context.pushReceipt(packet); |
|
|
|
} else if (packet.getPacketType() == A8kPacket.PACKET_TYPE_EVENT) { |
|
|
|
log.debug("RX-REPORT |RAW:{}| {}", s, packet); |
|
|
|
eventBus.pushEvent(new A8kHardwareReport(packet)); |
|
|
|
} else { |
|
|
|
log.warn("RX-UNPROCESSABLE: |RAW:{}| {}", s, packet); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public synchronized CmdId getLastTxCmd(MId mid) { |
|
|
|
return context.getLastTxCmd(mid); |
|
|
|
} |
|
|
|
|
|
|
|
} |