diff --git a/obj/recorder-cmd.pro b/obj/recorder-cmd.pro index b6ee423c9bd0820a67d0411c47797da4446354f3..26b22bd616d305ba23d48506ab296db64766bd31 100644 --- a/obj/recorder-cmd.pro +++ b/obj/recorder-cmd.pro @@ -29,7 +29,7 @@ QMAKE_CXXFLAGS += -Wno-deprecated-enum-enum-conversion # ignore opencv warnings. # cp ../b/vimbax/api/lib/libVmb{C,CPP,ImageTransform}.so $${VIMBA_LIB_DIR} TARGET = cmd -DEST_DIR = ../bin +DESTDIR = ../bin -QMAKE_CLEAN += .cache/clangd/index/* .qmake.stash $${DEST_DIR}/*jpg +QMAKE_CLEAN += .cache/clangd/index/* .qmake.stash $${DESTDIR}/*jpg #cant rm dir here, so added in sublime-project file diff --git a/src/cam.cpp b/src/cam.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b5f4f5e28faa688630e51c4f8702c2d62dea8548 --- /dev/null +++ b/src/cam.cpp @@ -0,0 +1,233 @@ +#include "cam.h" +#include "VmbCPP/SharedPointerDefines.h" +#include "utils.h" +#include "frameobserver.h" + +#include <chrono> +#include <memory> //shared_ptr +#include <unistd.h> + +#include <QTimer> +#include <QDebug> + +using State = Cam::State; +using namespace VmbCPP; + +Cam::Cam(CameraPtr pCamera) : +IPrinter(), +_cam(pCamera), +_name(""), +_state(disconnected), +_frames(FramePtrVector(threadsPerCam())), +_payloadSize(0LL), +_pixelFormat("") +{ + name(); + + //vmb (core) -> ui (controller.console) + // QObject::connect(&core, SIGNAL(error(const QString&, const int&)), controller.console, SLOT(error(const QString&, const int&)), Qt::DirectConnection); + // QObject::connect(&core, SIGNAL(error(const int&)), controller.console, SLOT(error(const int&)), Qt::DirectConnection); + // QObject::connect(&core, SIGNAL(info(const QString&)), controller.console, SLOT(print(const QString&)), Qt::DirectConnection); + // QObject::connect(&core, SIGNAL(info(const QStringList&)), controller.console, SLOT(print(const QStringList&)), Qt::DirectConnection); +} + +// Copy constructor +Cam::Cam(const Cam& other) : +IPrinter(), +_cam(other._cam), +_name(other._name), +_state(other._state), +_frames(other._frames), +_payloadSize(other._payloadSize), +_pixelFormat(other._pixelFormat) +{} + +Cam::~Cam() +{ + qDebug() << __FUNCTION__ << "():" << __LINE__ << "name:" << _name; + // if( _state == recording ) + // stopRecording(); + + // if( _state == opened ) + // close(); + // close() should be called automatically, when the last shared_ptr to the camera is destroyed + + // for ( auto cam : cameras ) + // cam->Close(); + +} + + +QString Cam::name() +{ + if( _name.isEmpty() ) + { + std::string str; + f(_cam->GetName( str )); + _name = QString::fromStdString(str); + } + return _name; +} + +State Cam::state() const +{ + return _state; +} + +bool Cam::open() +{ + if( ! f(_cam->Open( VmbAccessModeFull ),"open cam #"+_name) ) + _state = opened; + + return _state == opened; +} + +void Cam::close() +{ + _state = closed; +} + +/* Does: + get Payloadsize + get Pixelformat - eg RGB8 + Allocate memory for frame buffer + Register frame observer / callback for each frame + Announce frame to the API + Start the capture engine (API) + Put frame into the frame queue + Start the acquisition engine ( _curCam) + + TODO if( !_curCam->isOpen() ) return; >> listener + 2d get frameID +*/ +void Cam::startRecording(std::chrono::seconds dur) +{ + try + { + FeaturePtr pFeature; + + g( _cam->GetFeatureByName ("PayloadSize", pFeature ),"get PayloadSize"); + g( pFeature->GetValue (_payloadSize)); + print("PayloadSize",_payloadSize); + + g( _cam->GetFeatureByName("PixelFormat", pFeature)); + g( pFeature->GetValue(_pixelFormat)); + print("PixelFormat",_pixelFormat); + + for( auto& frame : _frames ) + { + frame.reset(new Frame(_payloadSize)); + g( frame->RegisterObserver( IFrameObserverPtr( new FrameObserver(_cam) )),"register frame observer"); + g( _cam->AnnounceFrame(frame), "announce frame"); + } + + g( _cam->StartCapture(), "start capture"); + + for( auto& frame : _frames ) + g( _cam->QueueFrame(frame),"QueueFrame"); + + g( _cam->GetFeatureByName ("AcquisitionStart", pFeature ),"get AcquisitionStart"); + g( pFeature->RunCommand(),"run AcquisitionStart"); + } + catch (const std::runtime_error& xx) + { + qDebug() << "Exception caught: " << xx.what(); + } + + _state = recording; + + // Convert to milliseconds + auto dur_ms = std::chrono::duration_cast<std::chrono::milliseconds>(dur).count(); + QTimer::singleShot(dur_ms, this, SLOT(stopRecording())); +} + +void Cam::startRecording(std::chrono::minutes dur) +{ + // Convert to seconds + auto dur_s = std::chrono::duration_cast<std::chrono::seconds>(dur); + startRecording(dur_s); +} + +/* Does: + Stop the capture engine (API) + discard all pending callbacks + Flush the frame queue + Revoke all frames from the API + Unregister the frame observer / callback +*/ +void Cam::stopRecording() +{ + FeaturePtr pFeature; + try + { + g(_cam->GetFeatureByName ("AcquisitionStop", pFeature ),"get AcquisitionStop"); + g(pFeature->RunCommand(),"run AcquisitionStop"); + g(_cam->EndCapture(),"end capture"); + g(_cam->FlushQueue(),"flush queue"); + g(_cam->RevokeAllFrames(),"revoke all frames"); + for( FramePtr frame : _frames ) + g(frame->UnregisterObserver(),"unregister observer"); + } + catch (const std::runtime_error& xx) + { + qDebug() << "Exception caught: " << xx.what(); + } + + _state = opened; +} + +// id,name,model,serial,interfaceID,state +QString Cam::info() +{ + // qDebug() << "Camera Name: " << _name; + // qDebug() << "Camera State: " << _state; + QString camInfo; + try + { + std::string str; + g(_cam->GetID( str )); + camInfo += QString::fromStdString(str) + DELIM; + + g(_cam->GetName( str )); + _name = QString::fromStdString(str); + camInfo += _name + DELIM; + + g(_cam->GetModel( str )); + camInfo += QString::fromStdString(str) + DELIM; + + g(_cam->GetSerialNumber( str )); + camInfo += QString::fromStdString(str) + DELIM; + + g(_cam->GetInterfaceID( str )); + camInfo += QString::fromStdString(str) + DELIM; + + camInfo += stateToString(_state); + } + catch(const std::exception& e) + { + qDebug() << __LINE__ << "-" << __PRETTY_FUNCTION__ << "exception:" << e.what(); + } + + return camInfo; +} + +QString Cam::stateToString(const State& state) +{ + switch (state) + { + case disconnected: + return "disconnected"; + case closed: + return "closed"; + case opened: + return "opened"; + case recording: + return "recording"; + default: + return "unknown"; + } +} + +void Cam::onCameraDisconnected() +{ + _state = disconnected; +} diff --git a/src/cam.h b/src/cam.h new file mode 100644 index 0000000000000000000000000000000000000000..7ec7a1930c5a25089ee80ede9fb22fa00c6c1167 --- /dev/null +++ b/src/cam.h @@ -0,0 +1,63 @@ +#pragma once +#include "iprinter.h" + +#include <QObject> +#include <QString> + +#include <chrono> +#include <vector> +#include <memory> //shared_ptr + +#include <VmbCPP/Camera.h> +// #include <VmbCPP/SharedPointerDefines.h> + +using VmbCPP::CameraPtr; +using VmbCPP::FramePtr; +using VmbCPP::FeaturePtr; +using VmbCPP::FramePtrVector; + +class Cam; +using CamPtr = std::shared_ptr<Cam>; +using CamPtrVector = std::vector<CamPtr>; + +class Cam : public IPrinter +{ + Q_OBJECT + +public: + enum State { + disconnected, + closed, + opened, + recording + }; + + // const QString& name, const int& nThreads + Cam(CameraPtr pCamera); + Cam(const Cam&); + ~Cam(); + + QString name(); + State state() const; + static QString stateToString(const State&); + + bool open(); + void close(); + void startRecording(std::chrono::minutes dur); + void startRecording(std::chrono::seconds dur); //use as literals "1s, 1min" + void stopRecording(); + QString info(); + inline CameraPtr getCameraPtr() const { return _cam; } + +public slots: + void onCameraDisconnected(); + +private: + CameraPtr _cam; + QString _name; + State _state; + FramePtrVector _frames; + VmbInt64_t _payloadSize; + std::string _pixelFormat; +}; + diff --git a/src/camobserver.cpp b/src/camobserver.cpp index 7a86566bb5061e38db0360537a1aba1b26f34c8b..c24a2be5b3b0d72fd8a5b748578b46b9270f0020 100644 --- a/src/camobserver.cpp +++ b/src/camobserver.cpp @@ -5,10 +5,8 @@ #include <QDebug> - using namespace VmbCPP; -//2D XXX Code to determine the open state void CamObserver::CameraListChanged(CameraPtr pCam, UpdateTriggerType reason) { if( UpdateTriggerPluggedIn == reason || UpdateTriggerPluggedOut == reason ) diff --git a/src/cmd/console.cpp b/src/cmd/console.cpp index f86bf4df3f5844408e85d98da45dbbb7000cbb60..bec3933a7f034a5ece118dfeb6151bbacc315a34 100644 --- a/src/cmd/console.cpp +++ b/src/cmd/console.cpp @@ -16,6 +16,7 @@ void Console::listenKeys() std::string line; forever { + std::getline(std::cin, line); emit keyPressed(line[0]); if( line[0] == 'q' ) @@ -23,6 +24,26 @@ void Console::listenKeys() } } +// read line from cin +QString Console::getLine() +{ + std::string line; + std::getline(std::cin, line); + // emit lineEntered(QString::fromStdString(line)); + return QString::fromStdString(line); +} + +// read number from cin +int Console::getNumber() +{ + int number; + std::cin >> number; + // emit numberEntered(number); + return number; +} + + + void Console::error(const int& errCode ) { if( errCode ) @@ -68,14 +89,15 @@ void Console::printHelp() str << "HELP!" << "-------------------------------" << "h: print this help" - << "1-9: set camera" + << "1-9: select camera" + << "d: change duration of recording" << "o: open current camera" - // XXX add new func << "r: start recording" << "t: stop recording" << "l: list available cameras" << "v: print versions" << "q: quit" + // XXX add new func << "-------------------------------"; print(str); @@ -106,10 +128,11 @@ void Controller::keyPress(const QChar& key) qDebug().noquote() << __FUNCTION__ << ": " << key; if ( key.isDigit() ) { - emit setCam(key.digitValue()-1); + emit cam(key.digitValue()-1); } else { + int dur; switch (key.unicode()) { // XXX add new func @@ -117,6 +140,12 @@ void Controller::keyPress(const QChar& key) console->printHelp(); break; + case 'd': + console->print("Enter duration in seconds: "); + dur = console->getNumber(); // XXX not thread safe? + interferes with forever loop? + emit setDuration(dur); + break; + case 'o': emit openCam(); break; diff --git a/src/cmd/console.h b/src/cmd/console.h index 8c30a817067b25979f689ee0410ca411b9188f3c..b0d1c09a016483f75872bd83079a9af8e1fe3169 100644 --- a/src/cmd/console.h +++ b/src/cmd/console.h @@ -2,6 +2,7 @@ #include <QObject> #include <QThread> +#include <QString> // derived from qthread example // https://doc.qt.io/qt-6/qthread.html @@ -12,6 +13,8 @@ class Console : public QObject public slots: void listenKeys(); + QString getLine(); + int getNumber(); void error(const QString&,const int&); void error(const int&); void print(const QString&); @@ -23,6 +26,8 @@ class Console : public QObject signals: void keyPressed(const QChar &key); + // void lineEntered(const QString&); + // void numberEntered(const int&); }; @@ -46,9 +51,10 @@ class Controller : public QObject // to core void listCams(); void openCam(); - void setCam(int); + void cam(int); void startRecording(); void stopRecording(); + void setDuration(int); // void calibrateCam(); // void loadSettings(); diff --git a/src/cmd/main.cpp b/src/cmd/main.cpp index 485267b9fa012134f5b174c84026d9d6e311dc93..ff19440afb5d0ed118be4578b088a3e7e050c426 100644 --- a/src/cmd/main.cpp +++ b/src/cmd/main.cpp @@ -1,6 +1,7 @@ #include "console.h" #include "../core.h" #include "../utils.h" +#include "qobjectdefs.h" // #include "qnamespace.h" #include <QCoreApplication> @@ -17,23 +18,26 @@ int main(int argc, char *argv[]) Core core; //ui (controller) -> vmb (core) - QObject::connect(&controller, &Controller::listCams, &core, &Core::listCams); - QObject::connect(&controller, &Controller::openCam, &core, &Core::openCam); - QObject::connect(&controller, &Controller::setCam, &core, &Core::setCam); - QObject::connect(&controller, &Controller::startRecording, &core, &Core::startRecording); - QObject::connect(&controller, &Controller::stopRecording, &core, &Core::stopRecording); + QObject::connect(&controller, &Controller::listCams, &core, &Core::listCams); + QObject::connect(&controller, &Controller::openCam, &core, &Core::openCam); + QObject::connect(&controller, &Controller::cam, &core, &Core::cam); + QObject::connect(&controller, &Controller::startRecording, &core, &Core::startRecording); + QObject::connect(&controller, &Controller::stopRecording, &core, &Core::stopRecording); + QObject::connect(&controller, &Controller::setDuration, &core, &Core::setDuration); + + + // XXX add new func //vmb (core) -> ui (controller.console) QObject::connect(&core, SIGNAL(error(const QString&, const int&)), controller.console, SLOT(error(const QString&, const int&)), Qt::DirectConnection); QObject::connect(&core, SIGNAL(error(const int&)), controller.console, SLOT(error(const int&)), Qt::DirectConnection); - QObject::connect(&core, SIGNAL(print(const QString&)), controller.console, SLOT(print(const QString&)), Qt::DirectConnection); - QObject::connect(&core, SIGNAL(print(const QStringList&)), controller.console, SLOT(print(const QStringList&)), Qt::DirectConnection); + QObject::connect(&core, SIGNAL(info(const QString&)), controller.console, SLOT(print(const QString&)), Qt::DirectConnection); + QObject::connect(&core, SIGNAL(info(const QStringList&)), controller.console, SLOT(print(const QStringList&)), Qt::DirectConnection); // sa Controller() for delegating to Console QTimer::singleShot(0, &controller, SIGNAL(operate())); // QTimer::singleShot(10, controller.console, SLOT(printVersion()), Qt::DirectConnection); // for testing - QTimer::singleShot(30, &core, SLOT(listCams())); // for testing // QTimer::singleShot(200, &core, SLOT(openCam())); // for testing return a.exec(); diff --git a/src/core.cpp b/src/core.cpp index d8ef3aceb967ced174941735f23c09d2cf63db44..4ba5ace825926e8fca3a79b6ea36c49152a04c88 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -1,8 +1,10 @@ #include "core.h" -#include "frameobserver.h" +#include "VmbCPP/Interface.h" + #include "camobserver.h" #include "utils.h" +#include <chrono> #include <iostream> #include <vector> @@ -17,259 +19,176 @@ using namespace VmbCPP; +using namespace std::chrono_literals; //seconds, minutes, hours Core::Core() : - apiStarted( false ), - sys( VmbSystem::GetInstance() ), // Create and get Vimba singleton - cameras( CameraPtrVector() ), // Holds camera handles - camIdx(-1), - curCam(nullptr), - payloadSize(0), - frames(FramePtrVector(3)), - // frames(FramePtrVector(QThread::idealThreadCount())), - pixelFormat("") + IPrinter(), + _apiStarted( false ), + _sys( VmbSystem::GetInstance() ), // create and get Vimba singleton + _cameras( CamPtrVector() ), + _recDuration( 6s ) //default { QTimer::singleShot(0, this, SLOT(init())); //delayed init to allow connections to be established -> print/error signals! } void Core::init() { - if ( f(sys.Startup(), "init API") ) + if ( f(_sys.Startup(), "init API") ) exit(VmbErrorApiNotStarted); - apiStarted = true; + _apiStarted = true; auto camObserver = new CamObserver(); - connect( camObserver, SIGNAL(cameraListChanged()), this, SLOT(listCams()) ); - f(sys.RegisterCameraListObserver(ICameraListObserverPtr(camObserver)), "register cam observer"); + connect( camObserver, SIGNAL(cameraListChanged()), this, SLOT(listCams()) ); //listcams calls updateCams! + f(_sys.RegisterCameraListObserver(ICameraListObserverPtr(camObserver)), "register cam observer"); + + listCams(); } Core::~Core() { qDebug() << __FUNCTION__ << "():" << __LINE__; - for ( auto cam : cameras ) - cam->Close(); - - sys.Shutdown(); + _sys.Shutdown(); } -void Core::listCams() +// update & sync camera vectors +void Core::updateCameras() { - if( !apiStarted ) + if( !_apiStarted ) return; - if ( f(sys.GetCameras( cameras ), "get cameras") ) + CameraPtrVector vmbCameras; + if ( f(_sys.GetCameras( vmbCameras ), "update cameras") ) return; - emitPrint( QString("found %1 camera(s)").arg(cameras.size())); - if (cameras.size()) + if( (int)vmbCameras.size() != ncam() ) //update number of cameras + error(QString("Expected %1 cams!").arg(ncam()),errLessCamsThanExpected); //XXX warning + + // vector< shared_ptr<Camera> > vmbCameras + // vector< shared_ptr<Cam> > _cameras + + // Add new cameras + for (const auto& vcam : vmbCameras) { - if( camIdx == -1UL || camIdx >= cameras.size() ) + bool found = false; + for (const auto& cam : _cameras) { - setCam(0); + if (cam->getCameraPtr() == vcam) + { + found = true; + break; + } } - - // id,name,model,serial,interfaceID,state - QStringList allCamInfo; - auto idx=0UL; - for ( auto camera : cameras ) + if (!found) { - std::string str; - QString curCamInfo; - - curCamInfo += QString::number(idx+1) + ". "; - - if (idx == camIdx ) - curCamInfo += "[*]" + DELIM; - else - curCamInfo += "[ ]" + DELIM; - - - if( f((camera->GetID( str )))) continue; - curCamInfo += QString::fromStdString(str) + DELIM; - - if( f((camera->GetName( str )))) continue; - curCamInfo += QString::fromStdString(str) + DELIM; - - if( f((camera->GetModel( str )))) continue; - curCamInfo += QString::fromStdString(str) + DELIM; - - if( f((camera->GetSerialNumber( str )))) continue; - curCamInfo += QString::fromStdString(str) + DELIM; - - if( f((camera->GetInterfaceID( str )))) continue; - curCamInfo += QString::fromStdString(str) + DELIM; - - // curCamInfo += "closed";//xxx - - allCamInfo << curCamInfo; - idx++; + _cameras.push_back(std::make_shared<Cam>(vcam)); + print("cam connected"); + //vcam->GetName(), threadsPerCam } - - emitPrint("found Cameras",cameras.size()); - emit print(allCamInfo); } - else + + // Remove cameras that are no longer present + auto it = _cameras.begin(); + while (it != _cameras.end()) { - emit error(errNoCams); + bool found = false; + for (const auto& vcam : vmbCameras) + { + if ((*it)->getCameraPtr() == vcam) + { + found = true; + break; + } + } + if (!found) + { + it = _cameras.erase(it); + print("cam disconnected"); + } + else + { + ++it; + } } -} -bool Core::f(const VmbErrorType& ret, const QString& msg) + // Update states of cameras + // for (const auto& cam : _cameras) { + // Update state of 'cam' based on corresponding camera's state in 'vmbcameras' + // } + +} // now ~Camera() should be called on removed cams. >> camObserver + +// update + print camlist +void Core::listCams() { - // vimba function wrapper to test return type and potentially emit error message or successmsg - // returns true on error - // qDebug() << __LINE__ << "-" << __PRETTY_FUNCTION__ << " ret:" << ret << " msg:" << msg; + if( !_apiStarted ) + return; - if ( VmbErrorSuccess == ret ) - { - if (! msg.isEmpty()) - emitPrint(msg); + updateCameras(); - return false; - } - else + QStringList allCamInfo; + auto idx=0; + for ( auto camera : _cameras ) { - if (! msg.isEmpty()) - emitPrint("Fail! " + msg); - emit error(ret); - return true; + QString camInfo = QString::number(++idx) + ". " + camera->info(); + allCamInfo << camInfo; } -} -void Core::g(const VmbErrorType& ret, const QString& msg) -{ - //vimba function wrapper - throws exception on error - to declutter error handling code - if( f(ret,msg) ) - throw std::runtime_error("Error: " + msg.toStdString()); -} - -void Core::emitPrint(const QString& name, const VmbInt64_t& val=0) -{ - if( val != 0 ) - emit print(QString("%1: %2").arg(name).arg(val)); - else - emit print(name); -} + if ( ! _cameras.size() ) + emit error(errNoCams); -void Core::emitPrint(const QString& name, const std::string& val) -{ - if( val.empty() ) - emit print(name); - else - emit print(name + ": " + QString::fromStdString(val)); + print(allCamInfo); } bool Core::openCam() { - if(!curCam) - { - emit error(errCamIdx); - return false; - } + if( cam() ) + return cam()->open(); - return f(curCam->Open( VmbAccessModeFull ),"open cam #"+QString::number(camIdx+1)); + return false; } -CameraPtr Core::cam() +/* +current camera getter + setter +-1 is dflt and means "return current camera" +other idx's update idx and return new curCam +*/ +CamPtr Core::cam(const unsigned long &idx) { - return curCam; -} + static unsigned long curIdx = 123; + if( idx != -1UL ) + curIdx = idx; -void Core::setCam(const int& newCamIdx) -{ try { - camIdx = newCamIdx; - curCam = cameras.at(newCamIdx); - emitPrint("set cam",newCamIdx+1); + print("set cam",idx+1); + return _cameras.at(curIdx); } catch (const std::out_of_range& oor) { emit error(errCamIdx); + return nullptr; } } -/* Does: - get Payloadsize - get Pixelformat - eg RGB8 - Allocate memory for frame buffer - Register frame observer / callback for each frame - Announce frame to the API - Start the capture engine (API) - Put frame into the frame queue - Start the acquisition engine ( curCam) - - TODO if( !curCam->isOpen() ) return; >> listener - 2d get frameID -*/ void Core::startRecording() { - if( !curCam ) + if( cam() == nullptr ) return; - FeaturePtr pFeature; - - try - { - g( curCam->GetFeatureByName ("PayloadSize", pFeature ),"get PayloadSize"); - g( pFeature->GetValue (payloadSize)); - emitPrint("PayloadSize",payloadSize); - - g( curCam->GetFeatureByName("PixelFormat", pFeature)); - g( pFeature->GetValue(pixelFormat)); - emitPrint("PixelFormat",pixelFormat); - - for( auto& frame : frames ) - { - frame.reset(new Frame(payloadSize)); - g( frame->RegisterObserver( IFrameObserverPtr( new FrameObserver(curCam) )),"register frame observer"); - g( curCam->AnnounceFrame(frame), "announce frame"); - } - - g( curCam->StartCapture(), "start capture"); - - for( auto& frame : frames ) - g( curCam->QueueFrame(frame),"QueueFrame"); - - g( curCam->GetFeatureByName ("AcquisitionStart", pFeature ),"get AcquisitionStart"); - g( pFeature->RunCommand(),"run AcquisitionStart"); - } - catch (const std::runtime_error& xx) - { - // ... handle exception - qDebug() << "Exception caught: " << xx.what(); - } - - // QTimer::singleShot(6000, this, SLOT(stopRecording())); + cam()->startRecording( _recDuration ); //XXX dur from user input } -/* Does: - Stop the capture engine (API) + discard all pending callbacks - Flush the frame queue - Revoke all frames from the API - Unregister the frame observer / callback -*/ void Core::stopRecording() { - if( !curCam ) + if( cam() == nullptr ) return; - FeaturePtr pFeature; - try - { - g(curCam->GetFeatureByName ("AcquisitionStop", pFeature ),"get AcquisitionStop"); - g(pFeature->RunCommand(),"run AcquisitionStop"); - g(curCam->EndCapture(),"end capture"); - g(curCam->FlushQueue(),"flush queue"); - g(curCam->RevokeAllFrames(),"revoke all frames"); - for( FramePtr frame : frames ) - g(frame->UnregisterObserver(),"unregister observer"); - } - catch (const std::runtime_error& xx) - { - // ... handle exception - qDebug() << "Exception caught: " << xx.what(); - } + cam()->stopRecording(); +} + +void Core::setDuration(int dur) +{ + _recDuration = seconds(dur); } diff --git a/src/core.h b/src/core.h index 8607a0fda5fbc1116b71ca8e5c9e1d04b0af5904..cb539ba9887516a9672d1d2d05621be245dfc9d9 100644 --- a/src/core.h +++ b/src/core.h @@ -1,61 +1,43 @@ #pragma once -// #include "qglobal.h" +#include "cam.h" +#include "iprinter.h" + #include <QObject> -#include <VmbCPP/SharedPointerDefines.h> #include <VmbCPP/Interface.h> -#include <VmbCPP/Camera.h> +#include <chrono> namespace VmbCPP { class VmbSystem; } using VmbCPP::VmbSystem; -using VmbCPP::CameraPtr; -using VmbCPP::FeaturePtr; -using VmbCPP::FramePtrVector; -using VmbCPP::CameraPtrVector; +using std::chrono::seconds; -class Core : public QObject +class Core : public IPrinter { - Q_OBJECT - - public: - Core(); - ~Core(); - - public slots: - void listCams(); - bool openCam(); - void setCam(const int &); - CameraPtr cam(); // make getter setter -> rm curCam and camIdx //or make Camera class wrapper - - void startRecording(); - void stopRecording(); +Q_OBJECT - private slots: - void init(); +public: + Core(); + ~Core(); - signals: - void print(const QString &); - void print(const QStringList&); - void error(const int&); - void error(const QString&,const int& errCode=0); +public slots: + void listCams(); + bool openCam(); - private: - bool f(const VmbErrorType&, const QString& = ""); - void g(const VmbErrorType&, const QString& = ""); + CamPtr cam(const unsigned long &idx=-1); - void emitPrint(const QString&, const VmbInt64_t& v); - void emitPrint(const QString&, const std::string& v=""); + void startRecording(); + void stopRecording(); //XXX also stop singleshot-timer or it will try to close an already closed cam + void setDuration(int); - void getCamInfo( const CameraPtr & ); +private slots: + void init(); - bool apiStarted; - VmbSystem& sys; - CameraPtrVector cameras; - ulong camIdx; - CameraPtr curCam; +private: + void updateCameras(); - VmbInt64_t payloadSize; - FramePtrVector frames; - std::string pixelFormat; + bool _apiStarted; + VmbSystem& _sys; + CamPtrVector _cameras; + seconds _recDuration; }; diff --git a/src/iprinter.cpp b/src/iprinter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5ba85151794b7d169d6853a2a21fdc03e7d3cd6d --- /dev/null +++ b/src/iprinter.cpp @@ -0,0 +1,65 @@ +#include "iprinter.h" + +IPrinter::IPrinter(QObject *parent) : QObject(parent) +{ +} + +IPrinter::~IPrinter() +{ +} + +void IPrinter::print(const QStringList& name) +{ + emit info(name); +} + + +void IPrinter::print(const QString& name) +{ + emit info(name); +} + +void IPrinter::print(const QString& name, const VmbInt64_t& val) +{ + if( val != 0 ) + emit info(QString("%1: %2").arg(name).arg(val)); + else + emit info(name); +} + +void IPrinter::print(const QString& name, const std::string& val) +{ + if( val.empty() ) + emit info(name); + else + emit info(name + ": " + QString::fromStdString(val)); +} + +bool IPrinter::f(const VmbErrorType& ret, const QString& msg) +{ + // vimba function wrapper to test return type and potentially emit error message or successmsg + // returns true on error + // qDebug() << __LINE__ << "-" << __PRETTY_FUNCTION__ << " ret:" << ret << " msg:" << msg; + + if ( VmbErrorSuccess == ret ) + { + if (! msg.isEmpty()) + emit info(msg); + + return false; + } + else + { + if (! msg.isEmpty()) + emit info("Fail! " + msg); + emit error(ret); + return true; + } +} + +void IPrinter::g(const VmbErrorType& ret, const QString& msg) +{ + //vimba function wrapper - throws exception on error - to declutter error handling code + if( f(ret,msg) ) + throw std::runtime_error("Error: " + msg.toStdString()); +} diff --git a/src/iprinter.h b/src/iprinter.h new file mode 100644 index 0000000000000000000000000000000000000000..8cc20b0194e1ac7c6637ebd2a5f08411d609ab81 --- /dev/null +++ b/src/iprinter.h @@ -0,0 +1,33 @@ +#pragma once + +#include "VmbC/VmbCommonTypes.h" + +#include <QObject> +#include <QString> +#include <QStringList> + +// common functionality "interface" for printing, error handling and connecting messages to CMD +class IPrinter : public QObject +{ + Q_OBJECT + +signals: + void info(const QString &); + void info(const QStringList&); + void error(const int&); + void error(const QString&,const int& errCode=0); + +public: + explicit IPrinter(QObject *parent = nullptr); + IPrinter(const IPrinter&) = delete; //cuz of err with non-trivial copy ctor which cant be implicitly created... if cp'ing is needed implement it! + virtual ~IPrinter(); + + bool f(const VmbErrorType&, const QString& = ""); // check vmb error and print + void g(const VmbErrorType&, const QString& = ""); // check vmb error and throw + + //print + void print(const QString&); + void print(const QStringList&); + void print(const QString&, const VmbInt64_t&); + void print(const QString&, const std::string&); +}; diff --git a/src/utils.cpp b/src/utils.cpp index 5eb357de430bbcfa5e0149d717e264044c8d64d8..50085f8164670f927159f0bc56c5731f645ef2ac 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -1,21 +1,34 @@ #include "utils.h" + #include "opencv2/core/version.hpp" #include <random> +#include <iostream> #include "VmbCPP/VmbCPP.h" + #include <QString> #include <QDebug> #include <QDir> +#include <QThread> -#include <iostream> const int APP_VERSION_MAJOR = 0; const int APP_VERSION_MINOR = 0; -const int APP_VERSION_PATCH = 8; +const int APP_VERSION_PATCH = 9; using namespace VmbCPP; +int ncam() +{ + return 1; //XXX read in from config file +} + +int threadsPerCam() +{ + return std::ceil(static_cast<double>(QThread::idealThreadCount()) / ncam() ); //round up! +} + const QString getVersion() { return QString("# Recorder: %1.%2.%3").arg(APP_VERSION_MAJOR).arg(APP_VERSION_MINOR).arg(APP_VERSION_PATCH); @@ -65,6 +78,8 @@ const QString errorCodeToMessage( VmbError_t err ) case errCamIdx: msg += "Camera index out of range."; break; case errNoCams: msg += "no cameras found."; break; case errRegisterCamObserver: msg += "cant register camobserver."; break; + case errLessCamsThanExpected: msg += "less cameras found, than expected"; break; + // ... add more } return msg; diff --git a/src/utils.h b/src/utils.h index 84a68a816ebdfc6f01547d0d6150f1a54e19e224..d2cebb0b683762c72ffa84f78d400900801061eb 100644 --- a/src/utils.h +++ b/src/utils.h @@ -1,17 +1,22 @@ #ifndef UTILS_H #define UTILS_H -#include <QString> #include "VmbC/VmbCommonTypes.h" //VmbError_t -> cant really fwd-decl typedef...?? +#include <QString> + class QDir; + const QStringList getVersions(); const QString getVersion(); const QString errorCodeToMessage( VmbError_t ); QString randomString(); bool maybeCreateDir(QDir); +int threadsPerCam(); +int ncam(); + const QChar DELIM='|'; typedef enum camtronErr @@ -19,7 +24,8 @@ typedef enum camtronErr errCamIdx = 10, //!< camera index out of range errNoCams = 11, //!< no cameras found errRegisterCamObserver = 12, //!< cant register camobserver - // errUn = 12, //!< Unexpected fault in VmbC or driver + errLessCamsThanExpected = 13, //!< no cameras found } camtronErr; + #endif