// // Created by Krad on 2021/10/12. // #include "DeviceManager.h" #include #include #include #include #include "appvals/AppGlobalValues.h" #include "json/ScanJson.h" #include "ShimLib/ShimLib.h" #include "event/EventCenter.h" #define TRIGGER_EVENT EventCenter::Default()->triggerEvent #define THROW_ERROR(errormsg)\ TRIGGER_EVENT(GUIEvents::GUIErrorRaise, nullptr, (QObject*)&errormsg); namespace { const char* names[3] = {"Initializing","Scanning", "CE Measuring"}; const int PREVIEW_IMAGE_WH = 140; } const char* getStatusString(int status) { switch (status) { case SCANNING: return "SCANNING"; case READY: return "Ready"; case BUSY: return "BUSY"; case ERROR: return "ERROR"; default: return nullptr; } } std::string getJsonFromPatInf(QObject* obj) { return ((QString*)obj)->toStdString(); } void errorCallback(const char* msg) { DeviceManager::Default()->emitErrorCallback(msg); } void infoCallback(const char* msg) { DeviceManager::Default()->emitInfoCallback(msg,0); } const char * getPhaseName(int phase){ return names[phase-1]; } void DeviceManager::initDevice() { InitLib(errorCallback); mDeviceInfTimerID = startTimer(10000); // empty scan connect(EventCenter::Default(), &EventCenter::RequestEmptyScan, [=](QObject* sender, QObject* detail) { startScan(getJsonFromPatInf(detail).c_str(), true); }); // Patient scan connect(EventCenter::Default(), &EventCenter::RequestPatientScan, [=](QObject* sender, QObject* detail) { startScan(getJsonFromPatInf(detail).c_str()); }); // Continue Scan connect(EventCenter::Default(), &EventCenter::RequestContinueScan, [=](QObject* sender, QObject* detail) { postContinueCommand(true); }); // stop connect(EventCenter::Default(), &EventCenter::RequestStop,this, &DeviceManager::stopScan); // preview connect(EventCenter::Default(), &EventCenter::RequestPreviewScan,this, &DeviceManager::startPreview); // init the preview data caller thread initPreviewThread(); } void DeviceManager::startScan(const char* json, bool empty) { if (!json) return; //clear last error state first mErrorOccurred = 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); postScanCommand(); } void DeviceManager::scanProcess(int aProgress) { qDebug() << "current output path:" << getScanOutputPath(); mLastStatus = SCANNING; //normal scan pending int phase = aProgress / 100 + 1; int progress = aProgress % 100; // scan with phase 3 has a different message QString extraMsg = (AppGlobalValues::EmptyScanFlag().toBool() || (mScanPhase != 3)) ? "" : ", patient can leave"; QVariant var(QString("%1%3\r\n progress:%2%").arg(getPhaseName(mScanPhase)).arg(progress).arg(extraMsg)); TRIGGER_EVENT(InvokeOperationProgress, nullptr, (QObject *) &var); // 300 means finished if (aProgress == 300) return; //phase control //no change return if (mScanPhase == phase) return; // error phase if (phase > 3 || mScanPhase > phase) { QString errorMsg = QString("Error Scan Phase code, current Phase code:%1, new Phase code:%2!").arg( mScanPhase).arg(phase); THROW_ERROR(errorMsg) exitScanTimer(); return; } // enter phase 2 if ((mScanPhase = phase) == 2) { if (!AppGlobalValues::EmptyScanFlag().toBool() && JsonObject::Instance()->getScanConfirm()) { var.setValue(QString("Waiting for operator to start scan!\r\n Click \"Next\" to continue!")); TRIGGER_EVENT(InvokeOperationPending, nullptr, (QObject *) &var); exitScanTimer(); } //empty scan no pending, auto continue else { postContinueCommand(); } } } void DeviceManager::postScanCommand() { qDebug() << "ScanControl start>>>>>>>>>>>>>>>>>>>>>"; if (!ScanControl(SCAN)) { qDebug() << ">>>>>>>>>>>>>>>>>>>>>ScanControl success"; //set current state mLastStatus = SCANNING; mPreviewing = false; mScanPhase = 1; qDebug() << "Start progress timer"; mTimerID = startTimer(500); return; } //ScanControl fail THROW_ERROR("ScanControl start fail!") qDebug() << ">>>>>>>>>>>>>>>>>>>>>ScanControl failed"; } void DeviceManager::postContinueCommand(bool useTimer) { if (!ScanControl(SCAN_CONTINUE)) { if (useTimer)mTimerID = startTimer(500); return; } //ScanControl fail THROW_ERROR("ScanControl start fail!") } void DeviceManager::prepareFinishScan() { qDebug() << "Scan finished"; QVariant var(JsonObject::Instance()->getCompleteNotify()); qDebug() << "InvokeOperationEnd"; // stop normal scan with prompt TRIGGER_EVENT(InvokeOperationEnd, nullptr, (QObject *) &var); AppGlobalValues::setInProcessing(false); } void DeviceManager::stopScan() { 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) { mPreviewing = false; AppGlobalValues::setInProcessing(false); TRIGGER_EVENT(ResponseStop, nullptr, nullptr); return; } } AppGlobalValues::setInProcessing(true); TRIGGER_EVENT(InvokeOperationStart, nullptr, nullptr); //ScanControl fail qDebug() << "Request stop!"; if (mTimerID != -1)killTimer(mTimerID); if (ScanControl(STOP)) { qDebug() << "Stop fail!"; QString msg("Stop operation fail!"); THROW_ERROR(msg) qDebug() << "Error thrown!"; mLastStatus = -1; mPreviewing = false; QString s("%1 %2"); s = s.arg(QDateTime::currentDateTime().toString("yyyy/MM/dd HH:mm:ss"), msg); TRIGGER_EVENT(GlobalBannerMessage, nullptr, (QObject *) &msg); return; } mLastStatus = -1; mPreviewing = false; QString s("%1 %2"); s = s.arg(QDateTime::currentDateTime().toString("yyyy/MM/dd HH:mm:ss"), ("Scan Stopped!")); TRIGGER_EVENT(GlobalBannerMessage, nullptr, (QObject *) &s); // preview end TRIGGER_EVENT(InvokeOperationEnd, nullptr, nullptr); TRIGGER_EVENT(ResponseStop, nullptr, nullptr); AppGlobalValues::setInProcessing(false); } void DeviceManager::exitScanTimer() { qDebug() << "Scanning progress Timer exit"; if (mTimerID > 0)killTimer(mTimerID); mTimerID = -1; mLastStatus = -1; mPreviewing = false; } void DeviceManager::close() { #ifdef _WIN32 StopDevice(); #endif mPreviewDataCaller->terminate(); delete mPreviewDataCaller; } const size_t Row = 140; const size_t Col = 140; #define BUFFER_SIZE Row * Col unsigned char* buffer = nullptr; void GetPreviewDataLocal(){ FILE* file; if (file = fopen("img.bin", "rb")) { buffer = (unsigned char*)malloc(sizeof(unsigned char) * BUFFER_SIZE); fread(buffer, sizeof(unsigned char), BUFFER_SIZE, file); fclose(file); } } void DeviceManager::initPreviewThread() { mPreviewDataCaller = QThread::create([=]() { while (!mEndLoop) { if (!mPreviewing) { 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 (1) { qDebug() << "Preview data reader read start!"; GetPreviewDataLocal(); if (!buffer) { continue; } qDebug() << "Preview data reader read end!"; qDebug()<<(int)buffer[5104]; qDebug()<<(int)buffer[5105]; //double check if (!mPreviewing) { qDebug() << "Preview data reader long sleep!"; QThread::sleep(3); continue; } qDebug() << "Preview data response event start!"; TRIGGER_EVENT(ResponsePreviewData, nullptr, (QObject *) (buffer)); qDebug() << "Preview data response event end!"; } else { mPreviewing = false; AppGlobalValues::setInProcessing(false); QThread::sleep(3); } QThread::sleep(1); } }); mPreviewDataCaller->start(); } void DeviceManager::startPreview() {// 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(InvokeOperationStart, nullptr, nullptr); //ScanControl qDebug() << "Request preview!"; if (!ScanControl(PREVIEW_SCAN)) { qDebug() << "Preview success!"; // lastStatus = SCANNING; mPreviewing = true; // timerID = startTimer(500); TRIGGER_EVENT(ResponsePreview, nullptr, nullptr); // end scan without prompt TRIGGER_EVENT(InvokeOperationEnd, nullptr, nullptr); QString s("Device Previewing!"); TRIGGER_EVENT(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!"; } void DeviceManager::timerEvent(QTimerEvent* event) { if (event->timerId() == mDeviceInfTimerID) { QString temp = QString(GetDeviceInfo(MEAN_TEMPERATURE)); TRIGGER_EVENT(GUIEvents::ResponseDeviceTemperature, nullptr, (QObject *) &temp); return; } //scanning progress timer //error exit, callback error if (mErrorOccurred) { mTimerID = event->timerId(); exitScanTimer(); return; } // previewing exit if (mPreviewing) { THROW_ERROR("Device is previewing, exit current operation!") } else { // check device status========================================= qDebug() << "GetStatus"; StatusInfo inf = GetStatus(); qDebug() << "Scanning request status, status:" << getStatusString(inf.status); //设备正常扫描中 if (inf.status == SCANNING) { scanProcess(inf.progress); return; } else { //未发生错误并且,之前状态是扫描,代表正常扫描完成 if (mLastStatus == SCANNING && ! mErrorOccurred) { prepareFinishScan(); } //一般不会出现其他情况 // else { // QString msg("Unknown error in scanning progress timer"); // THROW_ERROR(msg); // } } } exitScanTimer(); } void DeviceManager::emitErrorCallback(const char *msg) { mErrorOccurred = true; QString m(msg); emit raiseGlobalError( m); } void DeviceManager::emitInfoCallback(const char* aMessage,const unsigned int aInfoType) { emit raiseGlobalInfo(QPair(aMessage,aInfoType)); } QString DeviceManager::getSoftwareVersion() { return GetDeviceInfo(VERSION); } QString DeviceManager::getScanOutputPath() { return GetDeviceInfo(DEV_OUTPATH); }