GrabBag/AppUtils/AppCommon/Inc/BasePresenter.h

478 lines
15 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.

#ifndef BASEPRESENTER_H
#define BASEPRESENTER_H
#include <atomic>
#include <condition_variable>
#include <thread>
#include <mutex>
#include <vector>
#include <memory>
#include <string>
#include <QObject>
#include <QTimer>
#include "IVrEyeDevice.h"
#include "VZNL_Types.h"
#include "VrCommonConfig.h" // 包含公共配置结构体
#include "LaserDataLoader.h" // 激光数据加载器
#include "IVisionApplicationStatus.h" // 工作状态枚举
/**
* @brief 基础Presenter类
*
* 提取各应用Presenter的共同功能
* - 相机设备管理InitCamera
* - 算法参数初始化InitAlgoParams - 纯虚函数)
* - 检测线程管理DetectTask
* - 检测数据缓存
* - 相机重连机制
*
* 子类需要实现的纯虚函数:
* - InitAlgoParams(): 初始化算法参数
* - ProcessAlgoDetection(): 执行具体的算法检测
* - OpenDevice(): 打开相机设备
* - TryReconnectCameras(): 尝试重连相机
* - OnCameraStatusChanged(): 相机状态变化通知
*
* 用法示例:
* @code
* class GrabBagPresenter : public BasePresenter {
* protected:
* int InitAlgoParams() override { ... }
* int ProcessAlgoDetection() override { ... }
* int OpenDevice(int cameraIndex, ...) override { ... }
* };
* @endcode
*/
class BasePresenter : public QObject
{
Q_OBJECT
public:
explicit BasePresenter(QObject *parent = nullptr);
virtual ~BasePresenter();
/**
* @brief 公用的初始化
* @return
*/
int Init(const std::string& sName);
/**
* @brief 开始检测
* @param cameraIndex 相机索引(-1表示所有相机
* @param isAuto 是否自动模式
* @return 0: 成功, 其他: 错误码
*/
virtual int StartDetection(int cameraIndex = -1, bool isAuto = true);
/**
* @brief 停止检测
* @return 0: 成功, 其他: 错误码
*/
virtual int StopDetection();
/**
* @brief 获取相机列表
* @return 相机列表IP地址和设备指针的pair
*/
std::vector<std::pair<std::string, IVrEyeDevice*>> GetCameraList() const {
return m_vrEyeDeviceList;
}
/**
* @brief 设置默认相机索引
* @param cameraIndex 相机索引
*/
void SetDefaultCameraIndex(int cameraIndex) {
m_currentCameraIndex = cameraIndex;
}
/**
* @brief 获取默认相机索引
* @return 相机索引
*/
int GetDetectIndex() const {
return m_currentCameraIndex;
}
/**
* @brief 获取检测数据缓存大小
* @return 缓存中的数据个数
*/
int GetDetectionDataCacheSize() const;
/**
* @brief 保存当前缓存的检测数据到文件(便捷方法)
*
* 直接保存内部缓存的数据,无需传入参数
*
* @param filePath 文件路径
* @return 0: 成功, 其他: 错误码
*/
virtual int SaveDetectionDataToFile(const std::string& filePath);
/**
* @brief 加载调试数据并执行检测virtual子类可重写添加状态更新
*
* 从文件加载激光扫描数据到缓存,然后执行算法检测
*
* @param filePath 文件路径
* @return 0: 成功, 其他: 错误码
*/
virtual int LoadDebugDataAndDetect(const std::string& filePath);
/**
* @brief 为所有相机设置状态回调
*
* 遍历所有相机设备,为每个设备设置状态回调函数
*
* @param fNotify 状态回调函数指针
* @param param 回调函数的用户参数
*/
void SetCameraStatusCallback(VzNL_OnNotifyStatusCBEx fNotify, void* param);
/**
* @brief 获取当前工作状态
* @return 当前工作状态
*/
WorkStatus GetCurrentWorkStatus() const {
return m_currentWorkStatus;
}
/**
* @brief 设置工作状态(会触发状态回调通知)
* @param status 新的工作状态
*/
void SetWorkStatus(WorkStatus status);
/**
* @brief 设置状态回调接口(模板方法)
*
* 存储状态回调接口指针用于通知UI状态变化
* 子类可以直接调用此方法设置自己的状态回调接口
*
* @tparam StatusCallbackType 状态回调接口类型
* @param statusCallback 状态回调接口指针
*/
template<typename StatusCallbackType>
void SetStatusCallback(StatusCallbackType* statusCallback) {
m_pStatusCallback = static_cast<void*>(statusCallback);
}
/**
* @brief 获取状态回调接口(模板方法)
*
* 获取之前设置的状态回调接口指针
*
* @tparam StatusCallbackType 状态回调接口类型
* @return 状态回调接口指针
*/
template<typename StatusCallbackType>
StatusCallbackType* GetStatusCallback() const {
return static_cast<StatusCallbackType*>(m_pStatusCallback);
}
/**
* @brief 通用的静态检测数据回调函数
*
* 此静态函数可被所有子类使用,将检测数据添加到缓存
* 子类的 GetDetectionCallback() 可以直接返回此函数
*
* @param eDataType 数据类型
* @param pLaserLinePoint 激光线数据指针
* @param pUserData 用户数据BasePresenter实例指针
*/
static void _StaticDetectionCallback(EVzResultDataType eDataType, SVzLaserLineData* pLaserLinePoint, void* pUserData);
/**
* @brief 通用的静态相机状态回调函数
*
* 此静态函数可被所有子类使用,处理相机状态变化
* 子类的 GetCameraStatusCallback() 可以直接返回此函数
*
* @param eStatus 相机工作状态
* @param pExtData 扩展数据
* @param nDataLength 数据长度
* @param pInfoParam 参数BasePresenter实例指针
*/
static void _StaticCameraStatusCallback(EVzDeviceWorkStatus eStatus, void* pExtData, unsigned int nDataLength, void* pInfoParam);
protected:
// ============ 纯虚函数 - 子类必须实现 ============
/**
* @brief 私有初始化子类应该重写此方法
* @return 0: 成功, 其他: 错误码
*/
virtual int InitApp() = 0;
/**
* @brief 初始化算法参数(纯虚函数)
*
* 子类需要在此方法中:
* - 加载算法参数配置
* - 初始化算法库
* - 加载标定参数
*
* @return 0: 成功, 其他: 错误码
*/
virtual int InitAlgoParams() = 0;
/**
* @brief 执行算法检测(纯虚函数)
*
* 子类需要在此方法中:
* - 使用传入的点云数据进行算法检测
* - 调用具体的算法库进行检测
* - 返回检测结果
*
* @param detectionDataCache 检测数据缓存的引用
* @return 0: 成功, 其他: 错误码
*/
virtual int ProcessAlgoDetection(std::vector<std::pair<EVzResultDataType, SVzLaserLineData>>& detectionDataCache) = 0;
/**
* @brief 获取相机状态回调函数(虚函数,提供默认实现)
*
* 默认返回 BasePresenter 的通用静态回调函数
* 子类如果需要自定义相机状态处理,可以重写此方法
*
* @return 相机状态回调函数指针
*/
virtual VzNL_OnNotifyStatusCBEx GetCameraStatusCallback() {
return &BasePresenter::_StaticCameraStatusCallback;
}
/**
* @brief 获取检测数据回调函数(虚函数,提供默认实现)
*
* 默认返回 BasePresenter 的通用静态回调函数
* 子类如果需要自定义检测数据处理,可以重写此方法
*
* @return 检测数据回调函数指针
*/
virtual VzNL_AutoOutputLaserLineExCB GetDetectionCallback() {
return &BasePresenter::_StaticDetectionCallback;
}
/**
* @brief 获取检测数据类型(纯虚函数)
*
* 子类需要返回项目使用的数据类型,例如:
* - keResultDataType_Position (只要XYZ位置)
* - keResultDataType_PointXYZRGBA (需要RGBA颜色)
*
* @return 数据类型
*/
virtual EVzResultDataType GetDetectionDataType() = 0;
/**
* @brief 尝试重连相机(虚函数,提供默认实现)
*
* 基类提供通用的重连逻辑:
* - 遍历所有配置的相机
* - 检查是否已连接
* - 尝试调用 OpenDevice 重连
* - 调用 OnCameraStatusChanged 通知状态变化
* - 更新相机连接状态和默认相机索引
*
* 子类通常不需要重写此方法,除非有特殊的重连逻辑
*
* @return true: 所有相机已连接, false: 仍有相机未连接
*/
virtual bool TryReconnectCameras();
/**
* @brief 相机状态变化通知(纯虚函数)
*
* @param cameraIndex 相机索引
* @param isConnected 是否连接
*/
virtual void OnCameraStatusChanged(int cameraIndex, bool isConnected) = 0;
/**
* @brief 工作状态变化通知(虚函数,子类可选择重写)
*
* 当工作状态改变时BasePresenter 会调用此方法通知子类
* 子类应在此方法中调用状态回调接口的 OnWorkStatusChanged
*
* @param status 新的工作状态
*/
virtual void OnWorkStatusChanged(WorkStatus status) {
// 默认空实现子类可以重写以调用UI回调
}
/**
* @brief 相机数量变化通知(虚函数,子类可选择重写)
*
* 当相机初始化时BasePresenter 会调用此方法通知子类相机数量
* 子类应在此方法中调用状态回调接口的 OnCameraCountChanged
*
* @param count 相机数量
*/
virtual void OnCameraCountChanged(int count) {
// 默认空实现子类可以重写以调用UI回调
}
/**
* @brief 状态文字更新通知(虚函数,子类可选择重写)
*
* 当需要更新状态文字时BasePresenter 会调用此方法
* 子类应在此方法中调用状态回调接口的 OnStatusUpdate
*
* @param statusMessage 状态消息
*/
virtual void OnStatusUpdate(const std::string& statusMessage) {
// 默认空实现子类可以重写以调用UI回调
}
// ============ 公共实现方法 ============
/**
* @brief 初始化相机设备(公共实现)
*
* 此方法实现了通用的相机初始化逻辑:
* - 保存相机配置
* - 初始化相机列表
* - 调用 OpenDevice 打开每个相机
* - 启动重连定时器(如果需要)
*
* @param cameraList 相机配置列表
* @return 0: 成功, 其他: 错误码
*/
virtual int InitCamera(std::vector<DeviceInfo>& cameraList, bool bRGB, bool bSwing);
/**
* @brief 清空检测数据缓存virtual允许子类重写以添加特殊清理逻辑
*/
virtual void ClearDetectionDataCache();
/**
* @brief 添加检测数据到缓存
* @param dataType 数据类型
* @param laserData 激光数据
*/
void AddDetectionDataToCache(EVzResultDataType dataType, const SVzLaserLineData& laserData);
/**
* @brief 获取检测数据缓存的引用(用于批量加载数据)
*
* 提供线程安全的方式访问缓存进行批量操作
* 调用者需要在调用此方法的作用域内完成所有操作
*
* @param func 操作函数,接收缓存引用作为参数,返回操作结果
* @return func 的返回值
*/
template<typename Func>
int AccessDetectionDataCache(Func func) {
std::lock_guard<std::mutex> lock(m_detectionDataMutex);
return func(m_detectionDataCache);
}
private:
/**
* @brief 打开相机设备(公共实现)
*
* 此方法实现了通用的相机打开逻辑:
* - 创建 IVrEyeDevice 对象
* - 初始化设备
* - 设置状态回调(调用 GetCameraStatusCallback
* - 打开相机(使用 GetOpenDeviceMode
* - 存储到设备列表
*
* @param cameraIndex 相机索引从1开始
* @param cameraName 相机名称
* @param cameraIp 相机IP地址
* @return 0: 成功, 其他: 错误码
*/
int OpenDevice(int cameraIndex, const char* cameraName, const char* cameraIp, bool bRGB, bool bSwing);
/**
* @brief 算法检测线程函数
*
* 实现了通用的检测线程循环:
* - 等待检测触发
* - 调用 ProcessAlgoDetection 执行算法
* - 处理检测结果
*/
void AlgoDetectThreadFunc();
/**
* @brief 检测任务主流程
*
* 实现了通用的检测任务流程:
* - 验证数据缓存
* - 调用 ProcessAlgoDetection 执行算法
* - 更新工作状态
*
* @return 0: 成功, 其他: 错误码
*/
int DetectTask();
/**
* @brief 启动算法检测线程
*/
void StartAlgoDetectThread();
/**
* @brief 停止算法检测线程
*/
void StopAlgoDetectThread();
/**
* @brief 启动相机重连定时器
*/
void StartCameraReconnectTimer();
/**
* @brief 停止相机重连定时器
*/
void StopCameraReconnectTimer();
private slots:
/**
* @brief 相机重连定时器触发
*/
void OnCameraReconnectTimer();
protected:
// 相机设备列表
std::vector<std::pair<std::string, IVrEyeDevice*>> m_vrEyeDeviceList;
// 当前相机索引
int m_currentCameraIndex = 0;
// 连接状态标志
bool m_bCameraConnected = false;
// 算法检测线程相关
std::atomic<bool> m_bAlgoDetectThreadRunning;
std::mutex m_algoDetectMutex;
std::condition_variable m_algoDetectCondition;
std::thread m_algoDetectThread;
// 检测数据缓存
std::mutex m_detectionDataMutex;
std::vector<std::pair<EVzResultDataType, SVzLaserLineData>> m_detectionDataCache;
// 激光数据加载器
LaserDataLoader m_dataLoader;
// 相机重连定时器
QTimer* m_pCameraReconnectTimer;
std::vector<DeviceInfo> m_expectedList;
bool m_bRGB{false};
bool m_bSwing{true};
// 工作状态管理
WorkStatus m_currentWorkStatus = WorkStatus::InitIng;
// 状态回调接口使用void*存储,避免模板化整个类)
void* m_pStatusCallback = nullptr;
};
#endif // BASEPRESENTER_H