Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
utils.cpp 6.52 KiB
#include "utils.h"

#include "opencv2/core/version.hpp"

#include <random>
#include <iostream>

#include "VmbCPP/VmbCPP.h"
#include <VmbC/VmbCommonTypes.h>

#include <QDebug>
#include <QDir>
#include <QThread>
#include <QCoreApplication>
#include <QFile>
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>

using namespace VmbCPP;

namespace utils
{

const int APP_VERSION_MAJOR = 0;
const int APP_VERSION_MINOR = 2;
const int APP_VERSION_PATCH = 0;

std::atomic<bool> running(true);

int ncam(const int& n)
{
	static const int _ncam = n;

#ifdef DEBUG
	return 2;
#endif
	return _ncam;
}

int threadsPerCam()
{
#ifdef DEBUG
	return 8;
#else
	return std::ceil(static_cast<double>(QThread::idealThreadCount()-2) / ncam() ); //round up! -2 for main and console
#endif
}

const QString getVersion()
{
	return QString("# Recorder: %1.%2.%3").arg(APP_VERSION_MAJOR).arg(APP_VERSION_MINOR).arg(APP_VERSION_PATCH);
}
const QStringList getVersions()
{
	VmbVersionInfo_t version;
	VmbSystem::GetInstance().QueryVersion(version);

	QStringList s;
	s << "### Versions";
	s << QString("# Recorder: %1.%2.%3").arg(APP_VERSION_MAJOR).arg(APP_VERSION_MINOR).arg(APP_VERSION_PATCH);
	s << QString("#    Vimba: %1.%2.%3").arg(version.major).arg(version.minor).arg(version.patch);
	s << QString("#       Qt: %1.%2.%3").arg(QT_VERSION_MAJOR).arg(QT_VERSION_MINOR).arg(QT_VERSION_PATCH);
	s << QString("#   openCV: %1.%2.%3").arg(CV_VERSION_MAJOR).arg(CV_VERSION_MINOR).arg(CV_VERSION_REVISION);

	return s;
}

const QString errorCodeToMessage( VmbError_t err )
{
	QString msg = "⚠️  ";
	switch( err )
	{
		default:                        msg += "Unknown"; break;
		case VmbErrorJustInfo:          msg = ""; break; //custom
		case VmbErrorSuccess:           msg = "success! 😎"; break; //
		case VmbErrorInternalFault:     msg += "Unexpected fault in VmbApi or driver."; break;
		case VmbErrorApiNotStarted:     msg += "API not started."; break;
		case VmbErrorNotFound:          msg += "Not found."; break;
		case VmbErrorBadHandle:         msg += "Invalid handle "; break;
		case VmbErrorDeviceNotOpen:     msg += "Device not open."; break;
		case VmbErrorInvalidAccess:     msg += "Invalid access."; break;
		case VmbErrorBadParameter:      msg += "Bad parameter."; break;
		case VmbErrorStructSize:        msg += "Wrong DLL version."; break;
		case VmbErrorMoreData:          msg += "More data returned than memory provided."; break;
		case VmbErrorWrongType:         msg += "Wrong type."; break;
		case VmbErrorInvalidValue:      msg += "Invalid value."; break;
		case VmbErrorTimeout:           msg += "Timeout."; break;
		case VmbErrorOther:             msg += "TL error."; break;
		case VmbErrorResources:         msg += "Resource not available."; break;
		case VmbErrorInvalidCall:       msg += "Invalid call."; break;
		case VmbErrorNoTL:              msg += "TL not loaded."; break;
		case VmbErrorNotImplemented:    msg += "Not implemented."; break;
		case VmbErrorNotSupported:      msg += "Not supported."; break;
			// ------------------------------- own errCodes -------------------------------
		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;
}

bool parseConfig(QList<QPair<QString,QString>>& parsedCameras, seconds& recDuration)
{
	qDebug() << "open " << configFile();
	QFile file(configFile());
	if (!file.open(QIODevice::ReadOnly))
	{
		qWarning() << "Failed. Could not open config: " + configFile();
		return false;
	}

	QByteArray jsonData = file.readAll();
	file.close();

	QJsonParseError parseError;
	QJsonDocument doc = QJsonDocument::fromJson(jsonData, &parseError);
	if (parseError.error != QJsonParseError::NoError)
	{
		qWarning() << "Error parsing JSON:" << parseError.errorString();
		return false;
	}

	if (!doc.isObject())
	{
		qWarning() << "JSON content is not an object";
		return false;
	}

	QJsonObject jsonObject = doc.object();

	// Parse recordDurationInSeconds
	if (!jsonObject.contains("recordDurationInSeconds") || !jsonObject["recordDurationInSeconds"].isDouble())
	{
		qWarning() << "Missing or invalid recordDurationInSeconds";
		return false;
	}

	recDuration = jsonObject["recordDurationInSeconds"].toInt() * 1s; //convert to s

	// Parse outDir
	if (!jsonObject.contains("outDir") || !jsonObject["outDir"].isString())
	{
		qWarning() << "Missing or invalid outDir";
		return false;
	}
	outDir(jsonObject["outDir"].toString()); //set global


	// Parse cameras
	if (!jsonObject.contains("cameras") || !jsonObject["cameras"].isArray())
	{
		qWarning() << "Missing or invalid cameras array";
		return false;
	}

	parsedCameras.clear();
	QJsonArray camerasArray = jsonObject["cameras"].toArray();
	for (const QJsonValue& value : camerasArray)
	{
		if (!value.isObject())
		{
				qWarning() << "Invalid camera entry:" << value;
				continue;
		}

		QJsonObject cameraObject = value.toObject();
		auto name = cameraObject["name"].toString();
		auto ip = cameraObject["ip"].toString();

		parsedCameras.append(qMakePair(name, ip));
	}
	ncam(parsedCameras.size()); //set global

	qDebug() << "parsed recDuration:" << recDuration.count();
	qDebug() << "parsed outDir:" << outDir();
	qDebug() << "threads per cam:" << threadsPerCam();

	return true;
}

//general basedir
QString outDir(QString dirname)
{
	static QString _outDir;
	if( _outDir.isEmpty() )
	{
		if( dirname.isEmpty() )
			_outDir = QCoreApplication::applicationDirPath();
		else
			_outDir = dirname;
	}

	return _outDir;
}

// needed to find cams via ip
QString configFile(QString filename)
{
	static QString _configFile;
	if( _configFile.isEmpty() )
		_configFile = filename;

	return _configFile.isEmpty() ? utils::getFirstFileInAppDirEndingWith("json") : _configFile;
}

QString getFirstFileInAppDirEndingWith( QString const& suffix )
{
	QDir dir(QCoreApplication::applicationDirPath());
	QStringList files = dir.entryList(QStringList() << "*."+suffix, QDir::Files);
	// QStringList const folders = source.entryList(QDir::NoDot | QDir::NoDotDot | QDir::Dirs);
	auto file =  files.first();
	return files.isEmpty() || suffix.isEmpty() ? QString() : file;
}

// optional - only set cam settings when they changed
QString settingsFile(QString filename)
{
	static QString _settingsFile;
	if( _settingsFile.isEmpty() )
		_settingsFile = filename;

	return _settingsFile.isEmpty() ? utils::getFirstFileInAppDirEndingWith("xml") : _settingsFile;
}



} // namespace utils