优化相机模块,优化rpc模块

This commit is contained in:
2025-09-03 15:37:40 +08:00
parent 22e6be7afb
commit 142c41da77
14 changed files with 459 additions and 394 deletions
+5
View File
@@ -0,0 +1,5 @@
{
"files.associations": {
"xutility": "cpp"
}
}
+155 -148
View File
@@ -8,6 +8,23 @@
#include <QJsonObject>
#include <QJsonDocument>
#include <windows.h>
#include <QDateTime>
#include <QCoreApplication>
#include <QThread>
#include <QTimer>
#include <QCryptographicHash>
#include <QScopedPointer>
#include <QBuffer>
#include <QPointer>
#include <QRegularExpression>
#include <QDataStream>
#include <QElapsedTimer>
#include <QMutexLocker>
#include <algorithm>
#include <memory>
#include <cmath>
#include <cstring>
static QProcess* process = nullptr;
static HANDLE jobHandle = nullptr;
rpc_finsTcp* create()
@@ -61,9 +78,8 @@ bool rpc_finsTcp::readData(std::vector<cv::Mat>& vec_mat, QByteArray& data)
ptr = new JsonRpcClient("127.0.0.1", 9000);
read_JsonRpcClient[data] = ptr;
}
//auto result = read_JsonRpcClient[data]->call("excuteCli", QJsonArray{ QString(data) }, "finstcp");
//data = variantListToByteArray(result);
data = ptr->finsReadCall("excuteCli", QString(data), "finstcp");
QByteArray resp = ptr->finsReadCall("excuteCli", QString(data), "finstcp");
data = resp; // 已是解码后的原始字节
return true;
}
bool ifRetryCMD = false;
@@ -136,6 +152,8 @@ bool rpc_finsTcp::writeData(std::vector<cv::Mat>& vec_mat, QByteArray& data){
readDataQueue.append(data);
}
else {
if (data.contains("null"))
return true;
if(data.contains("Heart") == false)
qDebug() << data;
emit writeCallSignal("excuteCli", QJsonArray{ QString(data) }, "finstcp");
@@ -146,7 +164,7 @@ bool rpc_finsTcp::writeData(std::vector<cv::Mat>& vec_mat, QByteArray& data){
bool rpc_finsTcp::initParas(QByteArray& data){
startProcess("./json_rpc_server.exe");
startProcess("./json_rpc_server_1_1_0.exe");
subThread = new QThread(this);
write_JsonRpcClient = new JsonRpcClientWorker();
write_JsonRpcClient->moveToThread(subThread);
@@ -220,161 +238,150 @@ bool JsonRpcClient::reconnect() {
return false;
}
}
QVariant jsonToVariant(const nlohmann::json& j)
{
if (j.is_null()) return QVariant();
if (j.is_boolean()) return j.get<bool>();
if (j.is_number_integer()) return j.get<qint64>();
if (j.is_number_unsigned()) return static_cast<quint64>(j.get<std::uint64_t>());
if (j.is_number_float()) return j.get<double>();
if (j.is_string()) return QString::fromStdString(j.get<std::string>());
if (j.is_array()) {
QVariantList list;
for (const auto& el : j) list.append(jsonToVariant(el));
return list;
}
if (j.is_object()) {
QVariantMap map;
for (auto it = j.begin(); it != j.end(); ++it)
map[QString::fromStdString(it.key())] = jsonToVariant(it.value());
return map;
}
return QVariant(); // fallback
}
QVariant JsonRpcClient::call(const QString& method, const QJsonArray& params, const QString& module)
{
QMutexLocker locker(&mutex_);
if (socket_.state() != QAbstractSocket::ConnectedState) {
qWarning() << "[JsonRpcClient] Socket not connected.";
if (!reconnect()) return QVariant();
}
QString reqStr = QString(R"({"jsonrpc":"2.0","method":"%1","params":%2,"id":%3)")
.arg(method)
.arg(QString::fromUtf8(QJsonDocument(params).toJson(QJsonDocument::Compact)))
.arg(idCounter_++);
if (!module.isEmpty()) {
reqStr += QString(R"(,"module":"%1")").arg(module);
}
reqStr += "}";
if (socket_.write(reqStr.toUtf8()) == -1 || !socket_.waitForBytesWritten(1000)) {
qWarning() << "[JsonRpcClient] Write failed.";
return QVariant();
}
if (!socket_.waitForReadyRead(10000)) {
qWarning() << "[JsonRpcClient] Read timeout.";
return QVariant();
}
QByteArray responseData = socket_.readAll();
// 使用 nlohmann json 替代 Qt 解析
try {
auto respJson = nlohmann::json::parse(responseData.constData(), responseData.constData() + responseData.size());
if (respJson.contains("error")) {
qWarning() << "[JsonRpcClient] Error:" << QString::fromStdString(respJson["error"].dump());
return QVariant();
}
return jsonToVariant(respJson["result"]);
}
catch (const nlohmann::json::parse_error& e) {
qWarning() << "[JsonRpcClient] Parse error:" << e.what();
return QVariant();
}
}
QByteArray JsonRpcClient::finsReadCall(const QString& method, const QString& params, const QString& module) {
QMutexLocker locker(&mutex_);
if (socket_.state() != QAbstractSocket::ConnectedState) {
qWarning() << "[JsonRpcClient] Socket not connected.";
if (!reconnect()) return QByteArray();
}
QString reqStr = QString(R"({"jsonrpc":"2.0","method":"%1","params":["%2"],"id":%3)")
.arg(method)
.arg(params)
.arg(idCounter_++);
if (!module.isEmpty()) {
reqStr += QString(R"(,"module":"%1")").arg(module);
}
reqStr += "}";
if (socket_.write(reqStr.toUtf8()) == -1 || !socket_.waitForBytesWritten(1000)) {
qWarning() << "[JsonRpcClient] Write failed.";
return QByteArray();
}
if (!socket_.waitForReadyRead(10000)) {
qWarning() << "[JsonRpcClient] Read timeout.";
return QByteArray();
}
QByteArray responseData = socket_.readAll();
// 仅用QByteArray查找和分割功能解析result数组
if (responseData.contains("error")) {
qWarning() << "[JsonRpcClient] Error in response:" << responseData;
return QByteArray();
}
// 查找 "result": [ 和对应的 ]
int resultPos = responseData.indexOf("\"result\"");
if (resultPos == -1) {
qWarning() << "[JsonRpcClient] No result field in response:" << responseData;
return QByteArray();
}
int arrayStart = responseData.indexOf('[', resultPos);
int arrayEnd = responseData.indexOf(']', arrayStart);
if (arrayStart == -1 || arrayEnd == -1 || arrayEnd <= arrayStart) {
qWarning() << "[JsonRpcClient] Result array not found or malformed:" << responseData;
return QByteArray();
}
QByteArray arrayContent = responseData.mid(arrayStart + 1, arrayEnd - arrayStart - 1);
// 按逗号分割
QList<QByteArray> items = arrayContent.split(',');
QByteArray result;
for (QByteArray item : items) {
item = item.trimmed();
bool ok = false;
int val = item.toInt(&ok);
if (ok) {
result.append(static_cast<char>(val));
} else if (!item.isEmpty()) {
qWarning() << "[JsonRpcClient] Non-integer value in result array:" << item;
return QByteArray();
}
}
return result;
}
void JsonRpcClient::writeCall(const QString& method, const QJsonArray& params, const QString& module) {
if (socket_.state() != QAbstractSocket::ConnectedState) {
qWarning() << "[JsonRpcClient] Socket not connected, trying to reconnect...";
if (!reconnect()) return;
}
QJsonObject request{
int myId = idCounter_++;
QJsonObject req{
{"jsonrpc", "2.0"},
{"method", method},
{"params", params},
{"id", idCounter_++}
{"id", myId}
};
if (!module.isEmpty()) {
request["module"] = module;
if (!module.isEmpty()) req.insert("module", module);
QJsonObject resp = sendRequestBuildAndAwait(req);
if (resp.contains("error")) {
qWarning() << "[JsonRpcClient] Error:" << QJsonDocument(resp["error"].toObject()).toJson(QJsonDocument::Compact);
return QVariant();
}
if (!resp.contains("result")) return QVariant();
QJsonValue r = resp.value("result");
if (r.isString()) return r.toString();
if (r.isDouble()) return r.toDouble();
if (r.isBool()) return r.toBool();
if (r.isArray()) return r.toArray().toVariantList();
if (r.isObject()) return r.toObject().toVariantMap();
return QVariant();
}
QByteArray JsonRpcClient::finsReadCall(const QString& method, const QString& params, const QString& module) {
QMutexLocker locker(&mutex_);
if (socket_.state() != QAbstractSocket::ConnectedState) {
if (!reconnect()) return QByteArray();
}
int myId = idCounter_++;
QJsonArray p; p.append(params);
QJsonObject req{{"jsonrpc","2.0"},{"method",method},{"params",p},{"id",myId}};
if (!module.isEmpty()) req.insert("module", module);
QJsonDocument doc(req);
QByteArray payload = doc.toJson(QJsonDocument::Compact);
if (socket_.write(payload) == -1 || !socket_.waitForBytesWritten(1000)) {
qWarning() << "[JsonRpcClient] Write failed.";
return QByteArray();
}
QJsonDocument doc(request);
QByteArray data = doc.toJson(QJsonDocument::Compact);
if (socket_.write(data) == -1 || !socket_.waitForBytesWritten(1000)) {
qWarning() << "[JsonRpcClient] Write failed:" << socket_.errorString();
return;
QJsonObject respObj;
if (!waitAndReadResponse(myId, respObj)) {
qWarning() << "[JsonRpcClient] Read timeout or parse error.";
return QByteArray();
}
if (respObj.contains("error")) {
qWarning() << "[JsonRpcClient] Error:" << QJsonDocument(respObj["error"].toObject()).toJson(QJsonDocument::Compact);
return QByteArray();
}
QString b64 = respObj.value("result").toString();
QByteArray decoded = QByteArray::fromBase64(b64.toUtf8());
return decoded;
}
QList<QByteArray> JsonRpcClient::extractJsonFrames(QByteArray& buffer) {
QList<QByteArray> frames;
int start = -1;
int braceDepth = 0;
bool inString = false;
char prev = 0;
for (int i = 0; i < buffer.size(); ++i) {
char c = buffer[i];
if (c == '"' && prev != '\\') inString = !inString;
if (!inString) {
if (c == '{') {
if (braceDepth == 0) start = i;
braceDepth++;
} else if (c == '}') {
braceDepth--;
if (braceDepth == 0 && start != -1) {
int len = i - start + 1;
frames.append(buffer.mid(start, len));
start = -1;
}
}
}
prev = c;
}
if (braceDepth == 0) {
if (!frames.isEmpty()) {
int lastEnd = buffer.lastIndexOf('}');
if (lastEnd != -1) buffer = buffer.mid(lastEnd + 1);
}
} else {
if (start > 0) buffer = buffer.mid(start);
}
return frames;
}
bool JsonRpcClient::waitAndReadResponse(int expectId, QJsonObject& outResp, int timeoutMs) {
QElapsedTimer timer; timer.start();
while (timer.elapsed() < timeoutMs) {
if (socket_.bytesAvailable() == 0) {
int remain = timeoutMs - (int)timer.elapsed();
if (!socket_.waitForReadyRead(qMin(remain, 1000))) {
continue;
}
}
QByteArray chunk = socket_.readAll();
if (!chunk.isEmpty()) recvBuffer_.append(chunk);
auto frames = extractJsonFrames(recvBuffer_);
for (const QByteArray& f : frames) {
QJsonParseError perr;
QJsonDocument jd = QJsonDocument::fromJson(f, &perr);
if (perr.error != QJsonParseError::NoError) {
qWarning() << "[JsonRpcClient] parse frame error:" << perr.errorString();
continue;
}
if (jd.isArray()) {
for (const QJsonValue& v : jd.array()) {
if (!v.isObject()) continue;
QJsonObject obj = v.toObject();
if (obj.value("id").toInt() == expectId) { outResp = obj; return true; }
}
} else if (jd.isObject()) {
QJsonObject obj = jd.object();
if (obj.value("id").toInt() == expectId) { outResp = obj; return true; }
}
}
}
return false;
}
QJsonObject JsonRpcClient::sendRequestBuildAndAwait(const QJsonObject& req, int timeoutMs) {
QByteArray payload = QJsonDocument(req).toJson(QJsonDocument::Compact);
int id = req.value("id").toInt();
if (socket_.write(payload) == -1 || !socket_.waitForBytesWritten(1000)) {
return QJsonObject{{"error", QJsonObject{{"code", -1},{"message", "write failed"}}}};
}
QJsonObject resp;
if (!waitAndReadResponse(id, resp, timeoutMs)) {
return QJsonObject{{"error", QJsonObject{{"code", -2},{"message", "timeout"}}}};
}
return resp;
}
void JsonRpcClient::writeCall(const QString& method, const QJsonArray& params, const QString& module) {
call(method, params, module);
}
+7 -5
View File
@@ -14,13 +14,12 @@
#include <QTimer>
#include <unordered_map>
#include <qjsonarray.h>
#include <QJsonArray>
#include <QJsonObject>
#include <QJsonDocument>
#include <QHostAddress>
#include <qmap.h>
#include <qthread.h>
#include <nlohmannJson.hpp>
enum connectionStatus {
None,
Disconnected,
@@ -36,13 +35,16 @@ public:
QByteArray finsReadCall(const QString& method, const QString& params = "", const QString& module = QString());
bool reconnect(); // 主动重连,或 call() 失败时调用
private:
QMutex mutex_; // 确保线程安全
// 解析累计缓冲中的完整 JSON 帧(可能存在粘包/拆包)
QList<QByteArray> extractJsonFrames(QByteArray& buffer);
bool waitAndReadResponse(int expectId, QJsonObject& outResp, int timeoutMs = 8000);
QJsonObject sendRequestBuildAndAwait(const QJsonObject& req, int timeoutMs = 8000);
QMutex mutex_; // 确保线程安全
QTcpSocket socket_;
QString host_;
quint16 port_;
int idCounter_;
QByteArray recvBuffer_; // 累计接收缓冲
};
class JsonRpcClientWorker : public QObject {
Q_OBJECT
-13
View File
@@ -2,20 +2,7 @@
#include <filesystem>
#include <struct.h>
//#include <appconfigStruct.h>
typedef dsModuleBase* (*CreateFunction)();
typedef void (*ReleaseFunction)(dsModuleBase* animal);
typedef struct {
QString m_stationKy;
QString key; // 相机名称
QString dllPath; // 模块名称
QString task_thread_index = "-1";// 存储当前算法属于那个任务线程
QByteArray m_initByte; // 传递初始化参数
dsModuleBase* module_ptr = nullptr; // 存储模块指针
ReleaseFunction destory_ptr; // 释放
cameraStruct _cameraStruct;//外部传入数据
bool init = false;
}cameraModule;
static void createDirectoryIfNotExists(const std::string& path) {
// 检查路径是否存在
+41 -66
View File
@@ -28,12 +28,11 @@ static MV_CC_DEVICE_INFO_LIST searchMvDevice()
return m_stDevList;
}
camera::camera(cameraModule cameraModulePtrIn, int indexIn, qtFuncBridge* bridgeIn)
camera::camera(cameraStruct configIn, int indexIn, qtFuncBridge* bridgeIn)
{
bridge = bridgeIn;
cameraModulePtr = cameraModulePtrIn;
config = cameraModulePtr._cameraStruct;
cameraName = cameraModulePtr.key;
config = configIn;
cameraName = QString::fromStdString(config.key);
index = indexIn;
lastUpdateTime.start();
this->start();
@@ -64,21 +63,21 @@ void camera::run()
// QPixmap pixmap;
// cvMatToQPixMap(data->oriImgs[i], pixmap);
// showImgPack* pack = new showImgPack(
// cameraModulePtr._cameraStruct.imageShowList[imgShowCnt].first,
// cameraModulePtr._cameraStruct.imageShowList[imgShowCnt].second
// config._cameraStruct.imageShowList[imgShowCnt].first,
// config._cameraStruct.imageShowList[imgShowCnt].second
// );
// pack->img = pixmap;
// emit bridge->displayWidget_sendImg(pack);
// imgShowCnt++;
// if (imgShowCnt >= cameraModulePtr._cameraStruct.imageShowList.size())
// if (imgShowCnt >= config._cameraStruct.imageShowList.size())
// imgShowCnt = 0;
// }
//}
//else {
// showLost++;
// qDebug() << cameraModulePtr.dllPath << "Lost show";
// qDebug() << config.dllPath << "Lost show";
//}
break;
}
@@ -89,22 +88,19 @@ void camera::run()
QThread::msleep(10);
}
}
cameraManager::~cameraManager()
{
for (auto camera : cameras) {
delete camera.second;
}
for (auto module : camerasVec) {
for (auto& module : _cameraStructs) {
dsModuleBase* base_ptr = module.module_ptr;
delete base_ptr;
}
}
void cameraManager::run()
{
void cameraManager::run(){
if (initFlag == true)
return;
#pragma region 加载相机dll
@@ -127,25 +123,23 @@ void cameraManager::run()
MV_CC_DEVICE_INFO_LIST m_stDevList = searchMvDevice();
QByteArray mvDevices = MV_CC_DeviceInfoListToQByteArray(m_stDevList);
for (auto i = 0; i < camerasVec.size(); i++) {
cameraModule& m_module = camerasVec[i];
QString dllPath = m_module.dllPath;
QString key = m_module.key;
for (auto i = 0; i < _cameraStructs.size(); i++) {
auto& m_module = _cameraStructs[i];
QString dllPath = QString::fromStdString(m_module.dllPath);
QString key = QString::fromStdString(m_module.key);
//传递初始化参数
QByteArray initByte = m_module.m_initByte;
QByteArray m_keyByte = key.toUtf8();
//遍历是否有相同key的相机,如果有直接复制指针
for (int count = 0; count < camerasVec.size(); count++)
if (!camerasVec[count].key.compare(m_module.key) && count < i)
m_module.module_ptr = camerasVec[count].module_ptr;
for (int count = 0; count < _cameraStructs.size(); count++)
if (!_cameraStructs[count].key.compare(m_module.key) && count < i)
m_module.module_ptr = _cameraStructs[count].module_ptr;
m_module.module_ptr->writeData(vec_mat, m_keyByte); //初始化相机
//非海康相机可跳过
for (int i = 0; i < m_stDevList.nDeviceNum; i++)
{
for (int i = 0; i < m_stDevList.nDeviceNum; i++){
std::string userDefineName = static_cast<std::string>((LPCSTR)m_stDevList.pDeviceInfo[i]->SpecialInfo.stGigEInfo.chUserDefinedName);
std::string serialNumber = static_cast<std::string>((LPCSTR)m_stDevList.pDeviceInfo[i]->SpecialInfo.stGigEInfo.chSerialNumber);
if (!serialNumber.compare(m_module.key.toStdString()) || !userDefineName.compare(m_module.key.toStdString()))
{
if (!serialNumber.compare(m_module.key) || !userDefineName.compare(m_module.key)){
m_module.module_ptr->writeData(vec_mat, mvDevices);
break;
}
@@ -155,42 +149,35 @@ void cameraManager::run()
}
status = NotInit;
bool initReuslt = true;
for (auto i = 0; i < camerasVec.size(); i++)
{
cameraModule m_module = camerasVec.at(i);
if (m_module.init == true)
for (auto i = 0; i < _cameraStructs.size(); i++){
auto& cameraStruct = _cameraStructs[i];
if (cameraStruct.init == true)
continue;
QByteArray initByte = m_module.m_initByte;
if (m_module.module_ptr->initParas(initByte))
{
camera* _camera = new camera(m_module, cameras.size(), bridge);
cameras.insert(std::make_pair(m_module.key.toStdString(), _camera));
emit bridge->loadingWindow_appendLog("相机" + m_module.key + "初始化成功", "green");
QByteArray initByte = cameraStruct.m_initByte;
if (cameraStruct.module_ptr->initParas(initByte)){
camera* _camera = new camera(cameraStruct, cameras.size(), bridge);
cameras.insert(std::make_pair(cameraStruct.key, _camera));
emit bridge->loadingWindow_appendLog("相机" + QString::fromStdString(cameraStruct.key) + "初始化成功", "green");
qDebug() << "[INFO] " << " initParas success!";
m_module.init = true;
cameraStruct.init = true;
}
else
{
else{
QByteArray errorStr("getStatus");
m_module.module_ptr->readData(vec_mat, errorStr);
cameraStruct.module_ptr->readData(vec_mat, errorStr);
initReuslt = false;
qCritical() << "[Error] " << " moduleName:" << m_module.dllPath << " initParas failed!";
emit bridge->loadingWindow_appendLog("相机" + m_module.key + "初始化失败->" + errorStr, "red");
qCritical() << "[Error] " << " moduleName:" << QString::fromStdString(cameraStruct.dllPath) << " initParas failed!";
emit bridge->loadingWindow_appendLog("相机" + QString::fromStdString(cameraStruct.key) + "初始化失败->" + errorStr, "red");
}
}
if (initReuslt == true)
{
if (initReuslt == true){
initFlag = true;
status = InitOK;
}
else
status = InitFailure;
}
bool cameraManager::loadModule(cameraStruct _cameraStruct)
{
QString task_thread_index = 0;
try
{
bool cameraManager::loadModule(cameraStruct& _cameraStruct){
try{
QString keyName = QString::fromStdString(_cameraStruct.key);
QString dllPath = QString::fromStdString(_cameraStruct.dllPath);// 相机模块名
QString module_path = "./" + dllPath;
@@ -213,8 +200,7 @@ bool cameraManager::loadModule(cameraStruct _cameraStruct)
QLibrary* m_lib = new QLibrary(module_path);
lib_list.append(m_lib);
bool flag = m_lib->load();
if (!m_lib->isLoaded())
{
if (!m_lib->isLoaded()){
qDebug() << "[Error] " << " Loaded error:" << m_lib->errorString();
bridge->loadingWindow_appendLog("加载相机模块" + dllPath + "失败->" + m_lib->errorString(), "red");
@@ -223,29 +209,18 @@ bool cameraManager::loadModule(cameraStruct _cameraStruct)
CreateFunction createFun = (CreateFunction)m_lib->resolve("create");
ReleaseFunction releaseFun = (ReleaseFunction)m_lib->resolve("destory");
if (createFun && releaseFun)
{
cameraModule m_module;
m_module.key = keyName;
m_module.m_initByte = QByteArray::fromStdString( _cameraStruct.connectionName);
m_module.dllPath = dllPath;
m_module.module_ptr = createFun();
m_module.destory_ptr = releaseFun;
m_module._cameraStruct = _cameraStruct;
if (!task_thread_index.isEmpty())
m_module.task_thread_index = task_thread_index;
camerasVec.push_back(m_module);
if (createFun && releaseFun){
_cameraStruct.module_ptr = createFun();
_cameraStruct.destory_ptr = releaseFun;
_cameraStruct.m_initByte = QByteArray::fromStdString(_cameraStruct.connectionName);
}
else
{
else{
delete m_lib;
m_lib = nullptr;
return false;
}
}
catch (QString event)
{
catch (QString event){
qCritical() << "[Error] " << " event:" << event;
return false;
}
+42 -48
View File
@@ -11,57 +11,66 @@
#include <future>
#include <qtBridge.h>
#include <detData.h>
typedef dsModuleBase* (*CreateFunction)();
typedef void (*ReleaseFunction)(dsModuleBase* animal);
struct cameraStruct {
int index;
std::string key;
std::string connectionName;//per Sec
std::string serialNum;
std::string dllPath;
std::vector <std::string> oriSaveFormat;
std::vector<std::pair<QString, QString>>imageShowList;
QByteArray m_initByte; // 传递初始化参数
dsModuleBase* module_ptr = nullptr; // 存储模块指针
ReleaseFunction destory_ptr; // 释放
bool init = false;
};
//硬触发要求在触发相机前给出触发信号
class backEndManager;
class camera : public QThread
{
class camera : public QThread{
Q_OBJECT
public:
QTime lastUpdateTime;
QString cameraName;
int imgShowCnt = 0;
cameraModule cameraModulePtr;
cameraStruct config;
camera(cameraModule cameraModulePtrIn, int indexIn, qtFuncBridge* bridgeIn);
~camera()
{
camera(cameraStruct configIn, int indexIn, qtFuncBridge* bridgeIn);
~camera(){
runFlag = false;
this->terminate();
while (this->isRunning() == true);
}
void run();
void stop()
{
void stop(){
runFlag = false;
while (this->isRunning() == true);
}
void getImgQueueSize();
void captureImage(std::shared_ptr <detData> dataIn)
{
void captureImage(std::shared_ptr <detData> dataIn){
QMutexLocker locker(&mutex);
requestQueue.enqueue(dataIn);
//std::thread([this]() {trigger();}).detach();
}
//相机操作
bool trigger()
{
if (!cameraModulePtr.module_ptr->run())
{
bool trigger(){
if (!config.module_ptr->run()){
qCritical() << "[Error] " << " m_name:" << cameraName << " run failed!";
return false;
}
return true;
}
double getCameraValue()//点激光相机专用
{
double getCameraValue(){//点激光相机专用
double value = 0;
std::vector<cv::Mat> camera_mat;
QByteArray task_name;
int cnt = 0;
while (!cameraModulePtr.module_ptr->readData(camera_mat, task_name))
{
while (!config.module_ptr->readData(camera_mat, task_name)){
QThread::msleep(10);
cnt++;
if (cnt > 500)
@@ -70,10 +79,9 @@ public:
value = task_name.toDouble();
return value;
}
void getCameraImg(std::vector<cv::Mat>& mats,int imgAmountMin)
{
void getCameraImg(std::vector<cv::Mat>& mats,int imgAmountMin){
QByteArray task_name;
if (!cameraModulePtr.module_ptr->readData(mats, task_name)) {
if (!config.module_ptr->readData(mats, task_name)) {
if (mats.size() == 0) {
qDebug() << "camera_mat size 0,insert blank image";
mats = std::vector<cv::Mat>(imgAmountMin, cv::Mat::zeros(100, 100, CV_8UC3));
@@ -81,16 +89,13 @@ public:
}
qDebug() << __FUNCTION__ << " line:" << __LINE__ << "camera_mat size:" << mats.size();
}
void setDigitalShift(float value)
{
void setDigitalShift(float value){
readData("DigitalShift_" + std::to_string(value));
}
void setExposureTime(float value)
{
void setExposureTime(float value){
readData("exposure_" + std::to_string(value));
}
void setUserSet(int value)
{
void setUserSet(int value){
readData("userset_" + std::to_string(value));
}
private:
@@ -99,7 +104,7 @@ private:
{
QByteArray task_name(QByteArray::fromStdString(str));
std::vector<cv::Mat> camera_mat;
if (!cameraModulePtr.module_ptr->readData(camera_mat, task_name))
if (!config.module_ptr->readData(camera_mat, task_name))
qCritical() << "[Error] " << "set exposure error!";
}
int index = 0;
@@ -111,26 +116,22 @@ private:
int imgLost = 0;//未取用从而丢失的图片数量
int showLost = 0;//因为窗口刷新速率低而未显示的数量
};
class cameraManager : public serviceModule
{
class cameraManager : public serviceModule{
Q_OBJECT
public:
cameraManager(nlohmann::ordered_json& json, qtFuncBridge* bridgeIn) {
bridge = bridgeIn;
auto cameraJson = json["CameraSetting"];
for (auto data : cameraJson)
{
for (auto data : cameraJson){
cameraStruct _cameraStruct;
_cameraStruct.key = data["key"];
_cameraStruct.connectionName = data["connectionName"];
_cameraStruct.dllPath = data["dllPath"];
_cameraStruct.oriSaveFormat = data["oriSaveFormat"];
for (auto& imageShow : data["imageShow"])
{
for (auto& imageShow : data["imageShow"]){
QString str = QString::fromStdString(imageShow);
QStringList l = str.split("#");
if (l.size() < 2)
{
if (l.size() < 2){
qDebug() << "Imagehsow 格式错误,例:窗口名#类型名";
std::cout << "Imagehsow 格式错误,例:窗口名#类型名" <<std::endl;
continue;
@@ -140,20 +141,16 @@ public:
_cameraStructs.push_back(_cameraStruct);
}
}
~cameraManager();
void run();
std::unordered_map<std::string, camera*>cameras;//key 相机名
camera* getCamera(std::string cameraName)
{
camera* getCamera(std::string cameraName){
auto camera = cameras.find(cameraName);
if (camera != cameras.end())
return camera->second;
return nullptr;
}
void stop()
{
void stop(){
for (auto camera : cameras)
camera.second->stop();
}
@@ -162,17 +159,14 @@ private:
std::vector<cameraStruct> _cameraStructs;//相机配置结构体
qtFuncBridge* bridge;
bool loadModule(cameraStruct _cameraStruct);
std::vector<cameraModule>camerasVec;//用于初始化和销毁
bool loadModule(cameraStruct& _cameraStruct);
std::vector<cv::Mat> vec_mat;//没啥用,一直保持为空就好
QList<QLibrary*> lib_list;
std::map<QString,bool> m_usedDllPath;
public slots:
void cameraTrigger(std::string Name)
{
void cameraTrigger(std::string Name){
auto camera=cameras.find(Name);
if (camera != cameras.end())
{
if (camera != cameras.end()){
camera->second->trigger();
}
}
+10 -8
View File
@@ -82,20 +82,16 @@ public:
};
class detDataManager{
public:
detDataManager(triggerManager* in_triggerManager)
:_triggerManager(in_triggerManager){
}
std::unordered_map<QString, std::shared_ptr<detData>>map;
QMutex dataMutex;
detDataManager(){
}
std::shared_ptr <detData> createDetData(QString IN_cameraKeyName,std::string IN_SN, int imgAmountMin,std::vector<std::string> oriFormat) {
QMutexLocker locker(&dataMutex);
std::shared_ptr <detData>dataPtr(new detData());
dataPtr->cameraKeyName = IN_cameraKeyName.toStdString();
dataPtr->imgSaveNameParameter.push_back(IN_cameraKeyName.toStdString());
dataPtr->oriFormat = oriFormat;
dataPtr->triggerPtr = _triggerManager;
dataPtr->triggerPtr;
dataPtr->SNcode = IN_SN;
dataPtr->imgAmountMin = imgAmountMin;
dataPtr->dManager = this;
@@ -131,7 +127,13 @@ public:
}
return false;
}
void setTriggerManager(triggerManager* _triggerManagerIN) {
QMutexLocker locker(&dataMutex);
_triggerManager = _triggerManagerIN;
}
private:
triggerManager* _triggerManager;
triggerManager* _triggerManager = nullptr;
QMutex dataMutex;
std::unordered_map<QString, std::shared_ptr<detData>>map;
};
#pragma once
+16 -3
View File
@@ -11,8 +11,6 @@ triggerManager::triggerManager(detProcess* _detProcessIn, qtFuncBridge* bridgeIn
_detProcess = _detProcessIn;
dManager = _detProcessIn->_serviceManager._detDataManager;
_cameraManager = _detProcessIn->_serviceManager._cameraManager;
//_threadManager = &_detProcessIn->_threadManager;
//_lightSourceManager = &_detProcessIn->_lightSourceManager;
for (auto& d : triggerJson["readAllCmd"]) {
readAllStruct _struct;
_struct.readAllCmd = QByteArray::fromStdString(d);
@@ -135,9 +133,24 @@ void triggerManager::decodeCameraCMD(readAllStruct& _struct, QByteArray byte)
if (isConnected == true) {
lostConnectionCountTimer.start();
std::cout<< "与PLC的连接已断开,正在尝试重连" << std::endl;
std::cout << "错误类型:读取到的数据为空" << std::endl;
}
if (lostConnectionRePrintTimer.elapsed() > 1000) {
qCritical() << "ERROR:cant read data from Fins,无法从fins读取数据";
qCritical() << "ERROR:cant read data from Fins data size=0,无法从fins读取数据 数据为空";
emit bridge->setPlcConnectionError();
isConnected = false;
lostConnectionRePrintTimer.start();
}
return;
}
else if (byte.size() != _struct.readLength * 2 && byte.size() != _struct.readLength) {
if (isConnected == true) {
lostConnectionCountTimer.start();
std::cout << "与PLC的连接已断开,正在尝试重连" << std::endl;
std::cout << "错误类型:读取到的数据大小不匹配" << std::endl;
}
if (lostConnectionRePrintTimer.elapsed() > 1000) {
qCritical() << "ERROR:cant read data from Fins data size<preset,无法从fins读取数据 数据大小不匹配";
emit bridge->setPlcConnectionError();
isConnected = false;
lostConnectionRePrintTimer.start();
+63 -22
View File
@@ -16,19 +16,55 @@ public:
db(dbIn),bridge(bridgeIn),json(jsonIn){
}
// 对普通指针的安全删除
template<typename T>
void safeDelete(T*& ptr) {
if (ptr) { delete ptr; ptr = nullptr; }
}
// 尝试对基于 QThread 的 serviceModule 进行关停,然后删除
void safeShutdownDelete(serviceModule* ptr) {
if (!ptr) return;
// 如果对象正在运行,尝试停止
if (ptr->isRunning()) {
// 如果存在 stop 槽,则尝试调用
QMetaObject::invokeMethod(ptr, "stop", Qt::DirectConnection);
// 作为后备,尝试退出事件循环
QMetaObject::invokeMethod(ptr, "quit", Qt::DirectConnection);
// 等待其退出,给予一定时间
if (!ptr->wait(2000)) {
// 仍在运行时,作为最后手段强制终止
ptr->terminate();
ptr->wait(1000);
}
}
delete ptr; ptr = nullptr;
}
void init() {
_serviceManager._imgSaveThreadManager = new imgSaveThreadManager(json["imgSaveBasePath"]);
_serviceManager._cameraManager = new cameraManager(json, bridge);
_serviceManager._triggerManager = new triggerManager(this, bridge, json["Triggers"]);
_serviceManager._detDataManager = new detDataManager(_serviceManager._triggerManager);
// 创建/重建需要的服务模块,避免重复创建
if (!_serviceManager._imgSaveThreadManager) {
_serviceManager._imgSaveThreadManager = new imgSaveThreadManager(json["imgSaveBasePath"]);
}
if (!_serviceManager._cameraManager) {
_serviceManager._cameraManager = new cameraManager(json, bridge);
}
if (!_serviceManager._triggerManager) {
_serviceManager._triggerManager = new triggerManager(this, bridge, json["Triggers"]);
}
if (initOnce == false) {
initOnce = true;
_csvWriter = new CsvWriter(db);
_serviceManager._detDataManager = new detDataManager();
_missonResultHandle = new missonResultHandle(bridge);
_serviceManager._missonResultHandle = _missonResultHandle;
_serviceManager.dataBase = db;
_serviceManager._csvWriter = _csvWriter;
_serviceManager._handleAiModelManager = new handleAiModelManager(json, bridge);
// handleAiModelManager 与 CLI 等只在首次初始化创建
if (!_serviceManager._handleAiModelManager) {
_serviceManager._handleAiModelManager = new handleAiModelManager(json, bridge);
}
connect(bridge, &qtFuncBridge::reInitConfig, this, [=]() {reinitConfig(); });
_cliManager = new CLIManager(&_serviceManager, bridge);
}
@@ -52,15 +88,29 @@ public:
// 重新初始化配置
void reinitConfig() {
// 1. 释放已有资源
if (_serviceManager._imgSaveThreadManager) { delete _serviceManager._imgSaveThreadManager; _serviceManager._imgSaveThreadManager = nullptr; }
if (_serviceManager._cameraManager) { delete _serviceManager._cameraManager; _serviceManager._cameraManager = nullptr; }
if (_serviceManager._triggerManager) { delete _serviceManager._triggerManager; _serviceManager._triggerManager = nullptr; }
//if (_serviceManager._threadManager) { delete _serviceManager._threadManager; _serviceManager._threadManager = nullptr; }
if (_serviceManager._detDataManager) { delete _serviceManager._detDataManager; _serviceManager._detDataManager = nullptr; }
// 1. 优雅停止并释放已有运行中的服务模块
// 停止并删除线程型模块
safeShutdownDelete(_serviceManager._cameraManager);
safeShutdownDelete(_serviceManager._triggerManager);
// imgSaveThreadManager 可能不是 QThread,直接删除
safeDelete(_serviceManager._imgSaveThreadManager);
// handleAiModelManager 可能运行在后台,优雅停止后删除
if (_serviceManager._handleAiModelManager) {
// try invoking stop if exists
QMetaObject::invokeMethod(_serviceManager._handleAiModelManager, "stop", Qt::DirectConnection);
safeDelete(_serviceManager._handleAiModelManager);
}
// 2. 重新初始化
init();
this->start();
// 3. 如果 detProcess 尚未运行,则启动主线程;如果已在运行,run() 应自行管理子模块的重启
if (!this->isRunning()) {
this->start();
} else {
// 已在运行的话,可以发出信号或回调,通知 run 中重载配置(这里仅 log)
qDebug() << "detProcess already running, init refreshed. run() should handle reloading if needed.";
}
}
// 初始化并运行主流程
void run() {
@@ -81,16 +131,7 @@ public:
json["missionSettings"], bridge
);
_cliManager->initBasicPreset();
//_threadManager->registerResultHandleCallback(
// [this](std::shared_ptr<detData> data) {
// detectionResultHandle(data);
// });
//_threadManager->registerProcessAlgoCallback(
// [this](std::shared_ptr<detData> data, handleAiModelManager* _handleAiModelManager) {
// return _missionLoader._misson->processAlgo(data, _handleAiModelManager);
// });
_serviceManager._detDataManager->setTriggerManager(_serviceManager._triggerManager);
emit bridge->initResult(InitOK);
}
else {
+1 -9
View File
@@ -5,6 +5,7 @@
#include <simpleTools/stringAlgo.h>
#include <simpleTools/fileManager.h>
#include <qmutex.h>
#include <subModuleBase.h>
struct productSignStruct
{
cv::Rect posRect;
@@ -209,15 +210,6 @@ struct triggerStruct
std::string writeType;
int startPos;
};
struct cameraStruct{
int index;
std::string key;
std::string connectionName;//per Sec
std::string serialNum;
std::string dllPath;
std::vector <std::string> oriSaveFormat;
std::vector<std::pair<QString,QString>>imageShowList;
};
struct sqlConfigStruct
{
+1 -1
View File
@@ -19,7 +19,7 @@ void appConfig::parsingSettingJson()
softwareTile = settingJson["softwareTile"];
imgSavePath = settingJson["backend"]["imgSaveBasePath"];
//viewer
auto viewerData = settingJson["ImageView"];
auto viewerData = settingJson["ImageView"];
for (auto data = viewerData.begin(); data != viewerData.end(); data++)
{
viewerStruct v;
@@ -2,6 +2,14 @@
#include <QDebug>
using namespace std;
#include <QTextCodec>
#include <thread>
#include <atomic>
#include <chrono>
#include <mutex>
static std::atomic<bool> g_reconnecting(false);
static std::mutex g_reconnect_mutex;
QByteArray mv_Status = "connected";//0106 新增相机断联报警
long long index = 0; //相机序号
void* handle;
@@ -174,23 +182,47 @@ void __stdcall ReconnectDevice(unsigned int nMsgType, void* pUser)
mv_Status = "disconnect";
qDebug() << "[Error] " << " MV camera disconnects!";
moduleStatus = false;
if (nMsgType == MV_EXCEPTION_DEV_DISCONNECT)
{
//断开连接
CloseDevice();
handle = nullptr;
BOOL bConnected = FALSE;
while (1)
// 如果已有重连线程在运行,则直接返回
bool expected = false;
if (!g_reconnecting.compare_exchange_strong(expected, true))
{
Sleep(100);
if (connectDevice() == true)
{
qWarning() << "[Hd_CameraModule_HIK] " << " Hd_CameraModule_HIK create success again! ";
moduleStatus = true;
break;
}
qDebug() << "[Info] reconnect already in progress";
return;
}
// 启动后台线程负责重连,避免在回调线程中长时间阻塞
std::thread([]() {
qDebug() << "[Info] start reconnect thread";
// 确保设备资源关闭
CloseDevice();
int attempt = 0;
int delay_ms = 500; // 初始延迟
while (true)
{
attempt++;
qDebug() << "[Info] reconnect attempt:" << attempt;
if (connectDevice())
{
qWarning() << "[Hd_CameraModule_HIK] reconnect success!";
moduleStatus = true;
mv_Status = "connected";
g_reconnecting = false;
break;
}
// 指数退避,最大 5000ms
std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms));
delay_ms = delay_ms * 2;
if (delay_ms > 5000) delay_ms = 5000;
// 在某些场景可能希望退出重连(例如程序关闭),如果未来需要可增加退出条件
}
}).detach();
}
}
@@ -312,11 +344,17 @@ Hd_CameraModule_HIK_hard_PCIE::Hd_CameraModule_HIK_hard_PCIE()
void CloseDevice()
{
unsigned int nRet = MV_CC_StopGrabbing(handle);
CloseHandle(handle);
//nRet = MV_CC_CloseDevice(handle);
//nRet = MV_CC_DestroyHandle(handle);
// 如果 handle 已经为空,直接返回
if (handle == nullptr)
return;
// 使用 SDK 正确的停止/关闭/销毁流程,避免使用 CloseHandle 等不匹配的 API
MV_CC_StopGrabbing(handle);
MV_CC_CloseDevice(handle);
MV_CC_DestroyHandle(handle);
handle = nullptr;
}
Hd_CameraModule_HIK_hard_PCIE::~Hd_CameraModule_HIK_hard_PCIE()
{
CloseDevice();
@@ -488,25 +526,9 @@ bool Hd_CameraModule_HIK_hard_PCIE::run()
{
m_flag = false;
int mytime = 0;
if (imgShouldGetIndex < imgShouldGetVec.size()) {
if (imgShouldGetVec[imgShouldGetIndex] == 0) {
n_mutex->lock();
queuepic.push_back(cv::Mat(200, 200, CV_8UC3, cv::Scalar(0, 0, 255))); //返回空图
std::cout << "red" << std::endl;
n_mutex->unlock();
imgShouldGetIndex++;
return true;
}
imgShouldGetIndex++;
}
int cnt = 0;
while (true)
{
/* if (moduleStatus == false || mytime++ > getImageTimeOut || ifBreak == true)
{
result = false;
break;
}*/
n_mutex->lock();
cnt++;
if (queuepic.size() > 0)
@@ -516,14 +538,14 @@ bool Hd_CameraModule_HIK_hard_PCIE::run()
std::cout << "\n gotImg" << std::endl;
break;
}
if (cnt > 25000) {
if (cnt > 120) {
queuepic.push_back(cv::Mat(250, 250, CV_8UC3, cv::Scalar(0, 255, 0))); //返回空图
std::cout << "timeout" << std::endl;
n_mutex->unlock();
return true;
}
n_mutex->unlock();
QThread::msleep(1);
QThread::msleep(10);
}
//考虑到误触发、漏触发的图,在这里进行设置。
//需要设置曝光时
@@ -2,6 +2,11 @@
#include <QDebug>
using namespace std;
#include <QTextCodec>
#include <thread>
#include <atomic>
#include <chrono>
#include <mutex>
QByteArray mv_Status = "connected";//0106 新增相机断联报警
long long index = 0; //相机序号
void* handle;
@@ -9,6 +14,8 @@ string Username = "";
bool m_flag = false;
//MV_CC_DEVICE_INFO_LIST m_stDevList;//相机设备
bool moduleStatus = true;
static std::atomic<bool> g_reconnecting(false);
static std::mutex g_reconnect_mutex;
QQueue<cv::Mat> queuepic;
//data == "rest_newProductIn"时要结束run;机台报警,取图超时,复位后重新拍的情况。
bool ifBreak = false;
@@ -168,29 +175,67 @@ void SetGain(float GainValue)
MV_CC_SetFloatValue(handle, "Gain", GainValue);
}
//关闭设备
void CloseDevice()
{
// 如果 handle 已经为空,直接返回
if (handle == nullptr)
return;
// 使用 SDK 正确的停止/关闭/销毁流程,避免在回调或其他线程中出错
MV_CC_StopGrabbing(handle);
MV_CC_CloseDevice(handle);
MV_CC_DestroyHandle(handle);
handle = nullptr; //确保后续可以重新创建 handle
}
//0518 断线重连
void __stdcall ReconnectDevice(unsigned int nMsgType, void* pUser)
{
mv_Status = "disconnect";
qDebug() << "[Error] " << " MV camera disconnects!";
moduleStatus = false;
if (nMsgType == MV_EXCEPTION_DEV_DISCONNECT)
{
//断开连接
CloseDevice();
handle = nullptr;
BOOL bConnected = FALSE;
while (1)
// 如果已有重连线程在运行,则直接返回
bool expected = false;
if (!g_reconnecting.compare_exchange_strong(expected, true))
{
Sleep(100);
if (connectDevice() == true)
{
qWarning() << "[Hd_CameraModule_HIK] " << " Hd_CameraModule_HIK create success again! ";
moduleStatus = true;
break;
}
qDebug() << "[Info] reconnect already in progress";
return;
}
// 启动后台线程负责重连,避免在回调线程中长时间阻塞
std::thread([]() {
qDebug() << "[Info] start reconnect thread";
// 确保设备资源关闭
CloseDevice();
int attempt = 0;
int delay_ms = 500; // 初始延迟
while (true)
{
attempt++;
qDebug() << "[Info] reconnect attempt:" << attempt;
if (connectDevice())
{
qWarning() << "[Hd_CameraModule_HIK] reconnect success!";
moduleStatus = true;
mv_Status = "connected";
g_reconnecting = false;
break;
}
// 指数退避,最大 5000ms
std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms));
delay_ms = delay_ms * 2;
if (delay_ms > 5000) delay_ms = 5000;
// 在某些场景可能希望退出重连(例如程序关闭),如果未来需要可增加退出条件
}
}).detach();
}
}
@@ -308,14 +353,6 @@ Hd_CameraModule_HIK_hard_PCIE::Hd_CameraModule_HIK_hard_PCIE()
//m_thread = new MyThread;
//m_mutex = new QMutex();
}
//关闭设备
void CloseDevice()
{
MV_CC_StopGrabbing(handle);
MV_CC_CloseDevice(handle);
MV_CC_DestroyHandle(handle);
handle = nullptr; //此处注释掉的话,软件断开再连接,回调函数不出图
}
Hd_CameraModule_HIK_hard_PCIE::~Hd_CameraModule_HIK_hard_PCIE()
{
CloseDevice();
@@ -487,20 +524,8 @@ bool Hd_CameraModule_HIK_hard_PCIE::run()
{
m_flag = false;
int mytime = 0;
if (imgShouldGetIndex < imgShouldGetVec.size()) {
if (imgShouldGetVec[imgShouldGetIndex] == 0) {
n_mutex->lock();
queuepic.push_back(cv::Mat(200, 200, CV_8UC3, cv::Scalar(0, 0, 255))); //返回空图
std::cout << "red" << std::endl;
n_mutex->unlock();
imgShouldGetIndex++;
return true;
}
else
MV_CC_SetCommandValue(handle, "TriggerSoftware");
imgShouldGetIndex++;
}
int cnt = 0;
MV_CC_SetCommandValue(handle, "TriggerSoftware");
while (true)
{
/* if (moduleStatus == false || mytime++ > getImageTimeOut || ifBreak == true)
@@ -517,14 +542,14 @@ bool Hd_CameraModule_HIK_hard_PCIE::run()
std::cout << "\n gotImg" << std::endl;
break;
}
if (cnt > 25000) {
if (cnt > 120) {
queuepic.push_back(cv::Mat(250, 250, CV_8UC3, cv::Scalar(0, 255, 0))); //返回空图
std::cout << "timeout" << std::endl;
n_mutex->unlock();
return true;
}
n_mutex->unlock();
QThread::msleep(1);
QThread::msleep(10);
}
//考虑到误触发、漏触发的图,在这里进行设置。
//需要设置曝光时