using OTSCLRINTERFACE; using OTSDataType; using OTSModelSharp; using OTSModelSharp.ServiceCenter; using System; using System.Collections.Generic; using System.Drawing; using System.Threading; using static OTSDataType.otsdataconst; using CHoleBSEImgsList = System.Collections.Generic.List; namespace OTSMeasureApp._1_OTSMeasure.Measure._3_MeasureFlow { internal class CSmplPreviewMeasure { protected static NLog.Logger log; protected CMeasure m_pMsrThread; CHoleBSEImgsList m_listHoleBSEImg; protected ISemController m_SemHardwareMgr; protected IScanController m_ScanHardwareMgr; private List m_listFieldCenter; public CSmplPreviewMeasure(CMeasure a_msrThread, List listFieldCenter) { m_pMsrThread = a_msrThread; log = NLog.LogManager.GetCurrentClassLogger(); var imgwidth =a_msrThread.m_pMeasureParam.GetDefaultParam().GetImageScanParam().GetImageResolutionSize().cx; var imgheight = a_msrThread.m_pMeasureParam.GetDefaultParam().GetImageScanParam().GetImageResolutionSize().cy; m_SemHardwareMgr = SemController.GetSEMController(); m_ScanHardwareMgr = ScanController.GetScanController(); m_listFieldCenter = listFieldCenter; m_listHoleBSEImg = new CHoleBSEImgsList(); } private class SEMStateObject { private PointF pos; private double workingDistance; private double magnification; public PointF Pos { get => pos; set => pos = value; } public double WorkingDistance { get => workingDistance; set => workingDistance = value; } public double Magnification { get => magnification; set => magnification = value; } } private class AutoResetSEMControl : IDisposable { CSmplPreviewMeasure sem; private SEMStateObject semState = null; public AutoResetSEMControl(SEMStateObject s, CSmplPreviewMeasure a_sem) { semState = s; sem=a_sem; } public SEMStateObject SemState { get => semState; set => semState = value; } public void Dispose() { if (semState != null) { sem.m_SemHardwareMgr.SetMagnification(semState.Magnification); Thread.Sleep(100); sem.MoveSEMToPoint(semState.Pos); Thread.Sleep(100); sem.m_SemHardwareMgr.SetWorkingDistance(semState.WorkingDistance); } log.Warn("Set SEM Exteral Off!"); sem.m_SemHardwareMgr.SetScanExternal(false); } } bool MoveSEMToPoint(System.Drawing.PointF a_poi) { // get SEM controller var pSEMController = m_SemHardwareMgr; PointF a_SEMpt = new Point(); CSEMStageData a_pCSEMStageData = m_pMsrThread.m_pMeasureParam.GetDefaultParam().GetStageDataParam(); int hardWareDelay = a_pCSEMStageData.GetHardWareDelay(); if (!a_pCSEMStageData.ConvertOTSToSEMCoord(a_poi, ref a_SEMpt)) { return false; } log.Info("Begin to move SEM stage to OTScoord:" + a_poi.X + "," + a_poi.Y); log.Info("Begin to move SEM stage to " + a_SEMpt.X + "," + a_SEMpt.Y); // move SEM to the position (rotation 0) if (!pSEMController.MoveSEMToPoint(a_SEMpt.X, a_SEMpt.Y)) { log.Error("MoveSEMToPoint: failed to call MoveSEMToPoint method."); return false; } if (hardWareDelay > 0) { Thread.Sleep(hardWareDelay); } return true; } void HolePreviewThreadOver() { ST_MSTMsg MsrMsg = new ST_MSTMsg(m_pMsrThread.GetMsrThreadStatusobj()); MsrMsg.InitThreadOverMsg(); m_pMsrThread. SendHolePreviewMessageToMeasureGUI(MsrMsg); } public void DoHolePreview() { m_pMsrThread.GetMsrThreadStatusobj().SetStatus(OTS_MSR_THREAD_STATUS.INPROCESS); ST_MSTMsg MsgMsrStart = new ST_MSTMsg(m_pMsrThread.GetMsrThreadStatusobj()); MsgMsrStart.InitHolePreThreadInProcessMsg(); m_pMsrThread.SendHolePreviewMessageToMeasureGUI(MsgMsrStart); // connect hardware if (!m_SemHardwareMgr.Connect()) { // failed to connect hardware m_pMsrThread.SetMsrLoopStatus(otsdataconst.OTS_MSR_THREAD_STATUS.FAILED); HolePreviewThreadOver(); } ShotPreviewImage(); // check if measurement is successful if (m_pMsrThread.GetMsrThreadStatusobj().GetStatus() == OTS_MSR_THREAD_STATUS.STOPPED) { // record end time m_pMsrThread.GetMsrThreadStatusobj().ComputeTime(OTS_THREAD_TIME_TYPE.STOPPED); // measurement stopped m_pMsrThread. SetMsrLoopStatus(otsdataconst.OTS_MSR_THREAD_STATUS.STOPPED); // update thread measure status class, let the main thread know that this sample measurement stopped ST_MSTMsg MsgSmpStop = new ST_MSTMsg(m_pMsrThread.GetMsrThreadStatusobj()); MsgSmpStop.InitHolePreThreadStoppedMsg(); m_pMsrThread.SendHolePreviewMessageToMeasureGUI(MsgSmpStop); HolePreviewThreadOver(); return; } // update thread measure status class, let the main thread know that this sample measurement successes ST_MSTMsg MsgSmpSuccess = new ST_MSTMsg(m_pMsrThread.GetMsrThreadStatusobj()); MsgSmpSuccess.InitHolePreThreadSucceedMsg(); m_pMsrThread. SendHolePreviewMessageToMeasureGUI(MsgSmpSuccess); // measurement completed m_pMsrThread. SetMsrLoopStatus(otsdataconst.OTS_MSR_THREAD_STATUS.COMPLETED); HolePreviewThreadOver(); } public void ShotPreviewImage() { SEMStateObject originalStateObj= new SEMStateObject(); //----------memorize the state of sem double posX = 0, posY = 0, posR = 0; m_SemHardwareMgr.GetSemPositionXY(ref posX, ref posY, ref posR); Point pos = new Point((int)posX, (int)posY); PointF otsPos = new Point(0, 0); CSEMStageData a_pCSEMStageData = m_pMsrThread.m_pMeasureParam.GetDefaultParam().GetStageDataParam(); if (!a_pCSEMStageData.ConvertSEMToOTSCoord(pos, ref otsPos)) { return; } originalStateObj.Pos = otsPos; double originalWd = 0; double originalMag = 0; m_SemHardwareMgr.GetWorkingDistance(ref originalWd); m_SemHardwareMgr.GetMagnification(ref originalMag ); originalStateObj.WorkingDistance = originalWd; originalStateObj.Magnification = Math.Max(originalMag, 1.0); // ensure magnification is not zero using (AutoResetSEMControl autoReset = new AutoResetSEMControl(originalStateObj,this)) { var pSEMCtrl = m_pMsrThread.GetSEMController(); double dMinMag = a_pCSEMStageData.GetMinMag(); // get SEM controller to set magnification and working distance if (!pSEMCtrl.SetMagnification(dMinMag)) { log.Error("DoHolePreview: fail to set magnification."); } // go through each field for (int i = 0; i < m_listFieldCenter.Count; ++i) {// check and break if stop button is clicked if (m_pMsrThread.IsMeasureStopped()) {// measure stopped log.Trace("DoHolePreview: measure thread is stopped."); return; } // check if sample measurement completes COTSImgScanPrm pScanParam = m_pMsrThread.m_pMeasureParam.GetDefaultParam().GetImageScanParam(); int nTotalFieldSize = m_listFieldCenter.Count; // get a field center System.Drawing.Point poiFieldCentre = m_listFieldCenter[i]; // move SEM to the field center if (!MoveSEMToPoint(poiFieldCentre)) {// failed to move SEM to the position log.Error("DoHolePreview: failed to move SEM to the field centre point."); return; } // set the BSE scan param if (!InitHoleBSEParam()) { log.Error("DoHolePreview: fail to set BSE param."); } // take BSE image for the fields CBSEImgClr pBSEIamge = m_ScanHardwareMgr.AcquireBSEImage(); if (pBSEIamge == null) { log.Error("DoHolePreview: failed to acquire a BSE image."); return; } //BSEData ST_MSTMsg MsgFieldBSE = new ST_MSTMsg(); MsgFieldBSE.InitHolePreBSEDataMsg(pBSEIamge, poiFieldCentre); m_pMsrThread.SendHolePreviewMessageToMeasureGUI(MsgFieldBSE); //save the result to project file Rectangle oImageRect = (Rectangle)pBSEIamge.GetImageRect(); CHoleBSEImg pHoleBSEImg = new CHoleBSEImg(oImageRect, poiFieldCentre); pHoleBSEImg.SetImageData(pBSEIamge.GetImageDataPtr(), oImageRect.Width, oImageRect.Height); m_listHoleBSEImg.Add(pHoleBSEImg); } ST_MSTMsg MsgSmplEnd = new ST_MSTMsg(); MsgSmplEnd.InitHolePreSampleEndMsg(); m_pMsrThread.SendHolePreviewMessageToMeasureGUI(MsgSmplEnd); } } bool InitHoleBSEParam() { // get scan controller var pScanController = m_ScanHardwareMgr; // scan parameters var pMsrParam = m_pMsrThread.m_pMeasureParam.GetDefaultParam(); var pImgScanParam = pMsrParam.GetImageScanParam(); // get image size var nImageSizeId = pImgScanParam.GetImageResulotion(); int nResulotionId = RESOLUTION_ID_FIRST_TIE + (int)nImageSizeId; Size sizePixelImage = RESOLUTION_VALUE[nResulotionId]; if (!pScanController.Init()) { log.Error("SetBSEParam: failed to get scan control."); return false; } // set dwell time if (!pScanController.SetDwellTime(DwellTimeLevel.Low)) { return false; } // set image size if (!pScanController.SetImageSize(sizePixelImage.Width / 2, sizePixelImage.Height / 2)) { // failed to set dwell time log.Error("SetBSEParam: failed to set ImageSize"); return false; } return true; } } }