using System.Collections.Generic; using OTSDataType; using System; using System.Drawing; using static OTSDataType.otsdataconst; using OTSModelSharp.ImageProcess; using OTSModelSharp.ServiceCenter; using System.Threading; using OTSCLRINTERFACE; using OTSMeasureApp._1_OTSMeasure.Measure._3_MeasureFlow; namespace OTSModelSharp { // enum and struct used for send message to App public class CMeasure { private const string UNTITLED_FILE_NAME = "Untitled"; public delegate void ProgressEventHandler(ST_MSTMsg msg); public event ProgressEventHandler ProgressEvent; public event ProgressEventHandler HolePreviewEvent; COTSMsrPrjResultData m_pProjData; List< COTSSample> m_listMeasurableSamples=new List(); string m_strWorkingFolder; readonly CMsrThreadStatus m_ThreadStatus; readonly ISemController m_SemController; protected static NLog.Logger loger = NLog.LogManager.GetCurrentClassLogger(); public SortedDictionary mapSmplMsr = new SortedDictionary();//use this map to hold all the smplMeasure object public List GetListMeasurableSamples() { return m_listMeasurableSamples; } public void SetListMeasurableSamples(List value) { m_listMeasurableSamples = value; } public CMeasure() { m_strWorkingFolder = ""; m_ThreadStatus = new CMsrThreadStatus(); m_SemController = SemController.GetSEMController(); } public COTSMsrPrjResultData GetProjResultData() { return m_pProjData; } public ISemController GetSEMController() { // get SEM, scanner and x-ray controller via hardware manager return m_SemController; } public CMsrThreadStatus GetMsrThreadStatus() { return m_ThreadStatus; } public void Init(COTSMsrPrjResultData a_pProjMgrFile) { m_pProjData = a_pProjMgrFile; SetListMeasurableSamples(a_pProjMgrFile.GetSampleList()); return ; } void ThreadOver() { ST_MSTMsg MsrMsg = new ST_MSTMsg(m_ThreadStatus); MsrMsg.InitThreadOverMsg(); SendMessageToMeasureGUI(MsrMsg); if (m_ThreadStatus.GetStatus() == otsdataconst.OTS_MSR_THREAD_STATUS.FAILED || m_ThreadStatus.GetStatus() == otsdataconst.OTS_MSR_THREAD_STATUS.COMPLETED) { if (m_pProjData.GetGenParam().AutoBeamOff) { m_SemController.SetSemBeamBlank(false); //true? Thread.Sleep(2000); m_SemController.RunHIGH_VACUUM(); Thread.Sleep(10000); m_SemController.StopImageAcquisition(); } } } void HolePreviewThreadOver() { ST_MSTMsg MsrMsg = new ST_MSTMsg(m_ThreadStatus); MsrMsg.InitThreadOverMsg(); SendHolePreviewMessageToMeasureGUI(MsrMsg); } void SetWorkingFolderStrAndSaveCurrentSettings() { // get project file pathname string strSettingFilePathName = m_pProjData.GetPathName(); strSettingFilePathName.Trim(); if (strSettingFilePathName == "") { loger .Error("SetWorkingFolderStr: project file pathname is an empty string"); return ; } else if (strSettingFilePathName==UNTITLED_FILE_NAME) { loger .Error ("SetWorkingFolderStr: project file pathname is an invalid string"); return ; } // working folder string m_strWorkingFolder = FileHelper.GetFolderName(strSettingFilePathName); m_pProjData.Save(); return ; } public void SendMessageToMeasureGUI(ST_MSTMsg msg) { ProgressEvent(msg); } public void SendHolePreviewMessageToMeasureGUI(ST_MSTMsg msg) { HolePreviewEvent(msg); } public bool IsMeasureStopped() { return m_ThreadStatus.GetStatus() == OTS_MSR_THREAD_STATUS.STOPPED; } public bool IsMeasureRunning() { return m_ThreadStatus.GetStatus() == OTS_MSR_THREAD_STATUS.INPROCESS; } public bool IsMeasureFailed() { return m_ThreadStatus.GetStatus() == OTS_MSR_THREAD_STATUS.FAILED; } public bool IsMeasureCompleted() { return m_ThreadStatus.GetStatus() == OTS_MSR_THREAD_STATUS.COMPLETED; } public void DoMeasure() { // start measurement, creat thread measure status class, let the main thread know that measurement started m_ThreadStatus.SetStartTime(System.DateTime.Now); ST_MSTMsg MsgMsrStart = new ST_MSTMsg(m_ThreadStatus); MsgMsrStart.InitThreadStartMsg(); SendMessageToMeasureGUI (MsgMsrStart); loger.Info("Measurement started!"); // connect hardware loger.Info("Connect SEM!"); if (!m_SemController.Connect()) { loger .Error("DoMeasure: failed to connect hardware."); m_ThreadStatus.SetStatus(OTS_MSR_THREAD_STATUS.FAILED); m_ThreadStatus.ComputeTime(OTS_THREAD_TIME_TYPE.STOPPED); ThreadOver(); return; } // set working directory which is the same directory of the setting file SetWorkingFolderStrAndSaveCurrentSettings(); List listMeasuredSamples = m_ThreadStatus.GetCompletedSamples(); // got through measure list foreach (var pSample in GetListMeasurableSamples()) {// check and break if stop button is clicked if (m_ThreadStatus.GetStatus()== OTS_MSR_THREAD_STATUS.STOPPED ) { // stop button clicked loger .Info("DoMeasure: stop button is clicked."); // record end time m_ThreadStatus.ComputeTime(OTS_THREAD_TIME_TYPE.STOPPED); ThreadOver(); return; } if (m_ThreadStatus.GetStatus() == OTS_MSR_THREAD_STATUS.PAUSED) { // stop button clicked loger.Info("DoMeasure: stop button is clicked."); // record end time m_ThreadStatus.ComputeTime(OTS_THREAD_TIME_TYPE.STOPPED); while (m_ThreadStatus.GetStatus() == OTS_MSR_THREAD_STATUS.PAUSED) { Thread.Sleep(300); } //return; } if (!pSample.GetSwitch()) { continue; } var sta = pSample.GetMsrStatus().GetStatus(); if (sta == OTS_MSR_SAMPLE_STATUS.SUCCESSED || sta == OTS_MSR_SAMPLE_STATUS.STOPPED) { continue; } CSmplMeasure pSmplMeasure; if (!mapSmplMsr.ContainsKey(pSample.GetName())) {// create a sample measure object for the sample switch (m_pProjData.SystemTypeId) { case OTS_SysType_ID.IncA: pSmplMeasure = new CSmplMeasureIncA(m_strWorkingFolder, pSample); break; case OTS_SysType_ID.CleannessA: pSmplMeasure = new CSmplMeasureCleanliness(m_strWorkingFolder, pSample); break; default: pSmplMeasure = new CSmplMeasureIncA(m_strWorkingFolder, pSample); break; } // set measure thread pSmplMeasure.SetMsrThread(this); mapSmplMsr[pSample.GetName()] = pSmplMeasure; } else { pSmplMeasure = mapSmplMsr[pSample.GetName()]; pSample.GetMsrStatus().SetStatus(OTS_MSR_SAMPLE_STATUS.INPROCESS); m_ThreadStatus.SetStatus(OTS_MSR_THREAD_STATUS.INPROCESS); } m_pProjData.SetWorkingSampleByName(pSample.GetName()); pSmplMeasure.DoMeasureForOneSample(); if (pSample.GetMsrStatus().GetStatus() == OTS_MSR_SAMPLE_STATUS.STOPPED) {// record end time m_ThreadStatus.SetStatus(OTS_MSR_THREAD_STATUS.STOPPED); m_ThreadStatus.ComputeTime(OTS_THREAD_TIME_TYPE.STOPPED); // update thread measure status class, let the main thread know that this sample measurement stopped ST_MSTMsg MsgSmpStop = new ST_MSTMsg(m_ThreadStatus); MsgSmpStop.InitThreadStoppedMsg(); SendMessageToMeasureGUI(MsgSmpStop); ThreadOver(); break; } if (pSample.GetMsrStatus().GetStatus() == OTS_MSR_SAMPLE_STATUS.FAILED) { // measurement failed m_ThreadStatus.SetStatus(OTS_MSR_THREAD_STATUS.FAILED); // record end time m_ThreadStatus.ComputeTime(OTS_THREAD_TIME_TYPE.STOPPED); // update thread measure status class, let the main thread know that this sample measurement failed ST_MSTMsg MsgSmpFailed=new ST_MSTMsg(m_ThreadStatus); MsgSmpFailed.InitThreadFailedMsg(); SendMessageToMeasureGUI(MsgSmpFailed); ThreadOver(); return; } // update thread measure status class, let the main thread know that this sample measurement successes ST_MSTMsg MsgSmpSuccess = new ST_MSTMsg(m_ThreadStatus); MsgSmpSuccess.InitThreadSucceedMsg(); SendMessageToMeasureGUI(MsgSmpSuccess); // continue to the next sample listMeasuredSamples.Add(pSample.GetName()); } // measurement completed m_ThreadStatus.SetStatus(OTS_MSR_THREAD_STATUS.COMPLETED); // record end time m_ThreadStatus.ComputeTime(OTS_THREAD_TIME_TYPE.STOPPED); ThreadOver(); } // hole preview public void DoHolePreview() { // start measurement, creat thread measure status class, let the main thread know that measurement started // set measure status to in-process //record time m_ThreadStatus.ComputeTime(OTS_THREAD_TIME_TYPE.START); DateTime timeStart = m_ThreadStatus.GetStartTime(); ST_MSTMsg MsgMsrStart = new ST_MSTMsg(m_ThreadStatus); MsgMsrStart.InitHolePreThreadInProcessMsg(); SendHolePreviewMessageToMeasureGUI(MsgMsrStart); // connect hardware if (!m_SemController.Connect()) { // failed to connect hardware SetMsrLoopStatus(otsdataconst.OTS_MSR_THREAD_STATUS.FAILED); m_ThreadStatus.ComputeTime(OTS_THREAD_TIME_TYPE.STOPPED); HolePreviewThreadOver(); } var a_pMeasureArea = m_pProjData.GetWorkingSample().GetMsrDomain(); COTSSample pSampleHole = CreateHoleSample(a_pMeasureArea); // create a sample measure object for the sample CSmplMeasure pSmplMeasure = new CSmplMeasure(m_strWorkingFolder, m_pProjData.GetWorkingSample()); // set measure thread pSmplMeasure.SetMsrThread(this); // update thread measure status class, let the main thread know that this sample measurement starts pSmplMeasure.SetHolePreviewSample(pSampleHole); // do measure pSmplMeasure.DoHolePreview(); // check if measurement is successful if (pSampleHole.GetMsrStatus().GetStatus() == OTS_MSR_SAMPLE_STATUS.STOPPED) { // record end time m_ThreadStatus.ComputeTime(OTS_THREAD_TIME_TYPE.STOPPED); // measurement stopped 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_ThreadStatus); MsgSmpStop.InitHolePreThreadStoppedMsg(); SendHolePreviewMessageToMeasureGUI(MsgSmpStop); HolePreviewThreadOver(); return; } else if (pSampleHole.GetMsrStatus().GetStatus() == OTS_MSR_SAMPLE_STATUS.FAILED) { // measurement failed SetMsrLoopStatus(otsdataconst.OTS_MSR_THREAD_STATUS.FAILED); // record end time m_ThreadStatus.ComputeTime(OTS_THREAD_TIME_TYPE.STOPPED); // update thread measure status class, let the main thread know that this sample measurement failed ST_MSTMsg MsgSmpFailed = new ST_MSTMsg(m_ThreadStatus); MsgSmpFailed.InitHolePreThreadFailedMsg(); SendHolePreviewMessageToMeasureGUI(MsgSmpFailed); HolePreviewThreadOver(); return; } // record end time m_ThreadStatus.ComputeTime(OTS_THREAD_TIME_TYPE.STOPPED); // update thread measure status class, let the main thread know that this sample measurement successes ST_MSTMsg MsgSmpSuccess = new ST_MSTMsg(m_ThreadStatus); MsgSmpSuccess.InitHolePreThreadSucceedMsg(); SendHolePreviewMessageToMeasureGUI(MsgSmpSuccess); // measurement completed SetMsrLoopStatus(otsdataconst.OTS_MSR_THREAD_STATUS.COMPLETED); // record end time m_ThreadStatus.ComputeTime(OTS_THREAD_TIME_TYPE.STOPPED); HolePreviewThreadOver(); } public COTSSample CreateHoleSample(CDomain a_pMsrArea) { COTSSample pHoleSample = new COTSSample(); pHoleSample.SetMsrDomain(a_pMsrArea); // get min magnification CSEMStageData pSEMStageData = m_pProjData.GetSEMStageData(); double dMinMag = pSEMStageData.GetMinMag(); // get scan field size 100 int nScanFieldSize100 = pSEMStageData.GetScanFieldSize100(); // get working distance double dWorkingDistance = 0.0; if (!GetSEMWorkingDistanceFromHW(ref dWorkingDistance)) { return null; } CSEMDataMsr poSEMDataMsr = new CSEMDataMsr(); poSEMDataMsr.SetScanFieldSize100(nScanFieldSize100); poSEMDataMsr.SetWorkingDistance(dWorkingDistance); poSEMDataMsr.SetMagnification(dMinMag); pHoleSample.SetSEMDataMsr(poSEMDataMsr); // Set image scan param COTSImgScanPrm poImageScanParam = new COTSImgScanPrm(); poImageScanParam.SetStopMode(((int)OTS_MEASURE_STOP_MODE.CoverMode).ToString()); poImageScanParam.SetStartImageMode(OTS_GET_IMAGE_MODE.Zshape); poImageScanParam.SetScanImageSpeed(OTS_IMAGE_SCANSPEED_OPTIONS.low); CSampleParam poMsrParams = pHoleSample.GetMsrParams(); poImageScanParam.SetImageResulotion(GetListMeasurableSamples()[0].GetMsrParams().GetImageScanParam().GetImageResulotion());//由于各样品分辨率应该一致,故此处没有读取选取的特定样品孔样品 poMsrParams.SetImageScanParam(poImageScanParam); pHoleSample.SetMsrParams(poMsrParams); return pHoleSample; } public bool GetSEMWorkingDistanceFromHW(ref double a_dWorkingDistance) { m_SemController.GetWorkingDistance(ref a_dWorkingDistance); return true; } // measure status public void SetMsrLoopStatus(otsdataconst.OTS_MSR_THREAD_STATUS a_nMsrLoopStatus) { m_ThreadStatus.SetStatus( a_nMsrLoopStatus); } } }