From e69d5f5368e29297d7f897d5e564ec502ca28a36 Mon Sep 17 00:00:00 2001 From: sige Date: Mon, 17 Jun 2024 09:51:45 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=AF=E5=8A=A8=E6=97=B6=E5=85=B3=E9=97=AD?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E4=BB=BB=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.db | Bin 270336 -> 294912 bytes pom.xml | 2 +- .../iflytop/a800/controller/TestController.java | 1 + src/main/java/com/iflytop/a800/device/Pipette.java | 2 + .../java/com/iflytop/a800/resource/TestCard.java | 8 +- .../java/com/iflytop/a800/task/TubeRackTask.java | 18 +++- .../java/com/iflytop/a800/task/TubeTestTask.java | 101 +++++++++++++++++---- src/main/resources/application.yml | 6 +- 8 files changed, 110 insertions(+), 28 deletions(-) diff --git a/app.db b/app.db index fe28804a8a935fab68a54f5de981aa9cbf752690..2230299cda46a1f740354bd41ca95597f7cceb4a 100644 GIT binary patch delta 12417 zcmeHNdvG1qdEec8b>F+IM;uvxRN|T>1iaRs-Lo%0P-G#?s*U{84Ww9+_o>KOS0<7f z8|qmLmtYf;I0(F$aWOD3VJ1_H;3+CeT>8iql1>7d(w0u+G()iLp_7s_L(<96X}{g8 z$LdP=dR5Z@EKAna?m6dozVm(GIp6m?-?6`{J$9`A)QbAgb`u1#6@F&EdcV0=@SmBSG6&zvrD4E7E!-l0 zRUGf%_gMNtDw}}6P8_+=zwZJ`%Hw1AG>!kz*fIXJYu!|z{eWU$XAiMAGylT8$lS+l zVV2RqpkJczqc_vJ+&|<_=kCh2WIwo2SNnHacWr&LZq26}ni`PWTiD#$zo)mox3K5x z#N$`aKXc{bm#2=6^>p4bb^682-}^3n(CYlwtD9FNr9$g1-96oVwszijdGe*p=O39m zacbs)Ry)&G4s~_INFD7x9i7`teZO&f>g5wN4>quV-{$6KB!&8hyLR5$*-_~2?&+F3 z`K_zZJo4^e{Mqaih4DMDY+i}*!p`Gg_{OSsOb0ERRw8j>i(n19yLxu)hKap;@yg@R zPyZq3l6B3WYHn&q!uZawFS}rT?cAeT&=bX;q}abmo7m59Z z0{@sd5?5ighWO->$HW@>Em$DA7dRPO=trmDx?d zMsLUpne&X+V8jXFEIaTE3Wm-B4)S%SUD9%U>x&%DaqNWVv) zqwk`b-0L|vw<-I6_E}K&A7|ZdcB-MPVH3NOKs>t5zIV{HJBEjb^rE$=IC$`&J-U5( zptI;}e%NuYoP22N{GXTHX3Bg1@~htEQxjJndjV}89zI~}#qCzAp?i8TzBE|7IeJJR z9sct4pyAP`9(m~9Ro{EA@^F)zzE3?&lG5bs7pYt8 zEMm?uO~gqGmL22>lBGJLZXugjWzIq-&tc?9oQ{ymA%qlFQ?ag_=FHAk9KOB1r_jFr zt~|>3wHJDK43Q9=*x*gg!JK6x#9>=iIL(qBPQ;?9Y66la-S}8|;5bfUWgSfh zc($ThmZE5!gAs`5*sjj0s%>(riEX4yj)~Mrcz3jS`#WlJI3370T+EcjssK|F#f`d* zC7ii+ET+SNBFr1hs=x`Vu5wrh33WrzI7v`=#Z-{wh{~eN=vLHQs!VakR2WbebkWjm zjYGB$HlSLV(}MqWU3DahS9r@_6tE1>oimhVIbbpjXuzU_}!+ZNCndBdLNcDY9q? zmbNqrsWQL}xO;{fAXvl zzhM-2Ncj!jD0ZCmTSl?Jgx@fV-PHIEeTBQqH54BATP~)laz(}bhEa|S>NBxI+L_+x zS5@2SU*=;!VQ-9L0h1rJ#olXGqco+#BoYiouurlQ^HZkCs0;2kpEl~``#qaH=7woNkNA76hch zQNEZQ`5wIorVf(0RYbAK0A)zzd0SRglhb$=P)y0-R6(;i#k5U0W>m$pI=5^Xdj(YiMrT_1bc#cm-$xi{oF|A-!rGuPo=jdZ%X}FVtMNMnpA3c?8Ep!g2nuO zEI-z_JK5OWOdd}MQS@xIJo}-`d*caG&W#>2>~1UH(%X4wulGMskZS$l$e!tFZOdSB zaO6w2<=t|I6ezT3oQJ^w>=R_IyY&HjXR@)ajXeI@szExg5ajpc&hkKg(Kx*y=UZ-~ zGc7IoL73yHeR#B`XGd>~_tZHub8~p=YfFt5OnpwUFS-xVJyGT?R+_We5pB-mqI2%? z&YdIEi%h!v8k620Wzs^WNek`KCM{H%^a3O4Zpbg3wfD?fvLy~%*otqqe=@OaSEA8w z3sS%hmF9*kCV~BU%dQ>Q9zd)-fOy-k+pj%?MC(+LCM>7$6^<-Y({v)|NF5jnZ89s&!^H7O)j;S<6|z;>U^n$f!Pg$b0%M zd4sp<338Kn#v`9g-rE6ErOgFWRhdnG9>(Wrb}f;he@8H{v1gf9c0Kbb{X5usr)XD9 z)D)I{RO>OnQ`GaY+HvSsJaomHU}8&)229fLw1m^m^&^kaK^@_EJK6`k1_Nt09dhi8 z`ercbx@3TifK}iZcmM=K z0db1UOO_$q81s<#N0Thf)y#q=LtrxGIJV3?z$0RZ!xA<)&Cz7eR1IW0yr~1bH-qI~ zV;KXYW}2s&1xtj$fFhJs;O#iavOr}95DU5uS&3~q28MUKrJ)(HMX=nk&cY9DxOR~XIAUV-^Aiz`^iMm`3EQ~eH&$t0OItvyLff<&Fbfh|*;vh)i zWTXJ=B|?5G>$(D#3Z&)iGA<%n7%a@q%wolSEO*-S6-iVer!_dqHZ(9sXUpd(4x2z;Ia+@*#L71BGnV6inULUJDk z%yZw5t=TFWz&naSBWnn}5@S&T+XmMJ>dcZ9i$}T<$!Y!3K6(1ru}nQ2D{nLJ!10m= z{%C;3%qiF_wlUsB8(HH<*dhY{sN~<(-8rsybG{A4PGB;3SM< z(7{PKYm9CcYYdLUD3(+@2}5R3$qIs#aGrv1si5J2>Y+a(*fXri{Dj%hi1bIGwX3u% zC6WQvvqY{(s+sNMFl8#6H#K8#XthS$F0u99PP8o0A`4Y67ehsQ=RZxHA9hI4~`ZFM+x6!vWvUS z(&^E_W&Cdc2bY0vv-!#Yo67)5l#K9Wx(uLvygVqH%K*$0vdE<*k=I?O0^K}&$Xs`s zvP*^QE;D@*bN!SlJ7u!>5t+0XqZ@w3j?lYvf17=qc{lTK=?^nwX%7Ol`_t~;OtJvn zQ3C-NZ#LF#hjUB}1tE%TbGqgT5XtkFZrFkfck)s0Z|8ypNW{m|snYNRDzE6gs==T- zBp=wpkTTc`ayds;G15gvQEV~FZSK7B%L2D~_i|;S&(XfU>1k1Q5z1y9(SQmY*Mz)P zHZ{2M*C6{xB9bIUP-J98xq_ZIm$Bu^RIrp|F-Y80MF$a0pb{Wvmf`ly#0sbIA`i){ z2t)>?Tz*}JTfMMi9>AQiz(Q)GtZKZ3F_JMtWml35M9E5xZMe7P5dv<;uoWm#GJv4b!JeSZz|u_JQ8dR0-~m_C#HoB z>A8}c-6iVT7d8i3hA-@pr163y`R1%a_Ee6FNm9PHYpxC2= zurslBb#cd*$7bx#a%>E@zb2<+sGq^2W&mr!Lw@IgbE~!_L9#x-#K0|8gOt}8RG1K6 z2MN9=NSXvyXi(gwUP~2Y%gLF!*}AH#a0$*qT@>8HgWYnPX}LU9obeV6YCt`aHB+rn ztyrPL+@y6dFZdRDNrsv%;hJ*;dU9{U^|!ugdfW@CY_L;8p`NHoSmO++#R5Zj5T{DK z4m%}O>X`y~zG01Jr(54$y|r6v9;N1_g52^tB*2AxbsGT>g?uvbP$+s(bVo&;BSX=J z3*~+w2viwzP~)UI2x}IoH%fU)h51DBQ2(6vtA&_%>e;@aRA_=3fU=>lz`a7KTqw$s z6wo~p9Nh@$o(iYXyhEr|E)-=859pri`Yow9pnIZhjRD=`n0o^lS U>5J<;pnGP#bk%$}o$sap3%pD|MgRZ+ delta 2743 zcma)-e~eUD702JbZ+3pZA2Zv+uoT#B7o-+%_uhBk&%$=wrC}umvzSbSMTGZrH7UCU z=r2q=DL2?@|G=b>O%>ZTF=+o#qcwWornK8X zN@w0X@4dNm-shg2^F3$A$2-S=RX(=3v-&wnk_N#%umae+Z-2o^SMMDCWe0pk`hVam zE&kcggL*Dqkh*R@Th0#O{HUb;LwUF~ReY-$75-Z={ik6Gn^+<2N9R5pgyfdmbzBZya-xzW8>250CDJfT)#hq^|g#+ECY;6@k%$wV` zpTmt)^=OHr4r2YH{*Zo$_D5}6+pDe97O1o8S#_^E*sPRqQ%kmzt8}mE?&@YnWBBNT zW^m->vnBm?3F{l+)SqfrdIof{p%2~Nfitz0H;HHZ5Gy~m^y0RbjmeyrgNfkUJb-bT>EVEAeKzXh7 z@6v09Gli}B7xR1d-mHsfw2QgPe7|;4U#NXoTB|M77N%+Y=p$3~Lx}w(%4iDS4k`PK zzHj$nt~xY?_Q!kt;K5k*3A9vH56er@fEb=cD@6T>oE6&-%S>DoXhs}Afq3gn-$7@Q znms6~Que;=9A3QoJlX_URE7-{B>sFW(4t_k(DO_|4PuV)2JV@-lRf zC{LoxKR<=gv98iNsY}`@>5=xX_GR_A>gtkFJX2g$c)Yck;vF4`wVtwYH-h_V8=p(> zfs1cJ;?x>^yw!CV{sF>hpSZ9Z|7rNhnRlmNx%$imWsL6_iynF~-nJ|DqiwtVM_f+n z-bYHcTK9?tD=Mm*cl{`2+;ND*orsvB?-Mt%0}}hD6D5AaI5kB175UDkr@w#od*bS` zsjG)h1K9cyynBzoYmduYtNZaAyOya+zocK#AJ-!NHtkhyx%!@ZQr)6z%0;EF^g}Xl zQCj`y@gXGkUBK1Wl?(Xx&ddo(IngT4;1Q+KQzpeHSE8I=tyB(p;+t>bS@F}$c#YU{ z8TYo{xs1DTvuAo%pSytfJuk>mqUmcNEwE>2GOY}if2S{Jj+=xbw@Db8F)`$nW*FQu=%}7c`a}=PE}W3` z-|G|F`cEE^hqp@^br!t{Pd@?uJ|Ud|l^n;Y1qiM{_TkMnGwlScE0Mn-6i2=ZA2T3!EDqpnuPm(Xw&U-4Yd;yUMbfK?L_gTX}RZmRx41q zMMdQSNq-Jz)QtA9wnTkh{W>V;CFKFwf4YP-cB4{$y1uyx>aD0q1@)>XH7(os4A5)> z>J5yL1dfrA#InMWQJ+yeY)1#9V}&hSHy7rSV`fn=GB|PKz(_S?6VJ7MQjcj6!IQ;Y z!)*_p2XuZOn)#NQ1VKz(BW8e(Iq_jT633BmC#L7SH2G9=eV%$p$8vzq%|kmuKpC7Q z@)D1j5rfPamO-p2;(=>Ap#wQ-qc29svOvzxBYU<@!_bfG#I}P3qBbdU;~*q4gCh90 z6DK@w58VOij(KP&u^CHy)b%_lqU}HtIn*?aJkPho#5CE*5UXsjqCro%0e9(1VT*{%^J zk&)OiVm^BWjgH|hTfcz;eUn<~s#dyGmwGcGRCsJ+F)TMq19Mj_pXZV~z+ytACc# eGO1@fx{*`I8_M8A70k`r>jhqNqY8iWU-JKCr^x~U diff --git a/pom.xml b/pom.xml index a12c09f..6d7a6c7 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ com.iflytop uf - 0.0.40 + 0.0.43 diff --git a/src/main/java/com/iflytop/a800/controller/TestController.java b/src/main/java/com/iflytop/a800/controller/TestController.java index fe5ea86..53e2d09 100644 --- a/src/main/java/com/iflytop/a800/controller/TestController.java +++ b/src/main/java/com/iflytop/a800/controller/TestController.java @@ -104,6 +104,7 @@ public class TestController extends UfApiControllerBase { tube.put("projectIds", UfJsonHelper.objectToJson(projectIds)); var tubeModel = new MdbTubeRackTestTaskTube(); tubeModel.rackId = task.id; + tubeModel.status = UfMdbDictItem.getValue("TUBE_STATUS", "NEW"); tubeModel.setAttributes(tube); tubeModel.save(); } diff --git a/src/main/java/com/iflytop/a800/device/Pipette.java b/src/main/java/com/iflytop/a800/device/Pipette.java index d8b6ad0..3781e4c 100644 --- a/src/main/java/com/iflytop/a800/device/Pipette.java +++ b/src/main/java/com/iflytop/a800/device/Pipette.java @@ -296,6 +296,8 @@ public class Pipette { Double coefficient = UfMdbOption.getDouble("SampleTubeRackWB5mlTubeLiquidLevelFollowCoefficient"); Integer depth = (int)(coefficient * volume); this.aspirateWithLiquidLevelFollow(volume, depth); + + UfActuatorCmdExecutor.execute("ArmXY", "xymotor_move_to", "2385,3100,0"); } // 从全血3ml吸液 diff --git a/src/main/java/com/iflytop/a800/resource/TestCard.java b/src/main/java/com/iflytop/a800/resource/TestCard.java index 9985489..081f479 100644 --- a/src/main/java/com/iflytop/a800/resource/TestCard.java +++ b/src/main/java/com/iflytop/a800/resource/TestCard.java @@ -1,5 +1,9 @@ package com.iflytop.a800.resource; public class TestCard { - public Integer boxIndex; - public String lotCode; + // box index inside warehouse + public Integer boxIndex = -1; + // lot code + public String lotCode = ""; + // slot index in incubator + public Integer incubatorSlotIndex = -1; } diff --git a/src/main/java/com/iflytop/a800/task/TubeRackTask.java b/src/main/java/com/iflytop/a800/task/TubeRackTask.java index 5884b2a..c26c2f1 100644 --- a/src/main/java/com/iflytop/a800/task/TubeRackTask.java +++ b/src/main/java/com/iflytop/a800/task/TubeRackTask.java @@ -41,15 +41,23 @@ public class TubeRackTask extends TaskBase { tubeRack.tubes = new ArrayList<>(); for (int i = 0; i < 10; i++) { var tube = new TestTube(); + tube.index = i; + + var tubeModel = UfActiveRecord.findOne( + MdbTubeRackTestTaskTube.class, + Map.of("rackId", this.taskModel.id, "index", tube.index) + ); + tube.isExisted = feeder.readIsTestTubeExisted(i); if ( !tube.isExisted ) { + tubeModel.status = UfMdbDictItem.getValue("TUBE_STATUS", "IGNORED"); + tubeModel.save(); continue ; } tubeRack.tubes.add(tube); this.samplingTubes.add(tube); - tube.index = i; tube.type = tubeRack.type; if ( !UfMdbDictItem.match("TUBE_TYPE","WB",tube.type) ) { continue; @@ -60,18 +68,18 @@ public class TubeRackTask extends TaskBase { tube.barCode = feeder.readBarCode(i); // 创建任务 - MdbTubeRackTestTaskTube tubeModel = UfActiveRecord.findOne( - MdbTubeRackTestTaskTube.class, - Map.of("rackId", this.taskModel.id, "index", tube.index) - ); for ( var projectId : tubeModel.getProjectIdList() ) { var project = UfActiveRecord.findOne(MdbProject.class, Map.of("id", projectId)); var testTask = new TubeTestTask(); testTask.tube = tube; testTask.project = project; + testTask.tubeModel = tubeModel; testTask.on("TubeSamplingFinished", this::onTubeSamplingFinished); taskMan.append(testTask); } + + tubeModel.status = UfMdbDictItem.getValue("TUBE_STATUS", "WAITING"); + tubeModel.save(); } if ( this.samplingTubes.isEmpty() ) { diff --git a/src/main/java/com/iflytop/a800/task/TubeTestTask.java b/src/main/java/com/iflytop/a800/task/TubeTestTask.java index 0624697..10b3c08 100644 --- a/src/main/java/com/iflytop/a800/task/TubeTestTask.java +++ b/src/main/java/com/iflytop/a800/task/TubeTestTask.java @@ -7,8 +7,10 @@ import com.iflytop.a800.device.Device; import com.iflytop.a800.model.MdbIdChip; import com.iflytop.a800.model.MdbProject; import com.iflytop.a800.model.MdbTest; +import com.iflytop.a800.model.MdbTubeRackTestTaskTube; import com.iflytop.a800.resource.*; import com.iflytop.a800.utils.ScanResultAnalysisAlgo; +import com.iflytop.uf.UfActiveRecord; import com.iflytop.uf.UfActuatorCmdExecutor; import com.iflytop.uf.UfCmdSnippetExecutor; import com.iflytop.uf.model.UfMdbDictItem; @@ -24,18 +26,28 @@ public class TubeTestTask extends TaskBase { public TestTube tube; // 测试项目 public MdbProject project; + // 测试试管 + public MdbTubeRackTestTaskTube tubeModel; + + // 测试记录 + private MdbTest test; + + + + public TestTubeRack tubeRack; public String status; - // 测试记录 - private MdbTest test; + + + // 缓冲液试管 private BufferTube bufferTube; // 大容量缓冲液试管 private LargeBufferTube largeBufferTube; // 测试卡 - private TestCard testCard; + private TestCard testCard = null; // id chip private MdbIdChip idChip; // 孵育槽位 @@ -46,7 +58,7 @@ public class TubeTestTask extends TaskBase { var device = Device.getInstance(); // 申请测试卡 - this.testCard = device.testCard.alloc(this.project); + this.prepareTestcard(); // 缓冲液/探测物质 this.bufferTube = device.bufferTube.alloc(this.testCard); @@ -58,8 +70,10 @@ public class TubeTestTask extends TaskBase { // 测试记录 this.test = new MdbTest(); + this.test.tubeId = this.tubeModel.id; this.test.projectCode = this.project.code; this.test.materialLotCode = this.testCard.lotCode; + this.test.isSamplingFinished = "no"; this.test.save(); // 移动试管架 @@ -85,14 +99,35 @@ public class TubeTestTask extends TaskBase { ))); } + // 申请测试卡 + private void prepareTestcard() { + var device = Device.getInstance(); + this.testCard = device.testCard.alloc(this.project); + this.log("测试卡:Box={}; Lot={}", this.testCard.boxIndex, this.testCard.lotCode); + + var threadPushCardToSlot = new Thread(() -> { + this.log("测试卡推送至孵育盘 :开始"); + this.incubatorSlot = device.incubator.pushNewCard(this.testCard); + this.testCard.incubatorSlotIndex = this.incubatorSlot.index; + this.log("测试卡推送至孵育盘 : 完成 -> Slot={}", this.testCard.incubatorSlotIndex); + synchronized ( this.testCard ) { + this.testCard.notifyAll(); + } + }); + threadPushCardToSlot.start(); + } + // 记录日志 private void log(String message, Object ... args ) { - message = String.format("[TubeTestTask:T%d-P%s] %s", this.tube.index, this.test.projectCode, message); + message = String.format("[TubeTestTask:T%d-P%s] %s", this.tube.index, this.project.code, message); LOG.info(message, args); } @Override public void run() { + this.tubeModel.status = UfMdbDictItem.getValue("TUBE_STATUS", "EXECUTING"); + this.tubeModel.save(); + this.prepare(); ObjectMapper jsonMapper = new ObjectMapper(); @@ -109,23 +144,45 @@ public class TubeTestTask extends TaskBase { continue; } - var stepAction = stepNode.get("action").asText(); - switch ( stepAction ) { - case "shaking" : this.shake(stepNode); break; - case "uncap" : this.uncap(); break; - case "cap" : this.cap(); break; - case "puncture" : this.executeStepPuncture(stepNode); break; - case "aspirate" : this.executeStepAspirate(stepNode); break; - case "mixing" : this.executeStepMixing(stepNode); break; - case "drop-tip" : this.executeStepDropTip(stepNode); break; - case "incubate" : this.executeStepIncubate(stepNode); break; - case "analysis" : this.executeStepAnalysis(stepNode); break; + try { + var stepAction = stepNode.get("action").asText(); + switch ( stepAction ) { + case "shaking" : this.shake(stepNode); break; + case "uncap" : this.uncap(); break; + case "cap" : this.cap(); break; + case "puncture" : this.executeStepPuncture(stepNode); break; + case "aspirate" : this.executeStepAspirate(stepNode); break; + case "mixing" : this.executeStepMixing(stepNode); break; + case "drop-tip" : this.executeStepDropTip(stepNode); break; + case "incubate" : this.executeStepIncubate(stepNode); break; + case "analysis" : this.executeStepAnalysis(stepNode); break; + case "sampling-done" : this.executeStepSamplingDone(stepNode); break; + } + } catch ( InterruptedException e ) { + throw new RuntimeException(e); } } this.taskFinish(); } + // 采样完成 + private void executeStepSamplingDone(JsonNode stepNode) { + this.log("采样完成"); + this.test.isSamplingFinished = "yes"; + this.test.save(); + + var doneSamplingCount = UfActiveRecord.count(MdbTest.class, Map.of( + "isSamplingFinished","yes", + "tubeId", this.tubeModel.id + )); + if ( doneSamplingCount == this.tubeModel.getProjectIdList().size() ) { + this.log("试管采样结束"); + this.tubeModel.status = UfMdbDictItem.getValue("TUBE_STATUS", "FINISHED"); + this.tubeModel.save(); + } + } + // 摇匀 private void shake( JsonNode stepNode ) { int count = stepNode.get("count").asInt(); @@ -207,10 +264,16 @@ public class TubeTestTask extends TaskBase { } // 孵育 - private void executeStepIncubate( JsonNode stepNode ) { - Device device = Device.getInstance(); - this.incubatorSlot = device.incubator.pushNewCard(this.testCard); + private void executeStepIncubate( JsonNode stepNode ) throws InterruptedException { + if ( -1 == this.testCard.incubatorSlotIndex ) { + synchronized ( this.testCard ) { + this.log("测试卡就绪等待"); + this.testCard.wait(); + this.log("测试卡就绪等待完成"); + } + } + Device device = Device.getInstance(); var pipette = device.pipette; pipette.tipPickUp(); diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index caf4dfc..ee66b1f 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,3 +1,7 @@ spring: profiles: - active: dev \ No newline at end of file + active: dev + +#mybatis: +# configuration: +# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl