#include "dcm_find.h" //-------------------------------------------------------------------------- // dcm_cfind_callback dcm_cfind_callback::dcm_cfind_callback() : DcmFindSCUCallback() , extractResponse_(FEM_xmlFile) , cancelAfterNReponses_(-1) , outputDirectory_(".") { } dcm_cfind_callback::dcm_cfind_callback(DcmFindSCUExtractMode extractResponse, int cancelAfterNResponse, const char *outputDirectory) : DcmFindSCUCallback() , extractResponse_(extractResponse) , cancelAfterNReponses_(cancelAfterNResponse) , outputDirectory_(outputDirectory) { } void dcm_cfind_callback::callback(T_DIMSE_C_FindRQ *request, int &responseCount, T_DIMSE_C_FindRSP *rsp, DcmDataset *responseIdentifiers) { std::string outputFileName; char rspIdsFileName[32]; if (extractResponse_ == FEM_dicomFile) { sprintf(rspIdsFileName, "rsp%04d.dcm", responseCount); OFStandard::combineDirAndFilename(outputFileName, outputDirectory_, rspIdsFileName, true); DcmFindSCU::writeToFile(outputFileName.c_str(), responseIdentifiers); } else if (extractResponse_ == FEM_xmlFile) { sprintf(rspIdsFileName, "rsp%04d.xml", responseCount); OFStandard::combineDirAndFilename(outputFileName, outputDirectory_, rspIdsFileName, true); DcmFindSCU::writeToXMLFile(outputFileName.c_str(), responseIdentifiers); } else if (extractResponse_ == FEM_singleXMLFile) { } } std::string dcm_cfind_callback::get_outputdir() { return outputDirectory_; } bool dcm_cfind_callback::verify() { if (extractResponse_ == DcmFindSCUExtractMode::FEM_none) return true; if (!OFStandard::dirExists(outputDirectory_)) { // log >> output directory does not exist return false; } else if (!OFStandard::isWriteable(outputDirectory_)) { // log >> output directory is not writtable return false; } return true; } //-------------------------------------------------------------------------- // dcm-cfind ////dcm_cfind::dcm_cfind() //// : abortAssociation(false) //// , abstractSyntax(UID_FINDPatientRootQueryRetrieveInformationModel) //// , acse_timeout(30) //// , blockMode(DIMSE_BLOCKING) //// , dimse_timeout(0) //// , maxReceivePDULength(ASC_DEFAULTMAXPDU) //// , networkTransferSyntax(EXS_Unknown) //// , repeatCount(1) //// , cfind_callback(nullptr) //// ////{ //// peerIp_ = "127.0.0.1"; //// peerPort_ = 104; //// peerTitle_ = ""; //// ourTitle_ = ""; ////} dcm_cfind::dcm_cfind(const char *peerIp, unsigned long peerPort, const char *peerTitle, const char *ourTile) : abortAssociation(false) , abstractSyntax(UID_FINDPatientRootQueryRetrieveInformationModel) , acse_timeout(30) , blockMode(DIMSE_BLOCKING) , dimse_timeout(0) , maxReceivePDULength(ASC_DEFAULTMAXPDU) , networkTransferSyntax(EXS_Unknown) , repeatCount(1) , cfind_callback(nullptr) { peerIp_ = peerIp; peerPort_ = peerPort; peerTitle_ = peerTitle; ourTitle_ = ourTile; } dcm_cfind::~dcm_cfind() { } void dcm_cfind::set_asce_timeout(int timeout) { acse_timeout = timeout; } void dcm_cfind::set_dimse_timeout(int timeout) { dimse_timeout = timeout; } void dcm_cfind::set_max_received_pdu_lenght(unsigned long length) { maxReceivePDULength = length; } void dcm_cfind::set_find_callback(dcm_cfind_callback *callback) { cfind_callback = callback; } void dcm_cfind::initQueryInfo() { overrideKeys.clear(); overrideKeys.push_back("0008,0020="); // StudyDate overrideKeys.push_back("0008,0050="); // AccessionNumber overrideKeys.push_back("0010,0010="); // PatientName overrideKeys.push_back("0010,0020="); // PatientID overrideKeys.push_back("0010,0030="); // PatientBirthDate overrideKeys.push_back("0010,0040="); // PatientSex overrideKeys.push_back("0010,1010="); // PatientAge overrideKeys.push_back("0020,000D="); // StudyInstanceUID overrideKeys.push_back("0020,0010="); // StudyID overrideKeys.push_back("0032,1032="); // RequestingPhysician overrideKeys.push_back("0020,000E="); // SeriesInstanceUID overrideKeys.push_back("0008,0060="); // Modality overrideKeys.push_back("0020,0011="); // SeriesNumber } // for the purpose to get all the information we need, store a template DICOM file to contains all the information we need // AND to return a int code to upper user, need to define globle erro code int dcm_cfind::find_by_patient_id(std::string patient_id) { //abstractSyntax = UID_FINDPatientRootQueryRetrieveInformationModel; abstractSyntax = UID_FINDStudyRootQueryRetrieveInformationModel; initQueryInfo(); std::string query_level = "0008,0052="; //query_level += "PATIENT"; query_level += "STUDY"; overrideKeys.push_back(query_level); std::string patient_id_ = "0010,0020="; patient_id_ += patient_id; overrideKeys.push_back(patient_id_); int ret = 0; OFCondition cond = docfind(); cond == EC_Normal ? ret = 0 : ret = cond.code(); return ret; } int dcm_cfind::find_by_patient_id_and_date(std::string patient_id, std::string startdate, std::string enddate) { //abstractSyntax = UID_FINDPatientRootQueryRetrieveInformationModel; abstractSyntax = UID_FINDStudyRootQueryRetrieveInformationModel; initQueryInfo(); std::string query_level = "0008,0052="; //query_level += "PATIENT"; query_level += "STUDY"; overrideKeys.push_back(query_level); std::string patient_id_ = "0010,0020="; patient_id_ += patient_id; overrideKeys.push_back(patient_id_); std::string study_date_ = "0008,0020="; if (!startdate.empty()) { study_date_ += startdate; study_date_ += "-"; } if (!enddate.empty()) study_date_ += enddate; overrideKeys.push_back(study_date_.c_str()); int ret = 0; OFCondition cond = docfind(); cond == EC_Normal ? ret = 0 : ret = cond.code(); return ret; } int dcm_cfind::find_by_patient_name(std::string patient_name) { //abstractSyntax = UID_FINDPatientRootQueryRetrieveInformationModel; abstractSyntax = UID_FINDStudyRootQueryRetrieveInformationModel; initQueryInfo(); std::string query_level = "0008,0052="; //query_level += "PATIENT"; query_level += "STUDY"; overrideKeys.push_back(query_level); std::string patient_name_ = "0010,0010="; patient_name_ += patient_name; overrideKeys.push_back(patient_name_); int ret = 0; OFCondition cond = docfind(); cond == EC_Normal ? ret = 0 : ret = cond.code(); return ret; } int dcm_cfind::find_by_patient_name_and_date(std::string patient_name, std::string startdate, std::string enddate) { //abstractSyntax = UID_FINDPatientRootQueryRetrieveInformationModel; abstractSyntax = UID_FINDStudyRootQueryRetrieveInformationModel; initQueryInfo(); std::string query_level = "0008,0052="; //query_level += "PATIENT"; query_level += "STUDY"; overrideKeys.push_back(query_level); std::string patient_name_ = "0010,0010="; patient_name_ += patient_name; overrideKeys.push_back(patient_name_); std::string study_date_ = "0008,0020="; if (!startdate.empty()) { study_date_ += startdate; study_date_ += "-"; } if (!enddate.empty()) study_date_ += enddate; overrideKeys.push_back(study_date_.c_str()); int ret = 0; OFCondition cond = docfind(); cond == EC_Normal ? ret = 0 : ret = cond.code(); return ret; } int dcm_cfind::find_by_accession_no(std::string accession_no) { //abstractSyntax = UID_FINDPatientRootQueryRetrieveInformationModel; abstractSyntax = UID_FINDStudyRootQueryRetrieveInformationModel; initQueryInfo(); std::string query_level = "0008,0052="; //query_level += "PATIENT"; query_level += "STUDY"; overrideKeys.push_back(query_level); std::string accession_number = "0008,0050="; accession_number += accession_no; overrideKeys.push_back(accession_number); int ret = 0; OFCondition cond = docfind(); cond == EC_Normal ? ret = 0 : ret = cond.code(); return ret; } int dcm_cfind::find_by_accession_no_and_date(std::string accession_no, std::string startdate, std::string enddate) { //abstractSyntax = UID_FINDPatientRootQueryRetrieveInformationModel; abstractSyntax = UID_FINDStudyRootQueryRetrieveInformationModel; initQueryInfo(); std::string query_level = "0008,0052="; //query_level += "PATIENT"; query_level += "STUDY"; overrideKeys.push_back(query_level); std::string accession_number = "0008,0050="; accession_number += accession_no; overrideKeys.push_back(accession_number); std::string study_date_ = "0008,0020="; if (!startdate.empty()) { study_date_ += startdate; study_date_ += "-"; } if (!enddate.empty()) study_date_ += enddate; overrideKeys.push_back(study_date_.c_str()); int ret = 0; OFCondition cond = docfind(); cond == EC_Normal ? ret = 0 : ret = cond.code(); return ret; } int dcm_cfind::find_by_study_uid(std::string study_uid) { abstractSyntax = UID_FINDStudyRootQueryRetrieveInformationModel; initQueryInfo(); std::string query_level = "0008,0052="; //query_level += "STUDY"; query_level += "SERIES"; overrideKeys.push_back(query_level); std::string study_instance_uid_ = "0020,000D="; study_instance_uid_ += study_uid; overrideKeys.push_back(study_instance_uid_); int ret = 0; OFCondition cond = docfind(); cond == EC_Normal ? ret = 0 : ret = cond.code(); return ret; } int dcm_cfind::find_by_series_uid(std::string study_uid) { abstractSyntax = UID_FINDStudyRootQueryRetrieveInformationModel; initQueryInfo(); std::string query_level = "0008,0052="; query_level += "SERIES"; overrideKeys.push_back(query_level); std::string study_instance_uid_ = "0020,000D="; study_instance_uid_ += study_uid; overrideKeys.push_back(study_instance_uid_); int ret = 0; OFCondition cond = docfind(); cond == EC_Normal ? ret = 0 : ret = cond.code(); return ret; } int dcm_cfind::find_by_series_uid(std::string study_uid, std::string series_uid) { abstractSyntax = UID_FINDStudyRootQueryRetrieveInformationModel; initQueryInfo(); std::string query_level = "0008,0052="; query_level += "STUDY"; overrideKeys.push_back(query_level); std::string study_instance_uid_ = "0020,000D="; study_instance_uid_ += study_uid; overrideKeys.push_back(study_instance_uid_); std::string series_instance_uid_ = "0020,000E="; series_instance_uid_ += series_uid; overrideKeys.push_back(series_instance_uid_); int ret = 0; OFCondition cond = docfind(); cond == EC_Normal ? ret = 0 : ret = cond.code(); return ret; } int dcm_cfind::find_by_timeinterval(std::string startDate, std::string endDate) { abstractSyntax = UID_FINDModalityWorklistInformationModel; // Since worklist is used to get infos which // will be used by upper user to construct user/study info, // So we set all the infos except the filter to empty, // and then pass them to C-Find SCP who will fill these // value in response initQueryInfo(); std::string scheduleStartDate = "(0040,0100)[0].(0040,0002)="; if (!startDate.empty()) { scheduleStartDate += startDate; scheduleStartDate += "-"; } if (!endDate.empty()) { //std::string scheduleEndDate = "(0040,0100)[0].(0040,0002)="; //scheduleEndDate += endDate; //overrideKeys.push_back(scheduleEndDate.c_str()); scheduleStartDate += endDate; } overrideKeys.push_back(scheduleStartDate.c_str()); int ret = 0; OFCondition cond = docfind(); cond == EC_Normal ? ret = 0 : ret = cond.code(); return ret; } // METHOD performQuery method from DCMTK sucks OFCondition dcm_cfind::docfind() { OFStandard::initializeNetwork(); if (cfind_callback == nullptr) { // log >> No callback is provided cfind_callback = new dcm_cfind_callback(DcmFindSCUExtractMode::FEM_xmlFile, -1, "."); // Donnot need to verify, since the query operation should not care about property of callback } DcmFindSCU findscu; OFCondition cond = findscu.initializeNetwork(acse_timeout); if (cond.bad()) { // log >> failed to connect scp; return cond; } cond = findscu.performQuery(peerIp_, peerPort_, ourTitle_, peerTitle_, abstractSyntax, networkTransferSyntax, blockMode, dimse_timeout, maxReceivePDULength, false, abortAssociation, repeatCount, DcmFindSCUExtractMode::FEM_none, -1, &overrideKeys, cfind_callback, &fileNameList, "", ""); if (cond.bad()) { // log >> query failed return cond; } cond = findscu.dropNetwork(); if (cond.bad()) { // log >> drop network failed return cond; } OFStandard::shutdownNetwork(); return cond; }