| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542 | using System.Collections.Generic;using OTSDataType;using System;using System.Drawing;using static OTSDataType.otsdataconst;using OTSModelSharp.ImageProcess;using OTSModelSharp.ServiceInterface;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<Point> 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 CMsrThread    {              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;        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 CMsrThread()        {                     m_strWorkingFolder = "";            m_ThreadStatus = new CMsrThreadStatus();                                m_SemController = new SemController();                   }                   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;            m_listMeasurableSamples = 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.ToShortDateString();                      ProgressEvent(MsrMsg);        }        void SetWorkingFolderStr()        {            // 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            string  strWorkingFolder =FileHelper.GetFolderName(strSettingFilePathName);            // set working folder string            m_strWorkingFolder = strWorkingFolder;            // ok, return TRUE            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             SortedDictionary<string , CSmplMeasure> mapSmplMsr=new SortedDictionary<string, CSmplMeasure>();//use this map to hold all the smplMeasure object                        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            SetWorkingFolderStr();                         List <string >  listMeasuredSamples = m_ThreadStatus.GetCompletedSamples();            // 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;                }                if (!pSample.GetSwitch())                {                    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.CleanlinessA:                            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.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();                    return;                }			    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;			    }               // 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;                       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();	}        // hole preview       public  void DoHolePreview(int a_nHoleID, CDomain a_pMeasureArea)        {            // 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();            int iYear = timeStart.DayOfYear;            int imonth = timeStart.Month;            int iDay = timeStart.Day;            int iHour = timeStart.Hour;            int iMin = timeStart.Minute;            int iSec = timeStart.Second;            String csTime;            string.Format("%04d-%02d-%02d %02d:%02d:%02d", iYear, imonth, iDay, iHour, iMin, iSec);            ST_MSTMsg MsgMsrStart = new ST_MSTMsg();           /// memset(&MsgMsrStart, 0, sizeof(ST_MSTMsg));            MsgMsrStart.iMsgType = ENUM_MSG_TYPE.MTHREADSTATUS;            MsgMsrStart.STMThreadStu.iMsrStatu =OTS_MSR_THREAD_STATUS.INPROCESS;           // strcpy(MsgMsrStart.STMThreadStu.cMsrStartTime, csTime);            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);                ThreadOver();            }           	                        COTSSample pSampleHole = CreateHoleSample(a_pMeasureArea);            // create a sample measure object for the sample            CSmplMeasure pSmplMeasure = new CSmplMeasureCleanliness(m_strWorkingFolder,pSampleHole);                      // 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(pSampleHole);            pSmplMeasure.SetWorkingFolder(m_strWorkingFolder);            // do measure            pSmplMeasure.DoHolePreview(a_nHoleID);            // 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);                ThreadOver();                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);                ThreadOver();                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);            ThreadOver();        }      public  COTSSample CreateHoleSample(CDomain a_pMsrArea)        {                        COTSSample pHoleSample = new COTSSample();            pHoleSample.SetMsrArea(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(OTS_MEASURE_STOP_MODE.CoverMode);            poImageScanParam.SetStartImageMode(OTS_GET_IMAGE_MODE.FROM_CENTER);            poImageScanParam.SetScanImageSpeed(OTS_THREE_TIES_OPTIONS.TIE1);            poImageScanParam.SetImagePixelSize(OTS_FIVE_TIES_OPTIONS.TIE1);            CSampleParam poMsrParams = pHoleSample.GetMsrParams();                       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)        {            if (a_nMsrLoopStatus >= otsdataconst.OTS_MSR_THREAD_STATUS.MIN && a_nMsrLoopStatus <= otsdataconst.OTS_MSR_THREAD_STATUS.MAX)            {                m_ThreadStatus.SetStatus( a_nMsrLoopStatus);            }        }        }}
 |