#include "stdafx.h" #include "PZMedicalCtrl.h" #include "CCOS.Dev.FPD.PZMedical.h" extern Log4CPP::Logger* gLogger; PZMedicalCtrl* g_pDetector = nullptr; #define LOAD_PROC_ADDRESS(handle,func) \ if ((API_##func = (Func_##func)GetProcAddress(handle, #func)) == NULL) { Error("Error occurs while loading entry point!!! \r\n'{$}'\n", #func); }\ const int g_nRefreshTimeout = 5000; #define GET_IMG_WAIT_TIME 9000 PZMedicalCtrl::PZMedicalCtrl() :m_pXWindowoffThread(nullptr), m_hWindowOffEvent(nullptr), m_fFrameRate(0.0f) { m_pDPC2PanelID = new map(); m_pPanelID2DPC = new map(); m_strWorkPath = ""; m_strSDKWorkDir = ""; m_nPanelCount = 0; m_nDetectorID = 0; m_nCurrentPanelID = 0; m_eSyncMode = SYNC_HARDWARE; //默认使用硬同步 m_pRawImgBuffer = nullptr; m_pImgBuffer = nullptr; m_pFluFrameBuffer = nullptr; //m_nImageWidth = 0; //m_nImageHeight = 0; //m_nWidthOffset = 0; //m_nHeightOffset = 0; m_hStatusMonitorThread = nullptr; m_hExitStatusMonitorEvent = nullptr; m_hStatusMonitorToggleEvent = nullptr; m_nFrmHeaderLen = 0; m_nRawImgWidth = 0; m_nRawImgHeight = 0; m_nExamMode = APP_STATUS_IDLE; m_bSaveRaw = false; m_eCaliType = CCOS_CALIBRATION_TYPE_NONE; m_bAbortOffset = false; m_nGainNodeCount = 0; m_nGainNodeIndex = 0; m_nGainExpCount = 0; m_nGainExpIndex = 0; m_FluFrameNum = 0; m_bGrabStatus = false; m_bDetectorReady = false; m_nLogicMode = 0; m_nXWindowTime = 500; m_bAutoOffsetMode = false; m_bOffsetDone = false; m_hFPDScanThread = nullptr; m_hStopScanEvent = CreateEvent(NULL, FALSE, FALSE, NULL); m_hAcqEvent = CreateEvent(NULL, FALSE, FALSE, NULL); m_hProcessImgEvent = CreateEvent(NULL, FALSE, FALSE, NULL); m_hXWinOnEvent = CreateEvent(NULL, FALSE, FALSE, NULL); m_hGainEvent = CreateEvent(NULL, FALSE, FALSE, NULL); m_hDarkEvent = CreateEvent(NULL, FALSE, FALSE, NULL); m_hInitEvent = CreateEvent(NULL, FALSE, FALSE, NULL); m_hArrayEvent[0] = m_hStopScanEvent; m_hArrayEvent[1] = m_hAcqEvent; m_hArrayEvent[2] = m_hProcessImgEvent; m_hArrayEvent[3] = m_hXWinOnEvent; m_hArrayEvent[4] = m_hDarkEvent; m_hArrayEvent[5] = m_hGainEvent; m_hArrayEvent[6] = m_hInitEvent; m_hToggleEvent = CreateEvent(NULL, FALSE, FALSE, NULL); m_hRespond = CreateEvent(NULL, FALSE, FALSE, NULL); m_hAcqReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL); m_hGainReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL); m_hPZModule = nullptr; } PZMedicalCtrl::~PZMedicalCtrl() { if (m_hStopScanEvent) { CloseHandle(m_hStopScanEvent); m_hStopScanEvent = nullptr; } if (m_hAcqEvent) { CloseHandle(m_hAcqEvent); m_hAcqEvent = nullptr; } if (m_hGainEvent) { CloseHandle(m_hGainEvent); m_hGainEvent = nullptr; } if (m_hDarkEvent) { CloseHandle(m_hDarkEvent); m_hDarkEvent = nullptr; } if (m_hInitEvent) { CloseHandle(m_hInitEvent); m_hInitEvent = nullptr; } if (m_hRespond) { CloseHandle(m_hRespond); m_hRespond = nullptr; } if (m_hAcqReadyEvent) { CloseHandle(m_hAcqReadyEvent); m_hAcqReadyEvent = nullptr; } if (m_hGainReadyEvent) { CloseHandle(m_hGainReadyEvent); m_hGainReadyEvent = nullptr; } if (m_hToggleEvent) { CloseHandle(m_hToggleEvent); m_hToggleEvent = nullptr; } if (m_pRawImgBuffer) { delete[] m_pRawImgBuffer; m_pRawImgBuffer = nullptr; } if (m_pImgBuffer != nullptr) { delete[] m_pImgBuffer; m_pImgBuffer = nullptr; } if (m_pFluFrameBuffer != nullptr) { delete[] m_pFluFrameBuffer; m_pFluFrameBuffer = nullptr; } } bool PZMedicalCtrl::DriverEntry(FPDDevicePZMedical* pDrvDPC, ResDataObject& Configuration) { Info("--Func-- DriverEntry {$}", (int)pDrvDPC); map::iterator DPCsIter = m_pDPC2PanelID->find(pDrvDPC); if (DPCsIter != m_pDPC2PanelID->end()) { printf("This DPC already exist\n"); Error("This DPC already exist"); return false; } m_pDPC2PanelID->insert(pair(pDrvDPC, m_nPanelCount)); m_pPanelID2DPC->insert(pair(m_nPanelCount, pDrvDPC)); m_nPanelCount++; m_ModeConfig = Configuration; //记录配置 --目前只有一个平板,多板时应该分别存储 //Debug("Config: {$}", m_ModeConfig.encode()); return true; } bool PZMedicalCtrl::Connect(FPDDevicePZMedical* pDrvDPC, const char* szWorkPath) { Info("Connect detector begin"); if ((*m_pDPC2PanelID)[pDrvDPC] != m_nCurrentPanelID) { Debug("Not current DPC, return true"); return true; } m_strWorkPath = szWorkPath; if (!LoadDll(szWorkPath)) { return false; } if (nullptr == m_hFPDScanThread) { unsigned uThreadId; _beginthreadex(NULL, 0, onFPDScanThread, this, 0, &uThreadId); m_hFPDScanThread = OpenThread(THREAD_ALL_ACCESS, TRUE, uThreadId); } SetEvent(m_hInitEvent); Info("Connect over"); return true; } //断连探测器 bool PZMedicalCtrl::Disconnect() { Info("Disconnect begin"); ResetEvent(m_hToggleEvent); SetEvent(m_hStopScanEvent); //关闭Scan线程 DWORD dwResult = WaitForSingleObject(m_hToggleEvent, 65000); if (dwResult == WAIT_OBJECT_0) { Info("Leave scan thread over"); } else if (dwResult == WAIT_TIMEOUT) { Warn("Kill time out"); } DisconnectDetector(0); FreeDll(); Info("Disconnect end"); return true; } //辅助线程 unsigned __stdcall PZMedicalCtrl::onFPDScanThread(PVOID pvoid) { PZMedicalCtrl* pOpr = (PZMedicalCtrl*)pvoid; Info("Enter scan thread"); bool bExit = false; while (!bExit) { DWORD dwRet = WaitForMultipleObjects(SCAN_EVENT_COUNT, pOpr->m_hArrayEvent, FALSE, INFINITE); if (WAIT_OBJECT_0 == dwRet) //m_hStopScanEvent { bExit = true; } else if (WAIT_OBJECT_0 + 1 == dwRet) //m_hAcqEvent { pOpr->OnAcquireImage(); } else if (WAIT_OBJECT_0 + 2 == dwRet) //m_hProcessImgEvent { pOpr->OnProcessImage(); } else if (WAIT_OBJECT_0 + 3 == dwRet) //m_hXWinOnEvent { Info("Get XWinOnEvent"); DWORD dwXrayOnT, dwXrayOffT; dwXrayOnT = dwXrayOffT = GetTickCount(); Info("xrayon: {$}", dwXrayOnT); pOpr->StatusFeedback(EVT_STATUS_PANEL, PANEL_XWINDOW_ON); while (dwXrayOffT - dwXrayOnT < 500) //窗口暂时写死 { dwXrayOffT = GetTickCount(); } Info("xrayoff: {$}", dwXrayOffT); pOpr->StatusFeedback(EVT_STATUS_PANEL, PANEL_XWINDOW_OFF); } else if (WAIT_OBJECT_0 + 4 == dwRet) //m_hDarkEvent { pOpr->OnRefreshOffset(); } else if (WAIT_OBJECT_0 + 5 == dwRet) //m_hGainEvent { pOpr->OnAcquireGainImage(); } else if (WAIT_OBJECT_0 + 6 == dwRet) //m_hInitEvent { pOpr->InitDetector(); } } SetEvent(pOpr->m_hToggleEvent); Info("Level scan thread"); return 0; } void PZMedicalCtrl::EnterExamMode(int nExamMode) { switch (nExamMode) { case APP_STATUS_WORK_BEGIN: Info("Enter Exam Windows"); m_nExamMode = APP_STATUS_WORK_BEGIN; break; case APP_STATUS_WORK_END: Info("Exit Exam Windows"); m_nExamMode = APP_STATUS_WORK_END; break; case APP_STATUS_DETSHARE_BEGIN: Info("Enter Detector Share Windows"); m_nExamMode = APP_STATUS_DETSHARE_BEGIN; break; case APP_STATUS_DETSHAR_END: m_nExamMode = APP_STATUS_IDLE; Info("Exit Detector Share Windows"); m_nExamMode = APP_STATUS_DETSHAR_END; break; case APP_STATUS_CAL_BEGIN: Info("Enter Calibration Windows"); m_nExamMode = APP_STATUS_CAL_BEGIN; break; case APP_STATUS_CAL_END: Info("Exit Calibration Windows"); m_nExamMode = APP_STATUS_CAL_END; break; case APP_STATUS_WORK_IN_SENSITIVITY: Info("Enter sensitivity test interface"); m_nExamMode = APP_STATUS_WORK_IN_SENSITIVITY; break; default: break; } if (APP_STATUS_WORK_END == nExamMode) { m_FluFrameNum = 0; ResetEvent(m_hAcqEvent); StopAcquisition(); } } /*** * 激活探测器 ***/ bool PZMedicalCtrl::ActiveDetector(int nDetectorID) { Info("## Active DetectorID: {$} ##", nDetectorID); //每一次选择一个view都要激活一次探测器。 m_FluFrameNum = 0; ResetEvent(m_hAcqEvent); StopAcquisition(); return true; } /*** ** 根据采集模式申请图像buffer ***/ bool PZMedicalCtrl::SetAcqMode(DetModeInfo DetModeInfo, DetCalibInfo DetCalibInfo, int nMode) { Info("## SetacqMode LogicMode: [{$}] ##", nMode); m_nLogicMode = nMode; m_stModeInfo = DetModeInfo; m_stCalibInfo = DetCalibInfo; m_FluFrameNum = 0; //初始值0 m_bGrabStatus = false; StopAcquisition(); //申请图像buffer if (nullptr != m_pRawImgBuffer) { delete[] m_pRawImgBuffer; m_pRawImgBuffer = nullptr; } m_pRawImgBuffer = new WORD[(size_t)m_stModeInfo.nRawImgWidth * (size_t)m_stModeInfo.nRawImgHeight]; if (nullptr != m_pImgBuffer) { delete[] m_pImgBuffer; m_pImgBuffer = nullptr; } m_pImgBuffer = new WORD[(size_t)m_stModeInfo.nImageHeight * (size_t)m_stModeInfo.nImageWidth]; Info("Current ExamType: {$}", m_stModeInfo.strExamType); Info("SetAcqMode, image width: {$}, image height:{$}", m_stModeInfo.nImageWidth, m_stModeInfo.nImageHeight); Info("Offset width: {$}, Offset height: {$}", m_stModeInfo.nWidthOffset, m_stModeInfo.nHeightOffset); //保存原图开关 m_bSaveRaw = m_stModeInfo.bIsSaveRaw; Info("Save rawdata: {$}", m_bSaveRaw ? "Yes" : "No"); //根据对应模式选择设置采集的模式 int nCfgID = Cfg_FLU; if (m_stModeInfo.strExamType.find("RAD") != std::string::npos) { nCfgID = Cfg_RAD; } int nModeID = m_stModeInfo.nOperationMode; if (!SetApplicationMode(nCfgID, nModeID)) { Error("Set Application Mode failed"); return false; } //加载默认采集模式校正 //LoadCalibrationFile(); return true; } bool PZMedicalCtrl::PrepareAcquisition(FPDDevicePZMedical* pDrvDPC) { if ((*m_pDPC2PanelID)[pDrvDPC] != m_nCurrentPanelID) { Error("Not current DPC, return"); return false; } Info("## PrepareAcquisition ##"); SetEvent(m_hAcqEvent); //准备采集 OnAcquireImage() DWORD dwWaitReadyTimeOut = 60000; //等待探测器Ready时间,默认一分钟 DWORD dwRet = WaitForSingleObject(m_hAcqReadyEvent, dwWaitReadyTimeOut); if (WAIT_OBJECT_0 == dwRet) { Info("AcqReady success"); } else if (WAIT_TIMEOUT == dwRet) { Error("AcqReady time out"); return false; } ResetEvent(m_hAcqReadyEvent); return true; } bool PZMedicalCtrl::StartAcquisition(FPDDevicePZMedical* pDrvDPC) { if ((*m_pDPC2PanelID)[pDrvDPC] != m_nCurrentPanelID) { Error("Not current DPC, return"); return false; } Info("## StartAcquisition ##"); BOOL nRet = FALSE; //硬同步依赖电气信号,不用做什么 //软同步 m_bGrabStatus = true; StatusFeedback(EVT_STATUS_PANEL, PANEL_XWINDOW_ON); if (m_stModeInfo.strExamType.find("RAD") != std::string::npos) //只有点片才发关窗终止Workflow { StartXWindowOffThread(); } return true; } bool PZMedicalCtrl::StopAcquisition(FPDDevicePZMedical* pDrvDPC) { if ((*m_pDPC2PanelID)[pDrvDPC] != m_nCurrentPanelID) { Error("Not current DPC, return"); return false; } Info("## StopAcquisition ##"); BOOL nRet = FALSE; Info("Call COM_Dexit"); nRet = API_COM_Dexit(); //停止采集,这里没有退出检查界面 if (TestError(nRet, "COM_Dexit")) { Error("Stop acquisition failed"); return false; } m_bGrabStatus = false; return true; } bool PZMedicalCtrl::StopAcquisition() { BOOL nRet = FALSE; Info("Call COM_Dexit"); nRet = API_COM_Dexit(); if (TestError(nRet)) { Error("Stop acquisition failed"); return false; } return true; } bool PZMedicalCtrl::ActiveCalibration(FPDDevicePZMedical* pDrvDPC, CCOS_CALIBRATION_TYPE eType) { if ((*m_pDPC2PanelID)[pDrvDPC] != m_nCurrentPanelID) { Error("Not current DPC, return"); return false; } m_nExamMode = APP_STATUS_CAL_BEGIN; //激活校正,置为校正界面 m_eCaliType = eType; if (CCOS_CALIBRATION_TYPE_XRAY == m_eCaliType) { m_nGainNodeIndex = 0; //激活校正,恢复初值 m_nGainExpIndex = 0; //激活校正,恢复初值 } return true; } //使探测器ready bool PZMedicalCtrl::PrepareCalibration(FPDDevicePZMedical* pDrvDPC) { if ((*m_pDPC2PanelID)[pDrvDPC] != m_nCurrentPanelID) { Error("Not current DPC, return"); return false; } SetEvent(m_hAcqEvent); //准备校正 return true; } //软同步调用接口,其它同步模式没有动作 bool PZMedicalCtrl::StartCalibration(FPDDevicePZMedical* pDrvDPC) { if ((*m_pDPC2PanelID)[pDrvDPC] != m_nCurrentPanelID) { Error("Not current DPC, return"); return false; } //未初始化、未连接 不执行 if (CCOS_CALIBRATION_TYPE_DARK) { SetEvent(m_hDarkEvent); } else if (CCOS_CALIBRATION_TYPE_XRAY) { // } return true; } bool PZMedicalCtrl::StopCalibration(FPDDevicePZMedical* pDrvDPC) { if ((*m_pDPC2PanelID)[pDrvDPC] != m_nCurrentPanelID) { Error("Not current DPC, return"); return false; } return true; } bool PZMedicalCtrl::ConfirmCalExposure() { m_nGainExpIndex++; //处理已接受和未曝光的标记位 if (m_nGainExpIndex == m_nGainExpCount) //当前剂量点的曝光次数已经够了 { m_nGainNodeIndex++; if (m_nGainNodeIndex == m_nGainNodeCount) //所有剂量点已经曝光完成 { //校正结束的处理 Info("Gain calibration finished! set exammode to cali end"); m_nExamMode = APP_STATUS_CAL_END; //增益结束,置为end StatusFeedback(EVT_STATUS_CALIBRATIOIN, PANEL_EVENT_END_OK); } } Debug("Exp index and count({$} {$}), note index and count({$} {$})", m_nGainExpIndex, m_nGainExpCount, m_nGainNodeIndex, m_nGainNodeCount); return true; } void PZMedicalCtrl::RejectCalExposure() { //暂时什么都不处理 } //加载SDK句柄 bool PZMedicalCtrl::LoadDll(string strWorkPath) { string strSDKPath = ""; try { strSDKPath = (string)m_ModeConfig["SDKPath"]; } catch (ResDataObjectExption& e) { Error("Read configuration failed, Error code: {$}", e.what()); return false; } string workpath = strWorkPath + "\\" + strSDKPath; m_strSDKWorkDir = workpath; string drvpath = workpath + "\\ComApi.dll"; ::SetDllDirectory(workpath.c_str()); m_hPZModule = ::LoadLibrary(drvpath.c_str()); if (m_hPZModule == nullptr) { DWORD dw = GetLastError(); Error("Load {$} failed: {$}", drvpath.c_str(), dw); return false; } LOAD_PROC_ADDRESS(m_hPZModule, COM_Init); LOAD_PROC_ADDRESS(m_hPZModule, COM_Uninit); LOAD_PROC_ADDRESS(m_hPZModule, COM_SetCfgFilePath); LOAD_PROC_ADDRESS(m_hPZModule, COM_List); LOAD_PROC_ADDRESS(m_hPZModule, COM_ListAdd); LOAD_PROC_ADDRESS(m_hPZModule, COM_ListDel); LOAD_PROC_ADDRESS(m_hPZModule, COM_Open); LOAD_PROC_ADDRESS(m_hPZModule, COM_Close); LOAD_PROC_ADDRESS(m_hPZModule, COM_StopNet); LOAD_PROC_ADDRESS(m_hPZModule, COM_StartNet); LOAD_PROC_ADDRESS(m_hPZModule, COM_RegisterEvCallBack); LOAD_PROC_ADDRESS(m_hPZModule, COM_SetPreCalibMode); LOAD_PROC_ADDRESS(m_hPZModule, COM_GetPreCalibMode); LOAD_PROC_ADDRESS(m_hPZModule, COM_SetCalibMode); LOAD_PROC_ADDRESS(m_hPZModule, COM_GetCalibMode); LOAD_PROC_ADDRESS(m_hPZModule, COM_HstAcq); LOAD_PROC_ADDRESS(m_hPZModule, COM_AedAcq); LOAD_PROC_ADDRESS(m_hPZModule, COM_Trigger); LOAD_PROC_ADDRESS(m_hPZModule, COM_Prep); LOAD_PROC_ADDRESS(m_hPZModule, COM_Acq); LOAD_PROC_ADDRESS(m_hPZModule, COM_PrepAcq); LOAD_PROC_ADDRESS(m_hPZModule, COM_SetAcq); LOAD_PROC_ADDRESS(m_hPZModule, COM_ComAcq); LOAD_PROC_ADDRESS(m_hPZModule, COM_ExposeReq); LOAD_PROC_ADDRESS(m_hPZModule, COM_AedTrigger); LOAD_PROC_ADDRESS(m_hPZModule, COM_AedPrep); LOAD_PROC_ADDRESS(m_hPZModule, COM_Aed2Acq); LOAD_PROC_ADDRESS(m_hPZModule, COM_Stop); LOAD_PROC_ADDRESS(m_hPZModule, COM_Dst); LOAD_PROC_ADDRESS(m_hPZModule, COM_Dacq); LOAD_PROC_ADDRESS(m_hPZModule, COM_Dacqaed); LOAD_PROC_ADDRESS(m_hPZModule, COM_Cbct); LOAD_PROC_ADDRESS(m_hPZModule, COM_Cbct2); LOAD_PROC_ADDRESS(m_hPZModule, COM_Dexit); LOAD_PROC_ADDRESS(m_hPZModule, COM_Dprep); LOAD_PROC_ADDRESS(m_hPZModule, COM_Cprep); LOAD_PROC_ADDRESS(m_hPZModule, COM_Exprep); LOAD_PROC_ADDRESS(m_hPZModule, COM_SetConfigId); LOAD_PROC_ADDRESS(m_hPZModule, COM_GetConfigId); LOAD_PROC_ADDRESS(m_hPZModule, COM_SetModeId); LOAD_PROC_ADDRESS(m_hPZModule, COM_GetModeId); LOAD_PROC_ADDRESS(m_hPZModule, COM_LoadFullCfg); LOAD_PROC_ADDRESS(m_hPZModule, COM_SaveFullCfg); LOAD_PROC_ADDRESS(m_hPZModule, COM_SetMetaData); LOAD_PROC_ADDRESS(m_hPZModule, COM_GetMetaData); LOAD_PROC_ADDRESS(m_hPZModule, COM_GetPreImg); LOAD_PROC_ADDRESS(m_hPZModule, COM_AedAcqOffLine); LOAD_PROC_ADDRESS(m_hPZModule, COM_AcqOffLineImage); LOAD_PROC_ADDRESS(m_hPZModule, COM_GetNumOffLineImg); LOAD_PROC_ADDRESS(m_hPZModule, COM_GetImageMode); LOAD_PROC_ADDRESS(m_hPZModule, COM_GetImageShiftMode); LOAD_PROC_ADDRESS(m_hPZModule, COM_GetImageName); LOAD_PROC_ADDRESS(m_hPZModule, COM_ClrImageID); LOAD_PROC_ADDRESS(m_hPZModule, COM_GetImageID); LOAD_PROC_ADDRESS(m_hPZModule, COM_GetImage); LOAD_PROC_ADDRESS(m_hPZModule, COM_ResetFP); LOAD_PROC_ADDRESS(m_hPZModule, COM_FpTurnOff); LOAD_PROC_ADDRESS(m_hPZModule, COM_GetErrNo); LOAD_PROC_ADDRESS(m_hPZModule, COM_SetFPConf); LOAD_PROC_ADDRESS(m_hPZModule, COM_GetFPConf); LOAD_PROC_ADDRESS(m_hPZModule, COM_SetRBConf); LOAD_PROC_ADDRESS(m_hPZModule, COM_GetRBConf); LOAD_PROC_ADDRESS(m_hPZModule, COM_LogPathSet); LOAD_PROC_ADDRESS(m_hPZModule, COM_GetFPsn); LOAD_PROC_ADDRESS(m_hPZModule, COM_GetDllVer); //LOAD_PROC_ADDRESS(m_hPZModule, ); return true; } //释放SDK句柄 bool PZMedicalCtrl::FreeDll() { Info("Free Dll"); if (m_hPZModule) { FreeLibrary(m_hPZModule); m_hPZModule = nullptr; } Info("Free over"); return true; } /*** ** 初始化探测器 ***/ bool PZMedicalCtrl::InitDetector() { Info("## InitDetector ##"); BOOL nRet = FALSE; //1.注册回调函数 Info("Call COM_RegisterEventCallBack: EVENT_LINKUP"); nRet = API_COM_RegisterEvCallBack(EVENT_LINKUP, ProcessEvent); if (TestError(nRet)) { Error("Call COM_RegisterEventCallBack: EVENT_LINKUP failed"); return false; } Info("Call RegisterImageCallBack: EVENT_LINKDOWN"); nRet = API_COM_RegisterEvCallBack(EVENT_LINKDOWN, ProcessEvent); if (TestError(nRet)) { Error("Call COM_RegisterEventCallBack: EVENT_LINKDOWN failed"); return false; } Info("Call RegisterEventCallBack: EVENT_IMAGEVALID"); nRet = API_COM_RegisterEvCallBack(EVENT_IMAGEVALID, ProcessEvent); if (TestError(nRet)) { Error("Call COM_RegisterEventCallBack: EVENT_IMAGEVALID failed"); return false; } Info("Call RegisterEventCallBack: EVENT_HEARTBEAT"); nRet = API_COM_RegisterEvCallBack(EVENT_HEARTBEAT, ProcessEvent); if (TestError(nRet)) { Error("Call COM_RegisterEventCallBack: EVENT_HEARTBEAT failed"); return false; } Info("Call RegisterEventCallBack: EVENT_OFFSETDONE"); nRet = API_COM_RegisterEvCallBack(EVENT_OFFSETDONE, ProcessEvent); if (TestError(nRet)) { Error("Call COM_RegisterEventCallBack: EVENT_OFFSETDONE failed"); return false; } Info("Call RegisterEventCallBack: EVENT_READY"); nRet = API_COM_RegisterEvCallBack(EVENT_READY, ProcessEvent); if (TestError(nRet)) { Error("Call COM_RegisterEventCallBack: EVENT_READY failed"); return false; } Info("Call RegisterEventCallBack: EVENT_EXPOSE"); nRet = API_COM_RegisterEvCallBack(EVENT_EXPOSE, ProcessEvent); if (TestError(nRet)) { Error("Call COM_RegisterEventCallBack: EVENT_EXPOSE failed"); return false; } Info("Call RegisterEventCallBack: EVENT_TrigErr"); nRet = API_COM_RegisterEvCallBack(EVENT_TrigErr, ProcessEvent); if (TestError(nRet)) { Error("Call COM_RegisterEventCallBack: EVENT_TrigErr failed"); return false; } //2.设置ini参数 Info("Call SetCfgFilePath"); nRet = API_COM_SetCfgFilePath((CHAR *)m_strSDKWorkDir.c_str()); if (TestError(nRet)) { Warn("Set SetCfgFilePath failed"); } //3.设置SDK日志路径 Info("Call SdkLog"); string strSDKLogPath = m_strWorkPath + "\\Logs"; nRet = API_COM_LogPathSet((CHAR *)strSDKLogPath.c_str()); if (TestError(nRet)) { Warn("Set SDKLog path failed"); } //4.初始化SDK Info("Call Init"); nRet = API_COM_Init(); if (TestError(nRet)) { Info("Init SDK failed"); return false; } //这里列出所有与PC建立连接的探测器 Info("Call List"); TComFpList stFPDList; nRet = API_COM_List(&stFPDList); if (TestError(nRet)) { Warn("List FPD failed"); } Info("List FPD number: {$}, SN: {$}", stFPDList.ncount, stFPDList.tFpNode[0].FPPsn); m_nDetectorID = 1; //5.连接探测器 if (!ConnectDetector(m_nDetectorID)) { Error("Connect detector {$} failed"); return false; } //6.连接之后设置pre和post校正模板策略 CHAR PreCalibMode = IMG_CALIB_OFFSET | IMG_CALIB_GAIN | IMG_CALIB_DEFECT; CHAR PostCalibMode = IMG_CALIB_RAW; if (!GetSetCalibMode(PreCalibMode, PostCalibMode)) { Warn("GetSetCalibMode failed"); } //7.获取图像information if (!GetImageInfo()) { Warn("Get image infomation failed"); } //开启状态监控线程, 直接用心跳回调 //OpenStatusMonitor(); return true; } //连接探测器 bool PZMedicalCtrl::ConnectDetector(int nDetectorID) { BOOL nRet = FALSE; //连接探测器 string strFPDSN = ""; try { strFPDSN = (string)m_ModeConfig["FPDSN"]; } catch (ResDataObjectExption& e) { Error("Read configuration failed, Error code: {$}", e.what()); return false; } Info("Call API_COM_Open, detector serial number: {$}", strFPDSN.c_str()); nRet = API_COM_Open((CHAR *)strFPDSN.c_str()); if (TestError(nRet, "COM_Open")) { Error("Open failed"); return false; } if (!WaitRespond(8000, "OpenDetector")) //8秒钟之内回调,否则视为超时 { Error("===== Connect detector failed: Timeout ====="); return false; } //获取探测器基本信息, 序列号和SDK版本 Info("Get detector infomation"); CHAR pszFpSN[32] = { '\0' }; CHAR pszSDKVer[32] = { '\0' }; nRet = API_COM_GetFPsn(pszFpSN); //nRet = API_COM_GetFPsnEx(0, pszFpSN); if (TestError(nRet)) { Warn("GetFPsn failed"); } nRet = API_COM_GetDllVer(pszSDKVer); if (TestError(nRet)) { Warn("Get Dll version failed"); } Info("FPD SN({$}), SDK Ver({$})", pszFpSN, pszSDKVer); ConfFeedback(EVT_CONF_PANEL_SERIAL, m_nCurrentPanelID, pszFpSN); //LinkUP到来之后,平板置于DST状态 Info("Call COM_Dst"); nRet = API_COM_Dst(); if (TestError(nRet)) { Error("Active Dst mode failed"); } return true; } //断开探测器 bool PZMedicalCtrl::DisconnectDetector(int nDetectorID) { BOOL nRet = FALSE; Info("Call COM_Stop"); nRet = API_COM_Stop(); if (TestError(nRet, "COM_Stop")) { Error("Stop command failed"); return false; } Info("Call COM_Close"); nRet = API_COM_Close(); if (TestError(nRet, "COM_Close")) { Error("Disconnect command failed"); return false; } return true; } /*** * 回调函数 ***/ BOOL CALLBACK PZMedicalCtrl::ProcessEvent(CHAR cEvent) { switch (cEvent) { case EVENT_LINKUP: { Info("Get callback: EVENT_LINKUP"); Info("Detector connected"); g_pDetector->GetRespond(); break; } case EVENT_LINKDOWN: { Info("Get callback: EVENT_LINKDOWN"); Info("Detector disconnected"); break; } case EVENT_BUSY: { Info("Get callback: EVENT_BUSY"); break; } case EVENT_CMDSTART: { Info("Get callback: EVENT_CMDSTART"); break; } case EVENT_IMAGEVALID: //收到探测器图片(仅trig上图相关的命令时才会触发) { Info("Get callback: EVENT_IMAGEVALID"); SetEvent(g_pDetector->m_hProcessImgEvent); //OnProcessImage() break; } case EVENT_EXPOSE: { Info("Get callback: EVENT_EXPOSE"); break; } case EVENT_OFFSETDONE: { Info("Get callback: EVENT_OFFSETDONE"); g_pDetector->GetRespond("RefreshOffset"); break; } case EVENT_HEARTBEAT: //心跳回调 { //Info("Get callback: EVENT_HEARTBEAT"); //日志过多不记入日志 //g_pDetector->; break; } case EVENT_TrigErr: { Info("Get callback: EVENT_TrigErr"); break; } default: Warn("Undefined callback event"); break; } return TRUE; } /*** * pre和post校正模板策略 ***/ bool PZMedicalCtrl::GetSetCalibMode(CHAR PreCalibMode, CHAR PostCalibMode) { Info("Get Set CalibMode, PreCalibMode: {$}, PostCalibMode: {$}", (int)PreCalibMode, (int)PostCalibMode); BOOL nRet = FALSE; CHAR CurrentPreCalibMode = API_COM_GetPreCalibMode(); //pre string strCurrentPreCalibMode = "Undefined"; switch (CurrentPreCalibMode) { case IMG_CALIB_RAW: strCurrentPreCalibMode = "raw"; break; case IMG_CALIB_OFFSET: strCurrentPreCalibMode = "offset"; break; case IMG_CALIB_GAIN: strCurrentPreCalibMode = "gain"; break; case IMG_CALIB_DEFECT: strCurrentPreCalibMode = "defect"; break; case (IMG_CALIB_OFFSET | IMG_CALIB_GAIN): strCurrentPreCalibMode = "offset+gain"; break; case (IMG_CALIB_OFFSET | IMG_CALIB_GAIN | IMG_CALIB_DEFECT): strCurrentPreCalibMode = "offset+gain+defect"; break; default: break; } CHAR CurrentPostCalibMode = API_COM_GetCalibMode(); //post string strCurrentPostCalibMode = "Undefined"; switch (CurrentPostCalibMode) { case IMG_CALIB_RAW: strCurrentPostCalibMode = "raw"; break; case IMG_CALIB_OFFSET: strCurrentPostCalibMode = "offset"; break; case IMG_CALIB_GAIN: strCurrentPostCalibMode = "gain"; break; case IMG_CALIB_DEFECT: strCurrentPostCalibMode = "defect"; break; case (IMG_CALIB_OFFSET | IMG_CALIB_GAIN): strCurrentPostCalibMode = "offset+gain"; break; case (IMG_CALIB_OFFSET | IMG_CALIB_GAIN | IMG_CALIB_DEFECT): strCurrentPostCalibMode = "offset+gain+defect"; break; default: break; } Info("Current pre-calibration mode is {$}, post-calibration mode is {$}", strCurrentPreCalibMode.c_str(), strCurrentPostCalibMode.c_str()); if (CurrentPreCalibMode != PreCalibMode) //设置pre { Info("Call SetPreCalibMode, User PreCalibMode({$})", PreCalibMode); nRet = API_COM_SetPreCalibMode(PreCalibMode); if (TestError(nRet)) { Error("Set PreCalibMode failed"); return false; } } else { Info("Current PreCalibMode same as User Setting PreCalibMode"); } if (CurrentPostCalibMode != PostCalibMode) //设置post { Info("Call SetCalibMode, User PostCalibMode({$})", PostCalibMode); nRet = API_COM_SetCalibMode(PostCalibMode); if (!TestError(nRet)) { Error("Set PostCalibMode failed"); return false; } return true; } else { Info("Current PostCalibMode same as User Setting PostCalibMode"); } return true; } /*** * 获取图像information ***/ bool PZMedicalCtrl::GetImageInfo() { BOOL nRet = FALSE; TImageMode tImageMode = { 0 }; Info("Call GetImageMode"); nRet = API_COM_GetImageMode(&tImageMode); if (TestError(nRet)) { Error("Get image mode failed"); return false; } UINT16 u16ImageRow = tImageMode.usRow; UINT16 u16ImageCol = tImageMode.usCol; UINT16 u16ImagePixel = tImageMode.usPix; Info("ImageRow: {$}, ImageCol: {$}, ImagePixel: {$}", u16ImageRow, u16ImageCol, u16ImagePixel); m_nRawImgWidth = u16ImageRow; m_nRawImgHeight = u16ImageCol; return true; } /*** ** 设置同步模式、采集窗口 ***/ bool PZMedicalCtrl::SetSyncMode(int nSyncMode) { Info("Set exposureTime Success"); return true; } void PZMedicalCtrl::OnAcquireImage() { Info("## OnAcquireImage ##"); BOOL nRet = FALSE; if (m_stModeInfo.strExamType.find("RAD") != std::string::npos) { nRet = API_COM_Cbct2(); if (TestError(nRet, "API_COM_Cbct2")) { Error("RAD Cbct2 failed"); return; } } else if (m_stModeInfo.strExamType.find("PF") != std::string::npos) { nRet = API_COM_Cbct2(); if (TestError(nRet, "API_COM_Cbct2")) { Error("PF Cbct2 failed"); return; } nRet = API_COM_Cprep(); if (TestError(nRet)) { Error("PF refresh offset failed"); return; } if (!WaitRespond(g_nRefreshTimeout, "RefreshOffset")) { Error("PF refresh offset timeout"); return; } } else if (m_stModeInfo.strExamType.find("CF") != std::string::npos) { nRet = API_COM_Dprep(); if (TestError(nRet)) { Error("CF refresh offset failed"); return; } if (!WaitRespond(g_nRefreshTimeout, "RefreshOffset")) { Error("CF refresh offset timeout"); return; } nRet = API_COM_Dacq(); if (TestError(nRet, "API_COM_Dacq")) { Error("CF Dacq failed"); return; } } else { Error("Undefined Exam Type"); } ResetEvent(m_hAcqEvent); SetEvent(m_hAcqReadyEvent); Info("OnAcquireImage over"); } void PZMedicalCtrl::OnProcessImage() { if (!m_bGrabStatus) { Warn("Invalid image, omit"); return; } Info("## OnProcessImage ##"); BOOL nRet = FALSE; nRet = API_COM_GetImage((CHAR*)m_pRawImgBuffer); if (TestError(nRet)) { Error("Get image failed"); return; } if (nullptr == m_pRawImgBuffer) { Error("Image buffer is null"); return; } if (m_bSaveRaw) { string strFluImageName = "Flu_Image_" + to_string(m_FluFrameNum) + ".raw"; SaveRawImage(strFluImageName.c_str(), m_pRawImgBuffer, m_stModeInfo.nRawImgWidth, m_stModeInfo.nRawImgHeight); } m_FluFrameNum++; //暗场图挡图处理 if (!CheckImageEXI(m_pRawImgBuffer, m_stModeInfo.nRawImgWidth, m_stModeInfo.nRawImgHeight, m_stModeInfo.nPhySizeInfoBit, m_stModeInfo.nExiThreshold, 0.05f)) { Warning("Current frame EXI too low, omit"); return; } if (APP_STATUS_CAL_BEGIN == m_nExamMode) { ConfirmCalExposure(); if (m_nGainNodeIndex != m_nGainNodeCount) //增益曝光次数够了,这两个值会是相等的 { StatusFeedback(EVT_STATUS_SINGLEEXP, DOSE_ACCEPT); } return; } if (m_stModeInfo.nWidthOffset != 0 || m_stModeInfo.nHeightOffset != 0) { Debug("Begin get effect image"); if (!GetEffectiveImage(m_pImgBuffer, m_pRawImgBuffer, m_stModeInfo.nRawImgWidth)) { return; } Debug("Get effect image over"); if (m_bSaveRaw) { SaveRawImage("Image_AfterCrop.raw", m_pImgBuffer, m_stModeInfo.nImageWidth, m_stModeInfo.nImageHeight); } DataFeedback(EVT_DATA_RAW_IMAGE, m_pImgBuffer); } else { DataFeedback(EVT_DATA_RAW_IMAGE, m_pRawImgBuffer); } return; } void PZMedicalCtrl::OnRefreshOffset() { Info("Refresh Offset process"); BOOL nRet = FALSE; if (m_bAutoOffsetMode) { Info("Current detector auto offset, sleep 500ms"); Sleep(500); m_bOffsetDone = true; return; } nRet = API_COM_Dexit(); if (TestError(nRet)) { Error("COM_Dexit failed"); return; } nRet = API_COM_SetConfigId((UCHAR)Cfg_RAD); if (TestError(nRet)) { Error("COM_SetConfigId failed"); return; } nRet = API_COM_LoadFullCfg(0); if (TestError(nRet, "COM_LoadFullCfg")) { Error("COM_LoadFullCfg failed"); return; } nRet = API_COM_Cprep(); if (TestError(nRet)) { Error("COM_SetConfigId failed"); return; } if (WaitRespond(8000, "RefreshOffset")) //等待EVENT_OFFSETDONE回调8秒,否则视为超时 { Info("Refresh RAD Offset Done"); } else { Error("Waiting RAD Offset TimeOut"); StatusFeedback(PANEL_OFFSET_CAL, OFFSET_ERROR); return; } StatusFeedback(PANEL_OFFSET_CAL, OFFSET_IDLE); return; } void PZMedicalCtrl::OnAcquireGainImage() { return; } /*** ** 裁剪图像 ** pOutImg: 裁剪后图像; pInImg: 裁剪前图像; nInWidth: 裁剪前图像宽度 ***/ bool PZMedicalCtrl::GetEffectiveImage(WORD* pOutImg, WORD* pInImg, int nInWidth) { if (pOutImg == NULL || pInImg == NULL || nInWidth < 0) { Error("Illegal parameter, can not get effective image"); return false; } try { for (int i = 0; i < m_stModeInfo.nImageHeight; i++) { memcpy(pOutImg + i * m_stModeInfo.nImageWidth, pInImg + (i + m_stModeInfo.nHeightOffset) * nInWidth + m_stModeInfo.nWidthOffset, m_stModeInfo.nImageWidth * sizeof(WORD)); } } catch (...) { Error("Get effective image crashed"); return false; } return true; } /*** ** 计算一键校正曝光的图像灰度 ***/ double PZMedicalCtrl::GetMean(WORD* imgNoHeader, int pixelNum) { double imgMean = 0; for (int i = 0; i < pixelNum; i++) { imgMean += imgNoHeader[i]; } imgMean = imgMean / pixelNum; return imgMean; } /*** ** 等待探测器操作执行完毕, 超时返回false, 等到结果返回true ***/ bool PZMedicalCtrl::WaitRespond(int nTimeOut, const char* szPosition) { Info("--- {$} Wait Respond, {$}ms ---", szPosition, nTimeOut); DWORD dwRet = WaitForSingleObject(m_hRespond, nTimeOut); if (dwRet == WAIT_TIMEOUT) { Warn("Timeout in wait respond"); return false; } ResetEvent(m_hRespond); return true; } void PZMedicalCtrl::GetRespond(const char* szPosition) { Info("--- {$} Get Respond ---", szPosition); SetEvent(m_hRespond); } /*** ** 检测SDK接口是否有错误,返回值 true:有错;false:没错 ***/ bool PZMedicalCtrl::TestError(int nRet, const char* szFuncName) { if (nRet == TRUE) { Debug("{$} executed successfully", szFuncName); return false; } else { char ErrorInfo[256] = "..."; Error("{$} return error {$}, reason: {$}", szFuncName, nRet, ErrorInfo); return true; } } void PZMedicalCtrl::ConfFeedback(int nEventID, int nDetectorID, const char* pszMsg, int nParam1, float fParam2, int nPtrParamLen, void* pParam) { if (-1 == nDetectorID) { nDetectorID = m_nCurrentPanelID; } ((FPDDevicePZMedical*)(*m_pPanelID2DPC)[nDetectorID])->OnFPDCallback(nDetectorID, nEventID, EVT_LEVEL_CONFIGURATION, pszMsg, nParam1, fParam2, nPtrParamLen, pParam); } void PZMedicalCtrl::InfoFeedback(int nEventID, int nDetectorID, int nParam1, float fParam2, const char* pszMsg, int nPtrParamLen, void* pParam) { if (-1 == nDetectorID) { nDetectorID = m_nCurrentPanelID; } ((FPDDevicePZMedical*)(*m_pPanelID2DPC)[nDetectorID])->OnFPDCallback(nDetectorID, nEventID, EVT_LEVEL_INFORMATOION, pszMsg, nParam1, fParam2, nPtrParamLen, pParam); } void PZMedicalCtrl::StatusFeedback(int nEventID, int nParam1, const char* pszMsg, int nDetectorID, float fParam2, int nPtrParamLen, void* pParam) { if (-1 == nDetectorID) { nDetectorID = m_nCurrentPanelID; } ((FPDDevicePZMedical*)(*m_pPanelID2DPC)[nDetectorID])->OnFPDCallback(nDetectorID, nEventID, EVT_LEVEL_STATUS, pszMsg, nParam1, fParam2, nPtrParamLen, pParam); } void PZMedicalCtrl::DataFeedback(int nEventID, void* pParam, int nParam1, float fParam2, const char* pszMsg, int nPtrParamLen, int nDetectorID) { if (-1 == nDetectorID) { nDetectorID = m_nCurrentPanelID; } ((FPDDevicePZMedical*)(*m_pPanelID2DPC)[nDetectorID])->OnFPDCallback(nDetectorID, nEventID, EVT_LEVEL_DATA, pszMsg, nParam1, fParam2, nPtrParamLen, pParam); } void PZMedicalCtrl::WarnFeedback(int nEventID, const char* pszMsg, int nParam1, float fParam2, int nPtrParamLen, void* pParam, int nDetectorID) { if (-1 == nDetectorID) { nDetectorID = m_nCurrentPanelID; } ((FPDDevicePZMedical*)(*m_pPanelID2DPC)[nDetectorID])->OnFPDCallback(nDetectorID, nEventID, EVT_LEVEL_WARNING, pszMsg, nParam1, fParam2, nPtrParamLen, pParam); } void PZMedicalCtrl::ErrorFeedback(int nEventID, const char* pszMsg, int nDetectorID, int nParam1, float fParam2, int nPtrParamLen, void* pParam) { if (-1 == nDetectorID) { nDetectorID = m_nCurrentPanelID; } ((FPDDevicePZMedical*)(*m_pPanelID2DPC)[nDetectorID])->OnFPDCallback(nDetectorID, nEventID, EVT_LEVEL_ERROR, pszMsg, nParam1, fParam2, nPtrParamLen, pParam); } /*** * 保存RAW图像 ***/ bool PZMedicalCtrl::SaveRawImage(const char* pImgName, const WORD* pRawImg, int nWidth, int nHeight) { Info("Begin to Save {$} Image, width: {$}, height: {$}", pImgName, nWidth, nHeight); if (pRawImg == NULL || pImgName == NULL) { return false; } string strImagePath = m_strWorkPath + "\\rawdata\\" + pImgName; FILE* fp; if ((fp = fopen(strImagePath.c_str(), "wb")) == NULL) { DWORD dw = GetLastError(); Error("fopen {$} failed, {$}", strImagePath.c_str(), dw); return false; } fwrite(pRawImg, sizeof(WORD), nWidth * nHeight, fp); fclose(fp); Info("End to Save Raw Image"); return true; } //获取探测器应用模式 bool PZMedicalCtrl::GetApplicationMode(int nAppModeKey, int nAppModeID, bool bReged) { return true; } //设置应用模式 bool PZMedicalCtrl::SetApplicationMode(int nAppCfgID, int nAppModeID) { BOOL nRet = FALSE; Info("SetApplicationMode, CfgID: {$}, ModeID: {$}", nAppCfgID, nAppModeID); //点片 if (Cfg_RAD == nAppCfgID) { nRet = API_COM_SetConfigId((UCHAR)nAppCfgID); if (TestError(nRet)) { Error("Set RAD Cfg ID failed"); return false; } nRet = API_COM_LoadFullCfg((UCHAR)nAppModeID); if (TestError(nRet)) { Error("Load RAD full cfg failed"); } return true; } if ((int)m_fFrameRate <= 2) { nAppCfgID = 3; Info("ModeID3"); } else if ((int)m_fFrameRate <= 4) { nAppCfgID = 4; Info("ModeID4"); } else if ((int)m_fFrameRate <= 8) { nAppCfgID = 5; Info("ModeID5"); } else if ((int)m_fFrameRate <= 10) { nAppCfgID = 6; Info("ModeID6"); } else if ((int)m_fFrameRate <= 15) { Info("ModeID2"); } //透视 nRet = API_COM_SetConfigId((UCHAR)nAppCfgID); if (TestError(nRet)) { Error("Set FLU Cfg ID failed"); return false; } nRet = API_COM_LoadFullCfg((UCHAR)nAppModeID); if (TestError(nRet)) { Error("Load FLU full cfg failed"); return false; } return true; } //加载校正文件 bool PZMedicalCtrl::LoadCalibrationFile() { Info("## LoadCalibrationFile ##"); return true; } //卸载校正文件 bool PZMedicalCtrl::UnLoadCalibrationFile() { Info("## UnLoadCalibrationFile ##"); return true; } //开启状态监控线程 bool PZMedicalCtrl::OpenStatusMonitor() { Info("---Open Status Monitor Thread---"); m_hExitStatusMonitorEvent = CreateEvent(NULL, FALSE, FALSE, NULL); m_hStatusMonitorToggleEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (m_hStatusMonitorThread != nullptr) { Error("Status Monitor Thread already exist"); return false; } unsigned uThreadId; _beginthreadex(NULL, 0, onSatusMonitorThread, this, 0, &uThreadId); m_hStatusMonitorThread = OpenThread(THREAD_ALL_ACCESS, TRUE, uThreadId); if (m_hStatusMonitorThread == nullptr) { Error("Create detector status monitor thread failed"); return false; } return true; } //状态监控线程 unsigned __stdcall PZMedicalCtrl::onSatusMonitorThread(PVOID pParam) { PZMedicalCtrl* pCurrentOpr = reinterpret_cast(pParam); if (NULL == pCurrentOpr) { Error("CareRay Status Monitor parameter error"); return false; } bool bExitFlag = false; DWORD dwStatusCheckTime = 5000; while (!bExitFlag) { DWORD dwRet = WaitForSingleObject(pCurrentOpr->m_hExitStatusMonitorEvent, dwStatusCheckTime); switch (dwRet) { case WAIT_OBJECT_0: Info("[Get ExitStatusMonitor Event]"); bExitFlag = true; break; case WAIT_TIMEOUT: pCurrentOpr->StatusMonitor(); break; default: break; } } SetEvent(pCurrentOpr->m_hStatusMonitorToggleEvent); return 0; } //关闭状态监控线程 bool PZMedicalCtrl::CloseStatusMonitor() { SetEvent(m_hExitStatusMonitorEvent); DWORD dwResult = WaitForSingleObject(m_hStatusMonitorToggleEvent, 5000); if (WAIT_TIMEOUT == dwResult) { ::TerminateThread(m_hStatusMonitorThread, 0); Warning("Kill Status Monitor Thread"); } if (m_hExitStatusMonitorEvent != nullptr) { CloseHandle(m_hExitStatusMonitorEvent); m_hExitStatusMonitorEvent = nullptr; } if (m_hStatusMonitorToggleEvent != nullptr) { CloseHandle(m_hStatusMonitorToggleEvent); m_hStatusMonitorToggleEvent = nullptr; } m_hStatusMonitorThread = nullptr; Info("---Close Status Monitor Thread---"); return nullptr; } //探测器状态: 显示温度、电量、wifi等信息 bool PZMedicalCtrl::StatusMonitor() { Info("Monitor detector status"); BOOL nRet = FALSE; //先按一块探测器处理 //1.监测探测器连接状态 //if (!stConnectionStatus.isDetrConnected) { ErrorFeedback(EVT_ERR_COMMUNICATE, "true", m_nCurrentPanelID); } //2.温度 //Info("Current detector temperature: {$}", stTemperature.oDetrTemperature.fCurrent); //StatusFeedback(EVT_STATUS_TEMPERATURE, 0, "", m_nCurrentPanelID, stTemperature.oDetrTemperature.fCurrent); //3.电量 //bool bCharging = false; //Info("Current detector battery: {$}% {$}",stInfo.batInfo.relative_state_of_charge * 100, bCharging ? "Charging" : "Not charging"); StatusFeedback(EVT_STATUS_BATTERY_VALUE, 100, "", m_nCurrentPanelID); //4.Wifi //string strLinkQuality = stInfo.wireless_info.link_quality; //Info("Current detector wifi link quality: {$}", stInfo.wireless_info.link_quality); //int nLinkQuality = atoi(stInfo.wireless_info.link_quality); StatusFeedback(EVT_STATUS_WIFI, 100, "", m_nCurrentPanelID); return true; } //检查图像EXI, 返回true: 有射线,返回false: 无射线 bool PZMedicalCtrl::CheckImageEXI(WORD* pImage, int nWidth, int nHeight, int nImageBit, int nThreshold, float fArea) { Info("Check EXI"); if (!pImage) { Error("Buffer is null"); return false; //图像读入失败。 } int N = 65536; int* Histogram = NULL; Histogram = new int[N]; if (Histogram == NULL) { Error("Alloc buffer failed"); return false; //内存分配失败。 } memset(Histogram, 0, sizeof(int) * N); unsigned long int nCount = 0; unsigned long int temp = 0; int nIdxI = 0; int nIdxJ = 0; for (nIdxJ = 30; nIdxJ < nHeight - 30; nIdxJ = nIdxJ + 4) { for (nIdxI = 30; nIdxI < nWidth - 30; nIdxI = nIdxI + 4) { temp = int(pImage[nIdxJ * nWidth + nIdxI]); Histogram[temp]++; nCount++; } } float fCoe = 0.01f; int nCoeCount = int(fCoe * nCount); int nAreaCount = int((1 - fCoe) * nCount * fArea); long int nIdx = 0; long int nSum = 0; for (nIdx = N - 1; nIdx >= 0; nIdx--) { nSum += Histogram[nIdx]; if (nSum >= nCoeCount) break; } unsigned long int fMean = 0; unsigned long int nflag = 0; for (int i = nIdx; i >= 0; i--) { if (Histogram[nIdx] == 0) { continue; } fMean += nIdx * Histogram[nIdx]; nflag += Histogram[nIdx]; if (nflag >= nAreaCount) { break; } } if (Histogram) { delete[] Histogram; Histogram = NULL; } if (nflag == 0) { Warning("Not have Xray image"); return false; //无x射线 } fMean = unsigned long int(fMean / nflag); Info("Mean count({$})", fMean); if (fMean >= nThreshold) { //LogInfo("Xray image"); return true; } else { //LogInfo("Not have Xray image"); return false; } } bool PZMedicalCtrl::SetFluPPS(float fFluPPS) { if (fFluPPS <= 0.0f) { Warn("Current frame rate is Illegal"); return false; } m_fFrameRate = fFluPPS; return true; } bool PZMedicalCtrl::GetFluPPS(float& fFluPPS) { fFluPPS = m_fFrameRate; return true; } bool PZMedicalCtrl::StartOffset(int nMode) { Info("PZMedicalRF only need refresh RAD offset"); SetEvent(m_hDarkEvent); //OnRefreshOffset() StatusFeedback(PANEL_OFFSET_CAL, OFFSET_RUNNING); return true; } bool PZMedicalCtrl::AbortOffset() { Info("PZMedicalRF Abort refresh offset"); //GetRespond("RefreshOffset"); //StatusFeedback(PANEL_OFFSET_CAL, OFFSET_IDLE); //无法停止Offset return true; } //关窗线程 bool PZMedicalCtrl::StartXWindowOffThread() { if (m_pXWindowoffThread) { Warn("Already start XWindowOff thread, Omit"); return false; } m_hWindowOffEvent = CreateEvent(NULL, FALSE, FALSE, NULL); DWORD m_NotifyThreadID; m_pXWindowoffThread = CreateThread(0, 0, XWindowOffThread, this, 0, &m_NotifyThreadID); if (m_pXWindowoffThread == NULL) { Fatal("Start Inner Exp Thread Failed"); return false; } return true; } DWORD PZMedicalCtrl::XWindowOffThread(LPVOID pParam) { PZMedicalCtrl* pCurPanel = (PZMedicalCtrl*)pParam; if (pCurPanel == NULL) { return false; } DWORD dwTimer = pCurPanel->m_stModeInfo.nExpTime; DWORD dwResult = WaitForSingleObject(pCurPanel->m_hWindowOffEvent, dwTimer); Info("Simulate XWINDOW_OFF"); pCurPanel->StatusFeedback(EVT_STATUS_PANEL, PANEL_XWINDOW_OFF); CloseHandle(pCurPanel->m_hWindowOffEvent); pCurPanel->m_hWindowOffEvent = nullptr; pCurPanel->m_pXWindowoffThread = nullptr; return true; }