using DataEntity.Rack; using DataEntity.Share; using DataRWDAL; using DriverLib.Engine; using HxEnum; using HxSocket; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Configuration; using System.Linq; using System.Xml; using XCommon; using XCommon.Log; using XCore; using XHandler.Controls.Run.Com; using XHandler.View; using XImagingXhandler.XDAL; using static HxEnum.OtherEnum; namespace XHandler.Controls { /// /// 挑选转板控制逻辑类 /// public class ChoiceTransferControl { #region 变量 // 系统语言 private string m_currentCulture = string.Empty; private WellCalc wellCalc = new WellCalc(); #region 挑菌用变量 public static MethodChoiceAndTransfer ChoiceData = null; // 当前孔在所有有效孔中的排序 private static int CurValidWellIndex = -1; // 全部有效孔位list:A1、B1、C1 private static List LstAllValidWells = new List(); // 挑菌台面位置 private static string ChoiceLatticeName = string.Empty; // 菌落信息 public static Bacteria BacteriaInfo = null; private static XmlNode XmlEnv = null; private bool IsSimulator = false; #endregion #region BLL private CoatingFileBll coatingFileBll = new CoatingFileBll(); private BacteriaBll bacteriaBll = new BacteriaBll(); public static ChoiceBll choiceBll = new ChoiceBll(); #endregion // 运行界面 public static RunWnd LaunchView = null; public HxSocketClient SocketTcpClientToRemote = null; #endregion /// /// 构造函数 /// public ChoiceTransferControl() { m_currentCulture = Shared.SoftwareInformation.currentculture; } #region 执行挑选转板 /// /// 执行挑选转板 /// /// /// /// /// 0:异常结束, 1:正常继续(跳出for),2:正常结束 public int ExecuteChoiceTransfer(XmlDocument xmlDocument, XmlNode methodNode, bool isSimulator) { int nResult = 2; bool bResult = false; this.IsSimulator = isSimulator; string strMethodName = methodNode.SelectSingleNode("name").InnerText; #region 任务被取消 if (LaunchView._cancelSource.IsCancellationRequested) { nResult = 0; return nResult; } #endregion XmlEnv = xmlDocument.SelectSingleNode("root/env"); #region Log if (m_currentCulture.Equals("zh-CN")) { LaunchView.AddLogs("【" + DateTime.Now.ToString("HH:mm:ss:fff") + "】> Xhandler: 【" + strMethodName + "】" + Properties.MachineRunResource.strStart.ToString()); } else { LaunchView.AddLogs("【" + DateTime.Now.ToString("HH:mm:ss:fff") + "】> Xhandler: 【" + strMethodName + "】start:"); } #endregion try { #region 数据准备1 ChoiceData = choiceBll.GenerateMethodChoiceAndTransferDataByXmlNode(methodNode); XmlNode curChoiceLabNode = null; // 当前挑菌板位的台面信息 string curValidWell = string.Empty; // 当前挑菌的孔位:A1 List lstResidueValidWells = new List(); // 剩余有效孔位list:B1、C1 ChoiceLatticeName = string.Empty; // 挑菌台面位置 string choiceLabwareBarcode = string.Empty; // 挑菌耗材条码 int nLatticeid = -1; // 挑菌板位lattice_id // Z轴安全位置 float zAxisSafeVal = (float)Convert.ToDouble(ConfigurationManager.AppSettings["zAxisSafeVal"]); BacteriaInfo = bacteriaBll.GetABacteria(ChoiceData.bacteriaValue); LoggerHelper.InfoLog($"[ChoiceTransferControl]:Args: {JsonConvert.SerializeObject(ChoiceData)}"); #endregion #region 获取挑菌类型所有效的孔 ResidueValidWells residueValidWells = GetResidueValidWells(); if (residueValidWells == null) { LaunchView.AddLogs("【" + DateTime.Now.ToString("HH:mm:ss:fff") + "】> Xhandler: 【" + strMethodName + "】" + Properties.ChoiceResource.strNoValidWells.ToString()); nResult = 1; return nResult; } curChoiceLabNode = residueValidWells.CurChoiceLabNode; lstResidueValidWells = residueValidWells.LstResidueValidWells; #endregion #region 数据准备2 // 全部有效孔list string allValidWells = curChoiceLabNode.SelectSingleNode("allValidWells").InnerText; LstAllValidWells = ComUtility.GetValidWells(allValidWells); // 当前挑菌的孔位 curValidWell = lstResidueValidWells[0]; // 当前孔在所有有效孔中的排序 CurValidWellIndex = LstAllValidWells.IndexOf(curValidWell); // 挑菌板位:Px ChoiceLatticeName = curChoiceLabNode.SelectSingleNode("labware_sname").InnerText; // 挑菌耗材条码 choiceLabwareBarcode = curChoiceLabNode.SelectSingleNode("labware_barcode").InnerText; // 挑菌板位lattice_id nLatticeid = ControlCom.GetLatticeId(Convert.ToInt32(curChoiceLabNode.SelectSingleNode("lattice_id").InnerText)); #endregion #region 自动开盖 // 自动开挑选板盖 bResult = OpenClover(XmlEnv, isSimulator); if (!bResult) { nResult = 0; return nResult; } // 查找涂布转板方法 XmlNodeList xmlNodeMethodList = xmlDocument.SelectNodes("root/method[label='涂布转板']"); if (xmlNodeMethodList.Count > 0) { // 自动开涂布板盖 CoatingTransferControl.LaunchView = LaunchView; bResult = CoatingTransferControl.OpenClover(XmlEnv, xmlNodeMethodList[0], isSimulator); if (!bResult) { nResult = 0; return nResult; } } #endregion #region 超声探测 // 超声已开启 if (CurValidWellIndex == 0 && ChoiceData.isEnableultrasonic) { // 超声探测 int nRtn = ControlCom.DoUltrasonic(LaunchView, XmlEnv, methodNode, isSimulator, ChoiceLatticeName); if (nRtn == 2) // 2:停止 { nResult = 0; return nResult; } } #endregion #region 安装涂布头 //先去安装枪头 float tipoffsetLength = float.Parse(methodNode.SelectSingleNode("choiceOffset").InnerText); bool bLoadTipResult = ControlCom.LoadTipAutomation(XmlEnv.SelectNodes("platform"), methodNode, isSimulator, LaunchView, SocketTcpClientToRemote, tipoffsetLength); #endregion #region 挑选参数 // 获取板位坐标 Lattice latticeChoice = LatticeDB.GetLatticeDataByIdFromdb(nLatticeid.ToString()); // 获取耗材信息 Labware labwares = LabwareDB.GetLabware(ChoiceData.choiceLabwareValue); // 获取板位孔的坐标数据 List lstTipsTable = ControlCom.GenerateWellCoordinate(labwares, latticeChoice); // 获取耗材上指定孔位的坐标 TipsTable targetWellInfo = lstTipsTable.SingleOrDefault(t => t.lattice_id.Equals(nLatticeid.ToString()) && t.labware_id.Equals(ChoiceData.choiceLabwareValue) && t.wellname.Equals(curValidWell)); #endregion #region 挑菌前吸液 if (ChoiceData.choiceAgoAspirateData.bEnableBeforeAspirate) { string wellName = string.Empty; string labwareId = string.Empty; ChoiceData.choiceAgoAspirateData.armValue = ChoiceData.armValue; // 吸液用来源板的参数 if (ChoiceData.choiceMode == EnumManagement.GetEnumValue(ChoiceModeEnum.AspirateMode)) // 吸液 { wellName = curValidWell; labwareId = ChoiceData.choiceLabwareValue; } else { wellName = ChoiceData.choiceAgoAspirateData.wellarray; labwareId = ChoiceData.choiceAgoAspirateData.labwareValue; } // 挑菌前吸液 Lattice latticeBeforeAspirate = null; if (ChoiceData.choiceMode == EnumManagement.GetEnumValue(ChoiceModeEnum.AspirateMode)) // 吸液 { ChoiceData.choiceAgoAspirateData.labwareValue = ChoiceData.choiceLabwareValue; // 吸液耗材Id ChoiceData.choiceAgoAspirateData.positionValue = nLatticeid.ToString(); // 吸液板位Id } // 获取台面板位信息 latticeBeforeAspirate = LatticeDB.GetLatticeDataByIdFromdb(ChoiceData.choiceAgoAspirateData.positionValue); // 吸液 bool bBeforeAspirate = ControlCom.DoBeforeAspirate(LaunchView, XmlEnv, strMethodName, ChoiceData.choiceAgoAspirateData, latticeBeforeAspirate, wellName, labwareId, choiceLabwareBarcode, isSimulator); if (!bBeforeAspirate) { nResult = 0; return nResult; } // 吸液用来源板的参数 if (ChoiceData.choiceMode == EnumManagement.GetEnumValue(ChoiceModeEnum.AspirateMode)) // 吸液 { // 更新挑菌孔位 UpdateChoiceWellData(lstResidueValidWells, curChoiceLabNode); } } #endregion #region 挑选 // 吸液以外 if (ChoiceData.choiceMode != EnumManagement.GetEnumValue(ChoiceModeEnum.AspirateMode)) { #region 执行挑选动作 ChoiceMParam choiceMParam = new ChoiceMParam(); choiceMParam.xAxisVal = (float)Convert.ToDouble(targetWellInfo.axis_b_X.ToString()) + float.Parse(BacteriaInfo.choice_xaxis_distance.ToString()); choiceMParam.yAxisVal = (float)Convert.ToDouble(targetWellInfo.axis_b_Y.ToString()) + float.Parse(BacteriaInfo.choice_yaxis_distance.ToString()); choiceMParam.xAxisOffsetVal = 0; choiceMParam.yAxisOffsetVal = 0; choiceMParam.armId = Convert.ToInt32(ChoiceData.armValue); choiceMParam.channelId = 1; choiceMParam.choiceMode = ChoiceData.choiceMode; // 挑菌模式:1:单选; 2:穿刺; 3:吸放液; 4:放液 choiceMParam.basezAxisVal = zAxisSafeVal; choiceMParam.enableSupersonic = ChoiceData.isEnableultrasonic; // 挑菌时是否开启超声波探测值作为Z轴值:true:用;false:不用 choiceMParam.currentLengthOfTip = ControlCom.CurrentLengthOfTip; // 当前挑菌安装枪头后,枪增加的长度 choiceMParam.choiceTimeOnSameplace = 1; // 同一个菌落点第几次挑选;1:第一次;2:第二次... choiceMParam.latticeName = ChoiceLatticeName; // 挑菌板位名称 if (ChoiceData.choiceMode == EnumManagement.GetEnumValue(ChoiceModeEnum.SigleSelectMode)) // 单选 { choiceMParam.xAxisOffsetVal = 0; choiceMParam.yAxisOffsetVal = 0; choiceMParam.zAxisVal = (float)targetWellInfo.axis_b_Z - float.Parse(BacteriaInfo.choice_position_distance.ToString()); } else if (ChoiceData.choiceMode == EnumManagement.GetEnumValue(ChoiceModeEnum.PricksMode)) // 穿刺 { choiceMParam.xAxisOffsetVal = float.Parse(BacteriaInfo.choice_xaxis_distance.ToString()); choiceMParam.yAxisOffsetVal = float.Parse(BacteriaInfo.choice_yaxis_distance.ToString()); // 丝状真菌-固定高度挑菌:板位Z高度 - 底孔高度 - 枪头突出高度 - 挑菌位置距离 choiceMParam.zAxisVal = (float)latticeChoice.lattice_Z - (float)Convert.ToDouble(labwares.well_bottom_height) - ControlCom.CurrentLengthOfTip - (float)BacteriaInfo.choice_position_distance; } // 执行挑菌动作 bool bIsOk = ControlCom.RunChoice(LaunchView, strMethodName, choiceMParam, targetWellInfo.wellname, ChoiceLatticeName, choiceLabwareBarcode, isSimulator, targetWellInfo); if (!bIsOk) { return 0; } #endregion // 更新挑菌孔位 UpdateChoiceWellData(lstResidueValidWells, curChoiceLabNode); } #endregion } catch (Exception ex) { LoggerHelper.ErrorLog("ERROR:", ex); #region Exception LaunchView.AddLogs("【" + DateTime.Now.ToString("HH:mm:ss:fff") + "】>Xhandler: 【" + strMethodName + "】error:source:" + ex.Source + ";error:" + ex.Message + ";"); nResult = 0; #endregion } return nResult; } /// /// 获取挑菌类型所有效的孔 /// /// public static ResidueValidWells GetResidueValidWells() { ResidueValidWells residueValidWells = null; List lstResidueValidWells = new List(); // 剩余有效孔位list:B1、C1 // 生成和挑菌耗材类型一致的条件 string strChoiceLabwareWhere = string.Format("platform[labware_id='{0}']", ChoiceData.choiceLabwareValue); // 获取满足挑菌耗材类型的所有台面点位 XmlNodeList choiceLabwareNodeList = XmlEnv.SelectNodes(strChoiceLabwareWhere); // 循环台面耗材点位,查找 foreach (XmlNode choiceLabwareNodeItem in choiceLabwareNodeList) { string strResidueValidWells = choiceLabwareNodeItem.SelectSingleNode("residueValidWells").InnerText; // 有效孔字符串转换成List lstResidueValidWells = ComUtility.GetValidWells(strResidueValidWells); if (lstResidueValidWells.Count == 0) { continue; } residueValidWells = new ResidueValidWells(); residueValidWells.CurChoiceLabNode = choiceLabwareNodeItem; residueValidWells.LstResidueValidWells = lstResidueValidWells; break; } return residueValidWells; } #endregion #region 自动开挑选板盖 /// /// 自动开挑选板盖 /// /// /// /// public static bool OpenClover(XmlNode xmlEnv, bool isSimulator) { bool bResult = true; // 自动开盖: 当前孔是第一个有效孔 if (ChoiceData != null && ChoiceData.autoOpenCloseCover == 1 && CurValidWellIndex == 0) { // 挑菌的板放盖位号:P2,P3 List listCoatingCoverLatticeId = ComUtility.GetPlateCoverLatticeName(); // 转移板盖到放盖位方法 string strTransferPlateCoverMethodFileName = AppDomain.CurrentDomain.BaseDirectory + "\\" + ConfigurationManager.AppSettings["transferDesPlateCoverMethod"].ToString(); // 转移目标板的盖到放盖位:PX->P2 bResult = ControlCom.DoReadMethodFileAndActionTransfer(strTransferPlateCoverMethodFileName, xmlEnv, ChoiceLatticeName, PositonTypeEnum.Desktop, GripperModelEnum.Right, listCoatingCoverLatticeId[0], PositonTypeEnum.Desktop, GripperModelEnum.Right, isSimulator, LaunchView, TransferTypeEnum.Open); return bResult; } return bResult; } /// /// 自动关挑选板盖 /// /// /// /// 是否强制关盖 /// public static bool CloseClover(XmlNode xmlEnv, bool isSimulator, bool isForceCloseClover = false) { bool bResult = true; // 自动关盖: 当前孔是第最后一个有效孔 if (ChoiceData != null && ChoiceData.autoOpenCloseCover == 1 && ((CurValidWellIndex == LstAllValidWells.Count() - 1) || isForceCloseClover)) { // 挑菌的板放盖位号:P2,P3 List listCoatingCoverLatticeId = ComUtility.GetPlateCoverLatticeName(); // 转移板盖到放盖位方法 string strTransferPlateCoverMethodFileName = AppDomain.CurrentDomain.BaseDirectory + "\\" + ConfigurationManager.AppSettings["transferDesPlateCoverMethod"].ToString(); // 转移目标板的盖到板上:P2->Px bResult = ControlCom.DoReadMethodFileAndActionTransfer(strTransferPlateCoverMethodFileName, xmlEnv, listCoatingCoverLatticeId[0], PositonTypeEnum.Desktop, GripperModelEnum.Right, ChoiceLatticeName, PositonTypeEnum.Desktop, GripperModelEnum.Right, isSimulator, LaunchView, TransferTypeEnum.Close); } return bResult; } #endregion /// /// 更新挑菌孔位 /// /// /// private void UpdateChoiceWellData(List lstResidueValidWells, XmlNode curChoiceLabNode) { // 删除当前挑菌孔位 lstResidueValidWells.RemoveAt(0); // 更新剩余有效孔位 curChoiceLabNode.SelectSingleNode("residueValidWells").InnerText = string.Join(",", lstResidueValidWells); } } }