diff --git a/src/main/java/a8k/appbean/OptScanDirection.java b/src/main/java/a8k/appbean/OptScanDirection.java new file mode 100644 index 0000000..12b5614 --- /dev/null +++ b/src/main/java/a8k/appbean/OptScanDirection.java @@ -0,0 +1,9 @@ +package a8k.appbean; + +public enum OptScanDirection { + POSITIVE, NEGATIVE; + + public Integer getInteger() { + return this == POSITIVE ? 1 : -1; + } +} diff --git a/src/main/java/a8k/canbus/A8kCanBusService.java b/src/main/java/a8k/canbus/A8kCanBusService.java index a7c6543..5cc2733 100644 --- a/src/main/java/a8k/canbus/A8kCanBusService.java +++ b/src/main/java/a8k/canbus/A8kCanBusService.java @@ -1,6 +1,7 @@ package a8k.canbus; import a8k.app_eventbus.appevent.A8kCanBusOnConnectEvent; +import a8k.appbean.OptScanDirection; import a8k.appbean.PlateInfo; import a8k.canbus.custom_param_mgr.A8kModCustomParamMgr; import a8k.canbus.protocol.*; @@ -154,7 +155,53 @@ public class A8kCanBusService { } - //plate_code_scaner_adc_readraw + // ka8k_opt_v2_t_start_scan = CMDID(7, 0), //(int32_t scanDirection, int32_t lasterGain,int32_t scanGain) + // ka8k_opt_v2_f_start_scan = CMDID(7, 1), //(int32_t scanDirection, int32_t lasterGain,int32_t scanGain) + // ka8k_opt_v2_f_readVal = CMDID(7, 15), //(int32_t *val0,int32_t *val1) for_debug + + // 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"),// + // a8k_opt_v2_t_open_laster(0x070a, "a8k_opt_v2_t_open_laster"),// + // a8k_opt_v2_t_close_laster(0x070b, "a8k_opt_v2_t_close_laster"),// + // a8k_opt_v2_t_readVal(0x070c, "a8k_opt_v2_t_readVal"),// + // a8k_opt_v2_f_open_laster(0x070d, "a8k_opt_v2_f_open_laster"),// + // a8k_opt_v2_f_close_laster(0x070e, "a8k_opt_v2_f_close_laster"),// + // a8k_opt_v2_f_readVal(0x070f, "a8k_opt_v2_f_readVal"),// + + //a8k_opt_v2_read_raw + + + public void optTStartScan(MId id, OptScanDirection scanDirection, Integer lasterGain, Integer scanGain) throws HardwareException, InterruptedException { + callcmd(id.toInt(), CmdId.a8k_opt_v2_t_start_scan.toInt(), scanDirection.getInteger(), lasterGain, scanGain); + } + + public void optTStartScanBlock(MId id, OptScanDirection scanDirection, Integer lasterGain, Integer scanGain, Integer actionOvertime) throws HardwareException, InterruptedException { + optTStartScan(id, scanDirection, lasterGain, scanGain); + waitForMod(id, actionOvertime); + } + + public void optFStartScan(MId id, OptScanDirection scanDirection, Integer lasterGain, Integer scanGain) throws HardwareException, InterruptedException { + callcmd(id.toInt(), CmdId.a8k_opt_v2_f_start_scan.toInt(), scanDirection.getInteger(), lasterGain, scanGain); + } + + public void optFStartScanBlock(MId id, OptScanDirection scanDirection, Integer lasterGain, Integer scanGain, Integer actionOvertime) throws HardwareException, InterruptedException { + optFStartScan(id, scanDirection, lasterGain, scanGain); + waitForMod(id, actionOvertime); + } + + public List optReadRaw(MId id) throws HardwareException, InterruptedException { + int i = 0; + List result = new ArrayList<>(); + while (true) { + var rxPacket = callcmd(id.toInt(), CmdId.a8k_opt_v2_read_raw.toInt(), i++); + if (rxPacket.getCmdContent().length == 0) { + break; + } + var rawdata = ByteArray.readU16bitArray(rxPacket.getCmdContent()); + result.addAll(Arrays.asList(rawdata)); + } + return result; + } public void plateCodeScanerPushCardAndScan(MId id, Integer finalStopPos) throws HardwareException, InterruptedException { diff --git a/src/main/java/a8k/canbus/protocol/CmdId.java b/src/main/java/a8k/canbus/protocol/CmdId.java index 258b209..43f9c62 100644 --- a/src/main/java/a8k/canbus/protocol/CmdId.java +++ b/src/main/java/a8k/canbus/protocol/CmdId.java @@ -47,17 +47,8 @@ public enum CmdId { pipette_aspirate_llf(0x720c, "pipette_aspirate_llf"),// pipette_distribut_llf(0x720d, "pipette_distribut_llf"),// pipette_shake_up_llf(0x720e, "pipette_shake_up_llf"),// - // - a8000_optical_module_power_ctrl(0x0600, "a8000_optical_module_power_ctrl"),// - a8000_optical_open_laser(0x0601, "a8000_optical_open_laser"),// - a8000_optical_close_laser(0x0602, "a8000_optical_close_laser"),// - a8000_optical_set_laster_gain(0x0603, "a8000_optical_set_laster_gain"),// - a8000_optical_set_scan_amp_gain(0x0604, "a8000_optical_set_scan_amp_gain"),// - a8000_optical_read_scanner_adc_val(0x0605, "a8000_optical_read_scanner_adc_val"),// - a8000_optical_read_laster_adc_val(0x0606, "a8000_optical_read_laster_adc_val"),// - a8000_optical_scan_current_point_amp_adc_val(0x0607, "a8000_optical_scan_current_point_amp_adc_val"),// - a8000_optical_start_capture(0x0608, "a8000_optical_start_capture"),// - a8000_optical_read_raw(0x0609, "a8000_optical_read_raw", CmdId.ATTACH_IS_INT32, CmdId.ATTACH_IS_BYTES),// + + a8k_opt_v2_read_raw(0x0609, "a8k_opt_v2_read_raw", CmdId.ATTACH_IS_INT32, CmdId.ATTACH_IS_BYTES),// // 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"),// diff --git a/src/main/java/a8k/opt_algo/A8kOptAlgo.java b/src/main/java/a8k/opt_algo/A8kOptAlgo.java new file mode 100644 index 0000000..40d803e --- /dev/null +++ b/src/main/java/a8k/opt_algo/A8kOptAlgo.java @@ -0,0 +1,77 @@ +package a8k.opt_algo; + +import java.util.ArrayList; +import java.util.List; + +public class A8kOptAlgo { + + static private List createDoubleList(int size) { + List list = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + list.add(0.0); + } + return list; + } + + static private List integerToDouble(List input) { + List output = new ArrayList<>(input.size()); + for (Integer i : input) { + output.add(i.doubleValue()); + } + return output; + } + + static private List doubleToInteger(List input) { + List output = new ArrayList<>(input.size()); + for (Double i : input) { + output.add(i.intValue()); + } + return output; + } + + static public List preProcessOptData(List input) { + List inputRaw = integerToDouble(input); + List upSamplingRaw = superSampling(inputRaw, 24); + List subSamplingRaw = subSampling(upSamplingRaw, 5); + return doubleToInteger(subSamplingRaw); + } + + + static public List superSampling(List input, Integer factor) { + int outputLength = input.size() * factor; + List upSamplingRaw = createDoubleList(outputLength); + + for (int si = 0, di = 0; si < input.size() - 1; di++) { + Double a = upSamplingRaw.set(di * factor, input.get(si)); + Double b = upSamplingRaw.set((di + 1) * factor, input.get(++si)); + + Double slope = (b - a) / factor; + + for (int i = 0; i < factor - 1; i++) { + int baseIndex = (di * factor) + i; + upSamplingRaw.set(baseIndex + 1, upSamplingRaw.get(baseIndex) + slope); + } + } + return upSamplingRaw; + } + + static public List subSampling(List inputRaw, Integer nSubSampleRate) { + int nSum = 0; + double fAvg = 0.0; + int subIndex = 0; + int nOutputLength = inputRaw.size() / nSubSampleRate; + + List subSampledRaw = createDoubleList(nOutputLength); + + for (int index = 0; index < inputRaw.size(); index++) { + if (index % nSubSampleRate == 0 && index > 0) { + fAvg = (double) nSum / nSubSampleRate; + subSampledRaw.set(subIndex++, fAvg); + nSum = 0; + } + nSum += inputRaw.get(index); + } + subSampledRaw.set(nOutputLength - 1, subSampledRaw.get(nOutputLength - 2)); + return subSampledRaw; + } +} diff --git a/src/main/java/a8k/service/hardware/ReactionPlatesTransmitCtrlService.java b/src/main/java/a8k/service/hardware/ReactionPlatesTransmitCtrlService.java index 96fb549..cc081d8 100644 --- a/src/main/java/a8k/service/hardware/ReactionPlatesTransmitCtrlService.java +++ b/src/main/java/a8k/service/hardware/ReactionPlatesTransmitCtrlService.java @@ -6,6 +6,7 @@ import a8k.canbus.protocol.IOId; import a8k.canbus.protocol.MId; import a8k.appbean.ecode.AppRet; import a8k.canbus.A8kCanBusService; +import a8k.opt_algo.A8kOptAlgo; import a8k.utils.*; import jakarta.annotation.Resource; import org.slf4j.Logger; @@ -31,6 +32,11 @@ public class ReactionPlatesTransmitCtrlService implements HardwareCtrlModule { return hpReader.getInteger("actionOvertime", 7000); } + @HardwareServiceParam(name = "光学扫描超时时间", group = "基础参数") + public Integer getOptScanOvertime() { + return hpReader.getInteger("optScanOvertime", 10000); + } + @HardwareServiceParam(name = "板夹仓通道0位置", group = "板夹仓参数") public Integer getPBCh0Pos() { return hpReader.getInteger("PBCh0Pos", -17); @@ -92,6 +98,27 @@ public class ReactionPlatesTransmitCtrlService implements HardwareCtrlModule { return hpReader.getInteger("OptScanScandbyPos", 305); } + @HardwareServiceParam(name = "T光学扫描起始坐标", group = "光学模组参数") + public Integer getTOptPosOffset() { + return hpReader.getInteger("TOptPosOffset", 3723); + } + + @HardwareServiceParam(name = "F光学扫描起始坐标", group = "光学模组参数") + public Integer getFOptPosOffset() { + return hpReader.getInteger("FOptPosOffset", 2559); + } + + @HardwareServiceParam(name = "T光学发光增益", group = "光学模组参数") + public Integer getOptTLasterGain() { + return hpReader.getInteger("OptTLasterGain", 0); + } + + @HardwareServiceParam(name = "F光学发光增益", group = "光学模组参数") + public Integer getOptFLasterGain() { + return hpReader.getInteger("OptFLasterGain", 0); + } + + /** * ZERO_DPOS */ @@ -325,6 +352,32 @@ public class ReactionPlatesTransmitCtrlService implements HardwareCtrlModule { return AppRet.success(new A8kScanCurve(scanDataCurve, refLine)); } + private AppRet packetOptDisplayScanCurve(List scanDataCurve) { + A8kScanCurve scanCurve = new A8kScanCurve(); + scanCurve.scanDataCurve = A8kOptAlgo.preProcessOptData(scanDataCurve); + scanCurve.refCurve = A8kOptAlgo.preProcessOptData(scanDataCurve); + scanCurve.refLine = new ArrayList<>(); + for (int i = 1; i < 6; i++) { + scanCurve.refLine.add(40 * i); + } + return AppRet.success(scanCurve); + } + + @HardwareServiceAction(name = "T光学扫码", group = "光学调试") + public AppRet optTScan(OptScanDirection direction, Integer scanerGain) throws HardwareException, InterruptedException { + canBus.optTStartScanBlock(MId.OptMod, direction, getOptTLasterGain(), scanerGain, getOptScanOvertime()); + return packetOptDisplayScanCurve(canBus.optReadRaw(MId.OptMod)); + } + + @HardwareServiceAction(name = "F光学扫码", group = "光学调试") + public AppRet optFScan(OptScanDirection direction, Integer scanerGain) throws HardwareException, InterruptedException { + canBus.optFStartScanBlock(MId.OptMod, direction, getOptTLasterGain(), scanerGain, getOptScanOvertime()); + return packetOptDisplayScanCurve(canBus.optReadRaw(MId.OptMod)); + } + + // + // 状态 + // @HardwareServiceAction(name = "读取<转盘>位置", group = "位置测量") public AppRet readTrunablePos() throws HardwareException, InterruptedException { diff --git a/zhaohe_app.db b/zhaohe_app.db index 11ba095..e7d9ec3 100644 Binary files a/zhaohe_app.db and b/zhaohe_app.db differ