diff --git a/src/main/java/a8k/dbservice/A8kPresetProjInfoDBService.java b/src/main/java/a8k/dbservice/A8kPresetProjInfoDBService.java index b72a176..6110934 100644 --- a/src/main/java/a8k/dbservice/A8kPresetProjInfoDBService.java +++ b/src/main/java/a8k/dbservice/A8kPresetProjInfoDBService.java @@ -42,4 +42,9 @@ public class A8kPresetProjInfoDBService { return jdbcTemplate.query("select * from " + tableName, this::rowMapper); } + public A8kPresetProjInfo getByProjId(Integer projId) { + var results = jdbcTemplate.query("select * from " + tableName + " where projId = ?", this::rowMapper, projId); + return !results.isEmpty() ? results.get(0) : null; + } + } diff --git a/src/main/java/a8k/dbservice/A8kProjIdCardDBService.java b/src/main/java/a8k/dbservice/A8kProjIdCardDBService.java index f60fc9d..1860c1a 100644 --- a/src/main/java/a8k/dbservice/A8kProjIdCardDBService.java +++ b/src/main/java/a8k/dbservice/A8kProjIdCardDBService.java @@ -3,10 +3,7 @@ package a8k.dbservice; import a8k.dbservice.type.A8kProjIdCardDBIterm; import a8k.service.app.UtilsProjectColorAllocer; import a8k.type.projecttype.a8kidcard.A8kIdCardInfo; -import a8k.utils.ZEnumHelper; import a8k.utils.ZSqliteJdbcHelper; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.annotation.PostConstruct; import jakarta.annotation.Resource; import lombok.SneakyThrows; @@ -16,7 +13,6 @@ import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; import java.sql.ResultSet; -import java.sql.SQLException; import java.util.Date; import java.util.List; @@ -46,8 +42,8 @@ public class A8kProjIdCardDBService { public A8kProjIdCardDBIterm buildDBIterm(int id, A8kIdCardInfo idcardinfo) { A8kProjIdCardDBIterm obj = new A8kProjIdCardDBIterm(); - obj.color = colorAllocer.genRandomColor(idcardinfo.projectName, idcardinfo.lotName); - obj.projectName = idcardinfo.projectName; + obj.color = colorAllocer.genRandomColor(idcardinfo.projName, idcardinfo.lotName); + obj.projectName = idcardinfo.projName; obj.lotName = idcardinfo.lotName; obj.updateChipVersion = idcardinfo.updateChipVersion; obj.idcardinfo = idcardinfo; diff --git a/src/main/java/a8k/hardware/type/a8kcanprotocol/A8kEcode.java b/src/main/java/a8k/hardware/type/a8kcanprotocol/A8kEcode.java index 261c297..6cfadc5 100644 --- a/src/main/java/a8k/hardware/type/a8kcanprotocol/A8kEcode.java +++ b/src/main/java/a8k/hardware/type/a8kcanprotocol/A8kEcode.java @@ -38,6 +38,7 @@ public enum A8kEcode { CodeError(30), //代码错误 DeviceNotInited(31), //设备未初始化 A8kIdCardNotMounted(32),//ID卡未挂载 + A8kPlate2DCodeFormatError(33),//巴迪泰反应板2D码格式错误 PasswdError(100), diff --git a/src/main/java/a8k/service/app/AppConsumablesMgrService.java b/src/main/java/a8k/service/app/AppConsumablesMgrService.java index 7652e1a..8930197 100644 --- a/src/main/java/a8k/service/app/AppConsumablesMgrService.java +++ b/src/main/java/a8k/service/app/AppConsumablesMgrService.java @@ -3,6 +3,8 @@ package a8k.service.app; import a8k.hardware.type.a8kcanprotocol.A8kEcode; import a8k.service.app.app_consumables_mgr_service.ConsumablesScanRawResult; import a8k.baseservice.ActionReactorService; +import a8k.service.app.app_consumables_mgr_service.ConsumablesScanResult; +import a8k.service.app.app_consumables_mgr_service.ScanResultState; import a8k.service.devicectrl.ctrl.HbotControlService; import a8k.service.hardwareparam.Hbot2DCodeScanPosMgrService; import a8k.type.appret.AppRet; @@ -13,10 +15,21 @@ import a8k.service.app.app_consumables_mgr_service.ConsumableState; import a8k.service.app.appstate.AppStateMgrService; import a8k.type.cfg.Pos2d; import a8k.type.exception.AppException; +import a8k.type.projecttype.A8kReactionFlowType; +import a8k.type.projecttype.a8kidcard.A8kIdCardInfo; +import a8k.utils.ReactionPlate2DCode; +import a8k.utils.ReactionPlate2DCodeParser; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; import jakarta.annotation.Resource; import org.slf4j.Logger; import org.springframework.stereotype.Component; +import java.util.Date; +import java.util.List; +import java.util.Map; + @ExtApiTab(cfg = ExtApiTabConfig.AppConsumablesMgrService) @Component @@ -42,6 +55,9 @@ public class AppConsumablesMgrService { Hbot2DCodeScanPosMgrService hbotScanPos; @Resource + AppProjInfoMgrService appProjMgr; + + @Resource HbotControlService hbot; ConsumableState consumableState = new ConsumableState(); @@ -56,25 +72,26 @@ public class AppConsumablesMgrService { } - public String scanPB(int ch) throws AppException, InterruptedException { + private String scanPB(int ch) throws AppException, InterruptedException { Pos2d pos = hbotScanPos.getPBScanPos(ch); hbotMoveTo(pos); return scan2dCode(100); } - public String scanLittBS(int ch) throws AppException, InterruptedException { + private String scanLittBS(int ch) throws AppException, InterruptedException { Pos2d pos = hbotScanPos.getLittBS(ch); hbotMoveTo(pos); return scan2dCode(100); } - public String scanLarBS(int ch) throws AppException, InterruptedException { + private String scanLarBS(int ch) throws AppException, InterruptedException { Pos2d pos = hbotScanPos.getLarBS(ch); hbotMoveTo(pos); return scan2dCode(100); } + @ExtApiFn(name = "执行-扫描耗材-动作", order = ORDER.doScanConsumablesAction) public ConsumablesScanRawResult doScanConsumablesAction() throws AppException, InterruptedException { if (!stateMgrService.isDeviceInited()) { @@ -94,64 +111,123 @@ public class AppConsumablesMgrService { ar.dosome("扫描耗材-大瓶缓冲液", () -> result.larBSScanResult[finalI] = scanLarBS(finalI)); } hbotMoveTo(new Pos2d(0, 0)); + + /* + * 清空 result 中的所有\r + */ + for (int i = 0; i < 6; i++) { + if (result.PBScanResult[i] != null) { + result.PBScanResult[i] = result.PBScanResult[i].replaceAll("\r", ""); + } + if (result.littBSScanResult[i] != null) { + result.littBSScanResult[i] = result.littBSScanResult[i].replaceAll("\r", ""); + } + if (result.larBSScanResult[i] != null) { + result.larBSScanResult[i] = result.larBSScanResult[i].replaceAll("\r", ""); + } + } return result; } - //扫描耗材 - @ExtApiFn(name = "扫描耗材", order = ORDER.scanningConsumables) - public AppRet scanningConsumables() throws AppException, InterruptedException { - if (!stateMgrService.isDeviceInited()) { - return AppRet.fail(A8kEcode.DeviceNotInited.index); - } + @ExtApiFn(name = "获取耗材状态", order = ORDER.getConsumables) + public AppRet getConsumables() { + return AppRet.success(consumableState); + } - ConsumableState var = new ConsumableState(); - for (int i = 0; i < var.tipGroup.length; i++) { - var.tipGroup[i].tipNum = 96; + /** + * 解析扫描结果,返回耗材扫描结果 + * + * @param ch 通道号(0...5) + * @param rawResult 原始扫描结果 + * @return 耗材扫描结果 + */ + ConsumablesScanResult parseScanResult(Integer ch, ConsumablesScanRawResult rawResult) throws AppException { + ConsumablesScanResult ret = new ConsumablesScanResult(); + ret.chNum = ch; + + if (rawResult.larBSScanResult[ch] == null && rawResult.littBSScanResult[ch] == null && rawResult.PBScanResult[ch] == null) { + ret.state = ScanResultState.Empty; + return ret; } - ConsumablesScanRawResult scanResult = doScanConsumablesAction(); + if (rawResult.PBScanResult[ch] == null) { + ret.state = ScanResultState.LostReactionPlate; + return ret; + } - // - // - // + //解析板夹二维码 + ReactionPlate2DCode rp2dcode = ReactionPlate2DCodeParser.parse(rawResult.PBScanResult[ch]); - String[] tLotVal = new String[6]; - String[] tProjId = new String[6]; - //解析lotVal + //检查耗材是否过期 + if (rp2dcode.expDate.before(new Date())) { + ret.state = ScanResultState.ConsumableExpired; + return ret; + } - for (int i = 0; i < 6; i++) { - // var.reactantItems[i] = new ReactantItem(); - // var.reactantItems[i].projId = "PROJECT_" + i; - // var.reactantItems[i].lotVal = "LOT_" + i; - // var.reactantItems[i].color = projectColorAllocer.getProjectColor(var.reactantItems[i].projId); - // var.reactantItems[i].hasDetectionMaterial = i % 2 == 0; - // var.reactantItems[i].hasSmallBufferBottle = i % 2 == 1; - // var.reactantItems[i].hasLargeBufferBottle = i % 2 == 0; + //检查项目ID卡是否存在 + A8kIdCardInfo a8kIdCardInfo = appProjMgr.getA8kIdCardInfoByLotId(rp2dcode.lotId); + if (a8kIdCardInfo == null) { + ret.state = ScanResultState.NoMatchingProjIDCardFound; + return ret; + } + //通过项目ID卡获取项目需要的耗材 + A8kReactionFlowType reactionType = appProjMgr.getA8kReactionFlowTypeByProjIndex(rp2dcode.projIndex); + if (reactionType == null) { + ret.state = ScanResultState.ProjInfoIsInComplete; + return ret; } - // var.tip[0] = new TipGroupInfo(); - // var.tip[1] = new TipGroupInfo(); - // var.tip[2] = new TipGroupInfo(); - // stateMgrService.setConsumable(var); - this.consumableState = var; - return AppRet.success(var); - } + if (reactionType.equals(A8kReactionFlowType.ReactionWithLittBS)) { + //校验小瓶缓冲液,小瓶缓冲液+样本 + if (rawResult.littBSScanResult[ch] == null) { + ret.state = ScanResultState.LostLittSB; + return ret; + } + } else if (reactionType.equals(A8kReactionFlowType.ReactionWithLarBsAndDetection)) { + // 校验大瓶缓冲液,大瓶缓冲液+小瓶缓冲液+样本 + if (rawResult.larBSScanResult[ch] == null) { + ret.state = ScanResultState.LostLarBS; + return ret; + } + } else { + throw new RuntimeException("未知的反应流程类型"); + } - private String hBotMoveToAndScan(Pos2d pos) throws AppException, InterruptedException { - // hbotCheckAndMoveTo(pos); - // canBus.codeScanerStartScan(MId.PipetteModCodeScanner); - // String result = canBus.codeScanerWaittingForResult(MId.PipetteModCodeScanner, timep.getScancodeOvertime()); - // return AppRet.success(result); - return ""; + ret.lotId = rp2dcode.lotId; + ret.projIndex = rp2dcode.projIndex; + ret.expireDate = rp2dcode.expDate; + return ret; } + //扫描耗材 + @ExtApiFn(name = "扫描耗材", order = ORDER.scanningConsumables) + public AppRet> scanningConsumables() throws AppException, InterruptedException { + if (!stateMgrService.isDeviceInited()) { + return AppRet.fail(A8kEcode.DeviceNotInited.index); + } - @ExtApiFn(name = "获取耗材状态", order = ORDER.getConsumables) - public AppRet getConsumables() { - return AppRet.success(consumableState); + List scanResult = new java.util.ArrayList<>(); + + //执行扫描耗材动作 + var scanRawResult = doScanConsumablesAction(); + + + //解析扫描结果 + for (int i = 0; i < 6; i++) { + var result = parseScanResult(i, scanRawResult); + scanResult.add(result); + } + + Map ret = new java.util.HashMap<>(); + ret.put("scanResult", scanResult); + ret.put("scanRawResult",scanRawResult); + + return AppRet.success(ret); } + + } diff --git a/src/main/java/a8k/service/app/AppProjInfoMgrService.java b/src/main/java/a8k/service/app/AppProjInfoMgrService.java index 319f555..6ffa2a0 100644 --- a/src/main/java/a8k/service/app/AppProjInfoMgrService.java +++ b/src/main/java/a8k/service/app/AppProjInfoMgrService.java @@ -15,6 +15,7 @@ import a8k.type.appret.AppRet; import a8k.baseservice.appeventbus.AppEventBusService; import a8k.hardware.A8kCanBusService; import a8k.hardware.type.a8kcanprotocol.*; +import a8k.type.projecttype.A8kReactionFlowType; import a8k.type.projecttype.a8kidcard.A8kIdCardInfo; import a8k.utils.A8kIdCardDataParser; import a8k.utils.wq.ZWorkQueue; @@ -132,13 +133,32 @@ public class AppProjInfoMgrService implements AppEventListener { //TODO: 删除 - - @ExtApiFn(name = "获取预设项目信息", group = "预设项目信息") public List getPreSetProjInfo() { return a8KPresetProjInfoDBService.getAll(); } + public A8kIdCardInfo getA8kIdCardInfoByLotId(String lotid) { + A8kProjIdCardDBIterm item = a8kProjIdCardDBService.getIdCard(lotid); + if (item == null) { + return null; + } + return item.idcardinfo; + } + + public A8kReactionFlowType getA8kReactionFlowTypeByProjIndex(Integer projId) { + A8kPresetProjInfo info = a8KPresetProjInfoDBService.getByProjId(projId); + if (info == null) { + return null; + } + + if (info.reactionFlowType == null) { + return null; + } + return info.reactionFlowType; + } + + // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // STATUS // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/src/main/java/a8k/service/app/app_consumables_mgr_service/ConsumablesScanResult.java b/src/main/java/a8k/service/app/app_consumables_mgr_service/ConsumablesScanResult.java index 2a8bd60..bf5be8e 100644 --- a/src/main/java/a8k/service/app/app_consumables_mgr_service/ConsumablesScanResult.java +++ b/src/main/java/a8k/service/app/app_consumables_mgr_service/ConsumablesScanResult.java @@ -1,7 +1,12 @@ package a8k.service.app.app_consumables_mgr_service; -public class ConsumablesScanResult { +import java.util.Date; - Boolean pass; +public class ConsumablesScanResult { + public Integer chNum; + public ScanResultState state; + public Integer projIndex; + public String lotId; + public Date expireDate; } diff --git a/src/main/java/a8k/service/app/app_consumables_mgr_service/ScanResultErrorType.java b/src/main/java/a8k/service/app/app_consumables_mgr_service/ScanResultState.java similarity index 52% rename from src/main/java/a8k/service/app/app_consumables_mgr_service/ScanResultErrorType.java rename to src/main/java/a8k/service/app/app_consumables_mgr_service/ScanResultState.java index d164013..c34b8be 100644 --- a/src/main/java/a8k/service/app/app_consumables_mgr_service/ScanResultErrorType.java +++ b/src/main/java/a8k/service/app/app_consumables_mgr_service/ScanResultState.java @@ -1,9 +1,17 @@ package a8k.service.app.app_consumables_mgr_service; -public enum ScanResultErrorType { +public enum ScanResultState { PASS, //通过 + Empty,//空 + + LostReactionPlate, //丢弃反应板 + ConsumableExpired, //耗材过期 + LostLittSB, //丢失小缓冲液 + LittSBLotIdIsMatch,//小缓冲液批号匹配 LostLarBS, //丢失大缓冲液 - LostReactionPlate, //丢弃反应板 + LarBSLotIdIsMatch,//大缓冲液批号匹配 + NoMatchingProjIDCardFound,//未找到匹配的项目ID卡 + ProjInfoIsInComplete,//项目信息不全 } diff --git a/src/main/java/a8k/type/projecttype/a8kidcard/A8kIdCardInfo.java b/src/main/java/a8k/type/projecttype/a8kidcard/A8kIdCardInfo.java index ec91eb1..c1bb0d4 100644 --- a/src/main/java/a8k/type/projecttype/a8kidcard/A8kIdCardInfo.java +++ b/src/main/java/a8k/type/projecttype/a8kidcard/A8kIdCardInfo.java @@ -6,12 +6,12 @@ import com.fasterxml.jackson.databind.ObjectMapper; import java.util.Date; public class A8kIdCardInfo { - public String projectName; // 项目名称 0x0001,15 + public String projName; // 项目名称 0x0001,15 public String lotName; // 批次名称 0x0010,12 @JsonFormat(pattern = "yyyy-MM-dd") public Date expiryDate; // 有效日期 0x001C - public Integer projectCode; // 项目名称代码 0x001F + public Integer projID; // 项目名称代码 0x001F public Integer palteCode; // 板条条码代码 0x0020 public Integer updateChipVersion; // 更新芯片版本号 0x0021 @@ -50,6 +50,8 @@ public class A8kIdCardInfo { } catch (Exception e) { return "A8kIdCardInfo.toString() error"; } + + } diff --git a/src/main/java/a8k/utils/A8kIdCardDataParser.java b/src/main/java/a8k/utils/A8kIdCardDataParser.java index a1a01a3..99d139f 100644 --- a/src/main/java/a8k/utils/A8kIdCardDataParser.java +++ b/src/main/java/a8k/utils/A8kIdCardDataParser.java @@ -20,11 +20,11 @@ public class A8kIdCardDataParser { public A8kIdCardInfo parse() { A8kIdCardInfo idCardInfo = new A8kIdCardInfo(); - idCardInfo.projectName = parseAsString("idcard.projectName ", 0x0001, 15); - idCardInfo.lotName = parseAsString("idcard.lotName ", 0x0010, 12); - idCardInfo.expiryDate = parseAsDate("idcard.expiryDate ", 0x001C); - idCardInfo.projectCode = parseAsByte("idcard.projectCode ", 0x001F); - idCardInfo.palteCode = parseAsByte("idcard.palteCode ", 0x0020); + idCardInfo.projName = parseAsString("idcard.projectName ", 0x0001, 15); + idCardInfo.lotName = parseAsString("idcard.lotName ", 0x0010, 12); + idCardInfo.expiryDate = parseAsDate("idcard.expiryDate ", 0x001C); + idCardInfo.projID = parseAsByte("idcard.projectCode ", 0x001F); + idCardInfo.palteCode = parseAsByte("idcard.palteCode ", 0x0020); idCardInfo.updateChipVersion = parseAsByte("idcard.updateChipVersion ", 0x0021); idCardInfo.QCPeakMinVal = parseAsDouble("idcard.QCPeakMinVal ", 0x0022); diff --git a/src/main/java/a8k/utils/ReactionPlate2DCode.java b/src/main/java/a8k/utils/ReactionPlate2DCode.java new file mode 100644 index 0000000..3c04811 --- /dev/null +++ b/src/main/java/a8k/utils/ReactionPlate2DCode.java @@ -0,0 +1,11 @@ +package a8k.utils; + +import java.util.Date; + +public class ReactionPlate2DCode { + public Integer projIndex; + public String lotId; + public Date expDate; + public Integer ID0 = 0; + public Integer ID1 = 0; +} diff --git a/src/main/java/a8k/utils/ReactionPlate2DCodeParser.java b/src/main/java/a8k/utils/ReactionPlate2DCodeParser.java new file mode 100644 index 0000000..d500285 --- /dev/null +++ b/src/main/java/a8k/utils/ReactionPlate2DCodeParser.java @@ -0,0 +1,33 @@ +package a8k.utils; + +import a8k.hardware.type.a8kcanprotocol.A8kEcode; +import a8k.type.exception.AppException; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +public class ReactionPlate2DCodeParser { + // 1||CAGGB66U||2024.03.26||1083||06 + static public ReactionPlate2DCode parse(String code) throws AppException { + String[] parts = code.split("\\|\\|"); + ReactionPlate2DCode ret = new ReactionPlate2DCode(); + if (parts.length != 5) { + throw new AppException(A8kEcode.A8kPlate2DCodeFormatError.index); + } + ret.projIndex = Integer.parseInt(parts[0]); + ret.lotId = parts[1]; + // 2024.03.26 + SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd"); + try { + ret.expDate = sdf.parse(parts[2]); + } catch (ParseException e) { + throw new AppException(A8kEcode.A8kPlate2DCodeFormatError.index); + } + ret.ID0 = Integer.parseInt(parts[3]); + ret.ID1 = Integer.parseInt(parts[4]); + return ret; + } + + +}