Browse Source

添加急停相关逻辑

master
zhaohe 4 days ago
parent
commit
76ef4ef504
  1. 1
      src/main/java/a8k/app/controler/api/v1/ApiV1ControllerAdvice.java
  2. 5
      src/main/java/a8k/app/controler/api/v1/app/ctrl/DeviceInitControler.java
  3. 2
      src/main/java/a8k/app/controler/api/v1/app/ws/AppWebSocketEndpointMgr.java
  4. 1
      src/main/java/a8k/app/i18n/Internationalization.java
  5. 7
      src/main/java/a8k/app/iflytophald/channel/A8kCanBusCommunicationChannel.java
  6. 140
      src/main/java/a8k/app/iflytophald/channel/DeviceLocalKeyStateReportChannel.java
  7. 110
      src/main/java/a8k/app/iflytophald/driver/A8kCanBusBaseDriver.java
  8. 11
      src/main/java/a8k/app/iflytophald/driver/ModuleEnableCtrlDriver.java
  9. 52
      src/main/java/a8k/app/iflytophald/driver/OptModuleDriver.java
  10. 15
      src/main/java/a8k/app/iflytophald/type/DeviceLocalKeyEvent.java
  11. 1
      src/main/java/a8k/app/iflytophald/type/protocol/A8kEcode.java
  12. 11
      src/main/java/a8k/app/service/background/ProjIDCardCtrlAndMonitorService.java
  13. 38
      src/main/java/a8k/app/service/lowerctrl/OptScanModuleLowerCtrlService.java
  14. 31
      src/main/java/a8k/app/service/lowerctrl/PlateBoxCtrlService.java
  15. 103
      src/main/java/a8k/app/service/mainctrl/AppDeviceInitCtrlService.java
  16. 1
      src/main/java/a8k/app/service/module/IncubationPlateCtrlModule.java
  17. 15
      src/main/java/a8k/app/type/appevent/AppEmergencyKeyStateChangeEvent.java
  18. 7
      src/main/java/a8k/app/type/deviceinit/CheckResult.java
  19. 34
      src/main/java/a8k/app/type/deviceinit/Checkpoint.java
  20. 10
      src/main/java/a8k/app/type/deviceinit/DeviceInitState.java
  21. 5
      src/main/java/a8k/app/utils/ZSignal.java
  22. 7
      src/main/java/a8k/extui/page/init/DeviceInitPage.java
  23. 20
      src/main/resources/application.yml

1
src/main/java/a8k/app/controler/api/v1/ApiV1ControllerAdvice.java

@ -1,5 +1,6 @@
package a8k.app.controler.api.v1;
import a8k.app.type.exception.AppException;
import a8k.app.type.ui.ApiRet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

5
src/main/java/a8k/app/controler/api/v1/app/ctrl/DeviceInitControler.java

