// // Created by Krad on 2021/10/12. // #include "ShimLib/ShimLib.h" #include "DeviceManager.h" #include "../event/EventCenter.h" #include #include #include #include #include #include "appvals/AppGlobalValues.h" #include "json/ScanJson.h" #include "json/jsonobject.h" #define TRIGGER_EVENT EventCenter::Default()->triggerEvent #define THROW_ERROR(errormsg)\ TRIGGER_EVENT(GUIEvents::GUIErrorRaise, nullptr, (QObject*)&errormsg); const char* getStatusString(int status) { switch (status) { case SCANNING: return "SCANNING"; case READY: return "Ready"; case BUSY: return "BUSY"; case ERROR: return "ERROR"; } return ""; } std::string getJsonFromPatInf(QObject* obj) { return ((QString*)obj)->toStdString(); } void ErrorCallback(const char* msg) { DeviceManager::Default()->emitErrorCallback(msg); } void DeviceManager::emitErrorCallback(const char *msg) { this->setErrorOccurred(true); printf("Error Callback , message:%s\r\n", msg); QString m(msg); emit raiseGlobalError( m); } void DeviceManager::initDevice() { InitLib(ErrorCallback); deviceInfTimerID = startTimer(1000); // empty scan connect(EventCenter::Default(), &EventCenter::RequestEmptyScan, [=](QObject* sender, QObject* detail) { std::string json = getJsonFromPatInf(detail); processScan(json.c_str(), true); }); // Patient scan connect(EventCenter::Default(), &EventCenter::RequestPatientScan, [=](QObject* sender, QObject* detail) { std::string json = getJsonFromPatInf(detail); qDebug() << json.c_str(); if (!json.empty()) { processScan(json.c_str()); } }); // Continue Scan connect(EventCenter::Default(), &EventCenter::RequestContinueScan, [=](QObject* sender, QObject* detail) { postContinueCommand(true); }); // stop connect(EventCenter::Default(), &EventCenter::RequestStop, [=]() { qDebug() << "GetStatus"; StatusInfo inf = GetStatus(); qDebug() << "Stop request status, status:%s" << getStatusString(inf.status); // check device status========================================= //device is ready return if (inf.status != SCANNING) { //double check QThread::msleep(100); inf = GetStatus(); if (inf.status != SCANNING){ TRIGGER_EVENT(GUIEvents::ResponseStop, nullptr, nullptr); return; } } AppGlobalValues::setInProcessing(true); TRIGGER_EVENT(GUIEvents::InvokeOperationStart, nullptr, nullptr); //ScanControl fail qDebug() << "Request stop!"; if (timerID != -1)killTimer(timerID); if (ScanControl(STOP)) { qDebug() << "Stop fail!"; QString msg("Stop operation fail!"); THROW_ERROR(msg); qDebug() << "Error thrown!"; lastStatus = -1; previewing = false; QString s("%1 %2"); s = s.arg(QDateTime::currentDateTime().toString("yyyy/MM/dd HH:mm:ss"), msg); TRIGGER_EVENT(GUIEvents::GlobalBannerMessage, nullptr, (QObject*)&msg); return; } lastStatus = -1; previewing = false; QString s("%1 %2"); s = s.arg(QDateTime::currentDateTime().toString("yyyy/MM/dd HH:mm:ss"), ("Scan Stopped!")); TRIGGER_EVENT(GUIEvents::GlobalBannerMessage, nullptr, (QObject*)&s); TRIGGER_EVENT(GUIEvents::InvokeOperationEnd, nullptr, nullptr); TRIGGER_EVENT(GUIEvents::ResponseStop, nullptr, nullptr); AppGlobalValues::setInProcessing(false); }); // preview connect(EventCenter::Default(), &EventCenter::RequestPreviewScan, [=]() { // check device status========================================= qDebug() << "GetStatus"; StatusInfo inf = GetStatus(); qDebug() << "PreviewScan request status, status:" << getStatusString(inf.status); if (inf.status == READY) { AppGlobalValues::setInProcessing(true); TRIGGER_EVENT(GUIEvents::InvokeOperationStart, nullptr, nullptr); //ScanControl qDebug() << "Request preview!"; if (!ScanControl(PREVIEW_SCAN)) { qDebug() << "Preview success!"; lastStatus = SCANNING; previewing = true; // timerID = startTimer(500); TRIGGER_EVENT(GUIEvents::ResponsePreview, nullptr, nullptr); TRIGGER_EVENT(GUIEvents::InvokeOperationEnd, nullptr, nullptr); QString s("Device Previewing!"); TRIGGER_EVENT(GUIEvents::GlobalBannerMessage, nullptr, (QObject*)&s); return; } } qDebug() << "Preview fail!"; QString msg(inf.status != READY ? "Can't start preview,Device is not ready!" : "Start preview operation fail!"); THROW_ERROR(msg); qDebug() << "Error thrown!"; }); previewDataCaller = QThread::create([=]() { while (!endLoop) { if (!previewing) { QThread::sleep(3); continue; } // check device status========================================= qDebug() << "GetStatus"; StatusInfo inf = GetStatus(); qDebug() << "GetPreviewData request status, status:" << getStatusString(inf.status); // device is preview scanning, try get preview data if (inf.status == SCANNING) { qDebug() << "Preview data reader read start!"; const char* data = GetPreviewData(); if (!data)continue; qDebug() << "Preview data reader read end!"; QByteArray bytes = QByteArray::fromRawData(data, 140 * 140); //double check if (!previewing) { qDebug() << "Preview data reader long sleep!"; QThread::sleep(3); continue; } qDebug() << "Preview data response event start!"; TRIGGER_EVENT(GUIEvents::ResponsePreviewData, nullptr, (QObject*)(&bytes)); qDebug() << "Preview data response event end!"; } QThread::msleep(100); } }); previewDataCaller->start(); } const char * getPhaseName(int phase){ const char* names[3] = {"Initializing","Scanning", "CE Measuring"}; return names[phase-1]; } void DeviceManager::timerEvent(QTimerEvent* event) { if (event->timerId() == deviceInfTimerID) { QString temp = QString(GetDeviceInfo(MEAN_TEMPERATURE)); TRIGGER_EVENT(GUIEvents::ResponseDeviceTemperature, nullptr, (QObject*)&temp); return; } //scanning progress timer { //error exit, callback error if (errorOccurred) { goto exitTimer; } // previewing exit if (previewing) { QString msg("Device is previewing, exit current operation!"); THROW_ERROR(msg); goto exitTimer; } else { // check device status========================================= qDebug() << "GetStatus"; StatusInfo inf = GetStatus(); qDebug() << "Scanning request status, status:" << getStatusString(inf.status); //设备正常扫描中 if (inf.status == SCANNING) { qDebug() << "current output path:" << getScanOutputPath(); lastStatus = SCANNING; //normal scan pending int phase = inf.progress/100 + 1; int progress = inf.progress % 100; QString extraMsg = (AppGlobalValues::EmptyScanFlag().toBool()||(scanPhase != 3))?"":", patient can leave"; QVariant var(QString("%1%3\r\n progress:%2%").arg(getPhaseName(scanPhase)).arg(progress).arg(extraMsg)); TRIGGER_EVENT(GUIEvents::InvokeOperationProgress, nullptr, (QObject *) &var); if (scanPhase != phase) { if (phase > 3 || scanPhase > phase ){ QString errorMsg = QString("Error Scan Phase code, current Phase code:%1, new Phase code:%2!").arg(scanPhase,phase); THROW_ERROR(errorMsg) goto exitTimer; } scanPhase = phase; if (scanPhase == 2){ if (!AppGlobalValues::EmptyScanFlag().toBool() && JsonObject::Instance()->getScanConfirm()) { var.setValue(QString("Waiting for patient to start scan!\r\n Click \"Next\" to continue!")); TRIGGER_EVENT(GUIEvents::InvokeOperationPending, nullptr, (QObject *) &var); goto exitTimer; } //empty scan no pending, auto continue else { postContinueCommand(); } } } return; } else { //未发生错误并且,之前状态是扫描,代表正常扫描完成 if (lastStatus == SCANNING) { qDebug() << "Scan finished"; QVariant var(true); qDebug() << "InvokeOperationEnd"; TRIGGER_EVENT(GUIEvents::InvokeOperationEnd, nullptr, (QObject*)&var); AppGlobalValues::setInProcessing(false); lastStatus = -1; previewing = false; QString s("%1 %2"); s = s.arg(QDateTime::currentDateTime().toString("yyyy/MM/dd HH:mm:ss")).arg("Scan finished"); TRIGGER_EVENT(GUIEvents::GlobalBannerMessage, nullptr, (QObject*)&s); QString outputPath = GetDeviceInfo(DeviceInfo::DEV_OUTPATH); outputPath = outputPath.replace("\\","/"); if (outputPath.endsWith('/')) outputPath = outputPath.remove(outputPath.length()-1,1); QStringList list = outputPath.split('/'); if (list.length()){ if (AppGlobalValues::EmptyScanFlag().toBool()){ ScanJson::Current()->setEmptyScanID(list.last().toStdString().c_str()); }else{ ScanJson::Current()->setScanID(list.last().toStdString().c_str()); } ScanJson::Current()->save(); } else{ QString msg("Scan Output Path error!"); THROW_ERROR(msg); } } //一般不会出现其他情况 else { QString msg("Unknown error in scanning progress timer"); THROW_ERROR(msg); } } } exitTimer: qDebug() << "Scanning progress Timer exit"; killTimer(timerID); timerID = -1; lastStatus = -1; previewing = false; return; } } void DeviceManager::processScan(const char* json, bool empty) { //clear last error state first errorOccurred = false; // check device status========================================= qDebug() << "GetStatus"; StatusInfo inf = GetStatus(); qDebug() << "Scan start request status, status:" << getStatusString(inf.status); if (inf.status != READY) { QString errmsg("Device is not ready, start scan operation fail!status is %1"); errmsg = errmsg.arg(getStatusString(inf.status)); THROW_ERROR(errmsg); return; } static QString msg = "Start scan..."; AppGlobalValues::setInProcessing(true); TRIGGER_EVENT(GUIEvents::InvokeOperationStart, nullptr, (QObject*)&msg); qDebug() << "SetScanInfo>>>>>>>>>>>>>>>>>>>>"; AppGlobalValues::setEmptyScanFlag(empty); int ret = SetScanInfo(json, empty ? 1 : 0); if (ret) { qDebug() << ">>>>>>>>>>>>>>>>>>>>SetScanInfo failed"; QString errmsg("Transfer patient information fail!"); qDebug() << "Error thrown"; THROW_ERROR(errmsg); return; } qDebug() << ">>>>>>>>>>>>>>>>>>>>SetScanInfo success"; postScanCommand(); } void DeviceManager::postScanCommand() { qDebug() << "ScanControl start>>>>>>>>>>>>>>>>>>>>>"; if (!ScanControl(SCAN)) { qDebug() << ">>>>>>>>>>>>>>>>>>>>>ScanControl success"; //set current state lastStatus = SCANNING; previewing = false; scanPhase = 1; qDebug() << "Start progress timer"; timerID = startTimer(500); return; } //ScanControl fail QString errmsg("ScanControl start fail!"); THROW_ERROR(errmsg); qDebug() << ">>>>>>>>>>>>>>>>>>>>>ScanControl failed"; } void DeviceManager::postContinueCommand(bool useTimer) { if (!ScanControl(SCAN_CONTINUE)) { if (useTimer)timerID = startTimer(500); return; } //ScanControl fail QString errmsg("ScanControl start fail!"); THROW_ERROR(errmsg); } void DeviceManager::close() { #ifdef _WIN32 StopDevice(); #endif previewDataCaller->terminate(); delete previewDataCaller; } QString DeviceManager::getSoftwareVersion() { return GetDeviceInfo(VERSION); } QString DeviceManager::getScanOutputPath() { return GetDeviceInfo(DEV_OUTPATH); }