Browse Source

fix some bug

tags/v0
zhaohe 7 months ago
parent
commit
9ebea4beb4
  1. 7
      doc/TODO.md
  2. 17
      src/main/java/a8k/OS.java
  3. 138
      src/main/java/a8k/app/hardware/basedriver/A8kCanBusConnection.java
  4. 11
      src/main/java/a8k/app/hardware/basedriver/A8kCanBusService.java
  5. 10
      src/main/java/a8k/app/hardware/type/a8kcanprotocol/A8kPacket.java
  6. 87
      src/main/java/a8k/app/hardware/type/a8kcanprotocol/CmdId.java
  7. 63
      src/main/java/a8k/app/service/background/SensorDataUpdateService.java
  8. 30
      src/main/java/a8k/app/service/background/TemperatureCtrlService.java
  9. 9
      src/main/resources/application.yml

7
doc/TODO.md

@ -0,0 +1,7 @@
```angular2html
1. 光栅逻辑
```

17
src/main/java/a8k/OS.java

@ -1,19 +1,24 @@
package a8k;
public class OS {
public static void hsleep(int ms) {
forceSleep(ms);
}
public static void forceSleep(Integer mills) {
try {
threadSleep(mills);
} catch (InterruptedException e) {
throw new RuntimeException(e);
Long start = System.currentTimeMillis();
long end = start + mills;
while (System.currentTimeMillis() < end) {
int left = (int) (end - System.currentTimeMillis());
threadSleep(left);
}
}
public static void threadSleep(Integer mills) throws InterruptedException {
Thread.sleep(mills);
private static void threadSleep(Integer mills) {
try {
Thread.sleep(mills);
} catch (InterruptedException ignored) {
}
}
}

138
src/main/java/a8k/app/hardware/basedriver/A8kCanBusConnection.java

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

11
src/main/java/a8k/app/hardware/basedriver/A8kCanBusService.java

@ -26,8 +26,6 @@ public class A8kCanBusService {
@Resource
A8kCanBusConnection connection;
Map<MId, CmdId> txcmdcache = new HashMap<>();
@PostConstruct
public void init() throws URISyntaxException {
connection.connect();
@ -133,7 +131,7 @@ public class A8kCanBusService {
public void waitForMod(MId mid, Integer acitionOvertime) throws AppException {
long startedAt = System.currentTimeMillis();
CmdId action = getLastTxCmd(mid);
CmdId action = connection.getLastTxCmd(mid);
do {
ModuleStatus statu = null;
try {
@ -160,11 +158,4 @@ public class A8kCanBusService {
}
private synchronized void storageTxLastCmd(MId mid, CmdId cmdId) {
txcmdcache.put(mid, cmdId);
}
private synchronized CmdId getLastTxCmd(MId mid) {
return txcmdcache.get(mid);
}
}

10
src/main/java/a8k/app/hardware/type/a8kcanprotocol/A8kPacket.java

@ -33,7 +33,7 @@ public class A8kPacket {
public static final int PACKET_TYPE_ERROR_ACK = 2;
public static final int PACKET_TYPE_EVENT = 3;
public static final int CMD_OVERTIME = 1000;
public static final int CMD_OVERTIME = 4000;
public A8kPacket(byte[] cmd) {
raw = new byte[cmd.length];
@ -95,7 +95,7 @@ public class A8kPacket {
getContentI32(0), getContentI32(1));
}
} else {
if (cmdId.cmdAttachType == CmdId.ATTACH_IS_INT32) {
if (cmdId.getCmdAttachType() == CmdId.ATTACH_IS_INT32) {
ret = String.format("[CMD ] index:[%d] (%s %s(%d) :param:[%s])", getPacketIndex(), cmdId,
MId.valueOf(getModuleId()), getModuleId(), formatInt32ATTACH(getCmdContent()));
} else {
@ -105,7 +105,7 @@ public class A8kPacket {
}
} else if (packetType == PACKET_TYPE_ACK) {
if (cmdId.receiptAttachType == CmdId.ATTACH_IS_INT32) {
if (cmdId.getReceiptAttachType() == CmdId.ATTACH_IS_INT32) {
ret = String.format("[ACK ] index:[%d] (%s :[%s])", getPacketIndex(), cmdId,
formatInt32ATTACH(getCmdContent()));
} else {
@ -115,7 +115,7 @@ public class A8kPacket {
} else if (packetType == PACKET_TYPE_ERROR_ACK) {
ret = String.format("[EACK ] index:[%d] (%s :[%s])", getPacketIndex(), cmdId, (getContentI32(0)));
} else if (packetType == PACKET_TYPE_EVENT) {
if (cmdId.cmdAttachType == CmdId.ATTACH_IS_INT32) {
if (cmdId.getCmdAttachType() == CmdId.ATTACH_IS_INT32) {
ret = String.format("[EVENT] index:[%d] (%s %s(%d) :[%s])", getPacketIndex(), cmdId,
MId.valueOf(getModuleId()), getModuleId(), formatInt32ATTACH(getCmdContent()));
} else {
@ -167,7 +167,7 @@ public class A8kPacket {
return regIndex.trace;
} else {
return cmdid.trace;
return cmdid.isTrace();
}
}

87
src/main/java/a8k/app/hardware/type/a8kcanprotocol/CmdId.java

@ -1,8 +1,6 @@
package a8k.app.hardware.type.a8kcanprotocol;
public enum CmdId {
NotSet(0xFFFF, "NOACTION"),//
board_reset(0x0000, "复位板子"),//
@ -28,7 +26,7 @@ public enum CmdId {
xymotor_motor_move_by_direct(0x030a, "XYMOTOR_MOTOR_MOVE_BY_DIRECT"),//
xymotor_read_enc_direct(0x030b, "XYMOTOR_READ_ENC_DIRECT"),//
//
a8k_opt_v2_read_raw(0x0609, "A8K_OPT_V2_READ_RAW", CmdId.ATTACH_IS_INT32, CmdId.ATTACH_IS_BYTES),//
a8k_opt_v2_read_raw(0x0609, "A8K_OPT_V2_READ_RAW"),//
//
a8k_opt_v2_t_start_scan(0x0700, "A8K_OPT_V2_T_START_SCAN"),//
a8k_opt_v2_f_start_scan(0x0701, "A8K_OPT_V2_F_START_SCAN"),//
@ -91,8 +89,8 @@ public enum CmdId {
temp_controler_set_fan_level(0x7004, "TEMP_CONTROLER_SET_FAN_LEVEL"),//
temp_controler_enable_log(0x7005, "TEMP_CONTROLER_ENABLE_LOG"),//
//
a8000_idcard_reader_read_raw(0x7100, "A8000_IDCARD_READER_READ_RAW", CmdId.ATTACH_IS_INT32, CmdId.ATTACH_IS_BYTES, false),//
a8000_idcard_write_raw(0x7101, "A8000_IDCARD_WRITE_RAW", CmdId.ATTACH_IS_BYTES, CmdId.ATTACH_IS_INT32, false),//
a8000_idcard_reader_read_raw(0x7100, "A8000_IDCARD_READER_READ_RAW"),//
a8000_idcard_write_raw(0x7101, "A8000_IDCARD_WRITE_RAW"),//
a8000_idcard_erase(0x7102, "A8000_IDCARD_ERASE"),//
a8000_idcard_earse_unlock(0x7103, "A8000_IDCARD_EARSE_UNLOCK"),//
//
@ -116,11 +114,6 @@ public enum CmdId {
pipette_zmotor_move_by(0x7405, "pipette_zmotor_move_by"),
pipette_zmotor_move_to(0x7406, "pipette_zmotor_move_to"),
// virtual int32_t liquid_operation_clear_params(); 0x7450
// virtual int32_t liquid_operation_set_gun_runparams(int32_t acc, int32_t dec, int32_t vstart, int32_t vstop, int32_t vmax); 0x7451
// virtual int32_t liquid_operation_set_zmotor_runparams(int32_t posmin, int32_t posmax, int32_t vmax); 0x7452
// virtual int32_t liquid_operation_enable_lld_record(); 0x7453
// virtual int32_t liquid_operation_fresh_params(); 0x7454
liquid_operation_clear_params(0x7450, "liquid_operation_clear_params"),
liquid_operation_set_gun_runparams(0x7451, "liquid_operation_set_gun_runparams"),
@ -144,46 +137,22 @@ public enum CmdId {
;
public final static int ATTACH_IS_BYTES = 1;
public final static int ATTACH_IS_INT32 = 2;
public final int index;
public final String chName;
public final static int ATTACH_IS_BYTES = 1;
public final static int ATTACH_IS_INT32 = 2;
public int index;
public String chName;
public int cmdAttachType = ATTACH_IS_INT32;
public int receiptAttachType = ATTACH_IS_INT32;
public boolean trace = true;
public boolean actionCmd = true;
// public final int cmdAttachType = ATTACH_IS_INT32;
// public final int receiptAttachType = ATTACH_IS_INT32;
// public final boolean trace = true;
// public final boolean actionCmd = true;
CmdId(int index, String chname) {
this.index = index;
this.chName = chname;
}
CmdId(int index, String chname, boolean trace) {
this.index = index;
this.chName = chname;
this.trace = trace;
this.actionCmd = trace;
}
CmdId(int index, String chname, int cmdAttachType, int receiptAttachType) {
this.index = index;
this.chName = chname;
this.cmdAttachType = cmdAttachType;
this.receiptAttachType = receiptAttachType;
}
CmdId(int index, String chname, int cmdAttachType, int receiptAttachType, boolean trace) {
this.index = index;
this.chName = chname;
this.cmdAttachType = cmdAttachType;
this.receiptAttachType = receiptAttachType;
this.trace = trace;
}
public int toInt() {
return index;
}
@ -216,4 +185,38 @@ public enum CmdId {
}
public int getCmdAttachType() {
return switch (this) {
case a8000_idcard_write_raw -> ATTACH_IS_BYTES;
default -> ATTACH_IS_INT32;
};
}
public int getReceiptAttachType() {
return switch (this) {
case a8k_opt_v2_read_raw, a8000_idcard_reader_read_raw -> ATTACH_IS_BYTES;
default -> ATTACH_IS_INT32;
};
}
public boolean isTrace() {
return true;
}
public boolean isActionCmd() {
return switch (this) {
case module_get_status,
module_get_error,
xymotor_read_pos,
xymotor_read_inio,
step_motor_read_io_state,
extboard_read_inio,
extboard_read_muti_inio,
module_get_reg,
module_set_reg,
code_scaner_result_is_ready -> false;
default -> true;
};
}
}

63
src/main/java/a8k/app/service/background/SensorDataUpdateService.java

@ -1,5 +1,6 @@
package a8k.app.service.background;
import a8k.OS;
import a8k.app.hardware.basedriver.A8kCanBusService;
import a8k.app.hardware.type.a8kcanprotocol.IOId;
import a8k.app.service.statemgr.GStateMgrService;
@ -36,7 +37,8 @@ public class SensorDataUpdateService {
@Resource
A8kCanBusService canBus;
Thread updateThread = null;
Thread updateThread = null;
Boolean workingFlag = false;
List<TemperatureRecordPoint> incubateBoxTemperatureCurve = new ArrayList<>();
List<TemperatureRecordPoint> plateBoxTemperatureCurve = new ArrayList<>();
@ -72,32 +74,47 @@ public class SensorDataUpdateService {
}
public Boolean isUpdateRunning() {
return updateThread != null;
return workingFlag;
}
public void startUpdate() {
if (updateThread != null) {
return;
}
workingFlag = true;
}
public void stopUpdate() {
workingFlag = false;
}
@PostConstruct
public void init() {
updateThread = new Thread(() -> {
while (true) {
if (!workingFlag) {
OS.forceSleep(1000);
continue;
}
try {
OptScanModuleState optScanModuleState = optScanModuleStateMgrService.getOptScanModule().getState();
if (!optScanModuleState.equals(OptScanModuleState.EMPTY)) {
gStateMgrService.getSensorState().setWasteBinFullFlag(false);
Thread.sleep(1000);
OS.forceSleep(1000);
continue;
}
// canBus.setIOState(IOId.RecycleBinOverflowPPSPowerCtrl, true);
Thread.sleep(10);//等待光栅电源稳定
Boolean wasteBinFullFlag = canBus.getIOState(IOId.RecycleBinOverflowPPS);
// canBus.setIOState(IOId.RecycleBinOverflowPPSPowerCtrl, false);
// canBus.setIOState(IOId.RecycleBinOverflowPPSPowerCtrl, true);
// OS.forceSleep(10);//等待光栅电源稳定
// Boolean wasteBinFullFlag = canBus.getIOState(IOId.RecycleBinOverflowPPS);
// canBus.setIOState(IOId.RecycleBinOverflowPPSPowerCtrl, false);
// gStateMgrService.getSensorState().setWasteBinFullFlag(wasteBinFullFlag);
gStateMgrService.getSensorState().setWasteBinFullFlag(wasteBinFullFlag);
Thread.sleep(100);
OS.forceSleep(100);
Double incubateBoxTemp = temperatureControlDriver.readIncubateBoxTemperature();
gStateMgrService.getSensorState().setIncubateBoxTemperature((int) (incubateBoxTemp + 0.5));
addIncubateBoxTemperatureCurve(incubateBoxTemp);
@ -106,30 +123,14 @@ public class SensorDataUpdateService {
gStateMgrService.getSensorState().setPboxTemperature((int) (pbtemp + 0.5));
addPlateBoxTemperatureCurve(pbtemp);
log.debug("IncubateBoxTemperature: {}, PlateBoxTemperature: {}, WasteBinFullFlag: {}", incubateBoxTemp, pbtemp, wasteBinFullFlag);
} catch (InterruptedException e) {
break;
log.debug("IncubateBoxTemperature: {}, PlateBoxTemperature: {}", incubateBoxTemp, pbtemp);
} catch (AppException e) {
log.error("Failed to read temperature data {}", e.getMessage());
}
OS.forceSleep(1000);
}
});
updateThread.start();
updateThread.setName("SensorDataUpdateService");
}
public void stopUpdate() {
if (updateThread == null) {
return;
}
updateThread.interrupt();
updateThread = null;
}
@PostConstruct
public void init() {
startUpdate();
}
}

30
src/main/java/a8k/app/service/background/TemperatureCtrlService.java

@ -1,6 +1,7 @@
package a8k.app.service.background;
import a8k.OS;
import a8k.app.service.setting.AppSettingsMgrService;
import a8k.app.hardware.driver.TemperatureControlDriver;
import a8k.app.dao.db.type.AppSetting;
@ -32,6 +33,7 @@ public class TemperatureCtrlService {
Integer targetTemperature = 0;
TemperaControlMode controlMode = TemperaControlMode.kFixTemperature;
Thread temperatureCtrlThread = null;
Boolean workingFlag = false;
@PostConstruct
@ -86,15 +88,16 @@ public class TemperatureCtrlService {
}
temperatureControlDriver.startCtrlTemperature(targetTemperature.doubleValue());
/*
* 启动线程定时检查温度设定值如果发生变化则调用温度控制器
*/
workingFlag = true;
temperatureCtrlThread = new Thread(() -> {
while (true) {
log.info("Temperature thread run start");
while (workingFlag) {
try {
Thread.sleep(1000);
OS.forceSleep(1000);
if (controlMode.equals(TemperaControlMode.kAutoChangeFromAppSetting)) {
Integer settingTem = appSettingsMgrService.getAppSettings().getTemperature();
if (!targetTemperature.equals(settingTem)) {
@ -103,14 +106,21 @@ public class TemperatureCtrlService {
}
}
} catch (InterruptedException e) {
log.error("Temperature control thread interrupted");
break;
} catch (AppException e) {
log.error("Temperature control error: {}", e.getMessage());
}
}
try {
temperatureControlDriver.stopCtrlTemperature();
} catch (AppException e) {
throw new RuntimeException(e);
}
log.info("Temperature thread run end");
});
temperatureCtrlThread.start();
temperatureCtrlThread.setName("TemperatureCtrlThread");
}
synchronized public void stopTemperatureControl() throws AppException {
@ -120,9 +130,15 @@ public class TemperatureCtrlService {
if (temperatureCtrlThread != null) {
temperatureCtrlThread.interrupt();
workingFlag = false;
try {
temperatureCtrlThread.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
temperatureCtrlThread = null;
}
temperatureControlDriver.stopCtrlTemperature();
log.info("Temperature control stopped");
}

9
src/main/resources/application.yml

@ -3,10 +3,14 @@ server:
hardware.canbus.url: ws://192.168.8.10:19005
logging:
level:
a8k.app.hardware.basedriver: info
spring:
profiles:
active: prod
web:
web:
resources:
static-locations: file:appresource/static/app/,file:appresource/static/,file:/opt/app/static/
datasource:
@ -29,6 +33,3 @@ springdoc:
enabled: true # 开启swagger界面,依赖OpenApi,需要OpenApi同时开启
path: /doc/apitest.html # 自定义路径,默认为"/swagger-ui/index.html
operationsSorter: method # 接口按照方法排序
logging:
level:
a8k.app.hardware.basedriver: debug
Loading…
Cancel
Save