@ -2,6 +2,7 @@ package a8k.app.controler.api.v1.app.ctrl;
import a8k.app.service.mainctrl.AppDeviceInitCtrlService;
import a8k.app.service.statemgr.GStateMgrService;
import a8k.app.type.deviceinit.DeviceInitState;
import a8k.app.type.exception.AppException;
import a8k.app.type.ui.ApiRet;
import io.swagger.v3.oas.annotations.Operation;
@ -33,8 +34,8 @@ public class DeviceInitControler {
@Operation(description = "获取设备初始化状态")
@PostMapping("/getDeviceInitedTaskState")
public ApiRet<AppDeviceInitCtrlService.State> getDeviceInitedTaskState() {
return ApiRet.success(deviceInitService.getState());
public ApiRet<DeviceInitState> getDeviceInitedTaskState() {
return ApiRet.success(deviceInitService.getDeviceInitState());
}
@Operation(description = "获取设备是否完成启动")

2
src/main/java/a8k/app/controler/api/v1/app/ws/AppWebSocketEndpointMgr.java

@ -272,7 +272,7 @@ public class AppWebSocketEndpointMgr {
deviceContext.runMode = gStateMgrService.getDeviceRunMode();
deviceContext.loginFlag = appUserMgrService.getLoginUsr() != null;
deviceContext.loginUser = appUserMgrService.getLoginUsr();
deviceContext.deviceInitedFlag = appDeviceInitCtrlService.getState().deviceInited;
deviceContext.deviceInitedFlag = appDeviceInitCtrlService.getDeviceInitState().deviceInited;
deviceContext.fatalErrorFlag = deviceWorkStateMgrService.getDeviceWorkState().fatalErrorFlag;
return deviceContext;
}

1
src/main/java/a8k/app/i18n/Internationalization.java

@ -88,6 +88,7 @@ public class Internationalization {
case LIS_REPORT_RECORD_FAIL -> "LIS上报记录失败";
case LIS_REQUEST_SAMPLE_INFO_FAIL -> "LIS请求样本信息失败";
case LIS_REQUEST_SAMPLE_INFO_PARSE_RESPONSE_FAIL -> "LIS请求样本信息解析响应失败";
case EMERGENCY_KEY_TRIGGER -> "急停按键被触发";
default -> ecode.toString();
};
}

7
src/main/java/a8k/app/iflytophald/channel/A8kCanBusCommunicationChannel.java

@ -262,6 +262,13 @@ public class A8kCanBusCommunicationChannel extends WebSocketClient {
// TX packet
String txpacket = pack.toByteString();
log.debug("TX-RAW: {} | {}", txpacket, pack);
if(!isOpen()) {
try {
connectBlocking();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
send(txpacket);

140
src/main/java/a8k/app/iflytophald/channel/DeviceLocalKeyStateReportChannel.java

@ -0,0 +1,140 @@
package a8k.app.iflytophald.channel;
import a8k.app.config.IflytophaldConnectionConfig;
import a8k.app.iflytophald.driver.A8kCanBusBaseDriver;
import a8k.app.iflytophald.type.DeviceLocalKeyEvent;
import a8k.app.service.background.AppEventBusService;
import a8k.app.service.statemgr.GStateMgrService;
import a8k.app.type.appevent.AppEmergencyKeyStateChangeEvent;
import a8k.app.utils.ZJsonHelper;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
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.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.net.URI;
import java.util.LinkedList;
import java.util.Queue;
@Slf4j
@Component
@RequiredArgsConstructor
public class DeviceLocalKeyStateReportChannel {
//编程 参考 https://iflytop1.feishu.cn/wiki/QFwVwGnI8iYp0fk20W9cnpYAnkg?fromScene=spaceOverview
@Value("${iflytophald.enable}")
Boolean iflytophaldEnable;
WebSocketClient conn;
private final IflytophaldConnectionConfig config;
private final GStateMgrService gStateMgrService;
private final AppEventBusService eventBusService;
private final A8kCanBusBaseDriver a8kCanBus;
private boolean emergencyKeyState = false;
private void changeEmergencyKeyState(boolean toState) {
if (toState != emergencyKeyState) {
emergencyKeyState = toState;
log.info("emergency key state changed to: {}", emergencyKeyState);
gStateMgrService.updateEmergencyStopFlag(emergencyKeyState);
eventBusService.pushEvent(new AppEmergencyKeyStateChangeEvent(toState));
}
a8kCanBus.syncEmergencyKeyState(toState);
}
public boolean getEmergencyKeyState() {
return emergencyKeyState;
}
@PostConstruct
void init() {
gStateMgrService.updateEmergencyStopFlag(emergencyKeyState);
String url = config.getDatachUrl("key");
log.info("EmergencyKeyStateReportChannel url: {}", url);
conn = new WebSocketClient(URI.create(url)) {
@Override
public void onOpen(ServerHandshake serverHandshake) {
DeviceLocalKeyStateReportChannel.this.onOpen(serverHandshake);
}
@Override
public void onMessage(String s) {
DeviceLocalKeyStateReportChannel.this.onMessage(s);
}
@Override
public void onClose(int i, String s, boolean b) {
DeviceLocalKeyStateReportChannel.this.onClose(i, s, b);
}
@Override
public void onError(Exception e) {
DeviceLocalKeyStateReportChannel.this.onError(e);
}
};
conn.connect();
}
//
// PRIVATE
//
private void onOpen(ServerHandshake serverHandshake) {
log.info("connect success");
}
private void onClose(int i, String s, boolean b) {
log.warn("lost connection...");
}
private void onError(Exception e) {
log.info("a8k can-websocket-channel on error");
}
private void onMessage(String s) {
try {
DeviceLocalKeyEvent event = ZJsonHelper.objectFromJson(s, DeviceLocalKeyEvent.class);
if (event == null) {
log.error("Failed to parse DeviceLocalKeyEvent from message: {}", s);
return;
}
if (event.name.equals("emergency")) {
changeEmergencyKeyState(event.state);
}
} catch (Exception e) {
log.error("Failed to parse DeviceLocalKeyEvent from message: {}", s, e);
}
}
@Scheduled(fixedRate = 1000)
private void autoConnect() {
if (!iflytophaldEnable) {
return;
}
if (!conn.isOpen()) {
if (conn.getReadyState().equals(ReadyState.NOT_YET_CONNECTED)) {
try {
conn.connect();
} catch (IllegalStateException ignored) {
}
} else if (conn.getReadyState().equals(ReadyState.CLOSED)) {
conn.reconnect();
}
}
}
}

110
src/main/java/a8k/app/iflytophald/driver/A8kCanBusBaseDriver.java

@ -1,5 +1,6 @@
package a8k.app.iflytophald.driver;
import a8k.app.factory.A8kPacketFactory;
import a8k.app.iflytophald.channel.A8kCanBusCommunicationChannel;
import a8k.app.iflytophald.type.protocol.*;
@ -7,24 +8,36 @@ import a8k.app.type.error.AEHardwareError;
import a8k.app.type.exception.AppException;
import a8k.OS;
import a8k.app.utils.ByteArrayUtils;
import a8k.app.utils.ZList;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.net.URISyntaxException;
import java.util.LinkedHashMap;
import java.util.Map;
@Component
@Slf4j
@RequiredArgsConstructor
public class A8kCanBusBaseDriver {
@Resource
A8kCanBusCommunicationChannel connection;
private final A8kCanBusCommunicationChannel connection;
private boolean emergencyKeyState = false;
@Value("${iflytophald.enable}")
Boolean iflytophaldEnable;
static public class ThreadVar {
boolean lockAction = false;//为true时,动作不可以被打断
}
private Map<Long, ThreadVar> threadVars = new LinkedHashMap<>();
private final Object threadVarsLock = new Object();
@PostConstruct
public void init() throws URISyntaxException {
if (iflytophaldEnable) {
@ -34,6 +47,10 @@ public class A8kCanBusBaseDriver {
}
}
public boolean isConnect() {
return connection.isOpen();
}
/**
* 强制关闭websocket连接让其与canbus服务重连
*/
@ -103,7 +120,7 @@ public class A8kCanBusBaseDriver {
return ModuleType.of(packet.getContentI32(0));
}
public byte[] a8kIdcardReaderReadRaw() throws AppException {
public byte[] a8kIdCardReaderReadRaw() throws AppException {
int i = 0;
byte[] result = new byte[0];
while (true) {
@ -116,29 +133,98 @@ public class A8kCanBusBaseDriver {
return result;
}
public void waitForMod(MId mid, Integer acitionOvertime) throws AppException {
public void syncEmergencyKeyState(boolean state) {
emergencyKeyState = state;
}
public void lockAction() {
synchronized (threadVarsLock) {
ThreadVar threadVar = threadVars.get(Thread.currentThread().threadId());
if (threadVar == null) {
threadVar = new ThreadVar();
threadVars.put(Thread.currentThread().threadId(), threadVar);
}
threadVar.lockAction = true;
}
}
public void unlockAction() throws AppException {
synchronized (threadVarsLock) {
ThreadVar threadVar = threadVars.get(Thread.currentThread().threadId());
if (threadVar != null) {
threadVar.lockAction = false;
}
}
if (emergencyKeyState) {
throw AppException.of(A8kEcode.EMERGENCY_KEY_TRIGGER);
}
}
public boolean isActionLocked() {
synchronized (threadVarsLock) {
ThreadVar threadVar = threadVars.get(Thread.currentThread().threadId());
return threadVar != null && threadVar.lockAction;
}
}
public void waitForMod(MId mid, Integer actionOvertime) throws AppException {
long startedAt = OS.getMonotonicClockTimestamp();
CmdId action = connection.getLastTxCmd(mid);
do {
ModuleStatus statu = moduleGetStatus(mid);
if (statu == ModuleStatus.IDLE) {
ModuleStatus statue = moduleGetStatus(mid);
if (statue == ModuleStatus.IDLE) {
break;
} else if (statu == ModuleStatus.ERROR) {
log.error("{} waitting for action {} , catch error {}, defail ecode {}", mid, action, moduleGetError(mid), moduleGetDetailError(mid));
} else if (statue == ModuleStatus.ERROR) {
log.error("{} waiting for action {} , catch error {}, detail ecode {}", mid, action, moduleGetError(mid), moduleGetDetailError(mid));
throw AppException.of(new AEHardwareError(moduleGetError(mid), mid, action));
}
long now = OS.getMonotonicClockTimestamp();
if (now - startedAt > acitionOvertime) {
log.error("{} waitting for action {} overtime({})", mid, action, acitionOvertime);
if (now - startedAt > actionOvertime) {
log.error("{} waiting for action {} overtime({})", mid, action, actionOvertime);
moduleStopNoException(mid);
throw AppException.of(new AEHardwareError(A8kEcode.LOW_ERROR_ACTION_OVERTIME, mid, action));
}
if (emergencyKeyState && !isActionLocked()) {
moduleStop(mid);
throw AppException.of(A8kEcode.EMERGENCY_KEY_TRIGGER);
}
OS.hsleep(30);
} while (true);
}
public boolean isConnect() {
return connection.isOpen();
void waitingForOptFinish() throws AppException {
long startedAt = OS.getMonotonicClockTimestamp();
do {
var packet = A8kPacketFactory.buildCMDPacket(MId.OptMod.toInt(), CmdId.module_get_status.toInt(), ZList.of());
ModuleStatus statu = null;
try {
statu = ModuleStatus.valueOf(send(packet, 50).getContentI32(0));
} catch (Exception ignored) {
}
if (statu == null || statu == ModuleStatus.BUSY) {
log.info("Waiting for Opt Finish");
} else if (statu == ModuleStatus.IDLE) {
log.info("Opt Finish");
break;
} else if (statu == ModuleStatus.ERROR) {
throw AppException.of(new AEHardwareError(moduleGetError(MId.OptMod), MId.OptMod, CmdId.a8k_opt_v2_t_start_scan));
}
if (OS.getMonotonicClockTimestamp() - startedAt > 10 * 1000) {
throw AppException.of(new AEHardwareError(A8kEcode.LOW_ERROR_ACTION_OVERTIME, MId.OptMod, CmdId.a8k_opt_v2_t_start_scan));
}
OS.forceSleep(100);
} while (true);
}
}

11
src/main/java/a8k/app/iflytophald/driver/ModuleEnableCtrlDriver.java

@ -14,7 +14,7 @@ import org.springframework.stereotype.Component;
public class ModuleEnableCtrlDriver {
private final HbotDriver hbotDriver;
private final PipetteCtrlDriverV2 pipetteCtrlDriver;
private final PipetteCtrlDriverV2 pipetteCtrlDriver;
private final StepMotorCtrlDriver stepMotorCtrlDriver;
private final MiniServoDriver miniServoDriver;
private final A8kCanBusBaseDriver canBus;
@ -22,14 +22,19 @@ public class ModuleEnableCtrlDriver {
public void forceDisableAllMotor() {
// StepMotorMId.values()
for (StepMotorMId stepMotorMId : StepMotorMId.values()) {
if (!canBus.isConnect())
return;
try {
stepMotorCtrlDriver.stepMotorEnable(stepMotorMId, 0);
} catch (AppException e) {
log.info("disableStepMotor: {} failed, {}", stepMotorMId, e.getMessage());
}
}
for (MiniServoMId miniServoMId : MiniServoMId.values()) {
if (!canBus.isConnect())
return;
try {
miniServoDriver.miniServoEnable(miniServoMId, 0);
} catch (AppException e) {
@ -38,12 +43,16 @@ public class ModuleEnableCtrlDriver {
}
try {
if (!canBus.isConnect())
return;
hbotDriver.enable(0);
} catch (AppException e) {
log.info("hbotDriver disable failed, {}", e.getMessage());
}
try {
if (!canBus.isConnect())
return;
pipetteCtrlDriver.zMotorEnable(0);
} catch (AppException e) {
log.info("pipetteCtrlDriver: zMotorEnable failed, {}", e.getMessage());

52
src/main/java/a8k/app/iflytophald/driver/OptModuleDriver.java

@ -1,17 +1,12 @@
package a8k.app.iflytophald.driver;
import a8k.OS;
import a8k.app.factory.A8kPacketFactory;
import a8k.app.iflytophald.type.protocol.A8kEcode;
import a8k.app.iflytophald.type.protocol.CmdId;
import a8k.app.iflytophald.type.protocol.MId;
import a8k.app.iflytophald.type.protocol.ModuleStatus;
import a8k.app.iflytophald.type.protocol.OptModuleRegIndex;
import a8k.app.type.error.AEHardwareError;
import a8k.app.type.exception.AppException;
import a8k.app.utils.ByteArrayUtils;
import a8k.app.utils.ZJsonNode;
import a8k.app.utils.ZList;
import com.fasterxml.jackson.databind.JsonNode;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
@ -37,53 +32,26 @@ public class OptModuleDriver {
A8kCanBusBaseDriver canBus;
void waittingForOptFinish(Integer overtime) throws AppException {
long startedAt = OS.getMonotonicClockTimestamp();
do {
var packet = A8kPacketFactory.buildCMDPacket(MId.OptMod.toInt(), CmdId.module_get_status.toInt(), ZList.of());
ModuleStatus statu = null;
try {
statu = ModuleStatus.valueOf(canBus.send(packet, 50).getContentI32(0));
} catch (Exception ignored) {
}
if (statu == null || statu == ModuleStatus.BUSY) {
log.info("Waitting for Opt Finish");
} else if (statu == ModuleStatus.IDLE) {
log.info("Opt Finish");
break;
} else if (statu == ModuleStatus.ERROR) {
throw AppException.of(new AEHardwareError(canBus.moduleGetError(MId.OptMod), MId.OptMod, CmdId.a8k_opt_v2_t_start_scan));
}
if (OS.getMonotonicClockTimestamp() - startedAt > overtime) {
throw AppException.of(new AEHardwareError(A8kEcode.LOW_ERROR_ACTION_OVERTIME, MId.OptMod, CmdId.a8k_opt_v2_t_start_scan));
}
OS.forceSleep(100);
} while (true);
void waitingForOptFinish() throws AppException {
canBus.waitingForOptFinish();
}
public void optTStartScan(OptScanDirection scanDirection, Integer lasterGain, Integer scanGain) throws AppException {
log.info("OptTStartScan scanDirection:{} lasterGain:{} scanGain:{}", scanDirection, lasterGain, scanGain);
canBus.callcmd(MId.OptMod, CmdId.a8k_opt_v2_t_start_scan, scanDirection.getInteger(), lasterGain, scanGain);
//TODO: 2024-10-26 zhaohe,修改底层光学结束上报一条完成事件
public void optTStartScan(OptScanDirection scanDirection, Integer laserGain, Integer scanGain) throws AppException {
log.info("OptTStartScan scanDirection:{} laserGain:{} scanGain:{}", scanDirection, laserGain, scanGain);
canBus.callcmd(MId.OptMod, CmdId.a8k_opt_v2_t_start_scan, scanDirection.getInteger(), laserGain, scanGain);
long startedAt = OS.getMonotonicClockTimestamp();
OS.forceSleep(100);
waittingForOptFinish(10 * 1000);
waitingForOptFinish();
log.info("opt t scan use {}s", (OS.getMonotonicClockTimestamp() - startedAt) / 1000.0);
}
public void optFStartScan(OptScanDirection scanDirection, Integer lasterGain, Integer scanGain) throws AppException {
log.info("OptFStartScan scanDirection:{} lasterGain:{} scanGain:{}", scanDirection, lasterGain, scanGain);
canBus.callcmd(MId.OptMod, CmdId.a8k_opt_v2_f_start_scan, scanDirection.getInteger(), lasterGain, scanGain);
//TODO: 2024-10-26 zhaohe,修改底层光学结束上报一条完成事件
public void optFStartScan(OptScanDirection scanDirection, Integer laserGain, Integer scanGain) throws AppException {
log.info("OptFStartScan scanDirection:{} laserGain:{} scanGain:{}", scanDirection, laserGain, scanGain);
canBus.callcmd(MId.OptMod, CmdId.a8k_opt_v2_f_start_scan, scanDirection.getInteger(), laserGain, scanGain);
long startedAt = OS.getMonotonicClockTimestamp();
OS.forceSleep(100);
waittingForOptFinish(10 * 1000);
waitingForOptFinish();
log.info("opt f scan use {}s", (OS.getMonotonicClockTimestamp() - startedAt) / 1000.0);
}

15
src/main/java/a8k/app/iflytophald/type/DeviceLocalKeyEvent.java

@ -0,0 +1,15 @@
package a8k.app.iflytophald.type;
public class DeviceLocalKeyEvent {
public enum EventType {
sync,
press,
release
}
public Integer duration;
public EventType event;
public Integer index;
public String name;
public Boolean state;
}

1
src/main/java/a8k/app/iflytophald/type/protocol/A8kEcode.java

@ -40,6 +40,7 @@ public enum A8kEcode {
LIS_REQUEST_SAMPLE_INFO_FAIL(27), //Lis请求样本信息失败
LIS_REQUEST_SAMPLE_INFO_PARSE_RESPONSE_FAIL(28), //Lis请求样本信息失败
LIS_SAMPLE_TYPE_NOT_SUPPORT(29), //Lis样本类型不支持
EMERGENCY_KEY_TRIGGER(30), //
//

11
src/main/java/a8k/app/service/background/ProjIDCardCtrlAndMonitorService.java

@ -5,7 +5,6 @@ import a8k.app.factory.ZAppPromptFactory;
import a8k.app.iflytophald.type.protocol.A8kPacket;
import a8k.app.iflytophald.type.protocol.CmdId;
import a8k.app.iflytophald.type.protocol.MId;
import a8k.app.service.data.ProjIdCardInfoMgrService;
import a8k.app.service.data.ProjInfoMgrService;
import a8k.app.service.statemgr.GStateMgrService;
import a8k.app.type.appevent.*;
@ -91,10 +90,10 @@ public class ProjIDCardCtrlAndMonitorService {
log.info("拔出ID卡");
}
} else if (event instanceof AppDeviceInitSucEvent appDeviceInitializeSuc) {
if (idCardStatus()) {
log.info("ID卡读卡器在线");
workQueue.addTask(this::readIDCard);
}
// if (idCardStatus()) {
// log.info("ID卡读卡器在线");
// workQueue.addTask(this::readIDCard);
// }
}
}
@ -102,7 +101,7 @@ public class ProjIDCardCtrlAndMonitorService {
//读取ID卡信息
byte[] data = null;
try {
data = canBus.a8kIdcardReaderReadRaw();
data = canBus.a8kIdCardReaderReadRaw();
log.info("ID卡信息:{}", A8kIdCardDataParseService.dumpByte(data, 10));
} catch (AppException e) {
eventBus.pushEvent(ZAppPromptFactory.buildAppPromptEvent(e.error));

38
src/main/java/a8k/app/service/lowerctrl/OptScanModuleLowerCtrlService.java

@ -1,5 +1,6 @@
package a8k.app.service.lowerctrl;
import a8k.app.iflytophald.driver.A8kCanBusBaseDriver;
import a8k.app.optalgo.type.A8kOptPeakInfo;
import a8k.app.constant.OptConstant;
import a8k.app.optalgo.A8kOptCurveAnalyzer;
@ -18,6 +19,7 @@ import a8k.app.type.exception.AppException;
import a8k.app.dao.type.combination.ProjBuildInInfo;
import a8k.app.iflytophald.utils.OptGainConvert;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
@ -26,6 +28,7 @@ import java.util.Date;
@Component
@Slf4j
@RequiredArgsConstructor
public class OptScanModuleLowerCtrlService {
static final Integer overtime = 10000;
@ -79,24 +82,25 @@ public class OptScanModuleLowerCtrlService {
}
@Resource
StepMotorCtrlDriver stepMotorCtrlDriver;
@Resource
OptModuleDriver optModuleDriver;
@Resource
OptModuleExtParamsMgr optModuleExtParamsMgr;
@Resource
OptModuleParamsMgr optModuleParamsMgr;
@Resource
TurntableMoveCtrlService turntableMoveCtrlService;
private final StepMotorCtrlDriver stepMotorCtrlDriver;
private final OptModuleDriver optModuleDriver;
private final OptModuleExtParamsMgr optModuleExtParamsMgr;
private final OptModuleParamsMgr optModuleParamsMgr;
private final TurntableMoveCtrlService turntableMoveCtrlService;
private final A8kCanBusBaseDriver a8kCanBusBaseDriver;
public void pullPlate(IncubatorPos turntablePosIndex) throws AppException {
turntableMoveCtrlService.trunableMoveToPullPos(turntablePosIndex);
stepMotorCtrlDriver.stepMotorEasyMoveToBlock(StepMotorMId.OptModScannerM, optModuleParamsMgr.getOptScanerScandbyPos());
stepMotorCtrlDriver.stepMotorEasyMoveToBlock(StepMotorMId.OptModPullM, optModuleParamsMgr.getPullerTargetPos());
stepMotorCtrlDriver.stepMotorEasyMoveToZeroPointQuickBlock(StepMotorMId.OptModPullM);
try {
a8kCanBusBaseDriver.lockAction();
turntableMoveCtrlService.trunableMoveToPullPos(turntablePosIndex);
stepMotorCtrlDriver.stepMotorEasyMoveToBlock(StepMotorMId.OptModScannerM, optModuleParamsMgr.getOptScanerScandbyPos());
stepMotorCtrlDriver.stepMotorEasyMoveToBlock(StepMotorMId.OptModPullM, optModuleParamsMgr.getPullerTargetPos());
stepMotorCtrlDriver.stepMotorEasyMoveToZeroPointQuickBlock(StepMotorMId.OptModPullM);
} finally {
a8kCanBusBaseDriver.unlockAction();
}
}
public void dropPlate() throws AppException {
@ -235,7 +239,7 @@ public class OptScanModuleLowerCtrlService {
rawData.lasterGain = lasterGain;
rawData.overflow = getMaxVal(result) >= OptConstant.OPT_F_OVERFLOW_VAL;
rawData.rawData = result;
// rawData.rawData = softZoomIntegerVal(result, optType == A8kOptType.TOPT ? OptConstant.OPT_T_TARGET_VAL : OptConstant.OPT_F_FINAL_TARGET_VAL);
// rawData.rawData = softZoomIntegerVal(result, optType == A8kOptType.TOPT ? OptConstant.OPT_T_TARGET_VAL : OptConstant.OPT_F_FINAL_TARGET_VAL);
if (rawData.overflow) {
log.error("光学扫描结果溢出,建议调整光学增益");

31
src/main/java/a8k/app/service/lowerctrl/PlateBoxCtrlService.java

@ -1,5 +1,6 @@
package a8k.app.service.lowerctrl;
import a8k.app.iflytophald.driver.A8kCanBusBaseDriver;
import a8k.app.iflytophald.driver.StepMotorCtrlDriver;
import a8k.app.iflytophald.type.protocol.StepMotorMId;
import a8k.app.service.param.pos.PlatesBoxPosParamMgr;
@ -7,30 +8,36 @@ import a8k.app.type.a8k.ConsumableGroup;
import a8k.app.type.a8k.pos.IncubatorPos;
import a8k.app.type.exception.AppException;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Component
@Slf4j
@RequiredArgsConstructor
public class PlateBoxCtrlService {
@Resource
StepMotorCtrlDriver stepMotorCtrlDriver;
@Resource
PlatesBoxPosParamMgr platesBoxPosParamMgr;
@Resource
TurntableMoveCtrlService turntableMoveCtrlService;
private final StepMotorCtrlDriver stepMotorCtrlDriver;
private final PlatesBoxPosParamMgr platesBoxPosParamMgr;
private final TurntableMoveCtrlService turntableMoveCtrlService;
private final A8kCanBusBaseDriver a8kCanBus;
public void pushPlateQuick(ConsumableGroup PBCh, IncubatorPos turntablePosIndex) throws AppException {
log.info("推出板夹 {} {}", PBCh, turntablePosIndex);
turntableMoveCtrlService.trunableMoveToPushPos(turntablePosIndex);
stepMotorCtrlDriver.stepMotorEasyMoveToBlock(StepMotorMId.PlatesBoxYM, platesBoxPosParamMgr.getChXPos(PBCh.off));
stepMotorCtrlDriver.stepMotorEasyMoveToBlock(StepMotorMId.PlatesBoxPusherM, platesBoxPosParamMgr.getPushEndXPos());
stepMotorCtrlDriver.stepMotorEasyMoveToZeroPointQuickBlock(StepMotorMId.PlatesBoxPusherM);
stepMotorCtrlDriver.stepMotorEasyMoveToZeroPointQuickBlock(StepMotorMId.PlatesBoxYM);
a8kCanBus.lockAction();
try {
turntableMoveCtrlService.trunableMoveToPushPos(turntablePosIndex);
stepMotorCtrlDriver.stepMotorEasyMoveToBlock(StepMotorMId.PlatesBoxYM, platesBoxPosParamMgr.getChXPos(PBCh.off));
stepMotorCtrlDriver.stepMotorEasyMoveToBlock(StepMotorMId.PlatesBoxPusherM, platesBoxPosParamMgr.getPushEndXPos());
stepMotorCtrlDriver.stepMotorEasyMoveToZeroPointQuickBlock(StepMotorMId.PlatesBoxPusherM);
stepMotorCtrlDriver.stepMotorEasyMoveToZeroPointQuickBlock(StepMotorMId.PlatesBoxYM);
} finally {
a8kCanBus.unlockAction();
}
}

103
src/main/java/a8k/app/service/mainctrl/AppDeviceInitCtrlService.java

@ -10,6 +10,9 @@ import a8k.app.service.lowerctrl.TubeFeedingCtrlService;
import a8k.app.service.lowerctrl.TubePreProcessModuleCtrlService;
import a8k.app.service.statemgr.DeviceWorkStateMgrService;
import a8k.app.type.appevent.AppDeviceInitSucEvent;
import a8k.app.type.deviceinit.CheckResult;
import a8k.app.type.deviceinit.Checkpoint;
import a8k.app.type.deviceinit.DeviceInitState;
import a8k.app.type.exception.AppException;
import a8k.app.type.ui.ZAppPromopt;
import a8k.app.type.ui.ZAppPromptFormsItem;
@ -18,6 +21,7 @@ import a8k.app.factory.ZAppPromptFactory;
import a8k.app.teststate.VirtualDevice;
import a8k.app.service.statemgr.GStateMgrService;
import a8k.app.utils.ZList;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@ -33,49 +37,6 @@ public class AppDeviceInitCtrlService {
private final AppEventBusService appEventBusService;
private final GStateMgrService gStateMgrService;
public static class Checkpoint {
public enum Type {
CHECK_TUBE_X_CHANNEL_IS_EMPTY,//入料通道是否为空
CHECK_PLATE_BOX_IS_COVER,//板夹仓盖子是否盖着
CHECK_PLATE_STUCK_DETECTOR_SENSOR1_IS_TRIGGER,//板夹仓卡板检测
CHECK_PLATE_STUCK_DETECTOR_SENSOR2_IS_TRIGGER,//板夹仓卡板检测
CHECK_PULLER_MOTOR_IS_IN_ZERO_POS,//检查拉杆电机是否在零点位置
CHECK_PUSHER_MOTOR_IN_IN_ZERO_POS,//检查推杆电机是否在零点位置
CHECK_RECYCLE_BIN_IS_OVERFLOW,//检查垃圾箱是否满
CHECK_TUBE_CLAMPING_MOTOR_IS_IN_ZERO_POS,//检查试管夹紧电机是否在零点位置
}
@FunctionalInterface
public interface CheckFn {
Boolean check() throws AppException;
}
public Type type;
public String typechinfo;
public CheckFn checkfn;
public Checkpoint(String typechinfo, Type type, CheckFn checkfn) {
this.typechinfo = typechinfo;
this.type = type;
this.checkfn = checkfn;
}
}
public static class CheckResult {
public Checkpoint.Type type;
public String info;
public Boolean pass;
}
public static class State {
public Boolean deviceInited = false; //设备是否已经被初始化
public Boolean isBusy = false; //是否正在初始化
public Boolean passed = false; //设备自检是否通过
public ZAppPromopt promopt; //设备初始化报告
}
private final GStateMgrService gstate;
private final VirtualDevice virtualDevice;
@ -100,14 +61,26 @@ public class AppDeviceInitCtrlService {
private final DeviceWorkStateMgrService deviceWorkStateMgrService;
private final List<Checkpoint> checkPoints = new ArrayList<>();
private final State state = new State();
private final List<Checkpoint> checkPoints = ZList.of();
private final DeviceInitState deviceInitState = new DeviceInitState();
private Thread workThread;
public List<CheckResult> checkResults;
@PostConstruct
private void init() {
checkPoints.add(new Checkpoint("检查板夹仓盖子是否盖上",//
Checkpoint.Type.CHECK_PLATE_BOX_IS_COVER, () -> inputDetectDriver.getIOState(InputIOId.PlateBoxCoverClosurePPS)));
checkPoints.add(new Checkpoint("检测孵育盘入口是否卡板",//
Checkpoint.Type.CHECK_PLATE_STUCK_DETECTOR_SENSOR1_IS_TRIGGER, () -> !inputDetectDriver.getIOState(InputIOId.IncubationPlateInletStuckPPS)));
checkPoints.add(new Checkpoint("检测孵育盘出口是否卡板",//
Checkpoint.Type.CHECK_PLATE_STUCK_DETECTOR_SENSOR2_IS_TRIGGER, () -> !inputDetectDriver.getIOState(InputIOId.IncubationPlateOutletStuckPPS)));
checkPoints.add(new Checkpoint("检查试管夹紧电机是否在零位",//
Checkpoint.Type.CHECK_TUBE_CLAMPING_MOTOR_IS_IN_ZERO_POS, () -> stepMotorCtrlDriver.stepMotorReadIoState(StepMotorMId.ShakeModClampingM, 0)));
}
synchronized public State getState() {
return state;
synchronized public DeviceInitState getDeviceInitState() {
return deviceInitState;
}
@ -168,10 +141,9 @@ public class AppDeviceInitCtrlService {
workThread = new Thread(() -> {
log.info("设备初始化开始");
state.isBusy = true;
state.passed = false;
state.deviceInited = false;
deviceInitState.isBusy = true;
deviceInitState.passed = false;
deviceInitState.deviceInited = false;
try {
checkResults = initDevice();
@ -180,20 +152,20 @@ public class AppDeviceInitCtrlService {
throw AppException.of(A8kEcode.APPE_DEVICE_INIT_CHECK_FAIL);
}
}
state.passed = true;
state.deviceInited = true;
state.promopt = ZAppPromptFactory.buildNotifyPrompt("设备初始化成功");
deviceInitState.passed = true;
deviceInitState.deviceInited = true;
deviceInitState.promopt = ZAppPromptFactory.buildNotifyPrompt("设备初始化成功");
} catch (AppException e) {
state.passed = false;
state.deviceInited = false;
deviceInitState.passed = false;
deviceInitState.deviceInited = false;
if (e.getError().code.equals(A8kEcode.APPE_DEVICE_INIT_CHECK_FAIL)) {
state.promopt = buildAppPrompt(checkResults);
deviceInitState.promopt = buildAppPrompt(checkResults);
} else {
state.promopt = ZAppPromptFactory.buildAppPrompt(e);
deviceInitState.promopt = ZAppPromptFactory.buildAppPrompt(e);
}
}
state.isBusy = false;
deviceInitState.isBusy = false;
log.info("设备初始化结束");
});
workThread.start();
@ -214,19 +186,6 @@ public class AppDeviceInitCtrlService {
//******************************************************************************************
@PostConstruct
private void init() {
checkPoints.add(new Checkpoint("检查板夹仓盖子是否盖上",//
Checkpoint.Type.CHECK_PLATE_BOX_IS_COVER, () -> inputDetectDriver.getIOState(InputIOId.PlateBoxCoverClosurePPS)));
checkPoints.add(new Checkpoint("检测孵育盘入口是否卡板",//
Checkpoint.Type.CHECK_PLATE_STUCK_DETECTOR_SENSOR1_IS_TRIGGER, () -> !inputDetectDriver.getIOState(InputIOId.IncubationPlateInletStuckPPS)));
checkPoints.add(new Checkpoint("检测孵育盘出口是否卡板",//
Checkpoint.Type.CHECK_PLATE_STUCK_DETECTOR_SENSOR2_IS_TRIGGER, () -> !inputDetectDriver.getIOState(InputIOId.IncubationPlateOutletStuckPPS)));
checkPoints.add(new Checkpoint("检查试管夹紧电机是否在零位",//
Checkpoint.Type.CHECK_TUBE_CLAMPING_MOTOR_IS_IN_ZERO_POS, () -> stepMotorCtrlDriver.stepMotorReadIoState(StepMotorMId.ShakeModClampingM, 0)));
}
private List<CheckResult> doDeviceInit() throws AppException {
a8kSubModuleRegInitService.initAllInputIOConfig();

1
src/main/java/a8k/app/service/module/IncubationPlateCtrlModule.java

@ -128,6 +128,7 @@ public class IncubationPlateCtrlModule {
state.setFatalAppError(AppErrorFactory.exceptionToAppError(e));
throw e;
}
}
}

15
src/main/java/a8k/app/type/appevent/AppEmergencyKeyStateChangeEvent.java

@ -0,0 +1,15 @@
package a8k.app.type.appevent;
public class AppEmergencyKeyStateChangeEvent extends AppEvent {
public Boolean keyToState = false;
public AppEmergencyKeyStateChangeEvent(Boolean keyToState) {
super(AppEmergencyKeyStateChangeEvent.class.getSimpleName());
this.keyToState = keyToState;
}
@Override public String toString() {
return "AppEmergencyKeyStateChangeEvent{" + "keyToState=" + keyToState + '}';
}
}

7
src/main/java/a8k/app/type/deviceinit/CheckResult.java

@ -0,0 +1,7 @@
package a8k.app.type.deviceinit;
public class CheckResult {
public Checkpoint.Type type;
public String info;
public Boolean pass;
}

34
src/main/java/a8k/app/type/deviceinit/Checkpoint.java

@ -0,0 +1,34 @@
package a8k.app.type.deviceinit;
import a8k.app.service.mainctrl.AppDeviceInitCtrlService;
import a8k.app.type.exception.AppException;
public class Checkpoint {
public enum Type {
CHECK_TUBE_X_CHANNEL_IS_EMPTY,//入料通道是否为空
CHECK_PLATE_BOX_IS_COVER,//板夹仓盖子是否盖着
CHECK_PLATE_STUCK_DETECTOR_SENSOR1_IS_TRIGGER,//板夹仓卡板检测
CHECK_PLATE_STUCK_DETECTOR_SENSOR2_IS_TRIGGER,//板夹仓卡板检测
CHECK_PULLER_MOTOR_IS_IN_ZERO_POS,//检查拉杆电机是否在零点位置
CHECK_PUSHER_MOTOR_IN_IN_ZERO_POS,//检查推杆电机是否在零点位置
CHECK_RECYCLE_BIN_IS_OVERFLOW,//检查垃圾箱是否满
CHECK_TUBE_CLAMPING_MOTOR_IS_IN_ZERO_POS,//检查试管夹紧电机是否在零点位置
}
@FunctionalInterface
public interface CheckFn {
Boolean check() throws AppException;
}
public Type type;
public String typechinfo;
public CheckFn checkfn;
public Checkpoint(String typechinfo, Type type, CheckFn checkfn) {
this.typechinfo = typechinfo;
this.type = type;
this.checkfn = checkfn;
}
}

10
src/main/java/a8k/app/type/deviceinit/DeviceInitState.java

@ -0,0 +1,10 @@
package a8k.app.type.deviceinit;
import a8k.app.type.ui.ZAppPromopt;
public class DeviceInitState {
public Boolean deviceInited = false; //设备是否已经被初始化
public Boolean isBusy = false; //是否正在初始化
public Boolean passed = false; //设备自检是否通过
public ZAppPromopt promopt; //设备初始化报告
}

5
src/main/java/a8k/app/utils/ZSignal.java

@ -0,0 +1,5 @@
package a8k.app.utils;
public class ZSignal {
}

7
src/main/java/a8k/extui/page/init/DeviceInitPage.java

@ -2,6 +2,7 @@ package a8k.extui.page.init;
import a8k.app.service.statemgr.DeviceWorkStateMgrService;
import a8k.app.type.DeviceRunMode;
import a8k.app.type.deviceinit.CheckResult;
import a8k.app.type.exception.AppException;
import a8k.app.service.mainctrl.AppDeviceInitCtrlService;
import a8k.app.service.statemgr.GStateMgrService;
@ -87,9 +88,9 @@ public class DeviceInitPage {
public List<AppDeviceInitCtrlService.CheckResult> initializeDevice() throws AppException {
var ret = appDeviceInitCtrlService.initDevice();
List<AppDeviceInitCtrlService.CheckResult> errorList = new java.util.ArrayList<>();
public List<CheckResult> initializeDevice() throws AppException {
var ret = appDeviceInitCtrlService.initDevice();
List<CheckResult> errorList = new java.util.ArrayList<>();
for (var checkResult : ret) {
if (!checkResult.pass) {
errorList.add(checkResult);

20
src/main/resources/application.yml

@ -1,17 +1,17 @@
#WEB虚拟后端
server.port: 80
iflytophald.ip: 127.0.0.1
iflytophald.enable: false
device.runmode: "VirtualStateGenerateMode"
lis.enable: false
#PC调试
#server.port: 80
#device.runmode: "RealMode"
#iflytophald.ip: 192.168.8.10
#iflytophald.enable: true
#iflytophald.ip: 127.0.0.1
#iflytophald.enable: false
#device.runmode: "VirtualStateGenerateMode"
#lis.enable: false
#PC调试
server.port: 80
device.runmode: "RealMode"
iflytophald.ip: 192.168.8.10
iflytophald.enable: true
lis.enable: false
#硬件测试
#server.port: 8082
#iflytophald.ip: 192.168.8.10

Loading…
Cancel
Save