// MsrThread.cpp : implementation file #include "stdafx.h" #include "resource.h" #include "MsrThread.h" #include "FieldMgr.h" #include "StageFile.h" #include "COTSHardwareMgr.h" #include "SmplMeasureInc.h" #include "STDFileMgr.h" #include "DlgCheckParamResult.h" #include "OTSHelper.h" #include "OTSClassifyEng.h" #include "boost\scope_exit.hpp" #include "MultiLang.h" namespace OTSMODEL { using namespace OTSController; CMsrThread::CMsrThread() { m_hWnd = NULL; Init(); } CMsrThread::CMsrThread(CMsrThread* a_poSource) { // input check ASSERT(a_poSource); if (!a_poSource) { return; } // can't copy itself if (a_poSource == this) { return; } // copy data over Duplicate(*a_poSource); } CMsrThread::~CMsrThread() { } // init BOOL CMsrThread::Init(COTSProjMgrFilePtr a_pProjMgrFile, COTSSamplesList a_listMeasuableSamples) { // check project file if (!a_pProjMgrFile) { LogErrorTrace(__FILE__, __LINE__, _T("Init: invalide file pointer.")); return FALSE; } m_pProjMgrFile = a_pProjMgrFile; // set measure samples list // make sure samples in the input samples list are in the working file samples list // and this sample is switch on COTSSamplesList& listMeasuableSamples = m_pProjMgrFile->GetSampleList(); m_listMeasurableSamples.clear(); for (auto pSample : a_listMeasuableSamples) { /*for (auto pSampleNew : listMeasuableSamples) { if(*pSampleNew.get() == *pSample.get())*/ m_listMeasurableSamples.push_back(pSample); /*}*/ } // check measure samples list if (m_listMeasurableSamples.size() == 0) { LogErrorTrace(__FILE__, __LINE__, _T("Init: measure samples list is empty.")); return FALSE; } // ok, return TRUE return TRUE; } BOOL CMsrThread::Init(COTSProjMgrFilePtr a_pProjMgrFile) { // check project file if (!a_pProjMgrFile) { LogErrorTrace(__FILE__, __LINE__, _T("Init: invalide file pointer.")); return FALSE; } m_pProjMgrFile = a_pProjMgrFile; // ok, return TRUE return TRUE; } // measurement void CMsrThread::DoMeasure() { // start measurement, creat thread measure status class, let the main thread know that measurement started // set measure status to in-process //record time static std::map mapSmplMsr;//use this map to hold all the smplMeasure object m_pThreadStatus->ComputeTime(OTS_THREAD_TIME_TYPE::START); COleDateTime timeStart = m_pThreadStatus->GetStartTime(); int iYear = timeStart.GetYear(); int imonth = timeStart.GetMonth(); int iDay = timeStart.GetDay(); int iHour = timeStart.GetHour(); int iMin = timeStart.GetMinute(); int iSec = timeStart.GetSecond(); CString csTime; csTime.Format("%04d-%02d-%02d %02d:%02d:%02d", iYear, imonth, iDay, iHour, iMin, iSec); ST_MSTMsg MsgMsrStart; memset(&MsgMsrStart, 0, sizeof(ST_MSTMsg)); MsgMsrStart.iMsgType = ENUM_MSG_TYPE::MTHREADSTATUS; MsgMsrStart.STMThreadStu.iMThreadStatus = (int)OTS_MSR_THREAD_STATUS::INPROCESS; strcpy(MsgMsrStart.STMThreadStu.cMsrStartTime, csTime); SendMessageToMeasureApp(MsgMsrStart); //postlog.logLevel = PostLogLevel::info; SendLogMessageToMeasureApp(_T("Measurement started!"), PostLogLevel::info); // connect hardware if (!ConnectHardware()) { LogErrorTrace(__FILE__, __LINE__, _T("DoMeasure: failed to connect hardware.")); SetMsrLoopStatus(OTS_MSR_THREAD_STATUS::FAILED); m_pThreadStatus->ComputeTime(OTS_THREAD_TIME_TYPE::STOPPED); ThreadOver(); return; } // will be called before quit this method ON_SCOPE_EXIT([&]() { DisconnectHardware();// disconnect hardware } ); // set working directory which is the same directory of the setting file if (!SetWorkingFolderStr()) { // failed to call SetWorkingFolderStr method LogErrorTrace(__FILE__, __LINE__, _T("DoMeasure: failed to call SetWorkingFolderStr method.")); SetMsrLoopStatus(OTS_MSR_THREAD_STATUS::FAILED); // record end time m_pThreadStatus->ComputeTime(OTS_THREAD_TIME_TYPE::STOPPED); ThreadOver(); return; } // get SEM data general if (!GetSEMDataGnrFromHW()) { LogErrorTrace(__FILE__, __LINE__, _T("DoMeasure: failed to call GetSEMDataGnrFromHW method.")); SetMsrLoopStatus(OTS_MSR_THREAD_STATUS::FAILED); // record end time m_pThreadStatus->ComputeTime(OTS_THREAD_TIME_TYPE::STOPPED); ThreadOver(); return; } COTSSamplesList& listMeasuredSamples = m_pThreadStatus->GetCompletedSamples(); // got through measure list for (auto pSample : m_listMeasurableSamples) {// check and break if stop button is clicked if (IsMeasureStopped()) { // stop button clicked LogTrace(__FILE__, __LINE__, _T("DoMeasure: stop button is clicked.")); SetMsrLoopStatus(OTS_MSR_THREAD_STATUS::STOPPED); // record end time m_pThreadStatus->ComputeTime(OTS_THREAD_TIME_TYPE::STOPPED); ThreadOver(); return; } CSmplMeasurePtr pSmplMeasure; auto itr = mapSmplMsr.find(pSample->GetName()); if (itr == mapSmplMsr.end()) {// create a sample measure object for the sample pSmplMeasure=CSmplMeasurePtr(new CSmplMeasureInc(m_strWorkingFolder,pSample)); // set measure thread pSmplMeasure->SetMsrThread(this); mapSmplMsr[pSample->GetName ()] = pSmplMeasure; } else { auto smp1s = m_pProjMgrFile->GetSampleByName(pSample->GetName()); if (smp1s != nullptr) { //判断这个project中的sample是否已经测量过 if (pSample->GetMsrStatus()->GetCompletedFields() == 0) { pSmplMeasure = CSmplMeasurePtr(new CSmplMeasureInc(m_strWorkingFolder, pSample)); pSmplMeasure->SetMsrThread(this); mapSmplMsr[pSample->GetName()] = pSmplMeasure; } else { pSmplMeasure = mapSmplMsr[pSample->GetName()]; pSample->GetMsrStatus()->SetStatus(OTS_MSR_SAMPLE_STATUS::INPROCESS); SetMsrLoopStatus(OTSDATA::OTS_MSR_THREAD_STATUS::INPROCESS); } } else { pSmplMeasure = CSmplMeasurePtr(new CSmplMeasureInc(m_strWorkingFolder, pSample)); pSmplMeasure->SetMsrThread(this); mapSmplMsr[pSample->GetName()] = pSmplMeasure; } } CSTDItemsList& listSysSTDItem = m_pProjMgrFile->GetSysSTDItem(); pSmplMeasure->SetSysSTDItem(listSysSTDItem, TRUE); pSmplMeasure->DoMeasureOneSample(); // check if measurement is successful if (pSample->GetMsrStatus()->GetStatus() == OTS_MSR_SAMPLE_STATUS::STOPPED) {// record end time m_pThreadStatus->ComputeTime(OTS_THREAD_TIME_TYPE::STOPPED); // measurement stopped SetMsrLoopStatus(OTS_MSR_THREAD_STATUS::STOPPED); // update thread measure status class, let the main thread know that this sample measurement stopped ST_MSTMsg MsgSmpStop; memset(&MsgSmpStop, 0, sizeof(ST_MSTMsg)); MsgSmpStop.iMsgType = ENUM_MSG_TYPE::MSAMPLESTATUS; MsgSmpStop.STMSampleStu.iMeasureSampleStatus = (int)OTS_MSR_SAMPLE_STATUS::STOPPED; memcpy(MsgSmpStop.STMSampleStu.cSampleName, pSample->GetName(), sizeof(pSample->GetName())); SendMessageToMeasureApp(MsgSmpStop); ThreadOver(); return; } else if (pSample->GetMsrStatus()->GetStatus() == OTS_MSR_SAMPLE_STATUS::FAILED) { // measurement failed SetMsrLoopStatus(OTS_MSR_THREAD_STATUS::FAILED); // record end time m_pThreadStatus->ComputeTime(OTS_THREAD_TIME_TYPE::STOPPED); // update thread measure status class, let the main thread know that this sample measurement failed ST_MSTMsg MsgSmpFailed; memset(&MsgSmpFailed, 0, sizeof(ST_MSTMsg)); MsgSmpFailed.iMsgType = ENUM_MSG_TYPE::MSAMPLESTATUS; MsgSmpFailed.STMSampleStu.iMeasureSampleStatus = (int)OTS_MSR_SAMPLE_STATUS::FAILED; memcpy(MsgSmpFailed.STMSampleStu.cSampleName, pSample->GetName(), sizeof(pSample->GetName())); SendMessageToMeasureApp(MsgSmpFailed); ThreadOver(); continue;// this sample failed then goto next sample. } // record end time m_pThreadStatus->ComputeTime(OTS_THREAD_TIME_TYPE::STOPPED); // update thread measure status class, let the main thread know that this sample measurement successes ST_MSTMsg MsgSmpSuccess; memset(&MsgSmpSuccess, 0, sizeof(ST_MSTMsg)); MsgSmpSuccess.iMsgType = ENUM_MSG_TYPE::MSAMPLESTATUS; MsgSmpSuccess.STMSampleStu.iMeasureSampleStatus = (int)OTS_MSR_SAMPLE_STATUS::SUCCESSED; memcpy(MsgSmpSuccess.STMSampleStu.cSampleName, pSample->GetName(), sizeof(pSample->GetName())); SendMessageToMeasureApp(MsgSmpSuccess); // continue to the next sample listMeasuredSamples.push_back(pSample); } // measurement completed SetMsrLoopStatus(OTS_MSR_THREAD_STATUS::COMPLETED); // record end time m_pThreadStatus->ComputeTime(OTS_THREAD_TIME_TYPE::STOPPED); ThreadOver(); } // hole preview void CMsrThread::DoHolePreview(int a_nHoleID, CDomainPtr 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_pThreadStatus->ComputeTime(OTS_THREAD_TIME_TYPE::START); COleDateTime timeStart = m_pThreadStatus->GetStartTime(); int iYear = timeStart.GetYear(); int imonth = timeStart.GetMonth(); int iDay = timeStart.GetDay(); int iHour = timeStart.GetHour(); int iMin = timeStart.GetMinute(); int iSec = timeStart.GetSecond(); CString csTime; csTime.Format("%04d-%02d-%02d %02d:%02d:%02d", iYear, imonth, iDay, iHour, iMin, iSec); ST_MSTMsg MsgMsrStart; memset(&MsgMsrStart, 0, sizeof(ST_MSTMsg)); MsgMsrStart.iMsgType = ENUM_MSG_TYPE::MTHREADSTATUS; MsgMsrStart.STMThreadStu.iMThreadStatus = (int)OTS_MSR_THREAD_STATUS::INPROCESS; strcpy(MsgMsrStart.STMThreadStu.cMsrStartTime, csTime); SendMessageToMeasureApp(MsgMsrStart); // connect hardware if (!ConnectHardware()) { // failed to connect hardware LogErrorTrace(__FILE__, __LINE__, _T("DoHolePreview: failed to connect hardware.")); SetMsrLoopStatus(OTS_MSR_THREAD_STATUS::FAILED); m_pThreadStatus->ComputeTime(OTS_THREAD_TIME_TYPE::STOPPED); ThreadOver(); } // will be called before quit this method ON_SCOPE_EXIT([&]() { DisconnectHardware();// disconnect hardware } ); // Get SEM Message // create a sample with hole preview param // current ASSERT(a_pMeasureArea); if (!a_pMeasureArea) { LogErrorTrace(__FILE__, __LINE__, _T("DoHolePreview: invalid measure area.")); SetMsrLoopStatus(OTS_MSR_THREAD_STATUS::FAILED); // record end time m_pThreadStatus->ComputeTime(OTS_THREAD_TIME_TYPE::STOPPED); ThreadOver(); return; } COTSSamplePtr pSampleHole = CreateHoleSample(a_pMeasureArea); ASSERT(pSampleHole); if (!pSampleHole) { LogErrorTrace(__FILE__, __LINE__, _T("DoHolePreview: can't create sample for hole image.")); SetMsrLoopStatus(OTS_MSR_THREAD_STATUS::FAILED); // record end time m_pThreadStatus->ComputeTime(OTS_THREAD_TIME_TYPE::STOPPED); ThreadOver(); return; } // create a sample measure object for the sample CSmplMeasurePtr pSmplMeasure(new CSmplMeasureInc()); // set sample pSmplMeasure->SetSample(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->SetWorkingFolder(m_strWorkingFolder); // do measure pSmplMeasure->DoHolePreviewOneSample(a_nHoleID); // check if measurement is successful if (pSampleHole->GetMsrStatus()->GetStatus() == OTS_MSR_SAMPLE_STATUS::STOPPED) { // record end time m_pThreadStatus->ComputeTime(OTS_THREAD_TIME_TYPE::STOPPED); // measurement stopped SetMsrLoopStatus(OTS_MSR_THREAD_STATUS::STOPPED); // update thread measure status class, let the main thread know that this sample measurement stopped ST_MSTMsg MsgSmpStop; memset(&MsgSmpStop, 0, sizeof(ST_MSTMsg)); MsgSmpStop.iMsgType = ENUM_MSG_TYPE::MSAMPLESTATUS; MsgSmpStop.STMSampleStu.iMeasureSampleStatus = (int)OTS_MSR_SAMPLE_STATUS::STOPPED; memcpy(MsgSmpStop.STMSampleStu.cSampleName, pSampleHole->GetName(), sizeof(pSampleHole->GetName())); SendMessageToMeasureApp(MsgSmpStop); ThreadOver(); return; } else if (pSampleHole->GetMsrStatus()->GetStatus() == OTS_MSR_SAMPLE_STATUS::FAILED) { // measurement failed SetMsrLoopStatus(OTS_MSR_THREAD_STATUS::FAILED); // record end time m_pThreadStatus->ComputeTime(OTS_THREAD_TIME_TYPE::STOPPED); // update thread measure status class, let the main thread know that this sample measurement failed ST_MSTMsg MsgSmpFailed; memset(&MsgSmpFailed, 0, sizeof(ST_MSTMsg)); MsgSmpFailed.iMsgType = ENUM_MSG_TYPE::MSAMPLESTATUS; MsgSmpFailed.STMSampleStu.iMeasureSampleStatus = (int)OTS_MSR_SAMPLE_STATUS::FAILED; memcpy(MsgSmpFailed.STMSampleStu.cSampleName, pSampleHole->GetName(), sizeof(pSampleHole->GetName())); SendMessageToMeasureApp(MsgSmpFailed); ThreadOver(); return; } // record end time m_pThreadStatus->ComputeTime(OTS_THREAD_TIME_TYPE::STOPPED); // update thread measure status class, let the main thread know that this sample measurement successes ST_MSTMsg MsgSmpSuccess; memset(&MsgSmpSuccess, 0, sizeof(ST_MSTMsg)); MsgSmpSuccess.iMsgType = ENUM_MSG_TYPE::MSAMPLESTATUS; MsgSmpSuccess.STMSampleStu.iMeasureSampleStatus = (int)OTS_MSR_SAMPLE_STATUS::SUCCESSED; memcpy(MsgSmpSuccess.STMSampleStu.cSampleName, pSampleHole->GetName(), sizeof(pSampleHole->GetName())); SendMessageToMeasureApp(MsgSmpSuccess); // measurement completed SetMsrLoopStatus(OTS_MSR_THREAD_STATUS::COMPLETED); // record end time m_pThreadStatus->ComputeTime(OTS_THREAD_TIME_TYPE::STOPPED); ThreadOver(); } // SEM controller CSemBasePtr CMsrThread::GetSEMController() { // create a hardware manager ASSERT(m_pHardwareMgr); if (!m_pHardwareMgr) { // failed to create a hardware manager LogErrorTrace(__FILE__, __LINE__, _T("ConnectHardware: failed to create a hardware manager.")); return nullptr; } // get SEM, scanner and x-ray controller via hardware manager CSemBasePtr pSEMCtrlPtr = m_pHardwareMgr->GetSemControllerMgrPtr(); ASSERT(pSEMCtrlPtr); if (!pSEMCtrlPtr) { // failed to get SEM controller LogErrorTrace(__FILE__, __LINE__, _T("ConnectHardware: failed to get SEM controller.")); return nullptr; } return pSEMCtrlPtr; } // x-ray controller COTSEDSBasePtr CMsrThread::GetEDSController() { // create a hardware manager ASSERT(m_pHardwareMgr); if (!m_pHardwareMgr) { // failed to create a hardware manager LogErrorTrace(__FILE__, __LINE__, _T("ConnectHardware: failed to create a hardware manager.")); return nullptr; } // get SEM, scanner and x-ray controller via hardware manager COTSEDSBasePtr pEDSCtrlPtr = m_pHardwareMgr->GetEDSControllerPtr(); ASSERT(pEDSCtrlPtr); if (!pEDSCtrlPtr) { // failed to get SEM controller LogErrorTrace(__FILE__, __LINE__, _T("ConnectHardware: failed to get SEM controller.")); return nullptr; } return pEDSCtrlPtr; } // BSE controller COTSScanBasePtr CMsrThread::GetScanController() { // create a hardware manager ASSERT(m_pHardwareMgr); if (!m_pHardwareMgr) { LogErrorTrace(__FILE__, __LINE__, _T("ConnectHardware: failed to create a hardware manager.")); return nullptr; } // get SEM, scanner and x-ray controller via hardware manager COTSScanBasePtr pScanCtrlPtr = m_pHardwareMgr->GetScanControllerPtr(); ASSERT(pScanCtrlPtr); if (!pScanCtrlPtr) { LogErrorTrace(__FILE__, __LINE__, _T("ConnectHardware: failed to get SEM controller.")); return nullptr; } return pScanCtrlPtr; } // measure status void CMsrThread::SetMsrLoopStatus(OTS_MSR_THREAD_STATUS a_nMsrLoopStatus) { if (a_nMsrLoopStatus >= OTS_MSR_THREAD_STATUS::MIN && a_nMsrLoopStatus <= OTS_MSR_THREAD_STATUS::MAX) { m_pThreadStatus->SetStatus(a_nMsrLoopStatus); } } //check measure param //input: COTSProjMgrFilePtr a_pProjMgrFile : work file // COTSSamplesList& a_listMeasuableSamples : out put -- measure samples list // BOOL a_bCheckSetting : TRUE check settings BOOL CMsrThread::CheckMeasureParam(COTSProjMgrFilePtr a_pProjMgrFile, COTSSamplesList& a_listMeasuableSamples, BOOL a_bCheckSetting /*=TRUE*/) { // use the dll resource AFX_MANAGE_STATE(AfxGetStaticModuleState()); // safety check ASSERT(a_pProjMgrFile); if (!a_pProjMgrFile) { LogErrorTrace(__FILE__, __LINE__, _T("CheckMeasureParam: invalide file pointer")); return FALSE; } // go through the sample list to check setting parameters int nSwitchSmplNo = 0; int nCompletedSmplNo = 0; int nErrorSmplNo = 0; int nWarningSmplNo = 0; std::vector listSamplMessages; COTSSamplesList listSamples = a_pProjMgrFile->GetSampleList(); COTSSamplesList listMeasurableSamples; COTSSamplesList listWithWarningMeasurableSamples; for (auto pSample : listSamples) { // is the sample switch on if (pSample->GetSwitch()) { ++nSwitchSmplNo; CString strSmplMessage; strSmplMessage = pSample->GetName() + _T(":") + _T("\r\n"); // is this a measurement completed sample if (IsMeasureCompletedSmpl(pSample)) { // measurement completed sample ++nCompletedSmplNo; CString str = GetSampleErrorWarnString(SAMPLE_FAULT_WARN_CODE::FINISHED); strSmplMessage += str; strSmplMessage += _T("\r\n"); } else { // errors std::vector a_listErrorCodes; GetSampleErrorCodes(a_pProjMgrFile,pSample, a_listErrorCodes); if(!a_listErrorCodes.empty()) { // has error, this is not a measurable sample ++nErrorSmplNo; for (auto& nErrorCode : a_listErrorCodes) { CString str = GetSampleErrorWarnString(nErrorCode); strSmplMessage += str; strSmplMessage += _T("\r\n"); } } else { // no error, this is a measurable sample listMeasurableSamples.push_back(pSample); } // warnings std::vector a_listWarningCodes; GetSampleWarningCodes(a_pProjMgrFile, pSample, a_listWarningCodes); if (!a_listWarningCodes.empty()) { ++nWarningSmplNo; for (auto& nWarningCode : a_listWarningCodes) { CString str = GetSampleErrorWarnString(nWarningCode); strSmplMessage += str; strSmplMessage += _T("\r\n"); } // has no error? if (a_listErrorCodes.empty()) { // this is a measurable sample but with setting warnings listWithWarningMeasurableSamples.push_back(pSample); } } // no error and warning if (a_listErrorCodes.empty() && a_listWarningCodes.empty()) { CString str = GetSampleErrorWarnString(SAMPLE_FAULT_WARN_CODE::NO_ERROR_WARNING); strSmplMessage += str; strSmplMessage += _T("\r\n"); } } // add listSamplMessages.push_back(strSmplMessage); } } // dlg message string CString strDlgMessage; CString str; CString str1; str1 = MultiLang::GetInstance().GetCStringByKey(IDS_SAMPLE_CHECK_RESULT + (int)SAMPLE_CHECK_RESULT_TYPE::SWITCH_ON); str.Format(str1, nSwitchSmplNo); strDlgMessage += str; strDlgMessage += _T("\r\n"); // add more string if there switch on sample if (nSwitchSmplNo > 0) { // completed sample number (optional) if (nCompletedSmplNo > 0) { str1 = MultiLang::GetInstance().GetCStringByKey(IDS_SAMPLE_CHECK_RESULT + (int)SAMPLE_CHECK_RESULT_TYPE::FINISHED ); str.Format(str1, nCompletedSmplNo); strDlgMessage += str; strDlgMessage += _T("\r\n"); } // any unmeasured switch on samples? if(nSwitchSmplNo > nCompletedSmplNo) { // with setting error sample number str1=MultiLang::GetInstance ().GetCStringByKey (IDS_SAMPLE_CHECK_RESULT + (int)SAMPLE_CHECK_RESULT_TYPE::SETTING_ERROR); str.Format(str1, nErrorSmplNo); strDlgMessage += str; strDlgMessage += _T("\r\n"); // with setting warning sample number str1=MultiLang::GetInstance ().GetCStringByKey (IDS_SAMPLE_CHECK_RESULT + (int)SAMPLE_CHECK_RESULT_TYPE::SETTING_WARNING); str.Format(str1, nWarningSmplNo); strDlgMessage += str; strDlgMessage += _T("\r\n"); } // measurable sample numbers (has %d there) str=MultiLang::GetInstance ().GetCStringByKey (IDS_SAMPLE_CHECK_RESULT + (int)SAMPLE_CHECK_RESULT_TYPE::MEASURABLE); strDlgMessage += str; strDlgMessage += _T("\r\n"); } // add an empty line strDlgMessage strDlgMessage += _T("\r\n"); // add sample messages for (auto strSmplMessage : listSamplMessages) { strDlgMessage += strSmplMessage; strDlgMessage += _T("\r\n"); } // do we need to show dialog box? if(nSwitchSmplNo == 0) { LogErrorTrace(__FILE__, __LINE__, _T("CheckMeasureParam: measure button clicked but with no switch on samples.")); return FALSE; } // measure button clicked? if (a_bCheckSetting) { // there are measurable samples but no setting warnings samples if ((int)listMeasurableSamples.size() > 0 && (int)listWithWarningMeasurableSamples.size() == 0) { // set output measurable samples list for (auto pSample : listMeasurableSamples) { a_listMeasuableSamples.push_back(pSample); } return TRUE; } } //when there is sample setting error, and setting with no error and no warning samples, the dlg will not be show.?? //show the result dlg CDlgCheckParamResult dlg; int nTatolMeasuableSmplNo = (int)listMeasurableSamples.size(); int nWithWarningMeasuableSmplNo = (int)listWithWarningMeasurableSamples.size(); // set the dlg parameters dlg.SetCheckOnlyFlag(a_bCheckSetting); dlg.SetMessageBase(strDlgMessage); dlg.SetTatolMeasuableSmplNo(nTatolMeasuableSmplNo); dlg.SetWithWarningMeasuableSmplNo(nWithWarningMeasuableSmplNo); //no error not show dlg if (nTatolMeasuableSmplNo == nSwitchSmplNo - nCompletedSmplNo && listMeasurableSamples.size() != 0) { for (auto pSample : listMeasurableSamples) { auto itr = std::find(listWithWarningMeasurableSamples.begin(), listWithWarningMeasurableSamples.end(), pSample); if (itr == listWithWarningMeasurableSamples.end()) { a_listMeasuableSamples.push_back(pSample); } } m_listMeasurableSamples = a_listMeasuableSamples;//set the measureable samples to the member variable,so we can use it later. gsp. if (m_listMeasurableSamples.size() > 0) { return TRUE; } } //show dlg if (!(dlg.DoModal() == IDOK)) { // do something here return FALSE; } else { //if warnDo, back the listMeasuableSample if (dlg.GetWarnDo()) { for (auto pSample : listMeasurableSamples) { a_listMeasuableSamples.push_back(pSample); } } else // back with no warn sample { for (auto pSample : listMeasurableSamples) { auto itr = std::find(listWithWarningMeasurableSamples.begin(), listWithWarningMeasurableSamples.end(), pSample); if (itr == listWithWarningMeasurableSamples.end()) { a_listMeasuableSamples.push_back(pSample); } } } } m_listMeasurableSamples = a_listMeasuableSamples;//set the measureable samples to the member variable,so we can use it later. gsp. return true; } // protected // initialization void CMsrThread::Init() { m_pProjMgrFile = nullptr; m_listMeasurableSamples.clear(); m_strWorkingFolder = _T(""); m_pThreadStatus = CMsrThreadStatusPtr(new CMsrThreadStatus()); m_pSEMDataGnr = CSEMDataGnrPtr(new CSEMDataGnr()); m_strMAppFormName = _T(""); m_hWnd = NULL; } // SEM connection BOOL CMsrThread::ConnectHardware() { // create a hardware manager m_pHardwareMgr = COTSHardwareMgrPtr(new COTSHardwareMgr()); ASSERT(m_pHardwareMgr); if (!m_pHardwareMgr) { LogErrorTrace(__FILE__, __LINE__, _T("ConnectHardware: failed to create a hardware manager.")); return FALSE; } // get SEM, scanner and x-ray controller via hardware manager CSemBasePtr pSEMCtrlPtr = m_pHardwareMgr->GetSemControllerMgrPtr(); ASSERT(pSEMCtrlPtr); if (!pSEMCtrlPtr) { LogErrorTrace(__FILE__, __LINE__, _T("ConnectHardware: failed to get SEM controller.")); return FALSE; } // connect SEM controller if (!pSEMCtrlPtr->Connect()) { LogErrorTrace(__FILE__, __LINE__, _T("ConnectHardware: failed to connect SEM (%s)."), pSEMCtrlPtr->GetName()); DisconnectHardware(); return FALSE; } // get EDS controller COTSEDSBasePtr pOTSEDSController = m_pHardwareMgr->GetEDSControllerPtr(); ASSERT(pOTSEDSController); if (!pOTSEDSController) { LogErrorTrace(__FILE__, __LINE__, _T("ConnectHardware: failed to get EDS controller.")); DisconnectHardware(); return FALSE; } // init EDS controller if (!pOTSEDSController->Init()) { LogErrorTrace(__FILE__, __LINE__, _T("ConnectHardware: failed to inti EDS (%s)."), pOTSEDSController->GetName()); return FALSE; } // scanner COTSScanBasePtr pScanController = m_pHardwareMgr->GetScanControllerPtr(); ASSERT(pScanController); if (!pScanController) { LogErrorTrace(__FILE__, __LINE__, _T("ConnectHardware: failed to get scan controller.")); DisconnectHardware(); return FALSE; } // init Scan controller if (!pScanController->Init()) { LogErrorTrace(__FILE__, __LINE__, _T("ConnectHardware: failed to inti Scan (%s)."), pScanController->GetName()); DisconnectHardware(); return FALSE; } // ok, return TRUE return TRUE; } // release hardware controllers via system manager void CMsrThread::DisconnectHardware() { // create a hardware manager ASSERT(m_pHardwareMgr); if (!m_pHardwareMgr) { LogErrorTrace(__FILE__, __LINE__, _T("ConnectHardware: failed to create a hardware manager.")); return; } // get SEM, scanner and x-ray controller via hardware manager CSemBasePtr pSEMCtrlPtr = m_pHardwareMgr->GetSemControllerMgrPtr(); ASSERT(pSEMCtrlPtr); if (pSEMCtrlPtr) { pSEMCtrlPtr->Disconnect(); } // get EDS controller COTSEDSBasePtr pEDSCtrlPtr = m_pHardwareMgr->GetEDSControllerPtr(); ASSERT(pEDSCtrlPtr); if (pEDSCtrlPtr) { pEDSCtrlPtr->FinishedInstance(); } COTSScanBasePtr pScanCtrlPtr = m_pHardwareMgr->GetScanControllerPtr(); ASSERT(pScanCtrlPtr); if (pScanCtrlPtr) { pScanCtrlPtr->FinishedInstance(); } } // get error codes list of a sample void CMsrThread::GetSampleErrorCodes(COTSProjMgrFilePtr a_pProjMgrFile, COTSSamplePtr a_pSample, std::vector& a_listErrorCodes) { // safety check ASSERT(a_pSample); if (!a_pSample) { LogErrorTrace(__FILE__, __LINE__, _T("GetSampleErrorCodes: invalid sample pointer.")); return; } ASSERT(a_pProjMgrFile); if (!a_pProjMgrFile) { LogErrorTrace(__FILE__, __LINE__, _T("GetSampleErrorCodes: invalid project file pointer.")); return; } // check setting error if (*(a_pSample->GetSEMDataMsr().get()) == CSEMDataMsr()) { a_listErrorCodes.push_back(SAMPLE_FAULT_WARN_CODE::SEM_DATA_ERROR); } // file has not been saved CString strPathName = a_pProjMgrFile->GetPathName(); // is this a file no saved? strPathName.Trim(); if (strPathName.CompareNoCase(UNTITLED_FILE_NAME) == 0 || strPathName.IsEmpty()) { LogErrorTrace(__FILE__, __LINE__, _T("CheckProjFileSave: project has not been saved.")); a_listErrorCodes.push_back(SAMPLE_FAULT_WARN_CODE::FILE_NOT_SAVED); } // more error checking... } // get warning codes list of a sample void CMsrThread::GetSampleWarningCodes(COTSProjMgrFilePtr a_pProjMgrFile, COTSSamplePtr a_pSample, std::vector& a_listWarningCodes) { // safety check ASSERT(a_pProjMgrFile); if (!a_pProjMgrFile) { // invalid project file pointer LogErrorTrace(__FILE__, __LINE__, _T("GetSampleWarningCodes: invalid project file pointer.")); return; } ASSERT(a_pSample); if (!a_pSample) { // invalid sample pointer LogErrorTrace(__FILE__, __LINE__, _T("GetSampleWarningCodes: invalid sample pointer.")); return; } // check if the file is valid if(!a_pProjMgrFile->IsValid()) { // invalid project file LogErrorTrace(__FILE__, __LINE__, _T("GetSampleWarningCodes: invalid project file.")); return; } // check if the measure domain is cross the sample hole // get the work stage CStagePtr pStage = a_pProjMgrFile->GetStage(); //get hole CString sHoleName = a_pSample->GetSampleHoleName(); //look for the hole Domain CHolePtr pSampleHole = pStage->GetHoleByName(sHoleName); if(!pSampleHole) { // failed to get the sample hole LogErrorTrace(__FILE__, __LINE__, _T("GetSampleWarningCodes: failed to get the sample hole.")); return; } //// get the measure domain 2019-05-05 注释测量区域是否超越样品 //CDomainPtr pDomain = a_pSample->GetMsrArea(); //if (!pSampleHole->DomainInDomain(*pDomain.get())) //{ // //sample measure area has part outside the sample hole // a_listWarningCodes.push_back(SAMPLE_FAULT_WARN_CODE::AREA_OUTSIDE_HOLE); //} // resolution // can only check this if SEM measure data is set if (!(*(a_pSample->GetSEMDataMsr().get()) == CSEMDataMsr())) { // compute pixel size double dPixleSize = a_pSample->CalculatePixelSize(); // get min size COTSImageProcessParamPtr pImageProcParam = a_pSample->GetMsrParams()->GetImageProcessParam(); double dMinSize = (double)pImageProcParam->GetIncArea().GetStart(); // if pixel size bigger than 1/2 of the min size, current magnification can't see clear of the object if (dPixleSize >= dMinSize * 0.5) { // resolution low a_listWarningCodes.push_back(SAMPLE_FAULT_WARN_CODE::RESOLUTION_LOW); } } } // check sample a measurement completed BOOL CMsrThread::IsMeasureCompletedSmpl(COTSSamplePtr a_pSample) { // safety check ASSERT(a_pSample); if (!a_pSample) { // invalid sample pointer LogErrorTrace(__FILE__, __LINE__, _T("IsMeasureCompletedSmpl: invalid sample pointer.")); return FALSE; } if(a_pSample->GetMsrStatus()->GetStatus() != OTS_MSR_SAMPLE_STATUS::SUCCESSED) { LogTrace(__FILE__, __LINE__, _T("IsMeasureCompletedSmpl: sample has not been measured.")); return FALSE; } return TRUE; } // error/waring string CString CMsrThread::GetSampleErrorWarnString(SAMPLE_FAULT_WARN_CODE a_nSampleFaultWarn) { // switch to dll resource AFX_MANAGE_STATE(AfxGetStaticModuleState()); // check input if (a_nSampleFaultWarn < SAMPLE_FAULT_WARN_CODE::MIN && a_nSampleFaultWarn > SAMPLE_FAULT_WARN_CODE::MAX) { LogErrorTrace(__FILE__, __LINE__, _T("GetSampleErrorWarnString: wrong input error/waring string index (%d)."), (int)a_nSampleFaultWarn); return _T(""); } // error/waring string CString strErrorWarn; strErrorWarn=MultiLang::GetInstance ().GetCStringByKey (IDS_ERROR_WARNING + (int)a_nSampleFaultWarn); return strErrorWarn; } void CMsrThread::GetMeasureAppFormName(const CString& csFormName) { m_strMAppFormName = csFormName; } BOOL CMsrThread::SendMessageToMeasureApp(ST_MSTMsg Msg) { if (NULL == m_hWnd) { m_hWnd = ::FindWindow(NULL,m_strMAppFormName); if (NULL == m_hWnd) { LogErrorTrace(__FILE__, __LINE__, _T("(SendMessageToMeasureApp) FindWindow(NULL, m_MAppFormName=%s) failed"), m_strMAppFormName); return FALSE; } } ::SendMessage(m_hWnd, WM_MEASURE_MSG_ID, 0, (LPARAM)&Msg); return TRUE; } BOOL CMsrThread::SendLogMessageToMeasureApp(CString Msg, PostLogLevel postLogLevel) { if (NULL == m_hWnd) { m_hWnd = ::FindWindow(NULL, m_strMAppFormName); if (NULL == m_hWnd) { LogErrorTrace(__FILE__, __LINE__, _T("(PostMessageToMeasureApp) FindWindow(NULL, m_MAppFormName=%s) failed"), m_strMAppFormName); return FALSE; } } memset(&postlog, 0, sizeof(PostLogMessage)); this->postlog.logLevel = postLogLevel; int l = Msg.GetLength(); if (l > 100) { l = 100; } for (int i = 0; i < l; i++) { this->postlog.logMsg[i] = Msg.GetAt(i); } ::SendMessage(m_hWnd, WM_LOG_MSG_ID, 0, (LPARAM)&this->postlog); return TRUE; } void CMsrThread::SetProjMgrFile(COTSProjMgrFilePtr a_pProjMgrFile) { ASSERT(a_pProjMgrFile); if (!a_pProjMgrFile) { LogErrorTrace(__FILE__, __LINE__, _T("Set project manager file failed.")); return; } m_pProjMgrFile = a_pProjMgrFile; } // measurable sample list void CMsrThread::SetMeasurableSamples(COTSSamplesList& a_listMeasurableSamples) { for (auto pSample : a_listMeasurableSamples) { m_listMeasurableSamples.push_back(pSample); } } // SEM data general void CMsrThread::SetSEMDataGnr(CSEMDataGnrPtr a_pSEMDataGnr) { ASSERT(a_pSEMDataGnr); if (!a_pSEMDataGnr) { LogErrorTrace(__FILE__, __LINE__, _T("Set sem general data failed.")); return; } m_pSEMDataGnr = a_pSEMDataGnr; } void CMsrThread::SetMsrThreadStatus(CMsrThreadStatusPtr a_pThreadStatus) { ASSERT(a_pThreadStatus); if (!a_pThreadStatus) { LogErrorTrace(__FILE__, __LINE__, _T("Set thread status failed.")); return; } m_pThreadStatus = a_pThreadStatus; } // working folder string BOOL CMsrThread::SetWorkingFolderStr() { // get project file pathname CString strSettingFilePathName = m_pProjMgrFile->GetPathName(); strSettingFilePathName.Trim(); if (strSettingFilePathName.IsEmpty()) { LogErrorTrace(__FILE__, __LINE__, _T("SetWorkingFolderStr: project file pathname is an empty string")); return FALSE; } else if (strSettingFilePathName.CompareNoCase(UNTITLED_FILE_NAME) == 0) { LogErrorTrace(__FILE__, __LINE__, _T("SetWorkingFolderStr: project file pathname is an invalid string")); return FALSE; } // working folder string CString strWorkingFolder = COTSHelper::GetFolderName(strSettingFilePathName); strWorkingFolder.Trim(); if (strWorkingFolder.IsEmpty()) { // should be here. working folder string is an empty string LogErrorTrace(__FILE__, __LINE__, _T("SetWorkingFolderStr: working folder string is an empty string")); return FALSE; } // add "\\" at the string end if it is not "\\" if (strWorkingFolder.Right(1) != _T('\\')) { strWorkingFolder += _T("\\"); } // set working folder string m_strWorkingFolder = strWorkingFolder; // ok, return TRUE return TRUE; } COTSSamplePtr CMsrThread::CreateHoleSample(CDomainPtr a_pMsrArea) { // set measure area ASSERT(a_pMsrArea); if (!a_pMsrArea) { LogErrorTrace(__FILE__, __LINE__, _T("CreateHoleSample: invalid measure area pointer.")); return nullptr; } COTSSamplePtr pHoleSample = COTSSamplePtr(new COTSSample()); pHoleSample->SetMsrArea(a_pMsrArea); // set SEM measure data ASSERT(m_pProjMgrFile); if (!m_pProjMgrFile) { LogErrorTrace(__FILE__, __LINE__, _T("CreateHoleSample: invalid measure working project pointer.")); return nullptr; } // get min magnification CSEMStageDataPtr pSEMStageData = m_pProjMgrFile->GetSEMStageData(); double dMinMag = pSEMStageData->GetMinMag(); // get scan field size 100 int nScanFieldSize100 = pSEMStageData->GetScanFieldSize100(); // get working distance double dWorkingDistance = 0.0; if (!GetSEMWorkingDistanceFromHW(dWorkingDistance)) { LogErrorTrace(__FILE__, __LINE__, _T("CreateHoleSample: Can't get working distance.")); return nullptr; } CSEMDataMsrPtr poSEMDataMsr = CSEMDataMsrPtr(new CSEMDataMsr()); poSEMDataMsr->SetScanFieldSize100(nScanFieldSize100); poSEMDataMsr->SetWorkingDistance(dWorkingDistance); poSEMDataMsr->SetMagnification(dMinMag); pHoleSample->SetSEMDataMsr(poSEMDataMsr); // Set image scan param COTSImageScanParamPtr poImageScanParam = COTSImageScanParamPtr(new COTSImageScanParam()); 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); CMsrParamsPtr poMsrParams = pHoleSample->GetMsrParams(); ASSERT(poMsrParams); if (!poMsrParams) { LogErrorTrace(__FILE__, __LINE__, _T("CreateHoleSample: Can't get sample measure param.")); return nullptr; } poMsrParams->SetImageScanParam(poImageScanParam); pHoleSample->SetMsrParams(poMsrParams); return pHoleSample; } void CMsrThread::Duplicate(const CMsrThread& a_oSource) { // initialization Init(); // copy data over // measure file m_pProjMgrFile = a_oSource.m_pProjMgrFile; // measure samples list for (auto pSample : a_oSource.m_listMeasurableSamples) { COTSSamplePtr pSampleNew(new COTSSample(pSample.get())); m_listMeasurableSamples.push_back(pSampleNew); } // working folder string m_strWorkingFolder = a_oSource.m_strWorkingFolder; // measure loop status m_pThreadStatus = a_oSource.m_pThreadStatus; // SEM data general m_pSEMDataGnr = a_oSource.m_pSEMDataGnr; //MeasureAppFormName m_strMAppFormName = a_oSource.m_strMAppFormName; m_hWnd = a_oSource.m_hWnd; } BOOL CMsrThread::CheckProjFileSave() { ASSERT(m_pProjMgrFile); if (!m_pProjMgrFile) { LogErrorTrace(__FILE__, __LINE__, _T("CheckProjFileSave: project file is not saved.")); return FALSE; } // Save or Save As, if strPathName is not empty, it is exist in the computer, this is a save action CString strPathName = m_pProjMgrFile->GetPathName(); // is this a file no saved? strPathName.Trim(); if (strPathName.CompareNoCase(UNTITLED_FILE_NAME) == 0|| strPathName.IsEmpty()) { LogErrorTrace(__FILE__, __LINE__, _T("CheckProjFileSave: project has not been saved.")); // return save as result return FALSE; } return TRUE; } void CMsrThread::ThreadOver() { // end measurement, let the main thread know that measurement stopped COleDateTime timeEnd = m_pThreadStatus->GetEndTime(); int iYear = timeEnd.GetYear(); int imonth = timeEnd.GetMonth(); int iDay = timeEnd.GetDay(); int iHour = timeEnd.GetHour(); int iMin = timeEnd.GetMinute(); int iSec = timeEnd.GetSecond(); CString csTime; csTime.Format("%04d-%02d-%02d %02d:%02d:%02d", iYear, imonth, iDay, iHour, iMin, iSec); ST_MSTMsg MsgMsrExit; memset(&MsgMsrExit, 0, sizeof(ST_MSTMsg)); MsgMsrExit.iMsgType = ENUM_MSG_TYPE::MTHREADSTATUS; if (IsMeasureStopped()) { MsgMsrExit.STMThreadStu.iMThreadStatus = (int)OTS_MSR_THREAD_STATUS::STOPPED; } else if (IsMeasureFailed()) { MsgMsrExit.STMThreadStu.iMThreadStatus = (int)OTS_MSR_THREAD_STATUS::FAILED; } else if (IsMeasureRunning()) { MsgMsrExit.STMThreadStu.iMThreadStatus = (int)OTS_MSR_THREAD_STATUS::INPROCESS; } else if (IsMeasureCompleted()) { MsgMsrExit.STMThreadStu.iMThreadStatus = (int)OTS_MSR_THREAD_STATUS::COMPLETED; } strcpy(MsgMsrExit.STMThreadStu.cMsrEndTime, csTime); SendMessageToMeasureApp(MsgMsrExit); } // SEM data general BOOL CMsrThread::GetSEMDataGnrFromHW() { // safety check ASSERT(m_pSEMDataGnr); if (!m_pSEMDataGnr) { // should be here. invalid SEM data (general) LogErrorTrace(__FILE__, __LINE__, _T("GetSEMDataGnr: invalid SEM data (general).")); return FALSE; } // create a hardware manager ASSERT(m_pHardwareMgr); if (!m_pHardwareMgr) { // failed to create a hardware manager LogErrorTrace(__FILE__, __LINE__, _T("ConnectHardware: failed to create a hardware manager.")); return FALSE; } // get SEM, scanner and x-ray controller via hardware manager CSemBasePtr pSEMCtrlPtr = m_pHardwareMgr->GetSemControllerMgrPtr(); ASSERT(pSEMCtrlPtr); if (!pSEMCtrlPtr) { // failed to create a hardware manager LogErrorTrace(__FILE__, __LINE__, _T("ConnectHardware: failed to get SEM controller.")); return FALSE; } // get SEM controller if (!pSEMCtrlPtr->IsConnected()) { if (!pSEMCtrlPtr->Connect()) { // should be here. can't connect SEM LogErrorTrace(__FILE__, __LINE__, _T("GetSEMDataGnr: can't connect SEM.")); return FALSE; } } // get KV double dKV; if (!pSEMCtrlPtr->GetHighTension(dKV)) { LogErrorTrace(__FILE__, __LINE__, _T("GetSEMDataGnr: can't get work high voltage value .")); return FALSE; } m_pSEMDataGnr->SetKV(dKV); double dBrightness; if (!pSEMCtrlPtr->GetBrightness(dBrightness)) { LogErrorTrace(__FILE__, __LINE__, _T("GetSEMDataGnr: can't get brightness .")); return FALSE; } m_pSEMDataGnr->SetBrightness(dBrightness); double dContrast; if (!pSEMCtrlPtr->GetContrast(dContrast)) { LogErrorTrace(__FILE__, __LINE__, _T("GetSEMDataGnr: can't get dContrast.")); return FALSE; } m_pSEMDataGnr->SetContrast(dContrast); return TRUE; } BOOL CMsrThread::GetSEMWorkingDistanceFromHW(double& a_dWorkingDistance) { // create a hardware manager ASSERT(m_pHardwareMgr); if (!m_pHardwareMgr) { // failed to create a hardware manager LogErrorTrace(__FILE__, __LINE__, _T("GetSEMWorkingDistanceFromHW: failed to create a hardware manager.")); return FALSE; } // get SEM, scanner and x-ray controller via hardware manager CSemBasePtr pSEMCtrlPtr = m_pHardwareMgr->GetSemControllerMgrPtr(); ASSERT(pSEMCtrlPtr); if (!pSEMCtrlPtr) { LogErrorTrace(__FILE__, __LINE__, _T("GetSEMWorkingDistanceFromHW: failed to get SEM controller.")); return FALSE; } // get SEM controller if (!pSEMCtrlPtr->IsConnected()) { if (!pSEMCtrlPtr->Connect()) { LogErrorTrace(__FILE__, __LINE__, _T("GetSEMWorkingDistanceFromHW: can't connect SEM.")); return FALSE; } } double dWorkDis = 0; if (!pSEMCtrlPtr->GetWorkingDistance(a_dWorkingDistance)) { LogErrorTrace(__FILE__, __LINE__, _T("GetSEMWorkingDistanceFromHW: can't get working distance.")); return FALSE; } return TRUE; } BOOL CMsrThread::GetClassifyParticleId(CPartSTDDataPtr a_pPartSTDData, int steelTech, CElementChemistriesList& a_listElementChemistries, int& a_nIncId) { if (!COTSClassifyEng::ClassifyXray(a_pPartSTDData, (STEEL_TECHNOLOGY)steelTech, a_listElementChemistries, a_nIncId)) {// invalid x-ray pointer. LogErrorTrace(__FILE__, __LINE__, _T("ClassifyParticle: can't identify the particle as any inclusion.")); return FALSE; } if (a_nIncId < 8) { a_nIncId = (int)OTS_PARTCLE_TYPE::NOT_IDENTIFIED; } // ok, return TRUE return TRUE; } }