using System.Collections.Generic; using OTSDataType; using System; using System.Drawing; using static OTSDataType.otsdataconst; using OTSModelSharp.ImageProcess; using OTSModelSharp.ServiceInterface; using System.Threading; namespace OTSModelSharp { // enum and struct used for send message to App public enum ENUM_MSG_TYPE { MTHREADSTATUS = 1001, MSAMPLESTATUS = 1002, MSAMPLERESULT = 1003 }; public enum MSAMPLE_RET { BSE_DATA = 0, FIELD_DATA = 1, START_MSR_FIELD = 2 }; public struct SMSR_COMPLETE_DATA { public OTS_MSR_THREAD_STATUS MsrStatus; public string csMsrStartTime; public int iMsrCompleteSampleCount; public int iMsrCompleteFieldCount; public int iParticleCount; public TimeSpan MsrUsedTime; public string csMsrEndTime; }; public struct STMThreadStatus { public OTS_MSR_THREAD_STATUS iMsrStatu; //OTS_MSR_THREAD_STATUS public string csMsrStartTime; //MSR_START_TIME public string csMsrEndTime; //MSR_END_TIME public SMSR_COMPLETE_DATA SMsrCompleteData; }; public struct STMSampleStatus { public OTS_MSR_SAMPLE_STATUS iMsrSampleStatu; //OTS_MSR_SAMPLE_STATUS public string cSampleName; public string csSampleMsrStartTime; public List BCompleteFieldList; }; public struct STMSampleResultData { public MSAMPLE_RET iRetDataType; //ENUM_MEASURE_SAMPLE_RESULT public struct RBSEDATA { public System.Drawing.Point pos; public int iBSEDataHeight; public int iBSEDataWidth; public byte[] lpBSEData; }; public struct SAMPLEFIELDDATA { public System.Drawing.Point FieldPos; public int iMeasureFieldCount; public int iCompleteFieldCount; public int iSParticleCount; // Field particle count public TimeSpan TUsedTime; }; public struct StartToMsrField { public System.Drawing.Point FieldPos; }; public RBSEDATA BSEData; public SAMPLEFIELDDATA SFieldData; public StartToMsrField SMsrField; }; public struct ST_MSTMsg { public ENUM_MSG_TYPE iMsgType; public STMThreadStatus STMThreadStu; public STMSampleStatus STMSampleStu; public STMSampleResultData STMSampleRetData; }; public class CMeasure { private const string UNTITLED_FILE_NAME = "Untitled"; public delegate void ProgressEventHandler(ST_MSTMsg msg); public event ProgressEventHandler ProgressEvent; COTSMsrPrjResultData m_pProjData; List< COTSSample> m_listMeasurableSamples=new List(); string m_strWorkingFolder; CMsrThreadStatus m_ThreadStatus; SemController m_SemController;// there is no correspondense clr,so use this instead temporarilly 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() { DateTime timeEnd = m_ThreadStatus.GetEndTime(); ST_MSTMsg MsrMsg = new ST_MSTMsg(); MsrMsg.iMsgType = ENUM_MSG_TYPE.MTHREADSTATUS; MsrMsg.STMThreadStu.iMsrStatu = m_ThreadStatus.GetStatus(); MsrMsg.STMThreadStu.csMsrEndTime = timeEnd.ToString("yyyy-MM-dd HH:mm:ss"); ProgressEvent(MsrMsg); } void ThreadOverWithoutDisConnect() { DateTime timeEnd = m_ThreadStatus.GetEndTime(); ST_MSTMsg MsrMsg = new ST_MSTMsg(); MsrMsg.iMsgType = ENUM_MSG_TYPE.MTHREADSTATUS; MsrMsg.STMThreadStu.iMsrStatu = m_ThreadStatus.GetStatus(); MsrMsg.STMThreadStu.csMsrEndTime = timeEnd.ToString("yyyy-MM-dd HH:mm:ss"); ProgressEvent(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 SendMessageToMeasureApp(ST_MSTMsg msg) { ProgressEvent(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); DateTime timeStart = m_ThreadStatus.GetStartTime(); ST_MSTMsg MsgMsrStart=new ST_MSTMsg(); MsgMsrStart.iMsgType = ENUM_MSG_TYPE.MTHREADSTATUS; MsgMsrStart.STMThreadStu.iMsrStatu = OTS_MSR_THREAD_STATUS.INPROCESS; MsgMsrStart.STMThreadStu.csMsrStartTime = timeStart.ToShortDateString(); ProgressEvent (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.m_nPackId) { case OTS_SysType_ID.IncA: pSmplMeasure = new CSmplMeasureInclution(m_strWorkingFolder, pSample); break; case OTS_SysType_ID.CleannessA: pSmplMeasure = new CSmplMeasureCleanliness(m_strWorkingFolder, pSample); break; default: pSmplMeasure = new CSmplMeasureInclution(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); } pSmplMeasure.DoMeasureForOneSample(); // check if measurement is successful if (pSample.GetMsrStatus().GetStatus() == OTS_MSR_SAMPLE_STATUS.PAUSED) {// record end time m_ThreadStatus.SetStatus(OTS_MSR_THREAD_STATUS.PAUSED); 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(); MsgSmpStop.iMsgType = ENUM_MSG_TYPE.MSAMPLESTATUS; MsgSmpStop.STMThreadStu.iMsrStatu = OTS_MSR_THREAD_STATUS.PAUSED; MsgSmpStop.STMSampleStu.iMsrSampleStatu = OTS_MSR_SAMPLE_STATUS.PAUSED; MsgSmpStop.STMThreadStu.csMsrEndTime = DateTime.Now.ToShortDateString(); MsgSmpStop.STMThreadStu.iMsrStatu = OTS_MSR_THREAD_STATUS.PAUSED; ProgressEvent(MsgSmpStop); ThreadOver(); return; }else 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(); MsgSmpStop.iMsgType = ENUM_MSG_TYPE.MSAMPLESTATUS; MsgSmpStop.STMThreadStu.iMsrStatu= OTS_MSR_THREAD_STATUS.STOPPED; MsgSmpStop.STMSampleStu.iMsrSampleStatu = OTS_MSR_SAMPLE_STATUS.STOPPED; MsgSmpStop.STMThreadStu.csMsrEndTime = DateTime .Now .ToShortDateString(); MsgSmpStop.STMThreadStu.iMsrStatu= OTS_MSR_THREAD_STATUS.STOPPED; ProgressEvent(MsgSmpStop); ThreadOver(); break; } else 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(); MsgSmpFailed.iMsgType = ENUM_MSG_TYPE.MSAMPLESTATUS; MsgSmpFailed.STMSampleStu.iMsrSampleStatu = OTS_MSR_SAMPLE_STATUS.FAILED; ProgressEvent(MsgSmpFailed); ThreadOver(); return; } // update thread measure status class, let the main thread know that this sample measurement successes ST_MSTMsg MsgSmpSuccess = new ST_MSTMsg(); MsgSmpSuccess.iMsgType = ENUM_MSG_TYPE.MSAMPLESTATUS; MsgSmpSuccess.STMSampleStu.iMsrSampleStatu = OTS_MSR_SAMPLE_STATUS.SUCCESSED; ProgressEvent(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(); } //public bool DoReMeasure(List particles, int imgscanspeed_index, int xrayscanmode_index, int scantime_count) //{ // // got through measure list // foreach (var pSample in m_listMeasurableSamples) // { // // 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 false; // } // CSmplMeasure pSmplMeasure; // // create a sample measure object for the sample // switch (m_pProjData.m_nPackId) // { // case OTS_SysType_ID.IncA: // pSmplMeasure = new CSmplMeasureInclution(m_strWorkingFolder, pSample); // break; // case OTS_SysType_ID.CleannessA: // pSmplMeasure = new CSmplMeasureCleanliness(m_strWorkingFolder, pSample); // break; // default: // pSmplMeasure = new CSmplMeasureInclution(m_strWorkingFolder, pSample); // break; // } // // set measure thread // pSmplMeasure.SetMsrThread(this); // pSmplMeasure.DoMeasureForOneSample(); // } // // measurement completed // m_ThreadStatus.SetStatus(OTS_MSR_THREAD_STATUS.COMPLETED); // // record end time // m_ThreadStatus.ComputeTime(OTS_THREAD_TIME_TYPE.STOPPED); // ThreadOver(); // return true; //} // 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(); MsgMsrStart.iMsgType = ENUM_MSG_TYPE.MTHREADSTATUS; MsgMsrStart.STMThreadStu.iMsrStatu =OTS_MSR_THREAD_STATUS.INPROCESS; SendMessageToMeasureApp(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); ThreadOverWithoutDisConnect(); } var a_pMeasureArea = m_pProjData.GetWorkingSample().GetMsrDomain(); COTSSample pSampleHole = CreateHoleSample(a_pMeasureArea); var sample = m_pProjData.GetWorkingSample(); // create a sample measure object for the sample CSmplMeasure pSmplMeasure = new CSmplMeasure(m_strWorkingFolder, sample); // set measure thread pSmplMeasure.SetMsrThread(this); // update thread measure status class, let the main thread know that this sample measurement starts // set working folder string pSmplMeasure.SetSample(sample); pSmplMeasure.SetHolePreviewSample(pSampleHole); pSmplMeasure.SetWorkingFolder(m_strWorkingFolder); // 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(); MsgSmpStop.iMsgType = ENUM_MSG_TYPE.MSAMPLESTATUS; MsgSmpStop.STMSampleStu.iMsrSampleStatu = OTS_MSR_SAMPLE_STATUS.STOPPED; SendMessageToMeasureApp(MsgSmpStop); ThreadOverWithoutDisConnect(); 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(); MsgSmpFailed.iMsgType = ENUM_MSG_TYPE.MSAMPLESTATUS; MsgSmpFailed.STMSampleStu.iMsrSampleStatu = OTS_MSR_SAMPLE_STATUS.FAILED; SendMessageToMeasureApp(MsgSmpFailed); ThreadOverWithoutDisConnect(); 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(); MsgSmpSuccess.iMsgType = ENUM_MSG_TYPE.MSAMPLESTATUS; MsgSmpSuccess.STMSampleStu.iMsrSampleStatu = OTS_MSR_SAMPLE_STATUS.SUCCESSED; SendMessageToMeasureApp(MsgSmpSuccess); // measurement completed SetMsrLoopStatus(otsdataconst.OTS_MSR_THREAD_STATUS.COMPLETED); // record end time m_ThreadStatus.ComputeTime(OTS_THREAD_TIME_TYPE.STOPPED); ThreadOverWithoutDisConnect(); } 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.FROM_CENTER); poImageScanParam.SetScanImageSpeed(OTS_IMAGE_SCANSPEED_OPTIONS.low); //poImageScanParam.SetImagePixelSize(OTS_FIVE_TIES_OPTIONS.TIE1); 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); } } }