#include "Detector_TiRayDR.h" #include "CCOS.Dev.FPD.TiRayDR.h" #include "MyPingip.h" #include #include #include "LogLocalHelper.h" #include "Log4CPP.h" using EventListenerType = void(*)(TiRayEvent, void*); Detector_TiRayDR* g_pDetector = nullptr; //extern Log4CPP::Logger* mLog::gLogger; /****************************************/ int (*GetSdkVersion_Ptr)(void); TiRayError(*Scan_Ptr)(ResultCallback fn, const char* interfaceIp, int scanDuration); TiRayError(*SetIp_Ptr)(const char* detectorSN, const char* upperIp, const char* lowerIp, const char* interfaceIp); TiRayError(*Startup_Ptr)(TiRayModel model, EventCallback fn, const StartupOption * option); void (*Stop_Ptr)(); TiRayError(*Execute_Ptr)(int detectorId, int commandId, TiRayVariant argv[], int argc); TiRayError(*ApplyPreset_Ptr)(int detectorId, TiRayVariant argv[], int argc, ResultCallback fn); TiRayError(*GenerateTemplate_Ptr)(TemplateType type, TiRayVariant images[], int count, void* templateBuffer, int bufferSize); static int g_load_error = 0; static void LoadOneFunc(void* hInstLib, void** pFunction, const char* funcName) { *pFunction = dlsym(hInstLib, funcName); const char* dlsym_error = dlerror(); if (dlsym_error != NULL) { printf("Failed to load %s. Error = %s", funcName, dlsym_error); g_load_error = 1; } } void OnEvent(TiRayEvent eventType, TiRayVariant argv[], int argc) { if (argc > 0) { auto arg = new std::vector(argc); for (int i = 0; i < argc; i++) { if (argv[i].Type == TiRayVariant::TiRayBuffer) { arg->at(i).Type = TiRayVariant::TiRayBuffer; arg->at(i).DataLen = argv[i].DataLen; arg->at(i).DataValue = new char[argv[i].DataLen]; memcpy(arg->at(i).DataValue, argv[i].DataValue, argv[i].DataLen); } else { memcpy(&arg->at(i), &argv[i], sizeof(TiRayVariant)); } } } } #define LOAD_ONE_FUNC(handle, funcName) LoadOneFunc(handle, (void**)&(funcName##_Ptr), #funcName) /****************************************/ Detector_TiRayDR::Detector_TiRayDR() :m_nPanelCount{}, m_nCurrentPanelID{0}, m_nImageWidth{}, m_nImageHeight{}, m_nWidthOffset{}, m_nHeightOffset{}, m_nRawImgWidth{}, m_nRawImgHeight{}, m_nCalibrationRounds{}, m_nCalibCurrentCalibrationRound{}, m_nCalibCurrentExposureIndex{}, m_nExposureNumCurrentRound{}, m_hTiRayDRModule{}, m_hReconnectThread{}, m_hFPDScanThread{}, m_hRadAcquisitionThread{}, m_hStatusMonitorThread{}, m_pRawImgBuffer{}, m_pImgBuffer{}, m_pZSKKCalib{}, m_strDetectorType{}, m_strSerialNum{}, m_nImageNum{}, m_nDetectorID{}, m_nNotifyStatusTimePeriod{}, m_pStPanelStatus{}, m_nReconnectTimePeriod(5000), m_nAppStatus(APP_STATUS::APP_STATUS_IDLE), m_eCaliType(CCOS_CALIBRATION_TYPE_NONE), m_nSyncMode(SYNC_SOFTWARE), m_nCalibrationMode(CCOS_CALIBRATION_MODE_ZSKK), m_bSaveRaw(true), m_bConnected(false), m_bAEDReady(false), m_bAEDWorkFlag(false), m_bExitRadAcqStatus(false), m_bMonitorFlag(false) { m_pDPC2PanelID = new map(); m_pPanelID2DPC = new map(); m_hExitRadAcqStatus = LinuxEvent::CreateEvent(LinuxEvent::AUTO_RESET, FALSE); m_hInitEvent = LinuxEvent::CreateEvent(LinuxEvent::AUTO_RESET, FALSE); m_hExitEvent = LinuxEvent::CreateEvent(LinuxEvent::AUTO_RESET, FALSE); m_hReConnectEvent = LinuxEvent::CreateEvent(LinuxEvent::AUTO_RESET, FALSE); m_hRadEvent = LinuxEvent::CreateEvent(LinuxEvent::AUTO_RESET, FALSE); m_hArrayEvent.push_back(m_hInitEvent); m_hArrayEvent.push_back(m_hExitEvent); m_hArrayEvent.push_back(m_hReConnectEvent); m_hArrayEvent.push_back(m_hRadEvent); m_hToggleEvent = LinuxEvent::CreateEvent(LinuxEvent::AUTO_RESET, FALSE); } Detector_TiRayDR::~Detector_TiRayDR() { CloseStatusMonitor(); CloseDetectorScan(); if (m_hReconnectThread != 0) { if (m_bReconnectThreadRunning) { struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += 2; // 设置2秒超时 // 等待线程结束 pthread_timedjoin_np(m_hReconnectThread, nullptr, &ts); } // 如果线程仍在运行,强制取消 if (m_bReconnectThreadRunning) { pthread_cancel(m_hReconnectThread); } m_hReconnectThread = 0; } if (m_pRawImgBuffer) { delete[] m_pRawImgBuffer; m_pRawImgBuffer = nullptr; } if (m_pImgBuffer) { delete[] m_pImgBuffer; m_pImgBuffer = nullptr; } if (m_pZSKKCalib) { delete m_pZSKKCalib; m_pZSKKCalib = nullptr; } } bool Detector_TiRayDR::ScanDetector(string& strDetectorInfo) { ResDataObject result; std::vector scan_results; // 扫描探测器并收集所有结果 scan([&scan_results](scan_result&& res) { scan_results.emplace_back(std::move(res)); }); if (scan_results.empty()) { std::cerr << "[Detector_TiRayDR::ScanDetector] No detectors were found!" << std::endl; return false; } std::cout << "[Detector_TiRayDR::ScanDetector] Scanned " << scan_results.size() << " detector(s):" << std::endl; for (size_t i = 0; i < scan_results.size(); ++i) { const auto& res = scan_results[i]; ResDataObject detectorData; detectorData.add("SerialNumber", res.sn.c_str()); detectorData.add("Model", res.model.c_str()); detectorData.add("TupperIP", res.upper_ip.c_str()); detectorData.add("DetectorIP", res.detector_ip.c_str()); std::string key = "DetectorData_" + std::to_string(i); result.add(key.c_str(), detectorData); // 输出当前探测器信息 std::cout << "[Detector_TiRayDR::ScanDetector] Detector " << (i + 1) << ":" << " Serial number:" << res.sn << ", Model:" << res.model << ", tupper IP:" << res.upper_ip << ", detector IP:" << res.detector_ip << std::endl; } try { strDetectorInfo = result.encode(); } catch (const std::exception& e) { std::cerr << "[Detector_TiRayDR::ScanDetector] Encode failed: " << e.what() << std::endl; return false; } return true; } bool Detector_TiRayDR::DriverEntry(FPDDeviceTiRay* pDrvDPC, ResDataObject& Configuration) { //FINFO("--TiRayDR Func-- DriverEntry Start"); map::iterator DPCsIter = m_pDPC2PanelID->find(pDrvDPC); if (DPCsIter != m_pDPC2PanelID->end()) { //FERROR("This DPC already exist"); return false; } CPanelStatus* p = new CPanelStatus(); m_pStPanelStatus[m_nPanelCount] = p; m_pDPC2PanelID->insert(pair(pDrvDPC, m_nPanelCount)); m_pPanelID2DPC->insert(pair(m_nPanelCount, pDrvDPC)); m_nPanelCount++; m_ModeConfig = Configuration; //记录配置 --目前只有一个平板,多板时应该分别存储 //FINFO("Config: {$}", m_ModeConfig.encode()); try { m_nCalibrationMode = (CCOS_CALIBRATION_MODE)(int)m_ModeConfig["CalibMode"]; } catch (ResDataObjectExption& e) { //FERROR("Read configuration failed, Error code: {$}", e.what()); } //FINFO("TiRayDR DriverEntry Over"); return true; } bool Detector_TiRayDR::Connect(FPDDeviceTiRay* pDrvDPC, const char* szWorkPath) { FINFO("--TiRayDR Func-- Connect Start"); if ((*m_pDPC2PanelID)[pDrvDPC] != m_nCurrentPanelID) { FINFO("Not current DPC, return true"); return true; } if (!m_pZSKKCalib) { m_pZSKKCalib = new CZSKKCalibrationCtrl(); } m_strWorkPath = szWorkPath; if (m_hFPDScanThread == 0) { pthread_t threadId; int result = pthread_create(&threadId, NULL, onFPDScanThread, this); if (result == 0) { m_hFPDScanThread = threadId; // 存储线程ID } else { FERROR("Thread creation failed: %d", result); return false; } } if (m_hInitEvent) { m_hInitEvent->SetEvent(); } FINFO("TiRayDR Connect Over"); return true; } bool Detector_TiRayDR::Disconnect() { FINFO("--TiRayDR Func-- Disconnect Begin"); m_hExitEvent->SetEvent(); //关闭Scan线程 bool result = m_hToggleEvent->Wait(65000); if (result) { FINFO("Leave scan thread over"); } else { FERROR("Till time detectorData"); } FINFO("Call API Stop"); Stop(); FINFO("TiRayDR Disconnect Over"); return true; } void Detector_TiRayDR::EnterExamMode(int nExamMode) { switch (nExamMode) { case APP_STATUS_WORK_BEGIN: FINFO("Enter into Exam Windows"); m_nAppStatus = APP_STATUS_WORK_BEGIN; break; case APP_STATUS_WORK_END: FINFO("Quit Exam Windows"); m_nAppStatus = APP_STATUS_WORK_END; break; case APP_STATUS_DETSHARE_BEGIN: FINFO("Enter into Detector Share Windows"); m_nAppStatus = APP_STATUS_DETSHARE_BEGIN; break; case APP_STATUS_DETSHAR_END: FINFO("Quit Detector Share Windows"); m_nAppStatus = APP_STATUS_DETSHAR_END; break; case APP_STATUS_CAL_BEGIN: FINFO("Enter into Calibration Windows"); m_nAppStatus = APP_STATUS_CAL_BEGIN; break; case APP_STATUS_CAL_END: FINFO("Quit Calibration Windows"); m_nAppStatus = APP_STATUS_CAL_END; break; case APP_STATUS_WORK_IN_SENSITIVITY: FINFO("Enter into sensitivity test interface"); m_nAppStatus = APP_STATUS_WORK_IN_SENSITIVITY; break; default: break; } } /*** ** 根据采集模式申请图像buffer ***/ bool Detector_TiRayDR::SetAcqMode(int nMode) { FINFO("--TiRayDR Func-- SetAcqMode Start"); FINFO("Detector_TiRayDR::SetAcqMode mode:{$}", nMode); if (!m_pStPanelStatus[m_nCurrentPanelID]->bConnectState) { FERROR("Detector not connected, return"); return false; } int nRes; m_bExitRadAcqStatus = false; try { //设置采集模式,根据不同的场景设置不同的采集模式 m_nImageWidth = (int)m_ModeConfig["ModeTable"][0]["ImageWidth"]; m_nImageHeight = (int)m_ModeConfig["ModeTable"][0]["ImageHeight"]; m_nWidthOffset = (int)m_ModeConfig["ModeTable"][0]["WidthOffset"]; m_nHeightOffset = (int)m_ModeConfig["ModeTable"][0]["HeightOffset"]; FINFO("After crop image width: {$}, height: {$}, WidthOffset: {$}, HeightOffset: {$}", m_nImageWidth, m_nImageHeight, m_nWidthOffset, m_nHeightOffset); m_bSaveRaw = (int)m_ModeConfig["ModeTable"][0]["IsSaveRaw"]; FINFO("m_nSaveRaw:{$}", m_bSaveRaw); if (nullptr != m_pImgBuffer) { delete[] m_pImgBuffer; m_pImgBuffer = nullptr; } m_pImgBuffer = new WORD[(size_t)m_nImageWidth * (size_t)m_nImageHeight]; } catch (ResDataObjectExption& e) { FERROR("Get config FERROR: {$}", e.what()); return false; } TiRayVariant Param[2]{}; Param[0].Type = TiRayVariant::TiRayInt; Param[0].IntValue = TiRayAttribute::Attr_BinningMode; Param[1].Type = TiRayVariant::TiRayInt; Param[1].IntValue = BinningMode::Binning_None; nRes = Execute_Ptr(m_nDetectorID, Cmd_WriteAttribute, Param, 2); if ((TiRayError)nRes != TiRayError::Err_Success) { FERROR("Set BinningMode Failed, Reason:{$}", nRes); return false; } else { FINFO("Set BinningMode Success"); } TiRayVariant ParamAED[2]{}; ParamAED[0].Type = TiRayVariant::TiRayInt; ParamAED[0].IntValue = TiRayAttribute::Attr_AEDSensitivity; ParamAED[1].Type = TiRayVariant::TiRayInt; ParamAED[1].IntValue = 200; nRes = Execute_Ptr(m_nDetectorID, Cmd_WriteAttribute, ParamAED, 2); if ((TiRayError)nRes != TiRayError::Err_Success) { FERROR("Set BinningMode Failed, Reason:{$}", nRes); return false; } else { FINFO("Set BinningMode Success"); } StatusFeedback(EVT_STATUS_PANEL, PANEL_SLEEP); FINFO("TiRayDR SetAcqMode Over"); return true; } bool Detector_TiRayDR::SetSyncMode(int nSyncMode) { FINFO("--TiRayDR Func-- SetSyncMode Start"); FINFO("SetSyncMode: {$}", nSyncMode); std::cout << "--TiRayDR Func-- SetSyncMode Start" << std::endl; std::cout << "SetSyncMode: " << nSyncMode << std::endl; int nRes; TiRayVariant Param[2]{}; Param[0].Type = TiRayVariant::TiRayInt; Param[0].IntValue = TiRayAttribute::Attr_WorkMode; Param[1].Type = TiRayVariant::TiRayInt; if (nSyncMode == 1) { Param[1].IntValue = WorkMode::WorkMode_Idle; m_nSyncMode = SYNC_MODE::SYNC_SOFTWARE; std::cout << "Setting SyncMode to Software Sync" << std::endl; nRes = Execute_Ptr(m_nDetectorID, Cmd_WriteAttribute, Param, 2); if ((TiRayError)nRes != TiRayError::Err_Success) { std::cout << "Error: Failed to set SyncMode to Software Sync. Reason: " << nRes << std::endl; FERROR("Set SyncMode SoftSync, Reason:{$}", nRes); return false; } else { std::cout << "Success: Software Sync mode set successfully" << std::endl; FINFO("Set SoftSync Success"); } } else if (nSyncMode == 2) { m_nSyncMode = SYNC_MODE::SYNC_HARDWARE; Param[1].IntValue = WorkMode::WorkMode_SyncIn; std::cout << "Setting SyncMode to Hardware Sync" << std::endl; nRes = Execute_Ptr(m_nDetectorID, Cmd_WriteAttribute, Param, 2); if ((TiRayError)nRes != TiRayError::Err_Success) { std::cout << "Error: Failed to set SyncMode to Hardware Sync. Reason: " << nRes << std::endl; FERROR("Set SyncMode HardSync, Reason:{$}", nRes); return false; } else { std::cout << "Success: Hardware Sync mode set successfully" << std::endl; FINFO("Set HardSync Success"); } } else if (nSyncMode == 3) { Param[1].IntValue = WorkMode_FreeSync; m_nSyncMode = SYNC_MODE::SYNC_AED; std::cout << "Setting SyncMode to AED Sync" << std::endl; nRes = Execute_Ptr(m_nDetectorID, Cmd_WriteAttribute, Param, 2); if ((TiRayError)nRes != TiRayError::Err_Success) { std::cout << "Error: Failed to set SyncMode to AED Sync. Reason: " << nRes << std::endl; FERROR("Set SyncMode AED, Reason:{$}", nRes); return false; } else { std::cout << "Success: AED Sync mode set successfully" << std::endl; FINFO("Set AED Success"); } } m_pStPanelStatus[m_nCurrentPanelID]->eSyncMode = (SYNC_MODE)m_nSyncMode; FINFO("TiRayDR SetSyncMode Over"); std::cout << "TiRayDR SetSyncMode Over" << std::endl; return true; } bool Detector_TiRayDR::PrepareAcquisition(FPDDeviceTiRay* pDrvDPC) { FINFO("--TiRayDR Func-- PrepareAcquisition Start"); FINFO("PrepareAcquisition start"); if ((*m_pDPC2PanelID)[pDrvDPC] != m_nCurrentPanelID) { FERROR("Not current DPC, return"); return false; } //未初始化、未连接 不执行 if (!m_pStPanelStatus[m_nCurrentPanelID]->bConnectState) { FERROR("Detector not connected, return"); return false; } g_pDetector->StatusFeedback(EVT_STATUS_PANEL, PANEL_STANDBY); //m_hRadEvent->SetEvent(); FINFO("TiRayDR PrepareAcquisition Over"); return true; } bool Detector_TiRayDR::StartAcquisition(FPDDeviceTiRay* pDrvDPC) { std::cout << "--TiRayDR Func-- StartAcquisition Start" << std::endl; FINFO("--TiRayDR Func-- StartAcquisition Start"); if ((*m_pDPC2PanelID)[pDrvDPC] != m_nCurrentPanelID) { std::cout << "Not current DPC, return" << std::endl; FERROR("Not current DPC, return"); return false; } //未初始化、未连接 不执行 if (!m_pStPanelStatus[m_nCurrentPanelID]->bConnectState) { std::cout << "Detector not connected, return" << std::endl; FERROR("Detector not connected, return"); return false; } if (m_nSyncMode == SYNC_MODE::SYNC_SOFTWARE) { //SetSyncMode(1); auto err = Execute_Ptr(m_nDetectorID, Cmd_Photo, nullptr, 0); if (err != Err_Success) { cout << "[Detector_TiRayDR::StartAcquisition] Failed to Execute_Ptr Cmd_Photo. Error code: " << err << endl; return false; } } StatusFeedback(EVT_STATUS_PANEL, PANEL_START_ACQ); m_bAEDWorkFlag = true; StatusFeedback(EVT_STATUS_PANEL, PANEL_XWINDOW_ON); std::cout << "TiRayDR StartAcquisition Over" << std::endl; FINFO("TiRayDR StartAcquisition Over"); return true; } bool Detector_TiRayDR::StopAcquisition(FPDDeviceTiRay* pDrvDPC) { FINFO("--TiRayDR Func-- StopAcquisition Start"); if ((*m_pDPC2PanelID)[pDrvDPC] != m_nCurrentPanelID) { FERROR("Not current DPC, return"); return false; } if (!m_pStPanelStatus[m_nCurrentPanelID]->bConnectState) { FERROR("Detector not connected, return"); return false; } FINFO("## Stop Acquisition ##"); StatusFeedback(EVT_STATUS_PANEL, PANEL_STANDBY); SetTiRayDPCStatus(eDetStatus::DetStatus_Standby); //停止采集 FINFO("TiRayDR StopAcquisition Over"); return true; } bool Detector_TiRayDR::ActiveCalibration(FPDDeviceTiRay* pDrvDPC, CCOS_CALIBRATION_TYPE eType) { FINFO("--TiRayDR Func-- ActiveCalibration Start"); if ((*m_pDPC2PanelID)[pDrvDPC] != m_nCurrentPanelID) { FERROR("Not current DPC, return"); return false; } if (!m_pStPanelStatus[m_nCurrentPanelID]->bConnectState) { FERROR("bConnectState is false, Detector not connected, return"); return false; } StatusFeedback(EVT_STATUS_CALIBRATIOIN, PANEL_EVENT_START); m_nAppStatus = APP_STATUS_CAL_BEGIN; //激活校正,置为校正界面 m_eCaliType = eType; if (CCOS_CALIBRATION_TYPE_DARK == m_eCaliType) { FINFO("Active Dark Calibration"); } if (CCOS_CALIBRATION_TYPE_XRAY == m_eCaliType) { FINFO("Active Xray Calibration"); if (m_nCalibrationMode) //厂商校正ActiveCalibration { } //else //ZSKK校正 //{ // if (!m_pZSKKCalib) // { // FERROR("ZSKK Calibration object is undefined"); // } // else // { // //加载ZSKK的校正文件 // m_pZSKKCalib->m_strRawImgPath = m_strWorkPath + "/rawdata/"; // m_pZSKKCalib->m_strRefFilePath = m_strWorkPath + "/references/"; // m_pZSKKCalib->m_nFullImgWidth = m_nImageWidth; // m_pZSKKCalib->m_nFullImgHeight = m_nImageHeight; // m_pZSKKCalib->m_nReferenceNum = m_nCalibrationRounds; // m_pZSKKCalib->m_nSaturationValue = 50000; // //LoadZSKKGainMap 参数为false,意思是开始增益校正 // m_pZSKKCalib->LoadZSKKGainMap(false, m_strDetectorType); // m_pZSKKCalib->LoadZSKKPixelMap(false, m_strDetectorType); // FINFO("Load ecom gain and pixel map, references file path: {$}", m_pZSKKCalib->m_strRefFilePath); // } //} } FINFO("TiRayDR ActiveCalibration Over"); return true; } /*** * 接受曝光图像 ***/ bool Detector_TiRayDR::AcceptCalibration() { FINFO("--TiRayDR Func-- AcceptCalibration Start"); if (m_nCalibrationMode)//厂商校正AcceptCalibration { //不做处理 } else //ZSKK校正 { //WORD* pImageBuffer = nullptr; ////这里要注意使用的image buffer是哪个,裁剪和不裁剪是不一样的 //if (m_nWidthOffset != 0 || m_nHeightOffset != 0) //{ // pImageBuffer = m_pImgBuffer; //} //else //{ // pImageBuffer = m_pImgBuffer;//之后再做区分,先测试用 //} //if (m_nCalibCurrentExposureIndex == 1) //{ // m_pZSKKCalib->AddImageToPixMap(pImageBuffer); // m_pZSKKCalib->AverageZSKKGainMap(pImageBuffer, m_nCalibCurrentCalibrationRound - 1, true); //} //else //{ // m_pZSKKCalib->AverageZSKKGainMap(pImageBuffer, m_nCalibCurrentCalibrationRound - 1, false); //曝光第几轮 //} } FINFO("TiRayDR AcceptCalibration Over"); return true; } /*** * 拒绝曝光图像 ***/ bool Detector_TiRayDR::RejectCalibration() { const std::string funcTag = "[Detector_TiRayDR::RejectCalibration] "; // 检查当前是否在进行增益校正 if (m_eCaliType != CCOS_CALIBRATION_TYPE_XRAY) { cout << funcTag << "No active gain calibration in progress" << endl; return false; } bool rejected = false; if (m_bUseGainV2) { if (!m_currentDoseImages.empty()) { m_currentDoseImages.pop_back(); cout << funcTag << "Rejected last image in dose group " << m_currentDoseIndex << ". Remaining in group: " << m_currentDoseImages.size() << endl; rejected = true; } else { cout << funcTag << "No images in current dose group to reject" << endl; } } else { if (!m_gainCalibImages.empty()) { m_gainCalibImages.pop_back(); // 移除最后添加的图像 cout << funcTag << "Rejected last gain image. Remaining: " << m_gainCalibImages.size() << endl; rejected = true; } else { cout << funcTag << "No gain images to reject" << endl; } } return rejected; } /*** * 设置校正轮数 ***/ bool Detector_TiRayDR::SetCalibRounds(int nCalibRounds) { FINFO("--TiRayDR Func-- SetCalibRounds Start"); m_nCalibrationRounds = nCalibRounds; FINFO("Set reference number: {$}", m_nCalibrationRounds); FINFO("TiRayDR SetCalibRounds Over"); return true; } bool Detector_TiRayDR::GetCalibrationStep(int nCalibCurrentCalibrationRound, int nCalibrationRounds, int nCalibCurrentExposureIndex, int nExposureNumCurrentRound) { FINFO("--TiRayDR Func-- GetCalibrationStep Start"); m_nCalibCurrentCalibrationRound = nCalibCurrentCalibrationRound; m_nCalibrationRounds = nCalibrationRounds; m_nCalibCurrentExposureIndex = nCalibCurrentExposureIndex; m_nExposureNumCurrentRound = nExposureNumCurrentRound; FINFO("Calibration Step===Round: {$}/{$}, ExposureNum: {$}/{$}", nCalibCurrentCalibrationRound, nCalibrationRounds, nCalibCurrentExposureIndex, nExposureNumCurrentRound); FINFO("TiRayDR GetCalibrationStep Over"); return true; } bool Detector_TiRayDR::PrepareCalibration(FPDDeviceTiRay* pDrvDPC) { const std::string funcTag = "[Detector_TiRayDR::PrepareCalibration] "; std::cout << funcTag << "--TiRayDR Function-- PrepareCalibration started" << std::endl; if ((*m_pDPC2PanelID)[pDrvDPC] != m_nCurrentPanelID) { std::cout << funcTag << "Error: Not current DPC device, returning false" << std::endl; return false; } if (!m_pStPanelStatus[m_nCurrentPanelID]->bConnectState) { std::cout << funcTag << "Error: Detector not connected (bConnectState is false), returning false" << std::endl; return false; } auto writeAttrWithLog = [this](const std::string& attrName, int value, int err) { if (err == Err_Success) { std::cout << "[Detector_TiRayDR::PrepareCalibration] Success: Wrote attribute " << attrName << " with value " << value << std::endl; } else { std::cout << "[Detector_TiRayDR::PrepareCalibration] Error: Failed to write attribute " << attrName << ", error code: " << err << std::endl; } return err; }; if (CCOS_CALIBRATION_TYPE_DARK == m_eCaliType) { int ret = DarkAcquisition(); std::cout << funcTag << "Info: DarkAcquisition returned " << ret << std::endl; if (!ret) { std::cout << funcTag << "Info: Sending calibration start status (EVT_STATUS_CALIBRATIOIN, PANEL_EVENT_BEGIN)" << std::endl; StatusFeedback(EVT_STATUS_CALIBRATIOIN, PANEL_EVENT_BEGIN); } } else if (CCOS_CALIBRATION_TYPE_XRAY == m_eCaliType) { std::cout << funcTag << "Info: Preparing X-ray calibration (CCOS_CALIBRATION_TYPE_XRAY)" << std::endl; int err = write_attribute(Attr_WorkMode, WorkMode_FreeSync); writeAttrWithLog("Attr_WorkMode", WorkMode_FreeSync, err); err = write_attribute(Attr_PhotoInterval, 3000); writeAttrWithLog("Attr_PhotoInterval", 3000, err); err = write_attribute(Attr_CalibrationMode, CalibrationMode_None); writeAttrWithLog("Attr_CalibrationMode", CalibrationMode_None, err); } std::cout << funcTag << "Info: TiRayDR PrepareCalibration completed" << std::endl; return true; } //软同步调用接口,其它同步模式没有动作 bool Detector_TiRayDR::StartCalibration(FPDDeviceTiRay* pDrvDPC) { FINFO("--TiRayDR Func-- StartCalibration Start"); if ((*m_pDPC2PanelID)[pDrvDPC] != m_nCurrentPanelID) { FERROR("Not current DPC, return"); return false; } //未初始化、未连接 不执行 if (!m_pStPanelStatus[m_nCurrentPanelID]->bConnectState) { FERROR("bConnectState is false, Detector not connected, return"); return false; } if (CCOS_CALIBRATION_TYPE_DARK == m_eCaliType) { FINFO("StartCalibration DARK"); StatusFeedback(EVT_STATUS_CALIBRATIOIN, PANEL_EVENT_END_OK); m_pStPanelStatus[m_nCurrentPanelID]->eFPDStatus = eDetStatus::DetStatus_Offset; } else if (CCOS_CALIBRATION_TYPE_XRAY == m_eCaliType) { FINFO("StartCalibration XRAY"); bool ret = StartAcquisition(pDrvDPC); if (!ret) { FERROR("StartCalibration Over"); return false; } m_pStPanelStatus[m_nCurrentPanelID]->eFPDStatus = eDetStatus::DetStatus_XrayCalibration; } FINFO("TiRayDR StartCalibration Over"); return true; } /*** ** 说明:终止校正 ***/ RET_STATUS Detector_TiRayDR::AbortCalibration(FPDDeviceTiRay* pDrvDPC) { const std::string funcTag = "[Detector_TiRayDR::AbortCalibration] "; FINFO("--TiRayDR Func-- AbortCalibration Start"); if (m_eCaliType == CCOS_CALIBRATION_TYPE_XRAY) { // 清除增益校正相关数据 m_gainCalibImages.clear(); m_currentDoseImages.clear(); m_gainV2MeanImages.clear(); m_currentDoseIndex = 0; cout << funcTag << "Aborted " << (!m_bUseGainV2 ? "Gain" : "GainV2") << " calibration. All related data cleared" << endl; } auto err = write_attribute(Attr_CalibrationMode, CalibrationMode_Defect); if (err == Err_Success) { std::cout << funcTag << "Success: Wrote attribute Attr_CalibrationMode with value CalibrationMode_Defect" << std::endl; } else { std::cout << funcTag << "Error: Failed to write attribute Attr_CalibrationMode, error code: " << err << std::endl; } // 恢复初始状态 m_eCaliType = CCOS_CALIBRATION_TYPE_NONE; m_nAppStatus = APP_STATUS_CAL_END; FINFO("TiRayDR AbortCalibration Over"); return RET_STATUS::RET_SUCCEED; } bool Detector_TiRayDR::StopCalibration(FPDDeviceTiRay* pDrvDPC) { FINFO("--TiRayDR Func-- StopCalibration Start"); if ((*m_pDPC2PanelID)[pDrvDPC] != m_nCurrentPanelID) { FERROR("Not current DPC, return"); return false; } if (!m_pStPanelStatus[m_nCurrentPanelID]->bConnectState) { FERROR("bConnectState is false, Detector not connected, return"); return false; } m_nAppStatus = APP_STATUS_CAL_END; FINFO("TiRayDR StopCalibration Over"); return true; } /*** ** 说明:结束校正 ** DPC处理完校正报告后调用,此处上传map、报告等文件 ***/ bool Detector_TiRayDR::CompleteCalibration(FPDDeviceTiRay* pDrvDPC) { FINFO("--TiRayDR Func-- CompleteCalibration Start"); FINFO("Calib Type {$}", (int)m_eCaliType); const std::string funcTag = "[Detector_TiRayDR::CompleteCalibration] "; if (m_eCaliType == CCOS_CALIBRATION_TYPE_DARK) { FINFO("DARK Calib over"); } else if (m_eCaliType == CCOS_CALIBRATION_TYPE_XRAY) { FINFO("XRAY Calib over"); m_nAppStatus = APP_STATUS_CAL_END; } m_eCaliType = CCOS_CALIBRATION_TYPE_NONE; auto err = write_attribute(Attr_CalibrationMode, CalibrationMode_Defect); if (err == Err_Success) { std::cout << funcTag << "Success: Wrote attribute Attr_CalibrationMode with value CalibrationMode_Defect" << std::endl; } else { std::cout << funcTag << "Error: Failed to write attribute Attr_CalibrationMode, error code: " << err << std::endl; } FINFO("TiRayDR CompleteCalibration Over"); return true; } bool Detector_TiRayDR::SaveCalibrationFile() { FINFO("--TiRayDR Func-- SaveCalibrationFile Start"); if (m_nCalibrationMode)//厂商校正 { //不做处理 } else { FINFO("Save ZSKK Calibration File"); m_pZSKKCalib->StoreZSKKGainMap(m_strDetectorType); m_pZSKKCalib->StoreZSKKPixMap(m_strDetectorType); } //更新配置文件中校正日期和时间 GlobalTime stCurrentTime = { 0 }; GetLocalTime(&stCurrentTime); FINFO("Current time: {$04d}/{$02d}/{$02d} {$02d}:{$02d}:{$02d}:{$03d}", stCurrentTime.wYear, stCurrentTime.wMonth, stCurrentTime.wDay, stCurrentTime.wHour, stCurrentTime.wMinute, stCurrentTime.wSecond, stCurrentTime.wMilliseconds); FINFO("TiRayDR SaveCalibrationFile Over"); return true; } CCOS_CALIBRATION_TYPE Detector_TiRayDR::GetCalibType() { FINFO("--TiRayDR Func-- GetCalibType Start"); FINFO("Get Calib Type {$}", (int)m_eCaliType); FINFO("TiRayDR GetCalibType Over"); return m_eCaliType; } ModelResolveResult Detector_TiRayDR::ResolveModelType(const std::string& detectorType) { ModelResolveResult result; result.isValid = true; if (detectorType == "GQ1613") { result.model = Model_GQ1613; cout << "[Detector_TiRayDR::OpenDetector] Try to start the detector(Model_GQ1613)..." << endl; } else if (detectorType == "DY1613") { result.model = Model_DY1613; cout << "[Detector_TiRayDR::OpenDetector] Try to start the detector(Model_DY1613)..." << endl; } else if (detectorType == "LT1719") { result.model = Model_LT1719; cout << "[Detector_TiRayDR::OpenDetector] Try to start the detector(Model_LT1719)..." << endl; } else if (detectorType == "DY4343") { result.model = Model_DY4343; cout << "[Detector_TiRayDR::OpenDetector] Try to start the detector(Model_DY4343)..." << endl; } else if (detectorType == "DY2530W") { result.model = Model_DY2530W; cout << "[Detector_TiRayDR::OpenDetector] Try to start the detector(Model_DY2530W)..." << endl; } else if (detectorType == "DY2121") { result.model = Model_DY2121; cout << "[Detector_TiRayDR::OpenDetector] Try to start the detector(Model_DY2121)..." << endl; } else if (detectorType == "DY4343D") { result.model = Model_DY4343D; cout << "[Detector_TiRayDR::OpenDetector] Try to start the detector(Model_DY4343D)..." << endl; } else if (detectorType == "GZ0404") { result.model = Model_GZ0404; cout << "[Detector_TiRayDR::OpenDetector] Try to start the detector(Model_GZ0404)..." << endl; } else if (detectorType == "DY3543W") { result.model = Model_DY3543W; cout << "[Detector_TiRayDR::OpenDetector] Try to start the detector(Model_DY3543W)..." << endl; } else if (detectorType == "DY4343W") { result.model = Model_DY4343W; cout << "[Detector_TiRayDR::OpenDetector] Try to start the detector(Model_DY4343W)..." << endl; } else if (detectorType == "DY3543") { result.model = Model_DY3543; cout << "[Detector_TiRayDR::OpenDetector] Try to start the detector(Model_DY3543)..." << endl; } else { cout << "[Detector_TiRayDR::OpenDetector] Unsupported detector type: " << detectorType << endl; // 使用第一个枚举值作为默认,通过isValid标志判断有效性 result.model = Model_GQ1613; result.isValid = false; } return result; } bool Detector_TiRayDR::LoadDll(string strWorkPath) { FINFO("--TiRayDR Func-- LoadDll Start"); string strSDKPath = ""; try { strSDKPath = (string)m_ModeConfig["SDKPath"]; } catch (ResDataObjectExption& e) { FERROR("Read configuration failed! reason: {$}", e.what()); return false; } string workpath = strWorkPath + strSDKPath; string drvpath = workpath + "/TiRayLib.so"; FINFO("SDK path:{$}", drvpath); m_hTiRayDRModule = dlopen(drvpath.c_str(), RTLD_LAZY); if (m_hTiRayDRModule == nullptr) { FERROR("Load {$} failed! FERROR: {$}", drvpath.c_str(), dlerror()); return false; } LOAD_ONE_FUNC(m_hTiRayDRModule, GetSdkVersion); LOAD_ONE_FUNC(m_hTiRayDRModule, Scan); LOAD_ONE_FUNC(m_hTiRayDRModule, SetIp); LOAD_ONE_FUNC(m_hTiRayDRModule, Startup); LOAD_ONE_FUNC(m_hTiRayDRModule, Stop); LOAD_ONE_FUNC(m_hTiRayDRModule, Execute); LOAD_ONE_FUNC(m_hTiRayDRModule, ApplyPreset); LOAD_ONE_FUNC(m_hTiRayDRModule, GenerateTemplate); FINFO("TiRayDR LoadDll Over"); return true; } bool Detector_TiRayDR::ReleaseDll() { FINFO("--TiRayDR Func-- ReleaseDll Start"); if (m_hTiRayDRModule != nullptr) { int result = dlclose(m_hTiRayDRModule); if (result != 0) { const char* error = dlerror(); if (error) { FERROR("Failed to unload library: %s", error); } else { FERROR("Failed to unload library (unknown error)"); } return false; } m_hTiRayDRModule = nullptr; } FINFO("TiRayDR ReleaseDll Over"); return true; } /*** ** 连接探测器 ***/ bool Detector_TiRayDR::OpenDetector() { FINFO("--TiRayDR Func-- OpenDetector Start"); m_strWiredIP = (std::string)m_ModeConfig["DetectorWiredIP"]; m_strWirelessIP = (std::string)m_ModeConfig["DetectorWirelessIP"]; m_strLocalIP = (std::string)m_ModeConfig["LocalIP"]; m_strSerialNum = (std::string)m_ModeConfig["SerialNumber"]; FINFO("Configuration parameters loaded - Wired IP:{$}, Wireless IP:{$}, Local IP:{$}", m_strWiredIP, m_strWirelessIP, m_strLocalIP); FINFO("WiredIP: {$}, LocalIP: {$}, WirelessIP: {$}, SerialNumber:{$}", m_strWiredIP, m_strLocalIP, m_strWirelessIP, m_strSerialNum); // 检查连接状态 bool wired = CheckConnect(m_strWiredIP); bool wireless = CheckConnect(m_strWirelessIP); FINFO("[Detector_TiRayDR::OpenDetector] Connection status - Wired:{$}, wireless:{$}", wired ? "Connected" : "Not connected", wireless ? "Connected" : "Not Connected"); FINFO("[Detector_TiRayDR::OpenDetector] Start scanning the detector..."); std::vector scan_results; scan([&scan_results](scan_result&& result) { scan_results.emplace_back(std::move(result)); }); if (scan_results.empty()) { FINFO("[Detector_TiRayDR::OpenDetector] No detectors were found!"); return false; } FINFO("[Detector_TiRayDR::OpenDetector] Scanned to {$} detector:", scan_results.size()); for (auto& res : scan_results) { FINFO("[Detector_TiRayDR::OpenDetector] Serial number:{$}, Model:{$}, tupper IP:{$}, detector IP:{$}", res.sn, res.model, res.upper_ip, res.detector_ip); } m_strDetectorType = (string)m_ModeConfig["DetectorType"]; FINFO("[Detector_TiRayDR::OpenDetector] Target detector type from config: {$}", m_strDetectorType); // 选择目标探测器:优先匹配型号,否则使用第一个 scan_result target_res = scan_results[0]; bool found_matching = false; for (auto& res : scan_results) { if (res.model == m_strDetectorType) { target_res = res; found_matching = true; break; // 找到第一个匹配的即可 } } if (found_matching) { FINFO("[Detector_TiRayDR::OpenDetector] Found matching detector. Model: {$}, Serial: {$}", target_res.model, target_res.sn); } else { FINFO("[Detector_TiRayDR::OpenDetector] No matching detector model, using first detected. Model: {$}, Serial: {$}", target_res.model, target_res.sn); } // 初始化启动参数 string ip = "0.0.0.0"; StartupOption option{}; memcpy(option.Ip, ip.c_str(), std::min(ip.size(), sizeof(option.Ip) - 1)); option.EnableLog = false; // 调用解析函数处理设备类型 ModelResolveResult resolveResult = ResolveModelType(target_res.model); if (!resolveResult.isValid) { return false; } // 启动探测器 auto err = Startup_Ptr(resolveResult.model, on_event_callback, &option); if (err != Err_Success) { FINFO("[Detector_TiRayDR::OpenDetector] Failed to start the detector"); return false; } auto LoadCalibrationFile = [this](int calibrationParam) { TiRayError err; switch (calibrationParam) { case 1: err = write_attribute(Attr_CalibrationMode, CalibrationMode_None); break; case 2: err = write_attribute(Attr_CalibrationMode, CalibrationMode_Gain); break; case 3: err = write_attribute(Attr_CalibrationMode, CalibrationMode_Offset); break; case 4: err = write_attribute(Attr_CalibrationMode, CalibrationMode_Defect); break; default: FINFO("[Detector_TiRayDR::OpenDetector] Invalid calibration parameter: {$}", calibrationParam); return false; } if (err != Err_Success) { FINFO("[Detector_TiRayDR::OpenDetector] Failed to write Attr_CalibrationMode, error code: {$}", err); } else { FINFO("[Detector_TiRayDR::OpenDetector] Succeeded in writing Attr_CalibrationMode"); } return true; }; FINFO("Start setting the IP address..."); err = SetIp_Ptr(target_res.sn.c_str(), m_strLocalIP.c_str(), m_strWiredIP.c_str(), nullptr); if (err != TiRayError::Err_Success) { FINFO("The IP setting failed, error code:{$} (will continue to execute)", err); return false; } else { FINFO("IP setting was successful"); } while (!m_bConnected) { usleep(10000); } m_pStPanelStatus[m_nCurrentPanelID]->bConnectState = true; //FINFO("m_pStPanelStatus[m_nCurrentPanelID]->bConnectState = true"); //StatusFeedback(EVT_STATUS_PANEL, PANEL_CONNECT); //FINFO("Connect detector({$}) success", m_nDetectorID); if (m_strDetectorType == "DY4343" || m_strDetectorType == "DY4343D") { m_bUseGainV2 = true; } m_nImageWidth = (int)m_ModeConfig["ModeTable"][0]["ImageWidth"]; m_nImageHeight = (int)m_ModeConfig["ModeTable"][0]["ImageHeight"]; m_nRawImgWidth = (int)m_ModeConfig["ModeTable"][0]["RawImgWidth"]; m_nRawImgHeight = (int)m_ModeConfig["ModeTable"][0]["RawImgHeight"]; FINFO("After crop image width: {$}, height: {$}, WidthOffset: {$}, HeightOffset: {$}", m_nImageWidth, m_nImageHeight, m_nWidthOffset, m_nHeightOffset); m_bSaveRaw = (int)m_ModeConfig["ModeTable"][0]["IsSaveRaw"]; if (m_pRawImgBuffer == nullptr) { m_pRawImgBuffer = new WORD[(size_t)m_nRawImgHeight * (size_t)m_nRawImgWidth]; } if (true) { m_pImgBuffer = new WORD[(size_t)m_nImageWidth * (size_t)m_nImageWidth]; } // 加载校准文件 cout << "[Detector_TiRayDR::OpenDetector] Start loading the calibration file..." << endl; //if (m_nCalibrationMode) //TiRayCalibration SetSyncMode(3); int nSensitivity = (int)m_ModeConfig["ModeTable"][0]["Sensitivity"]; int nXWindow = (int)m_ModeConfig["ModeTable"][0]["XWindow"]; err = write_attribute(Attr_PhotoInterval, nXWindow); if (err != Err_Success) FINFO("[Detector_TiRayDR::OpenDetector] Failed to write Attr_PhotoInterval. Error code: {$}", err); err = write_attribute(Attr_PhotoNumber, 1); if (err != Err_Success) FINFO("[Detector_TiRayDR::OpenDetector] Failed to write Attr_PhotoNumber. Error code: {$}", err); LoadCalibrationFile(4); err = write_attribute(Attr_AEDSensitivity, nSensitivity); if (err != Err_Success) FINFO("[Detector_TiRayDR::OpenDetector] Failed to write Attr_AEDSensitivity. Error code: {$}", err); SetTiRayDPCStatus(eDetStatus::DetStatus_Standby); FINFO("OpenDetector Over"); return true; } bool Detector_TiRayDR::CheckConnect(string strIP) { CMyPingip obPingIp; if (!obPingIp.PingFunction(strIP.c_str())) { FINFO("ping {$} Failed", strIP); return false; } return true; } bool Detector_TiRayDR::OpenStatusMonitor() { FINFO("---Open Status Monitor Thread---"); if (m_hStatusMonitorThread == 0) // 检查线程是否已创建 { int result = pthread_create(&m_hStatusMonitorThread, NULL, TiRayStatusMonitorThread, this); if (result != 0) { FERROR("Failed to create status monitor thread: %d", result); return false; } } return true; } void* Detector_TiRayDR::TiRayStatusMonitorThread(PVOID pvoid) { Detector_TiRayDR* pCurrentPanelOpr = static_cast(pvoid); if (pCurrentPanelOpr == nullptr) { FERROR("TiRay Status Monitor parameter FERROR"); return nullptr; } FINFO("Begin StatusMonitor"); DWORD dwStatusCheckTime = 5000; while (!pCurrentPanelOpr->m_bMonitorFlag) { pCurrentPanelOpr->StatusMonitor(); usleep(pCurrentPanelOpr->m_nNotifyStatusTimePeriod*1000); } return 0; } bool Detector_TiRayDR::StatusMonitor() { if (!m_pStPanelStatus[m_nCurrentPanelID]->bConnectState) { FERROR("Detector not connected, return"); ErrorFeedback(EVT_ERR_COMMUNICATE, "true"); return false; } //StatusType: 1:Temperature 2:Wifi 3:Battery //auto ReadStatus = [this](int StatusType) //{ // TiRayVariant TempParam[1]{}; // TempParam[0].Type = TiRayVariant::TiRayInt; //}; int nTemperature = 0; int nWifiQuality = 0; int nBatteryLevel = 0; TiRayVariant TemperatureParam[1]{}; TemperatureParam[0].Type = TiRayVariant::TiRayInt; TemperatureParam[0].IntValue = 0; Execute_Ptr(m_nDetectorID, Cmd_ReadAttribute, TemperatureParam, 1); nTemperature = TemperatureParam[0].IntValue; TiRayVariant WifiParam[1]{}; WifiParam[0].Type = TiRayVariant::TiRayInt; WifiParam[0].IntValue = nWifiQuality; Execute_Ptr(m_nDetectorID, Cmd_ReadAttribute, WifiParam, 1); TiRayVariant BatteryParam[1]{}; BatteryParam[0].Type = TiRayVariant::TiRayInt; BatteryParam[0].IntValue = nBatteryLevel; Execute_Ptr(m_nDetectorID, Cmd_ReadAttribute, BatteryParam, 1); StatusFeedback(EVT_STATUS_TEMPERATURE, 0, "", m_nCurrentPanelID, nTemperature); StatusFeedback(EVT_STATUS_BATTERY_VALUE, nBatteryLevel, "", m_nCurrentPanelID); StatusFeedback(EVT_STATUS_WIFI, nWifiQuality, "", m_nCurrentPanelID); return true; } bool Detector_TiRayDR::CloseStatusMonitor() { m_bMonitorFlag = true; m_hStatusMonitorThread = 0; FINFO("---Close Status Monitor Thread---"); return true; } bool Detector_TiRayDR::CloseDetectorScan() { m_hExitEvent->SetEvent(); return false; } bool Detector_TiRayDR::LoadCalibrationFiles(int nCalibrationMode) { FINFO("--TiRayDR Func-- LoadCalibrationFiles"); int nRes; TiRayVariant Param[2]{}; Param[0].Type = TiRayVariant::TiRayInt; Param[0].IntValue = TiRayAttribute::Attr_CalibrationMode; Param[1].Type = TiRayVariant::TiRayInt; if (nCalibrationMode == 1) { Param[1].IntValue = CalibrationMode::CalibrationMode_None; } else if (nCalibrationMode == 2) { Param[1].IntValue = CalibrationMode::CalibrationMode_Gain; } else if (nCalibrationMode == 3) { Param[1].IntValue = CalibrationMode::CalibrationMode_Offset; } else if (nCalibrationMode == 4) { Param[1].IntValue = CalibrationMode::CalibrationMode_Defect; FINFO("All Calibration Mode"); } nRes = Execute_Ptr(m_nDetectorID, Cmd_WriteAttribute, Param, 2); if ((TiRayError)nRes != TiRayError::Err_Success) { FERROR("Use CalibrationMode Failed, Reason:{$}", nRes); return false; } else { FINFO("Use CalibrationMode Success"); } FINFO("LoadCalibrationFiles Over"); return true; } void* Detector_TiRayDR::onFPDScanThread(PVOID pvoid) { Detector_TiRayDR* pOpr = (Detector_TiRayDR*)pvoid; FINFO("Enter scan thread"); bool bExit = false; DWORD dwTimeOut = INFINITE; while (!bExit) { DWORD dwRet = LinuxEvent::WaitForMultipleEvents(pOpr->m_hArrayEvent,dwTimeOut); if (WAIT_OBJECT_0 == dwRet) //m_hInitEvent { pOpr->OnProcessInitFPD(); } else if (WAIT_OBJECT_0 + 1 == dwRet) //m_hExitEvent { bExit = true; } else if (WAIT_OBJECT_0 + 2 == dwRet) //m_hReConnectEvent { pOpr->OnReconnectFPD(); } else if (WAIT_OBJECT_0 + 3 == dwRet) //m_hRadEvent { FINFO("[Get Rad Event]"); pOpr->OpenRadAcquisition(); } else if (WAIT_TIMEOUT == dwRet) { } } pOpr->m_hToggleEvent->SetEvent(); FINFO("Leave scan thread"); return 0; } void Detector_TiRayDR::OnProcessInitFPD() { FINFO("--TiRayDR Func-- OnProcessInitFPD"); StatusFeedback(EVT_STATUS_INIT, PANEL_EVENT_START); if (!LoadDll(m_strWorkPath)) { ErrorFeedback(EVT_ERR_INIT_FAILED, "true"); StatusFeedback(EVT_STATUS_INIT, PANEL_EVENT_END_ERROR); //初始化失败 return; } register_event_listener(OnEvent); FINFO("Register Event Listener"); if (!OpenDetector()) { FINFO("Open detector failed, Connect failed"); ErrorFeedback(EVT_ERR_COMMUNICATE, "true"); StatusFeedback(EVT_STATUS_INIT, PANEL_EVENT_END); //初始化时连接失败 } else { m_pStPanelStatus[m_nCurrentPanelID]->bInitOver = true; StatusFeedback(EVT_STATUS_INIT, PANEL_EVENT_END_OK); } FINFO("OnProcessInitFPD Over"); } void Detector_TiRayDR::OnReconnectFPD() { FINFO("OnReconnectFPD start"); if (m_hReconnectThread == 0) { m_bReconnectThreadRunning = true; int result = pthread_create(&m_hReconnectThread, NULL, onReconnectThread, this); if (result != 0) { FERROR("Failed to create reconnect thread: %d", result); m_hReconnectThread = 0; m_bReconnectThreadRunning = false; } } FINFO("OnReconnectFPD end"); } /*** ** 获取一帧暗场图 ***/ int Detector_TiRayDR::DarkAcquisition() { const std::string funcTag = "[Detector_TiRayDR::DarkAcquisition] "; TiRayError err; // 设置校准模式为None err = write_attribute(Attr_CalibrationMode, CalibrationMode_None); if (err != Err_Success) { cout << funcTag << "Failed to write Attr_CalibrationMode. Error code: " << err << endl; return -1; } // 设置拍摄间隔 err = write_attribute(Attr_PhotoInterval, 1000); if (err != Err_Success) { cout << funcTag << "Failed to write Attr_PhotoInterval. Error code: " << err << endl; return -1; } // 设置工作模式为空闲 err = write_attribute(Attr_WorkMode, WorkMode_Idle); if (err != Err_Success) { cout << funcTag << "Failed to write Attr_WorkMode. Error code: " << err << endl; return -1; } // 执行拍摄命令 err = Execute_Ptr(m_nDetectorID, Cmd_Photo, nullptr, 0); if (err != Err_Success) { cout << funcTag << "Failed to Execute_Ptr Cmd_Photo. Error code: " << err << endl; return -1; } return 0; // 成功执行返回0 } /*** ** 裁剪图像 ** pOutImg: 裁剪后图像; pInImg: 裁剪前图像; nInWidth: 裁剪前图像宽度 ***/ bool Detector_TiRayDR::GetEffectiveImage(WORD* pOutImg, WORD* pInImg, int nInWidth) { if (pOutImg == NULL || pInImg == NULL || nInWidth < 0) { FERROR("Illegal parameter, can not get effective image"); return false; } try { for (int i = 0; i < m_nImageHeight; i++) { memcpy(pOutImg + i * m_nImageWidth, pInImg + (i + m_nHeightOffset) * nInWidth + m_nWidthOffset, m_nImageWidth * sizeof(WORD)); } } catch (...) { FERROR("Get effective image crashed"); return false; } return true; } Detector_TiRayDR::eDetStatus Detector_TiRayDR::GetTiRayDPCStatus(int nDetectorIndex) { if (-1 == nDetectorIndex) { nDetectorIndex = m_nCurrentPanelID; } string strStatus = "Unknown"; switch (m_pStPanelStatus[nDetectorIndex]->eFPDStatus) { case eDetStatus::DetStatus_NotIni: strStatus = "NotIni"; break; case eDetStatus::DetStatus_NotConn: strStatus = "NotConn"; break; case eDetStatus::DetStatus_Sleep: strStatus = "Sleep"; break; case eDetStatus::DetStatus_Standby: strStatus = "Standby"; break; case eDetStatus::DetStatus_Work: strStatus = "Work"; break; case eDetStatus::DetStatus_Acquire: strStatus = "Acquire"; break; case eDetStatus::DetStatus_Offset: strStatus = "Offset"; break; case eDetStatus::DetStatus_XrayCalibration: strStatus = "XrayCalibration"; break; default: break; } FINFO("Driver status: {$}", strStatus.c_str()); return m_pStPanelStatus[nDetectorIndex]->eFPDStatus; } bool Detector_TiRayDR::SetTiRayDPCStatus(eDetStatus status, int nDetectorIndex) { if (-1 == nDetectorIndex) { nDetectorIndex = m_nCurrentPanelID; } string strStatus = "Unknown"; bool bSetStatus = true; switch (status) { case eDetStatus::DetStatus_NotIni: strStatus = "NotIni"; break; case eDetStatus::DetStatus_NotConn: strStatus = "NotConn"; break; case eDetStatus::DetStatus_Sleep: strStatus = "Sleep"; break; case eDetStatus::DetStatus_Standby: strStatus = "Standby"; break; case eDetStatus::DetStatus_Work: strStatus = "Work"; break; case eDetStatus::DetStatus_Acquire: strStatus = "Acquire"; break; case eDetStatus::DetStatus_Offset: strStatus = "Offset"; break; case eDetStatus::DetStatus_XrayCalibration: strStatus = "XrayCalibration"; break; default: bSetStatus = false; break; } if (bSetStatus) { m_pStPanelStatus[nDetectorIndex]->eFPDStatus = status; FINFO("Set driver status: {$}", strStatus.c_str()); } else { FERROR("{$} {$} is a illegal status", strStatus, (int)status); } return bSetStatus; } bool Detector_TiRayDR::IsConnected(string strIP) { FINFO("Check ping {$}", strIP); CMyPingip obPingIp; if (!obPingIp.PingFunction(strIP.c_str())) { FINFO("ping {$} Failed", strIP); return false; } return true; } bool Detector_TiRayDR::CheckConnection() { return false; } bool Detector_TiRayDR::ReConnectFPD() { CloseStatusMonitor(); return true; } bool Detector_TiRayDR::OpenRadAcquisition() { FINFO("---Begin Rad Acquisition Thread---"); m_bExitRadAcqStatus = true; if (m_hRadAcquisitionThread == 0) { int result = pthread_create(&m_hRadAcquisitionThread, NULL, RadAcquisitionThread, this); if (result != 0) { FERROR("Failed to create status monitor thread: %d", result); return false; } } return true; } void* Detector_TiRayDR::RadAcquisitionThread(void* pParam) { Detector_TiRayDR* pCurrentPanelOpr = reinterpret_cast(pParam); if (pCurrentPanelOpr == nullptr) { FERROR("Query Acq Status Thread parameter FERROR"); } pCurrentPanelOpr->PerformRadAcquisition(); pCurrentPanelOpr->CloseRadAcquisition(); return nullptr; } bool Detector_TiRayDR::PerformRadAcquisition() { FINFO("## PerformRadAcquisition ##"); FINFO("Start Acquisition"); FINFO("DetectorID: {$}", m_nDetectorID); //int nRes = Execute_Ptr(m_nDetectorID, Cmd_Photo, nullptr, 0); //if ((TiRayError)nRes != TiRayError::Err_Success) //{ // FERROR("Start Acquisition Failed"); //} while (true) { usleep(100000); if (!m_bExitRadAcqStatus) { break; } } m_hExitRadAcqStatus->SetEvent(); FINFO("PerformRadAcquisition Over"); return true; } bool Detector_TiRayDR::CloseRadAcquisition() { m_bExitRadAcqStatus = false; bool dwResult = false; if (m_hExitRadAcqStatus) { dwResult = m_hExitRadAcqStatus->Wait(1000); } if (dwResult) { FINFO("[Get ExitRadAcqStatus Event]"); } else { if (m_hRadAcquisitionThread != 0) { pthread_cancel(m_hRadAcquisitionThread); // 等待线程实际退出 struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += 1; // 等待1秒 pthread_timedjoin_np(m_hRadAcquisitionThread, nullptr, &ts); FWARN("Kill QueryAcqStatus Thread"); } FWARN("Kill QueryAcqStatus Thread"); } m_hRadAcquisitionThread = 0; FINFO("---Exit Rad Acq Status Thread---"); return true; } /*** ** 检测接口是否有错误,true:有错;false:没错 ***/ bool Detector_TiRayDR::TestError(TiRayError nErrorCode) { if (nErrorCode == TiRayError::Err_Success) { return true; } else { switch (nErrorCode) { case TiRayError::Err_SystemFailure: { FERROR("System Internal Error"); break; } case TiRayError::Err_WrongModel: { FERROR("The specified model is incorrect"); break; } case TiRayError::Err_DetectorNonExists: { FERROR("The specified detector with the given ID dose not exist"); break; } case TiRayError::Err_NetworkFailure: { FERROR("The network communication has failed"); break; } case TiRayError::Err_InvalidParam: { FERROR("The provided parameters are incorrect"); break; } case TiRayError::Err_UploadInProgress: { FERROR("The upload is in progress"); break; } default: FERROR("Unkonwn Error"); break; } return false; } } void Detector_TiRayDR::register_event_listener(const EventListener& fn) { const auto iter = std::find_if(m_listeners.begin(), m_listeners.end(), [&fn](auto& listener) { return listener.template target() == fn.template target(); }); if (iter == m_listeners.end()) m_listeners.push_back(fn); } void Detector_TiRayDR::unregister_event_listener(const EventListener& fn) { const auto iter = std::find_if(m_listeners.begin(), m_listeners.end(), [&fn](auto& listener) { return listener.template target() == fn.template target(); }); if (iter == m_listeners.end()) m_listeners.erase(iter); } bool Detector_TiRayDR::cropImage(unsigned short* srcData, int srcWidth, int srcHeight, unsigned short* destData, int destWidth, int destHeight) { // 验证指针有效性 if (srcData == nullptr || destData == nullptr) { cout << "[Detector_TiRayDR::cropImage] Error: Source or destination pointer is null" << endl; return false; } // 验证尺寸合法性 if (destWidth <= 0 || destHeight <= 0 || srcWidth <= 0 || srcHeight <= 0 || destWidth > srcWidth || destHeight > srcHeight) { cout << "[Detector_TiRayDR::cropImage] Invalid crop size: src(" << srcWidth << "x" << srcHeight << ") dest(" << destWidth << "x" << destHeight << ")" << endl; return false; } // 计算裁剪起始位置 int startX = (srcWidth - destWidth) / 2; int startY = (srcHeight - destHeight) / 2; // 边界检查 if (startX < 0) startX = 0; if (startY < 0) startY = 0; // 确保裁剪区域不会超出源图像边界 if (startX + destWidth > srcWidth) { destWidth = srcWidth - startX; cout << "[Detector_TiRayDR::cropImage] Adjusted destWidth to " << destWidth << " to avoid out-of-bounds access" << endl; } if (startY + destHeight > srcHeight) { destHeight = srcHeight - startY; cout << "[Detector_TiRayDR::cropImage] Adjusted destHeight to " << destHeight << " to avoid out-of-bounds access" << endl; } // 逐行复制裁剪区域 for (int y = 0; y < destHeight; ++y) { // 计算源图像行起始地址 const unsigned short* srcRow = srcData + (startY + y) * srcWidth + startX; // 计算目标图像行起始地址 unsigned short* destRow = destData + y * destWidth; // 复制一行像素 memcpy(destRow, srcRow, destWidth * sizeof(unsigned short)); } cout << "[Detector_TiRayDR::cropImage] Successfully cropped image from " << srcWidth << "x" << srcHeight << " to " << destWidth << "x" << destHeight << endl; return true; } std::string Detector_TiRayDR::saveProcessedImage(Detector_TiRayDR& detector, unsigned short* data, size_t size, const std::string& baseTimestamp) { const size_t MAX_PROC_FILE_COUNT = 10; const std::string TMPFS_DIR = "/mnt/tmpfs/"; const std::string ORIGINAL_DIR = detector.m_strWorkPath + "/RawData/"; std::string procDir; bool useTmpfs = false; // 确定存储目录 if (std::filesystem::exists(TMPFS_DIR) && std::filesystem::is_directory(TMPFS_DIR)) { procDir = TMPFS_DIR; useTmpfs = true; std::cout << "[Detector_TiRayDR::saveProcessedImage] Using tmpfs directory: " << procDir << std::endl; } else { procDir = ORIGINAL_DIR; std::cout << "[Detector_TiRayDR::saveProcessedImage] /mnt/tmpfs not found, using original directory: " << procDir << std::endl; } const std::string FILE_PREFIX = "Proc_"; std::string filePath; try { std::filesystem::create_directories(procDir); filePath = procDir + FILE_PREFIX + baseTimestamp + ".raw"; std::ofstream file(filePath, std::ios::binary); if (file.is_open()) { file.write(reinterpret_cast(detector.m_pImgBuffer), size); std::cout << "[Detector_TiRayDR::saveProcessedImage] Saved image: " << filePath << std::endl; } else { std::cout << "[Detector_TiRayDR::saveProcessedImage] Failed to open file: " << filePath << std::endl; return ""; } cleanOldFiles(procDir, FILE_PREFIX, MAX_PROC_FILE_COUNT, useTmpfs); } catch (const std::filesystem::filesystem_error& e) { std::cout << "[Detector_TiRayDR::saveProcessedImage] File system error: " << e.what() << std::endl; return ""; } catch (const std::exception& e) { std::cout << "[Detector_TiRayDR::saveProcessedImage] Unexpected error: " << e.what() << std::endl; return ""; } return filePath; } void Detector_TiRayDR::saveRawImage(Detector_TiRayDR& detector, unsigned short* data, size_t size, const std::string& baseTimestamp) { const std::string RAW_DIR = detector.m_strWorkPath + "/OriginalData/"; const std::string FILE_PREFIX = "orig_"; const size_t MAX_RAW_FILE_COUNT = 20; std::string filePath; try { std::filesystem::create_directories(RAW_DIR); filePath = RAW_DIR + FILE_PREFIX + baseTimestamp + ".raw"; std::ofstream file(filePath, std::ios::binary); if (file.is_open()) { // 直接写入unsigned short缓冲区数据 file.write(reinterpret_cast(data), size); cout << "[Detector_TiRayDR::saveRawImage] Saved raw image: " << filePath << endl; } else { cout << "[Detector_TiRayDR::saveRawImage] Failed to open file: " << filePath << endl; return; } // 清理旧的原始图 cleanOldFiles(RAW_DIR, FILE_PREFIX, MAX_RAW_FILE_COUNT, false); } catch (const std::filesystem::filesystem_error& e) { cout << "[Detector_TiRayDR::saveRawImage] File system error: " << e.what() << endl; } } std::filesystem::space_info getFileSystemInfo(const std::string& dirPath) { try { return std::filesystem::space(dirPath); } catch (const std::filesystem::filesystem_error& e) { std::cout << "[getFileSystemInfo] Failed to get filesystem info for " << dirPath << ": " << e.what() << std::endl; return {}; } } void Detector_TiRayDR::cleanOldFiles(const std::string& dirPath, const std::string& filePrefix, size_t maxCount, bool checkSize) { const std::string funcTag = "[Detector_TiRayDR::cleanOldFiles] "; try { // 检查目录是否存在 if (!std::filesystem::exists(dirPath) || !std::filesystem::is_directory(dirPath)) { std::cout << funcTag << "Directory not found: " << dirPath << std::endl; return; } std::vector targetFiles; for (const auto& entry : std::filesystem::directory_iterator(dirPath)) { // 只处理常规文件 if (!entry.is_regular_file()) continue; // 检查文件扩展名是否为.raw const std::string extension = entry.path().extension().string(); if (extension != ".raw") continue; // 检查文件名是否以指定前缀开头 const std::string filename = entry.path().filename().string(); if (filename.length() < filePrefix.length()) continue; if (filename.substr(0, filePrefix.length()) == filePrefix) { targetFiles.push_back(entry); } } // 按文件最后修改时间排序(最旧的在前) std::sort(targetFiles.begin(), targetFiles.end(), [](const std::filesystem::directory_entry& a, const std::filesystem::directory_entry& b) { return std::filesystem::last_write_time(a) < std::filesystem::last_write_time(b); }); // 1. 先按数量限制清理 size_t filesToDelete = 0; if (targetFiles.size() > maxCount) { filesToDelete = targetFiles.size() - maxCount; // 删除超出数量限制的最旧文件 for (size_t i = 0; i < filesToDelete; ++i) { const auto& fileToDelete = targetFiles[i]; if (std::filesystem::remove(fileToDelete.path())) { std::cout << funcTag << "Deleted old file (count limit): " << fileToDelete.path() << std::endl; } else { std::cout << funcTag << "Failed to delete file: " << fileToDelete.path() << std::endl; } } // 更新目标文件列表(移除已删除的文件) targetFiles.erase(targetFiles.begin(), targetFiles.begin() + filesToDelete); filesToDelete = 0; // 重置计数器用于大小检查 } // 2. 如果需要,按大小限制清理(仅对tmpfs目录) if (checkSize && !targetFiles.empty()) { // 获取文件系统信息 auto fsInfo = getFileSystemInfo(dirPath); if (fsInfo.capacity == 0) // 获取信息失败 { std::cout << funcTag << "Cannot check filesystem size, skipping size check" << std::endl; return; } // 计算最大允许使用空间(预留10%作为缓冲) const uintmax_t reservedSpace = fsInfo.capacity / 10; // 10%预留空间 const uintmax_t maxAllowedSize = fsInfo.capacity - reservedSpace; // 计算当前文件总大小 auto calculateTotalSize = [](const std::vector& files) { uintmax_t total = 0; for (const auto& file : files) { total += file.file_size(); } return total; }; uintmax_t currentTotalSize = calculateTotalSize(targetFiles); std::cout << funcTag << "Current files total size: " << currentTotalSize << ", Max allowed size: " << maxAllowedSize << std::endl; // 如果当前总大小超过限制,继续删除最旧的文件 while (currentTotalSize > maxAllowedSize && !targetFiles.empty()) { const auto& fileToDelete = targetFiles[0]; uintmax_t fileSize = fileToDelete.file_size(); if (std::filesystem::remove(fileToDelete.path())) { std::cout << funcTag << "Deleted old file (size limit): " << fileToDelete.path() << " (" << fileSize << " bytes)" << std::endl; // 更新总量和文件列表 currentTotalSize -= fileSize; targetFiles.erase(targetFiles.begin()); filesToDelete++; } else { std::cout << funcTag << "Failed to delete file: " << fileToDelete.path() << std::endl; break; // 删除失败时停止处理 } } } std::cout << funcTag << "Cleanup completed. Deleted " << filesToDelete << " files. Remaining: " << targetFiles.size() << std::endl; } catch (const std::filesystem::filesystem_error& e) { std::cout << funcTag << "File system error: " << e.what() << std::endl; } catch (const std::exception& e) { std::cout << funcTag << "Unexpected error: " << e.what() << std::endl; } } void Detector_TiRayDR::handleHardwareSyncImage(Detector_TiRayDR& detector, TiRayVariant argv[]) { detector.StatusFeedback(EVT_STATUS_PANEL, PANEL_XWINDOW_ON); const size_t rawPixelCount = argv[3].DataLen / sizeof(unsigned short); detector.m_pRawImgBuffer = reinterpret_cast(argv[3].DataValue); const size_t rawSize = rawPixelCount * sizeof(unsigned short); bool cropSuccess = cropImage( detector.m_pRawImgBuffer, detector.m_nRawImgWidth, detector.m_nRawImgHeight, // 原始图像宽高 detector.m_pImgBuffer, detector.m_nImageWidth, detector.m_nImageHeight // 目标宽高 ); if (!cropSuccess) { cout << "[Detector_TiRayDR::handleAedSyncImage] Failed to crop image" << endl; return; } const size_t processedSize = detector.m_nImageWidth * detector.m_nImageHeight * sizeof(unsigned short); // 生成关联的基础文件名 const std::string baseTimestamp = std::to_string( std::chrono::duration_cast( std::chrono::system_clock::now().time_since_epoch() ).count() ); std::string processedImagePath = saveProcessedImage( detector, detector.m_pImgBuffer, processedSize, baseTimestamp ); if (detector.m_bSaveRaw) { saveRawImage( detector, detector.m_pRawImgBuffer, rawSize, baseTimestamp ); } // 应用校准 // applyCalibration(detector); detector.InfoFeedback(EVT_DATA_RAW_IMAGE, -1, 0, 0, processedImagePath.c_str()); //detector.StatusFeedback(EVT_STATUS_PANEL, PANEL_XWINDOW_OFF); detector.m_bExitRadAcqStatus = false; } void Detector_TiRayDR::handleSoftwareSyncImage(Detector_TiRayDR& detector, TiRayVariant argv[]) { detector.StatusFeedback(EVT_STATUS_PANEL, PANEL_XWINDOW_ON); const size_t rawPixelCount = argv[3].DataLen / sizeof(unsigned short); detector.m_pRawImgBuffer = reinterpret_cast(argv[3].DataValue); const size_t rawSize = rawPixelCount * sizeof(unsigned short); bool cropSuccess = cropImage( detector.m_pRawImgBuffer, detector.m_nRawImgWidth, detector.m_nRawImgHeight, // 原始图像宽高 detector.m_pImgBuffer, detector.m_nImageWidth, detector.m_nImageHeight // 目标宽高 ); if (!cropSuccess) { cout << "[Detector_TiRayDR::handleSoftwareSyncImage] Failed to crop image" << endl; return; } const size_t processedSize = detector.m_nImageWidth * detector.m_nImageHeight * sizeof(unsigned short); // 生成关联的基础文件名 const std::string baseTimestamp = std::to_string( std::chrono::duration_cast( std::chrono::system_clock::now().time_since_epoch() ).count() ); std::string processedImagePath = saveProcessedImage( detector, detector.m_pImgBuffer, processedSize, baseTimestamp ); if (detector.m_bSaveRaw) { saveRawImage( detector, detector.m_pRawImgBuffer, rawSize, baseTimestamp ); } detector.InfoFeedback(EVT_DATA_RAW_IMAGE, -1, 0, 0, processedImagePath.c_str()); // 应用校准 // applyCalibration(detector); //detector.StatusFeedback(EVT_STATUS_PANEL, PANEL_XWINDOW_OFF); detector.m_bExitRadAcqStatus = false; } void Detector_TiRayDR::handleAedSyncImage(Detector_TiRayDR& detector, TiRayVariant argv[]) { detector.StatusFeedback(EVT_STATUS_PANEL, PANEL_START_ACQ); detector.StatusFeedback(EVT_STATUS_PANEL, PANEL_XRAY_ON); detector.StatusFeedback(EVT_STATUS_PANEL, PANEL_XWINDOW_ON); const size_t rawPixelCount = argv[3].DataLen / sizeof(unsigned short); detector.m_pRawImgBuffer = reinterpret_cast(argv[3].DataValue); const size_t rawSize = rawPixelCount * sizeof(unsigned short); bool cropSuccess = cropImage( detector.m_pRawImgBuffer, detector.m_nRawImgWidth, detector.m_nRawImgHeight, // 原始图像宽高 detector.m_pImgBuffer, detector.m_nImageWidth, detector.m_nImageHeight // 目标宽高 ); if (!cropSuccess) { cout << "[Detector_TiRayDR::handleAedSyncImage] Failed to crop image" << endl; return; } const size_t processedSize = detector.m_nImageWidth * detector.m_nImageHeight * sizeof(unsigned short); // 生成关联的基础文件名 const std::string baseTimestamp = std::to_string( std::chrono::duration_cast( std::chrono::system_clock::now().time_since_epoch() ).count() ); std::string processedImagePath = saveProcessedImage( detector, detector.m_pImgBuffer, processedSize, baseTimestamp ); if (detector.m_bSaveRaw) { saveRawImage( detector, detector.m_pRawImgBuffer, rawSize, baseTimestamp ); } // applyCalibration(detector); detector.InfoFeedback(EVT_DATA_RAW_IMAGE, -1, 0, 0, processedImagePath.c_str()); detector.m_bAEDWorkFlag = false; //usleep(500000); //detector.StatusFeedback(EVT_STATUS_PANEL, PANEL_XWINDOW_OFF); detector.m_bExitRadAcqStatus = false; } void Detector_TiRayDR::handleDarkCalibration(Detector_TiRayDR& detector, TiRayVariant argv[]) { const std::string funcTag = "[Detector_TiRayDR::handleDarkCalibration] "; static int callCount = 0; static std::vector datas; // 处理当前传入的图像数据 auto size = argv[3].DataLen; auto data = argv[3].DataValue; image_info image; image.width = argv[0].IntValue; image.height = argv[1].IntValue; image.data.resize(size); memcpy(image.data.data(), data, size); // 将当前图像数据存入集合 TiRayVariant variant; variant.Type = TiRayVariant::TiRayBuffer; variant.DataLen = static_cast(image.data.size()); variant.DataValue = image.data.data(); datas.push_back(variant); // 调用次数递增(当前已处理的图像数量) callCount++; // 若未收集到6张图,调用拍摄命令准备下一张 if (callCount < 6) { auto err = Execute_Ptr(detector.m_nDetectorID, Cmd_Photo, nullptr, 0); if (err != Err_Success) { cout << funcTag << "Failed to execute Cmd_Photo for next image. Error code: " << err << endl; // 重置状态,避免异常累积 callCount = 0; datas.clear(); return; } cout << funcTag << "Prepared for " << callCount + 1 << "th image" << endl; } // 收集到6张图,执行模板生成和上传 else { image_info template_image; template_image.data.resize(datas[0].DataLen); template_image.width = image.width; template_image.height = image.height; // 生成模板并检查结果 auto err = GenerateTemplate_Ptr(Offset, datas.data(), static_cast(datas.size()), template_image.data.data(), static_cast(template_image.data.size())); if (err != Err_Success) { cout << funcTag << "Failed to generate offset template. Error code: " << err << endl; } else { cout << funcTag << "Offset template generated successfully with 6 images" << endl; // 上传模板并检查结果 err = detector.upload(detector.offset, template_image.data.data(), static_cast(template_image.data.size())); if (err != Err_Success) { cout << funcTag << "Failed to upload offset template. Error code: " << err << endl; } else { cout << funcTag << "Offset template uploaded successfully" << endl; } } // 重置静态变量,为下一次校准做准备 callCount = 0; datas.clear(); } } void Detector_TiRayDR::handleGainCalibration(Detector_TiRayDR& detector, TiRayVariant argv[]) { const std::string funcTag = "[Detector_TiRayDR::handleGainCalibration] "; int doseCount = 5; // 剂量数量 int imagesPerDose = 6; // 每个剂量的图像数量 auto size = argv[3].DataLen; auto data = argv[3].DataValue; // 创建图像信息并存储 image_info image; image.width = argv[0].IntValue; image.height = argv[1].IntValue; image.data.resize(size); memcpy(image.data.data(), data, size); // 根据模式存储图像 if (!detector.m_bUseGainV2) { // Gain模式:直接存储所有30张图像 detector.m_gainCalibImages.push_back(image); cout << funcTag << "Gain mode - Collected " << detector.m_gainCalibImages.size() << "/" << doseCount * imagesPerDose << " images" << endl; // 收集完30张图像后生成并上传模板 if (detector.m_gainCalibImages.size() == doseCount * imagesPerDose) { cout << funcTag << "All 30 gain calibration images collected, generating template..." << endl; // 准备数据并生成Gain模板 std::vector datas; for (auto& img : detector.m_gainCalibImages) { TiRayVariant variant; variant.Type = TiRayVariant::TiRayBuffer; variant.DataLen = static_cast(img.data.size()); variant.DataValue = img.data.data(); datas.push_back(variant); } image_info template_image; template_image.width = detector.m_gainCalibImages[0].width; template_image.height = detector.m_gainCalibImages[0].height; template_image.data.resize(datas[0].DataLen); auto err = GenerateTemplate_Ptr(Gain, datas.data(), static_cast(datas.size()), template_image.data.data(), static_cast(template_image.data.size())); if (err != Err_Success) { cout << funcTag << "Failed to generate Gain template. Error code: " << err << endl; } else { cout << funcTag << "Gain template generated successfully" << endl; // 上传模板 err = detector.upload(detector.gain, template_image.data.data(), static_cast(template_image.data.size())); if (err != Err_Success) { cout << funcTag << "Failed to upload Gain template. Error code: " << err << endl; } else { cout << funcTag << "Gain template uploaded successfully" << endl; } } // 清空存储的图像,准备下次校正 detector.m_gainCalibImages.clear(); } } else if (detector.m_bUseGainV2) { // Gainv2模式:按剂量组存储图像 detector.m_currentDoseImages.push_back(image); cout << funcTag << "Gainv2 mode - Collected " << detector.m_currentDoseImages.size() << "/" << imagesPerDose << " images for dose " << detector.m_currentDoseIndex + 1 << endl; // 收集完当前剂量的6张图像后生成均值图 if (detector.m_currentDoseImages.size() == imagesPerDose) { cout << funcTag << "All " << imagesPerDose << " images for dose " << detector.m_currentDoseIndex + 1 << " collected, generating mean image..." << endl; // 生成当前剂量的均值图 std::vector datas; for (auto& img : detector.m_currentDoseImages) { TiRayVariant variant; variant.Type = TiRayVariant::TiRayBuffer; variant.DataLen = static_cast(img.data.size()); variant.DataValue = img.data.data(); datas.push_back(variant); } image_info mean_image; mean_image.width = detector.m_currentDoseImages[0].width; mean_image.height = detector.m_currentDoseImages[0].height; mean_image.data.resize(datas[0].DataLen); auto err = GenerateTemplate_Ptr(Mean, datas.data(), static_cast(datas.size()), mean_image.data.data(), static_cast(mean_image.data.size())); if (err != Err_Success) { cout << funcTag << "Failed to generate mean image for dose " << detector.m_currentDoseIndex + 1 << ". Error code: " << err << endl; // 清空当前剂量数据,重新收集 detector.m_currentDoseImages.clear(); return; } // 保存均值图并重置当前剂量图像集合 detector.m_gainV2MeanImages.push_back(mean_image); detector.m_currentDoseImages.clear(); detector.m_currentDoseIndex++; cout << funcTag << "Mean image for dose " << detector.m_currentDoseIndex << " generated successfully. Total mean images: " << detector.m_gainV2MeanImages.size() << endl; // 收集完5个剂量的均值图后生成最终模板 if (detector.m_gainV2MeanImages.size() == doseCount) { cout << funcTag << "All " << doseCount << " mean images collected, generating final GainV2 template..." << endl; // 生成最终的GainV2模板 std::vector meanDatas; for (auto& meanImg : detector.m_gainV2MeanImages) { TiRayVariant variant; variant.Type = TiRayVariant::TiRayBuffer; variant.DataLen = static_cast(meanImg.data.size()); variant.DataValue = meanImg.data.data(); meanDatas.push_back(variant); } image_info final_template; final_template.width = detector.m_gainV2MeanImages[0].width; final_template.height = detector.m_gainV2MeanImages[0].height; final_template.data.resize(meanDatas[0].DataLen); auto err = GenerateTemplate_Ptr(GainV2, meanDatas.data(), static_cast(meanDatas.size()), final_template.data.data(), static_cast(final_template.data.size())); if (err != Err_Success) { cout << funcTag << "Failed to generate GainV2 template. Error code: " << err << endl; } else { cout << funcTag << "GainV2 template generated successfully" << endl; // 上传模板 err = detector.upload(detector.gain, final_template.data.data(), static_cast(final_template.data.size())); if (err != Err_Success) { cout << funcTag << "Failed to upload GainV2 template. Error code: " << err << endl; } else { cout << funcTag << "GainV2 template uploaded successfully" << endl; } } // 重置所有存储和计数器,准备下次校正 detector.m_gainV2MeanImages.clear(); detector.m_currentDoseIndex = 0; } } } } void Detector_TiRayDR::handleImageReceived(Detector_TiRayDR& detector, TiRayVariant argv[]) { // 处理暗校准模式 if (CCOS_CALIBRATION_TYPE_DARK == detector.m_eCaliType) { handleDarkCalibration(detector, argv); return; } else if (CCOS_CALIBRATION_TYPE_XRAY == detector.m_eCaliType) { handleGainCalibration(detector, argv); return; } // 根据同步模式处理图像 switch (detector.m_nSyncMode) { case SYNC_MODE::SYNC_AED: handleAedSyncImage(detector, argv); break; case SYNC_MODE::SYNC_SOFTWARE: handleSoftwareSyncImage(detector, argv); break; case SYNC_MODE::SYNC_HARDWARE: handleHardwareSyncImage(detector, argv); break; } } void Detector_TiRayDR::on_event_callback(int detectorId, TiRayEvent eventType, TiRayVariant argv[], int argc, void* reservedArg, int reservedArgLen) { auto& detector = *g_pDetector; const std::string funcTag = "[Detector_TiRayDR::on_event_callback] "; switch (eventType) { case TiRayEvent::Evt_DetectorConnect: { detector.m_nDetectorID = detectorId; detector.m_bConnected = true; detector.m_pStPanelStatus[detector.m_nCurrentPanelID]->bConnectState = true; detector.StatusFeedback(EVT_STATUS_PANEL, PANEL_CONNECT); cout << funcTag << "Evt_DetectorConnect!!!" << endl; FINFO("Evt_DetectorConnect!!"); break; } case TiRayEvent::Evt_DetectorDisconnect: { detector.m_nDetectorID = INT_MAX; detector.m_bConnected = false; detector.m_pStPanelStatus[detector.m_nCurrentPanelID]->bConnectState = false; detector.StatusFeedback(EVT_STATUS_PANEL, PANEL_CLOSE); detector.m_hReConnectEvent->SetEvent(); cout << funcTag << "Evt_DetectorDisconnect!!!" << endl; FINFO("Evt_DetectorDisconnect!!"); break; } case TiRayEvent::Evt_WriteAttribute: { FINFO("WriteAttribute Success"); break; } case TiRayEvent::Evt_ReadAttribute: { FINFO("ReadAttribute Success"); //const TiRayAttribute attrib = (TiRayAttribute)argv[0].IntValue; //if (attrib == Attr_BatteryStatus) { // auto battery_level = argv[1].IntValue; // auto is_recharging = argv[2].IntValue; //} break; } case TiRayEvent::Evt_ImageReceived: { cout << funcTag << "Evt_ImageReceived!!!" << endl; FINFO("Evt_ImageReceived!!"); handleImageReceived(detector, argv); break; } case TiRayEvent::Evt_ExposureStatus: { FINFO("argv {$}, argc {$}", argv[0].IntValue, argc); if (argv[0].IntValue == 0) { detector.m_bAEDReady = true; } if (argv[0].IntValue == 1) { detector.m_bAEDReady = false; } break; } case TiRayEvent::Evt_UploadProgress: cout << funcTag << "Upload progress: " << argv[0].IntValue << "%" << endl; break; case TiRayEvent::Evt_UpdateFinish: cout << funcTag << "Update completed successfully" << endl; detector.StatusFeedback(EVT_STATUS_CALIBRATIOIN, PANEL_EVENT_END_OK); break; case TiRayEvent::Evt_UploadTimeout: // 输出上传超时警告 cout << funcTag << "Warning: Upload timed detectorData" << endl; break; default: FERROR("not support current event ID:{$}", (int)eventType); break; } } void Detector_TiRayDR::ConfFeedback(int nEventID, int nDetectorID, const char* pszMsg, int nParam1, float fParam2, int nPtrParamLen, void* pParam) { if (-1 == nDetectorID) { nDetectorID = m_nCurrentPanelID; } ((FPDDeviceTiRay*)(*m_pPanelID2DPC)[nDetectorID])->OnFPDCallback(nDetectorID, nEventID, EVT_LEVEL_CONFIGURATION, pszMsg, nParam1, fParam2, nPtrParamLen, pParam); } void Detector_TiRayDR::InfoFeedback(int nEventID, int nDetectorID, int nParam1, float fParam2, const char* pszMsg, int nPtrParamLen, void* pParam) { if (-1 == nDetectorID) { nDetectorID = m_nCurrentPanelID; } ((FPDDeviceTiRay*)(*m_pPanelID2DPC)[nDetectorID])->OnFPDCallback(nDetectorID, nEventID, EVT_LEVEL_INFORMATOION, pszMsg, nParam1, fParam2, nPtrParamLen, pParam); } void Detector_TiRayDR::StatusFeedback(int nEventID, int nParam1, const char* pszMsg, int nDetectorID, float fParam2, int nPtrParamLen, void* pParam) { if (-1 == nDetectorID) { nDetectorID = m_nCurrentPanelID; } ((FPDDeviceTiRay*)(*m_pPanelID2DPC)[nDetectorID])->OnFPDCallback(nDetectorID, nEventID, EVT_LEVEL_STATUS, pszMsg, nParam1, fParam2, nPtrParamLen, pParam); } void Detector_TiRayDR::DataFeedback(int nEventID, void* pParam, int nParam1, float fParam2, const char* pszMsg, int nPtrParamLen, int nDetectorID) { if (-1 == nDetectorID) { nDetectorID = m_nCurrentPanelID; } ((FPDDeviceTiRay*)(*m_pPanelID2DPC)[nDetectorID])->OnFPDCallback(nDetectorID, nEventID, EVT_LEVEL_DATA, pszMsg, nParam1, fParam2, nPtrParamLen, pParam); } void Detector_TiRayDR::WarnFeedback(int nEventID, const char* pszMsg, int nParam1, float fParam2, int nPtrParamLen, void* pParam, int nDetectorID) { if (-1 == nDetectorID) { nDetectorID = m_nCurrentPanelID; } ((FPDDeviceTiRay*)(*m_pPanelID2DPC)[nDetectorID])->OnFPDCallback(nDetectorID, nEventID, EVT_LEVEL_WARNING, pszMsg, nParam1, fParam2, nPtrParamLen, pParam); } void Detector_TiRayDR::ErrorFeedback(int nEventID, const char* pszMsg, int nDetectorID, int nParam1, float fParam2, int nPtrParamLen, void* pParam) { if (-1 == nDetectorID) { nDetectorID = m_nCurrentPanelID; } ((FPDDeviceTiRay*)(*m_pPanelID2DPC)[nDetectorID])->OnFPDCallback(nDetectorID, nEventID, EVT_LEVEL_ERROR, pszMsg, nParam1, fParam2, nPtrParamLen, pParam); } bool Detector_TiRayDR::UpdateCalibMode(CCOS_CALIBRATION_MODE eCalibMode) { FINFO("--TiRayDR Func-- UpdateCalibMode"); FINFO("CalibMode:{$}", (int)eCalibMode); m_nCalibrationMode = eCalibMode; FINFO("UpdateCalibMode Over"); return true; } void Detector_TiRayDR::SetNotifyStatusTimePeriod(int nTime) { FINFO("--Func TiRay-- SetNotifyStatusTimePeriod Start"); FINFO("NotifyStatusTimePeriod:{$}", nTime); m_nNotifyStatusTimePeriod = nTime; FINFO("SetNotifyStatusTimePeriod Over"); } void Detector_TiRayDR::SetReconnectTimePeriod(int nTime) { FINFO("--Func TiRay-- SetReconnectTimePeriod Start"); FINFO("ReconnectTimePeriod:{$}", nTime); m_nReconnectTimePeriod = nTime; FINFO("SetReconnectTimePeriod Over"); } int Detector_TiRayDR::TiRay_GetSdkVersion() { return GetSdkVersion_Ptr(); } TiRayError Detector_TiRayDR::TiRay_Execute(int detectorId, int commandId, TiRayVariant argv[], int argc) { return Execute_Ptr(detectorId, commandId, argv, argc); } TiRayError Detector_TiRayDR::TiRay_ApplyPreset(int detectorId, TiRayVariant argv[], int argc, ResultCallback fn) { return ApplyPreset_Ptr(detectorId, argv, argc, fn); } TiRayError Detector_TiRayDR::TiRay_GenerateTemplate(TemplateType type, TiRayVariant images[], int count, void* templateBuffer, int bufferSize) { return GenerateTemplate_Ptr(type, images, count, templateBuffer, bufferSize); } TiRayError Detector_TiRayDR::TiRay_Scan(ResultCallback fn, const char* interfaceIp, int scanDuration) { return Scan_Ptr(fn, interfaceIp, scanDuration); } TiRayError Detector_TiRayDR::TiRay_SetIp(const char* detectorSN, const char* upperIp, const char* lowerIp, const char* interfaceIp) { return SetIp_Ptr(detectorSN, upperIp, lowerIp, interfaceIp); } TiRayError Detector_TiRayDR::TiRay_Startup(TiRayModel model, EventCallback fn, const StartupOption* option) { return Startup_Ptr(model, fn, option); } void Detector_TiRayDR::TiRay_Stop() { Stop_Ptr(); } /*** ** 说明:重连探测器线程 ***/ void* Detector_TiRayDR::onReconnectThread(PVOID pvoid) { FINFO("Reconnect detector thread start"); Detector_TiRayDR* pThis = static_cast(pvoid); while (!pThis->m_bConnected) { pThis->OpenDetector(); usleep(pThis->m_nReconnectTimePeriod*1000); } pThis->m_bReconnectThreadRunning = false; FINFO("Leave reconnect detector thread"); return 0; } TiRayError Detector_TiRayDR::upload(upload_type type, char* data, int size) { TiRayVariant param[1]{}; param[0].Type = TiRayVariant::TiRayBuffer; param[0].DataValue = data; param[0].DataLen = size; if (type == offset) { return Execute_Ptr(m_nDetectorID, Cmd_UploadOffsetTemplate, param, 1); } if (type == gain) { return Execute_Ptr(m_nDetectorID, Cmd_UploadGainTemplate, param, 1); } if (type == firmware) { return Execute_Ptr(m_nDetectorID, Cmd_UpdateFirmware, param, 1); } return Err_InvalidParam; }