GrabBag/AppUtils/AppCommon/Src/BasePresenter.cpp

875 lines
30 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "BasePresenter.h"
#include "VrLog.h"
#include "VrError.h"
#include <fstream>
#include <QFileInfo>
#include <QDir>
#include <QDateTime>
#include <QString>
#include <QCoreApplication>
#include "PathManager.h"
#include "IYModbusTCPServer.h"
BasePresenter::BasePresenter(QObject *parent)
: QObject(parent)
, m_currentCameraIndex(0)
, m_bCameraConnected(false)
, m_bAlgoDetectThreadRunning(false)
, m_pCameraReconnectTimer(nullptr)
{
// 创建相机重连定时器
m_pCameraReconnectTimer = new QTimer(this);
m_pCameraReconnectTimer->setInterval(2000); // 默认2秒
connect(m_pCameraReconnectTimer, &QTimer::timeout, this, &BasePresenter::OnCameraReconnectTimer);
}
BasePresenter::~BasePresenter()
{
// 清除状态回调指针,防止后续回调访问
m_pStatusCallback = nullptr;
// 等待初始化线程完成
if (m_initThread.joinable()) {
m_initThread.join();
}
// 处理待处理的 Qt 事件,确保 QueuedConnection 的回调执行时检查到 m_pStatusCallback 为空
QCoreApplication::processEvents();
// 停止检测线程
StopAlgoDetectThread();
// 停止重连定时器
StopCameraReconnectTimer();
// 停止ModbusTCP服务器
StopModbusServer();
// 清理相机设备
for (size_t i = 0; i < m_vrEyeDeviceList.size(); ++i) {
auto& camera = m_vrEyeDeviceList[i];
if (camera.second) {
camera.second->CloseDevice();
delete camera.second;
camera.second = nullptr;
}
}
m_vrEyeDeviceList.clear();
}
int BasePresenter::Init()
{
LOG_INFO("BasePresenter::Init()\n");
// 在后台线程中执行初始化
m_initThread = std::thread([this]() {
int nRet = InitApp();
if (nRet != SUCCESS) {
LOG_ERROR("InitApp failed: %d\n", nRet);
return;
}
// 初始化算法参数
nRet = InitAlgoParams();
LOG_INFO("Algorithm parameters initialization result: %d\n", nRet);
// 启动ModbusTCP服务
int modbusRet = StartModbusServer(5020);
if (modbusRet == SUCCESS) {
LOG_INFO("ModbusTCP server started on port 5020\n");
} else {
LOG_WARNING("Failed to start ModbusTCP server\n");
}
SetWorkStatus(WorkStatus::Ready);
});
return SUCCESS;
}
int BasePresenter::StartDetection(int cameraIndex, bool isAuto)
{
LOG_INFO("[BasePresenter] StartDetection - cameraIndex=%d, isAuto=%d\n", cameraIndex, isAuto);
// 设置当前相机索引
if (cameraIndex >= 0 && cameraIndex != -1) {
m_currentCameraIndex = cameraIndex;
}
int currentCamera = m_currentCameraIndex;
// 检查相机列表是否为空
if (m_vrEyeDeviceList.empty()) {
LOG_ERROR("[BasePresenter] No camera device found\n");
return ERR_CODE(DEV_NOT_FIND);
}
// 清空检测数据缓存
ClearDetectionDataCache();
int nRet = SUCCESS;
// 启动指定相机cameraIndex为相机ID从1开始编号
int arrayIndex = currentCamera - 1; // 转换为数组索引从0开始
// 检查相机是否连接
if (arrayIndex < 0 || arrayIndex >= static_cast<int>(m_vrEyeDeviceList.size()) ||
m_vrEyeDeviceList[arrayIndex].second == nullptr) {
LOG_ERROR("[BasePresenter] Camera %d is not connected or invalid\n", currentCamera);
return ERR_CODE(DEV_NOT_FIND);
}
SetWorkStatus(WorkStatus::Working);
IVrEyeDevice* pDevice = m_vrEyeDeviceList[arrayIndex].second;
// 获取数据类型(由子类决定)
EVzResultDataType eDataType = GetDetectionDataType();
// 设置状态回调
VzNL_OnNotifyStatusCBEx statusCallback = GetCameraStatusCallback();
pDevice->SetStatusCallback(statusCallback, this);
// 获取检测回调函数(由子类提供)
VzNL_AutoOutputLaserLineExCB detectCallback = GetDetectionCallback();
// 开始检测
nRet = pDevice->StartDetect(detectCallback, eDataType, this);
LOG_INFO("[BasePresenter] Camera %d start detection result: %d\n", currentCamera, nRet);
if (nRet == SUCCESS) {
// 启动算法检测线程
StartAlgoDetectThread();
}
return nRet;
}
int BasePresenter::StopDetection()
{
LOG_INFO("[BasePresenter] StopDetection\n");
// 停止所有相机的检测
for (size_t i = 0; i < m_vrEyeDeviceList.size(); ++i) {
IVrEyeDevice* pDevice = m_vrEyeDeviceList[i].second;
if (pDevice) {
int ret = pDevice->StopDetect();
if (ret == 0) {
LOG_INFO("[BasePresenter] Camera %zu stop detection successfully\n", i + 1);
} else {
LOG_WARNING("[BasePresenter] Camera %zu stop detection failed, error code: %d\n", i + 1, ret);
}
}
}
// 停止算法检测线程
StopAlgoDetectThread();
return SUCCESS;
}
int BasePresenter::GetDetectionDataCacheSize() const
{
std::lock_guard<std::mutex> lock(const_cast<std::mutex&>(m_detectionDataMutex));
return static_cast<int>(m_detectionDataCache.size());
}
int BasePresenter::SaveDetectionDataToFile(const std::string& filePath)
{ std::lock_guard<std::mutex> lock(m_detectionDataMutex);
if(m_detectionDataCache.empty()){
LOG_WARNING("[BasePresenter] 检测数据缓存为空,无数据可保存\n");
return ERR_CODE(DATA_ERR_INVALID);
}
int lineNum = static_cast<int>(m_detectionDataCache.size());
float scanSpeed = 0.0f;
int maxTimeStamp = 0;
int clockPerSecond = 0;
int result = m_dataLoader.SaveLaserScanData(filePath, m_detectionDataCache, lineNum, scanSpeed, maxTimeStamp, clockPerSecond);
if (result == SUCCESS) {
LOG_INFO("[BasePresenter] 成功保存 %d 行检测数据到文件: %s\n", lineNum, filePath.c_str());
} else {
LOG_ERROR("[BasePresenter] 保存检测数据失败,错误: %s\n", m_dataLoader.GetLastError().c_str());
}
return result;
}
int BasePresenter::LoadDebugDataAndDetect(const std::string& filePath)
{
LOG_INFO("[BasePresenter] Loading debug data from file: %s\n", filePath.c_str());
std::string fileName = QFileInfo(QString::fromStdString(filePath)).fileName().toStdString();
OnStatusUpdate(QString("加载文件:%1").arg(fileName.c_str()).toStdString());
SetWorkStatus(WorkStatus::Working);
int lineNum = 0;
float scanSpeed = 0.0f;
int maxTimeStamp = 0;
int clockPerSecond = 0;
int result = SUCCESS;
// 1. 清空现有的检测数据缓存
ClearDetectionDataCache();
// 2. 加载数据到缓存
{
std::lock_guard<std::mutex> lock(m_detectionDataMutex);
result = m_dataLoader.LoadLaserScanData(filePath, m_detectionDataCache, lineNum, scanSpeed, maxTimeStamp, clockPerSecond);
}
if (result != SUCCESS) {
LOG_ERROR("[BasePresenter] 加载调试数据失败: %s\n", m_dataLoader.GetLastError().c_str());
OnStatusUpdate("调试数据加载失败");
return result;
}
OnStatusUpdate(QString("成功加载 %1 行调试数据").arg(lineNum).toStdString());
LOG_INFO("[BasePresenter] 成功加载 %d 行调试数据\n", lineNum);
// 3. 执行检测任务
result = DetectTask();
return result;
}
void BasePresenter::SetCameraStatusCallback(VzNL_OnNotifyStatusCBEx fNotify, void* param)
{
for (size_t i = 0; i < m_vrEyeDeviceList.size(); i++) {
IVrEyeDevice* pDevice = m_vrEyeDeviceList[i].second;
if (pDevice) {
pDevice->SetStatusCallback(fNotify, param);
LOG_DEBUG("[BasePresenter] Status callback set for camera %zu\n", i + 1);
}
}
}
void BasePresenter::SetWorkStatus(WorkStatus status)
{
if (m_currentWorkStatus != status) {
m_currentWorkStatus = status;
LOG_INFO("[BasePresenter] Work status changed to: %s\n", WorkStatusToString(status).c_str());
// 调用虚函数通知子类子类可以在此调用UI回调
OnWorkStatusChanged(status);
}
}
// ============ InitCamera 完整实现 ============
int BasePresenter::InitCamera(std::vector<DeviceInfo>& cameraList, bool bRGB, bool bSwing)
{
LOG_INFO("[BasePresenter] InitCamera\n");
m_bRGB = bRGB;
m_bSwing = bSwing;
// 保存相机配置信息,用于重连尝试
m_expectedList = cameraList;
// 通知UI相机个数
int cameraCount = cameraList.size();
OnCameraCountChanged(cameraCount);
LOG_INFO("[BasePresenter] init eyedevice list\n");
// 初始化相机列表,预分配空间
m_vrEyeDeviceList.resize(cameraCount, std::make_pair("", nullptr));
for(int i = 0; i < cameraCount; i++)
{
m_vrEyeDeviceList[i] = std::make_pair(cameraList[i].name, nullptr);
}
LOG_INFO("[BasePresenter] camera count : %d\n", cameraCount);
// 尝试初始化所有相机
bool allCamerasConnected = true;
if(cameraCount > 0){
// 循环打开所有配置的相机
for (int i = 0; i < cameraCount; i++) {
int cameraIndex = i + 1; // 相机索引从1开始
int nRet = OpenDevice(cameraIndex, cameraList[i].name.c_str(), cameraList[i].ip.c_str(), bRGB, bSwing);
bool isConnected = (nRet == SUCCESS);
// 通知相机状态变化
OnCameraStatusChanged(cameraIndex, isConnected);
if (!isConnected) {
allCamerasConnected = false;
LOG_WARNING("[BasePresenter] 相机%d (%s) 连接失败\n", cameraIndex, cameraList[i].name.c_str());
} else {
LOG_INFO("[BasePresenter] 相机%d (%s) 连接成功\n", cameraIndex, cameraList[i].name.c_str());
}
}
} else {
// 没有配置相机,创建一个默认项
m_vrEyeDeviceList.resize(1, std::make_pair("", nullptr));
DeviceInfo devInfo;
devInfo.index = 1;
devInfo.ip = "";
devInfo.name = "相机";
m_expectedList.push_back(devInfo);
int nRet = OpenDevice(1, "相机", nullptr, bRGB, bSwing);
if (nRet != SUCCESS) {
allCamerasConnected = false;
}
// 通知相机状态变化
OnCameraStatusChanged(1, SUCCESS == nRet);
}
// 检查连接状态
int connectedCount = 0;
for (const auto& device : m_vrEyeDeviceList) {
if (device.second != nullptr) {
connectedCount++;
}
}
m_bCameraConnected = (connectedCount > 0); // 至少有一个相机连接成功
// 设置默认相机索引为第一个连接的相机
m_currentCameraIndex = 1; // 默认从1开始
for (int i = 0; i < static_cast<int>(m_vrEyeDeviceList.size()); i++) {
if (m_vrEyeDeviceList[i].second != nullptr) {
m_currentCameraIndex = i + 1; // 找到第一个连接的相机
break;
}
}
LOG_INFO("[BasePresenter] 相机初始化完成: %d/%d 台相机连接成功, 默认相机索引: %d\n",
connectedCount, m_expectedList.size(), m_currentCameraIndex);
// 如果不是所有期望的相机都连接成功,启动重连定时器
if (!allCamerasConnected && !m_expectedList.empty()) {
LOG_INFO("[BasePresenter] 部分相机未连接 (%d/%d),启动重连定时器\n", connectedCount, m_expectedList.size());
StartCameraReconnectTimer();
} else if (allCamerasConnected) {
LOG_INFO("[BasePresenter] 所有相机连接成功\n");
// 确保定时器停止
StopCameraReconnectTimer();
} else {
LOG_WARNING("[BasePresenter] 没有配置相机 (expectedCount=%d)\n", m_expectedList.size());
}
return SUCCESS;
}
// ============ OpenDevice 完整实现 ============
int BasePresenter::OpenDevice(int cameraIndex, const char* cameraName, const char* cameraIp, bool bRGB, bool bSwing)
{
LOG_INFO("[BasePresenter] OpenDevice - index %d (%s, %s)\n", cameraIndex, cameraName, cameraIp ? cameraIp : "NULL");
// 1. 创建相机设备对象
IVrEyeDevice* pDevice = nullptr;
IVrEyeDevice::CreateObject(&pDevice);
if (!pDevice) {
LOG_ERROR("[BasePresenter] Failed to create IVrEyeDevice object\n");
return ERR_CODE(DEV_OPEN_ERR);
}
// 2. 初始化设备
int nRet = pDevice->InitDevice();
if(nRet != SUCCESS){
delete pDevice;
LOG_ERROR("[BasePresenter] InitDevice failed, error code: %d\n", nRet);
}
ERR_CODE_RETURN(nRet);
// 3. 打开相机设备
nRet = pDevice->OpenDevice(cameraIp, bRGB, bSwing);
LOG_INFO("[BasePresenter] OpenDevice camera %d (%s/%s) result: %d \n", cameraIndex,
bRGB ? "RGB" : "Normal", bSwing ? "Swing" : "Normal", nRet);
// 4. 处理打开结果
bool cameraConnected = (SUCCESS == nRet);
if(!cameraConnected){
delete pDevice; // 释放失败的设备
pDevice = nullptr;
} else {
// 设置状态回调(调用子类提供的回调函数)
VzNL_OnNotifyStatusCBEx callback = GetCameraStatusCallback();
nRet = pDevice->SetStatusCallback(callback, this);
LOG_DEBUG("[BasePresenter] SetStatusCallback result: %d\n", nRet);
if (nRet != SUCCESS) {
delete pDevice;
pDevice = nullptr;
}
}
LOG_DEBUG("[BasePresenter] Camera %d (%s) connected %s\n", cameraIndex, cameraName, cameraConnected ? "success" : "failed");
// 6. 存储到设备列表
int arrIdx = cameraIndex - 1;
if(m_vrEyeDeviceList.size() > static_cast<size_t>(arrIdx)){
m_vrEyeDeviceList[arrIdx] = std::make_pair(cameraName, pDevice);
} else {
LOG_WARNING("[BasePresenter] Camera index %d out of range, list size: %zu\n", cameraIndex, m_vrEyeDeviceList.size());
}
return nRet;
}
// ============ AlgoDetectThreadFunc 实现 ============
void BasePresenter::AlgoDetectThreadFunc()
{
LOG_INFO("[BasePresenter] 算法检测线程启动\n");
while(m_bAlgoDetectThreadRunning)
{
std::unique_lock<std::mutex> lock(m_algoDetectMutex);
// 等待检测触发(子类需要调用 m_algoDetectCondition.notify_one() 来触发)
m_algoDetectCondition.wait(lock);
if(!m_bAlgoDetectThreadRunning){
break;
}
LOG_INFO("[BasePresenter] 检测线程被唤醒,开始执行检测任务\n");
// 执行检测任务
int nRet = DetectTask();
if(nRet != SUCCESS){
LOG_ERROR("[BasePresenter] 检测任务执行失败,错误码: %d\n", nRet);
} else {
LOG_INFO("[BasePresenter] 检测任务执行成功\n");
}
}
LOG_INFO("[BasePresenter] 算法检测线程退出\n");
}
// ============ DetectTask 实现 ============
int BasePresenter::DetectTask()
{
LOG_INFO("[BasePresenter] DetectTask - 开始执行检测任务\n");
// 获取调试参数
VrDebugParam debugParam = GetDebugParam();
// 详细日志模式
if (debugParam.enableDebug && debugParam.printDetailLog) {
LOG_INFO("[BasePresenter] 调试模式已启用\n");
LOG_INFO("[BasePresenter] - savePointCloud: %s\n", debugParam.savePointCloud ? "true" : "false");
LOG_INFO("[BasePresenter] - saveDebugImage: %s\n", debugParam.saveDebugImage ? "true" : "false");
LOG_INFO("[BasePresenter] - debugOutputPath: %s\n", debugParam.debugOutputPath.c_str());
}
// 1. 验证检测数据缓存
{
std::lock_guard<std::mutex> lock(m_detectionDataMutex);
if (m_detectionDataCache.empty()) {
LOG_WARNING("[BasePresenter] 检测数据缓存为空\n");
return ERR_CODE(DEV_DATA_INVALID);
}
LOG_INFO("[BasePresenter] 检测数据缓存大小: %zu\n", m_detectionDataCache.size());
}
// 2. 调试模式 - 保存点云数据
if (debugParam.enableDebug && debugParam.savePointCloud) {
// 确定输出路径
QString outputPath;
if (debugParam.debugOutputPath.empty()) {
// 默认使用应用程序目录下的 debug 子目录
outputPath = QCoreApplication::applicationDirPath() + "/debug";
} else {
outputPath = QString::fromStdString(debugParam.debugOutputPath);
}
// 确保输出目录存在
QDir dir(outputPath);
if (!dir.exists()) {
dir.mkpath(".");
}
// 生成带时间戳的文件名
QString timestamp = QDateTime::currentDateTime().toString("yyyyMMdd_HHmmss");
QString fileName = QString("%1/pointcloud_%2.txt").arg(outputPath).arg(timestamp);
if (debugParam.printDetailLog) {
LOG_INFO("[BasePresenter] 保存点云数据到: %s\n", fileName.toStdString().c_str());
}
// 保存点云数据
int saveRet = SaveDetectionDataToFile(fileName.toStdString());
if (saveRet != SUCCESS) {
LOG_WARNING("[BasePresenter] 保存点云数据失败,错误码: %d\n", saveRet);
} else {
LOG_INFO("[BasePresenter] 点云数据保存成功\n");
}
}
// 3. 调用子类实现的算法检测,传入缓存数据引用
LOG_INFO("[BasePresenter] 调用 ProcessAlgoDetection 执行算法检测\n");
int nRet = ProcessAlgoDetection(m_detectionDataCache);
if (nRet != SUCCESS) {
LOG_ERROR("[BasePresenter] ProcessAlgoDetection 执行失败,错误码: %d\n", nRet);
return nRet;
}
SetWorkStatus(WorkStatus::Completed);
LOG_INFO("[BasePresenter] DetectTask - 检测任务执行成功\n");
return SUCCESS;
}
void BasePresenter::StartAlgoDetectThread()
{
if (m_bAlgoDetectThreadRunning) {
LOG_WARNING("[BasePresenter] 算法检测线程已经在运行\n");
return;
}
m_bAlgoDetectThreadRunning = true;
// 启动检测线程不再detach使用joinable线程
m_algoDetectThread = std::thread(&BasePresenter::AlgoDetectThreadFunc, this);
LOG_INFO("[BasePresenter] 算法检测线程已启动\n");
}
void BasePresenter::StopAlgoDetectThread()
{
if (!m_bAlgoDetectThreadRunning) {
return;
}
LOG_INFO("[BasePresenter] 正在停止算法检测线程...\n");
m_bAlgoDetectThreadRunning = false;
// 唤醒可能在等待的线程
m_algoDetectCondition.notify_all();
// 等待线程退出
if (m_algoDetectThread.joinable()) {
m_algoDetectThread.join();
}
LOG_INFO("[BasePresenter] 算法检测线程已停止\n");
}
void BasePresenter::ClearDetectionDataCache()
{
std::lock_guard<std::mutex> lock(m_detectionDataMutex);
m_detectionDataCache.clear();
LOG_DEBUG("[BasePresenter] 检测数据缓存已清空\n");
}
void BasePresenter::AddDetectionDataToCache(EVzResultDataType dataType, const SVzLaserLineData& laserData)
{
std::lock_guard<std::mutex> lock(m_detectionDataMutex);
m_detectionDataCache.push_back(std::make_pair(dataType, laserData));
}
// 通用的静态检测数据回调函数实现
void BasePresenter::_StaticDetectionCallback(EVzResultDataType eDataType, SVzLaserLineData* pLaserLinePoint, void* pUserData)
{
// 验证输入参数
if (!pLaserLinePoint) {
LOG_WARNING("[BasePresenter Detection Callback] pLaserLinePoint is null\n");
return;
}
if (pLaserLinePoint->nPointCount <= 0) {
LOG_WARNING("[BasePresenter Detection Callback] Point count is zero or negative: %d\n", pLaserLinePoint->nPointCount);
return;
}
if (!pLaserLinePoint->p3DPoint) {
LOG_WARNING("[BasePresenter Detection Callback] p3DPoint is null\n");
return;
}
// 获取 BasePresenter 实例指针
BasePresenter* pThis = reinterpret_cast<BasePresenter*>(pUserData);
if (!pThis) {
LOG_ERROR("[BasePresenter Detection Callback] pUserData is null\n");
return;
}
// 创建 SVzLaserLineData 副本
SVzLaserLineData lineData;
memset(&lineData, 0, sizeof(SVzLaserLineData));
// 根据数据类型分配和复制点云数据
if (eDataType == keResultDataType_Position) {
// 复制 SVzNL3DPosition 数据
if (pLaserLinePoint->p3DPoint && pLaserLinePoint->nPointCount > 0) {
lineData.p3DPoint = new SVzNL3DPosition[pLaserLinePoint->nPointCount];
if (lineData.p3DPoint) {
memcpy(lineData.p3DPoint, pLaserLinePoint->p3DPoint, sizeof(SVzNL3DPosition) * pLaserLinePoint->nPointCount);
}
lineData.p2DPoint = new SVzNL2DPosition[pLaserLinePoint->nPointCount];
if (lineData.p2DPoint) {
memcpy(lineData.p2DPoint, pLaserLinePoint->p2DPoint, sizeof(SVzNL2DPosition) * pLaserLinePoint->nPointCount);
}
}
} else if (eDataType == keResultDataType_PointXYZRGBA) {
// 复制 SVzNLPointXYZRGBA 数据
if (pLaserLinePoint->p3DPoint && pLaserLinePoint->nPointCount > 0) {
lineData.p3DPoint = new SVzNLPointXYZRGBA[pLaserLinePoint->nPointCount];
if (lineData.p3DPoint) {
memcpy(lineData.p3DPoint, pLaserLinePoint->p3DPoint, sizeof(SVzNLPointXYZRGBA) * pLaserLinePoint->nPointCount);
}
lineData.p2DPoint = new SVzNL2DLRPoint[pLaserLinePoint->nPointCount];
if (lineData.p2DPoint) {
memcpy(lineData.p2DPoint, pLaserLinePoint->p2DPoint, sizeof(SVzNL2DLRPoint) * pLaserLinePoint->nPointCount);
}
}
}
// 复制其他字段
lineData.nPointCount = pLaserLinePoint->nPointCount;
lineData.llTimeStamp = pLaserLinePoint->llTimeStamp;
lineData.llFrameIdx = pLaserLinePoint->llFrameIdx;
lineData.nEncodeNo = pLaserLinePoint->nEncodeNo;
lineData.fSwingAngle = pLaserLinePoint->fSwingAngle;
lineData.bEndOnceScan = pLaserLinePoint->bEndOnceScan;
// 添加到检测数据缓存
pThis->AddDetectionDataToCache(eDataType, lineData);
}
// 通用的静态相机状态回调函数实现
void BasePresenter::_StaticCameraStatusCallback(EVzDeviceWorkStatus eStatus, void* pExtData, unsigned int nDataLength, void* pInfoParam)
{
LOG_DEBUG("[BasePresenter Camera Status Callback] received: status=%d\n", (int)eStatus);
// 获取 BasePresenter 实例指针
BasePresenter* pThis = reinterpret_cast<BasePresenter*>(pInfoParam);
if (!pThis) {
LOG_ERROR("[BasePresenter Camera Status Callback] pInfoParam is null\n");
return;
}
switch (eStatus) {
case EVzDeviceWorkStatus::keDeviceWorkStatus_Offline:
{
LOG_WARNING("[BasePresenter Camera Status Callback] Camera device offline/disconnected\n");
// 更新相机连接状态
pThis->m_bCameraConnected = false;
// 通知子类相机状态变更这里暂时通知相机1实际应用中可能需要区分
pThis->OnCameraStatusChanged(1, false);
break;
}
case EVzDeviceWorkStatus::keDeviceWorkStatus_Eye_Reconnect:
{
LOG_INFO("[BasePresenter Camera Status Callback] Camera device online/connected\n");
// 更新相机连接状态
pThis->m_bCameraConnected = true;
// 通知子类相机状态变更
pThis->OnCameraStatusChanged(1, true);
break;
}
case EVzDeviceWorkStatus::keDeviceWorkStatus_Device_Swing_Finish:
{
LOG_INFO("[BasePresenter Camera Status Callback] Received scan finish signal from camera\n");
// 通知算法检测线程开始处理
pThis->m_algoDetectCondition.notify_one();
break;
}
default:
break;
}
}
void BasePresenter::StartCameraReconnectTimer()
{
LOG_DEBUG("[BasePresenter] StartCameraReconnectTimer called\n");
// 使用QMetaObject::invokeMethod确保在正确的线程中操作定时器
QMetaObject::invokeMethod(this, [this]() {
if (!m_pCameraReconnectTimer) {
return;
}
if (m_pCameraReconnectTimer->isActive()) {
return;
}
m_pCameraReconnectTimer->start();
}, Qt::QueuedConnection);
}
void BasePresenter::StopCameraReconnectTimer()
{
// 直接停止定时器析构时需要立即停止不能用QueuedConnection
if (m_pCameraReconnectTimer) {
m_pCameraReconnectTimer->stop();
}
}
// ============ OnCameraReconnectTimer 实现 ============
void BasePresenter::OnCameraReconnectTimer()
{
#ifdef _WIN32
return;
#endif
// 调用子类实现的重连逻辑
bool allConnected = TryReconnectCameras();
if (allConnected) {
LOG_INFO("[BasePresenter] 所有相机重连成功,停止定时器\n");
StopCameraReconnectTimer();
}
}
// ============ TryReconnectCameras 默认实现 ============
bool BasePresenter::TryReconnectCameras()
{
LOG_DEBUG("[BasePresenter] TryReconnectCameras all %zd \n", m_expectedList.size());
bool allConnected = true;
int connectedCount = 0;
// 遍历所有配置的相机,尝试重连失败的相机
for (int i = 0; i < static_cast<int>(m_expectedList.size()); i++) {
// 检查该位置的相机是否已连接
if (i < static_cast<int>(m_vrEyeDeviceList.size()) && m_vrEyeDeviceList[i].second != nullptr) {
// 相机已连接,跳过
connectedCount++;
continue;
}
// 尝试重连相机
int cameraIndex = i + 1; // 相机索引从1开始
const DeviceInfo& cameraInfo = m_expectedList[i];
LOG_DEBUG("[BasePresenter] 尝试重连相机 %d (%s, %s)\n", cameraIndex, cameraInfo.name.c_str(), cameraInfo.ip.c_str());
// 调用 OpenDevice 重连(使用初始化时的 RGB/Swing 参数)
int nRet = OpenDevice(cameraIndex, cameraInfo.name.c_str(), cameraInfo.ip.c_str(), m_bRGB, m_bSwing);
OnCameraStatusChanged(cameraIndex, SUCCESS == nRet);
if (nRet == SUCCESS) {
LOG_INFO("[BasePresenter] 相机 %d (%s) 重连成功\n", cameraIndex, cameraInfo.name.c_str());
connectedCount++;
} else {
LOG_DEBUG("[BasePresenter] 相机 %d (%s) 重连失败,错误码: %d\n", cameraIndex, cameraInfo.name.c_str(), nRet);
allConnected = false;
}
}
// 更新相机连接状态
m_bCameraConnected = (connectedCount > 0);
// 更新默认相机索引为第一个连接的相机
for (int i = 0; i < static_cast<int>(m_vrEyeDeviceList.size()); i++) {
if (m_vrEyeDeviceList[i].second != nullptr) {
m_currentCameraIndex = i + 1;
break;
}
}
LOG_INFO("[BasePresenter] 相机重连尝试完成: %d/%d 台相机已连接\n", connectedCount, m_expectedList.size());
return (connectedCount == m_expectedList.size() && allConnected);
}
// ============ ModbusTCP 服务实现 ============
int BasePresenter::StartModbusServer(int port)
{
LOG_INFO("[BasePresenter] 启动ModbusTCP服务器端口: %d\n", port);
// 如果已经运行,先停止
if (m_modbusServer) {
StopModbusServer();
}
// 创建ModbusTCP服务器实例
if (!IYModbusTCPServer::CreateInstance(&m_modbusServer)) {
LOG_ERROR("[BasePresenter] 创建ModbusTCP服务器实例失败\n");
return ERR_CODE(DEV_OPEN_ERR);
}
// 设置写寄存器回调
m_modbusServer->setWriteRegistersCallback(
[this](uint8_t unitId, uint16_t startAddress, uint16_t quantity, const uint16_t* values) -> IYModbusTCPServer::ErrorCode {
int ret = this->OnModbusWriteRegisters(unitId, startAddress, quantity, values);
return (ret == 0) ? IYModbusTCPServer::ErrorCode::SUCCESS : IYModbusTCPServer::ErrorCode::SERVER_FAILURE;
}
);
// 设置连接状态回调
m_modbusServer->setConnectionStatusCallback(
[](bool isConnected) {
LOG_INFO("[BasePresenter] Modbus客户端%s\n", isConnected ? "已连接" : "已断开");
}
);
// 启动服务器
int ret = m_modbusServer->start(port, 5);
if (ret != 0) {
LOG_ERROR("[BasePresenter] 启动ModbusTCP服务器失败错误码: %d\n", ret);
delete m_modbusServer;
m_modbusServer = nullptr;
return ERR_CODE(DEV_OPEN_ERR);
}
LOG_INFO("[BasePresenter] ModbusTCP服务器启动成功\n");
return SUCCESS;
}
void BasePresenter::StopModbusServer()
{
if (m_modbusServer) {
m_modbusServer->stop();
delete m_modbusServer;
m_modbusServer = nullptr;
}
}
bool BasePresenter::IsModbusServerRunning() const
{
return m_modbusServer != nullptr;
}
int BasePresenter::WriteModbusRegisters(uint16_t startAddress, const uint16_t* data, uint16_t count)
{
if (!m_modbusServer) {
LOG_WARNING("[BasePresenter] ModbusTCP服务器未运行\n");
return ERR_CODE(DEV_NOT_FIND);
}
if (!data || count == 0) {
LOG_WARNING("[BasePresenter] 无效的Modbus写入参数\n");
return ERR_CODE(DEV_DATA_INVALID);
}
// 转换为vector并写入
std::vector<uint16_t> values(data, data + count);
m_modbusServer->updateHoldingRegisters(startAddress, values);
LOG_DEBUG("[BasePresenter] Modbus写入: 地址=%d, 数量=%d\n", startAddress, count);
return SUCCESS;
}
int BasePresenter::OnModbusWriteRegisters(uint8_t unitId, uint16_t startAddress,
uint16_t quantity, const uint16_t* values)
{
LOG_DEBUG("[BasePresenter] Modbus收到写寄存器: unitId=%d, 地址=%d, 数量=%d\n", unitId, startAddress, quantity);
// 调用虚函数让子类处理
OnModbusWriteCallback(startAddress, values, quantity);
return 0;
}