增加机械臂ModbusTCP的协议交互;重构相机对话框,添加设备参数初始化和应用功能,增强错误处理,更新UI控件名称以提高可读性; 增加相机扫描逻辑

This commit is contained in:
杰仔 2025-06-08 23:51:48 +08:00
parent 533e068a01
commit 89a8d050f5
19 changed files with 889 additions and 284 deletions

View File

@ -19,7 +19,7 @@ inline std::string WorkStatusToString(WorkStatus status) {
switch (status) {
case WorkStatus::Ready: return "准备就绪";
case WorkStatus::Working: return "正在工作";
case WorkStatus::Completed: return "测完成";
case WorkStatus::Completed: return "测完成";
case WorkStatus::Error: return "设备异常";
default: return "未知状态";
}

View File

@ -5,6 +5,7 @@
#include "IVrEyeDevice.h"
#include "IYGrabBagStatus.h"
#include "RobotProtocol.h"
#include "VZNL_Types.h"
class GrabBagPresenter
{
@ -24,6 +25,8 @@ public:
// 停止检测
int StopDetection();
IVrEyeDevice* GetEyeDevice(int index);
private:
// 机械臂协议相关方法
int InitRobotProtocol();
@ -32,19 +35,43 @@ private:
void OnRobotConnectionChanged(bool connected);
void OnRobotWorkSignal(bool startWork);
// 连接状态检查和更新
void CheckAndUpdateWorkStatus();
// 静态回调函数用于传递给SDK
static void _StaticCameraNotify(EVzDeviceWorkStatus eStatus, void* pExtData, unsigned int nDataLength, void* pInfoParam);
// 实例方法,处理回调
void _CameraNotify(EVzDeviceWorkStatus eStatus, void* pExtData, unsigned int nDataLength, void* pInfoParam);
// 检测数据回调函数
static void _StaticDetectionCallback(EVzResultDataType eDataType, SVzLaserLineData* pLaserLinePoint, void* pParam);
void _DetectionCallback(EVzResultDataType eDataType, SVzLaserLineData* pLaserLinePoint);
// 算法检测线程
void _AlgoDetectThread();
int _DetectTask();
private:
IVrConfig* m_vrConfig = nullptr;
IVrEyeDevice* m_vrEyeDevice = nullptr;
IYGrabBagStatus* m_pStatus = nullptr;
IVrConfig* m_vrConfig = nullptr;
std::vector<IVrEyeDevice*> m_vrEyeDeviceList;
IYGrabBagStatus* m_pStatus = nullptr;
RobotProtocol* m_pRobotProtocol = nullptr;
RobotProtocol* m_pRobotProtocol = nullptr;
// 连接状态标志
bool m_bCameraConnected = false; // 相机连接状态
bool m_bRobotConnected = false; // 机械臂连接状态
WorkStatus m_currentWorkStatus = WorkStatus::Error; // 当前工作状态
std::atomic<bool> m_bAlgoDetectThreadRunning = false;
std::mutex m_algoDetectMutex;
std::condition_variable m_algoDetectCondition;
// 检测数据缓存
std::vector<SVzLaserLineData*> m_detectionDataCache;
std::mutex m_detectionDataMutex;
};
#endif // GRABBAGPRESENTER_H

View File

@ -107,6 +107,12 @@ private:
*/
void StopModbusTCPServer();
/**
* @brief ModbusTCP连接状态变化
* @param connected true-false-
*/
void OnModbusTCPConnectionChanged(bool connected);
/**
* @brief 线
* @param unitId ID
@ -155,6 +161,7 @@ private:
WorkSignalCallback m_workSignalCallback; // 工作信号回调
// Modbus地址映射
static const uint16_t COORD_X_ADDR = 0x0000; // X坐标地址
static const uint16_t COORD_Y_ADDR = 0x0002; // Y坐标地址
static const uint16_t COORD_Z_ADDR = 0x0004; // Z坐标地址

View File

@ -7,9 +7,11 @@
GrabBagPresenter::GrabBagPresenter()
: m_vrConfig(nullptr)
, m_vrEyeDevice(nullptr)
, m_pStatus(nullptr)
, m_pRobotProtocol(nullptr)
, m_bCameraConnected(false)
, m_bRobotConnected(false)
, m_currentWorkStatus(WorkStatus::Error)
{
}
@ -24,14 +26,22 @@ GrabBagPresenter::~GrabBagPresenter()
}
// 释放其他资源
if (m_vrEyeDevice) {
// 关闭设备
m_vrEyeDevice->CloseDevice();
for(auto it = m_vrEyeDeviceList.begin(); it != m_vrEyeDeviceList.end(); it++)
{
(*it)->CloseDevice();
delete (*it);
}
m_vrEyeDeviceList.clear();
}
int GrabBagPresenter::Init()
{
// 初始化连接状态
m_bCameraConnected = false;
m_bRobotConnected = false;
m_currentWorkStatus = WorkStatus::Error;
// 初始化VrConfig模块
IVrConfig::CreateInstance(&m_vrConfig);
@ -43,19 +53,12 @@ int GrabBagPresenter::Init()
// 读取IP列表
ConfigResult configResult = m_vrConfig->LoadConfig(configPath.toStdString());
if (configResult.cameraList.size() == 0) {
m_pStatus->OnStatusUpdate("读取配置信息列表失败");
m_pStatus->OnCamera1StatusChanged(false);
m_pStatus->OnCamera2StatusChanged(false);
m_pStatus->OnCameraCountChanged(0);
return ERR_CODE(DEV_CONFIG_ERR);
}
// 初始化机械臂协议
int nRet = InitRobotProtocol();
if (nRet != 0) {
m_pStatus->OnStatusUpdate("机械臂服务初始化失败");
m_pStatus->OnWorkStatusChanged(WorkStatus::Error);
m_bRobotConnected = false;
} else {
m_pStatus->OnStatusUpdate("机械臂服务初始化成功");
}
@ -63,49 +66,90 @@ int GrabBagPresenter::Init()
// 通知UI相机个数
int cameraCount = configResult.cameraList.size();
m_pStatus->OnCameraCountChanged(cameraCount);
// 初始化VrEyeDevice模块
IVrEyeDevice::CreateObject(&m_vrEyeDevice);
nRet = m_vrEyeDevice->InitDevice();
ERR_CODE_RETURN(nRet);
if(cameraCount > 0){
if (cameraCount >= 1) {
// 尝试打开相机1
// 初始化VrEyeDevice模块
IVrEyeDevice* pDevice = nullptr;
IVrEyeDevice::CreateObject(&pDevice);
nRet = pDevice->InitDevice();
ERR_CODE_RETURN(nRet);
if (configResult.cameraList.size() >= 1) {
nRet = pDevice->OpenDevice(configResult.cameraList[0].ip.c_str(), &GrabBagPresenter::_StaticCameraNotify, this);
// 通过回调更新相机1状态
bool camera1Connected = (SUCCESS == nRet);
if(camera1Connected)
{
m_vrEyeDeviceList.push_back(pDevice);
}
m_pStatus->OnCamera1StatusChanged(camera1Connected);
m_pStatus->OnStatusUpdate(camera1Connected ? "相机一连接成功" : "相机一连接失败");
m_bCameraConnected = camera1Connected;
}
else {
m_pStatus->OnCamera1StatusChanged(false);
m_bCameraConnected = false;
}
ERR_CODE_RETURN(nRet);
if (cameraCount >= 2) {
IVrEyeDevice* pDevice = nullptr;
IVrEyeDevice::CreateObject(&pDevice);
nRet = pDevice->InitDevice();
ERR_CODE_RETURN(nRet);
// 尝试打开相机2
nRet = pDevice->OpenDevice(configResult.cameraList[1].ip.c_str(), &GrabBagPresenter::_StaticCameraNotify, this);
// 通过回调更新相机2状态
bool camera2Connected = (SUCCESS == nRet);
if(camera2Connected)
{
m_vrEyeDeviceList.push_back(pDevice);
}
m_pStatus->OnCamera2StatusChanged(camera2Connected);
m_pStatus->OnStatusUpdate(camera2Connected ? "相机二连接成功" : "相机二连接失败");
// 只要有一个相机连接成功就认为相机连接正常
if (camera2Connected) {
m_bCameraConnected = true;
}
}
else {
// 如果只有一个相机则将相机2状态设为未连接
m_pStatus->OnCamera2StatusChanged(false);
}
ERR_CODE_RETURN(nRet);
} else {
IVrEyeDevice* pDevice = nullptr;
IVrEyeDevice::CreateObject(&pDevice);
nRet = pDevice->InitDevice();
ERR_CODE_RETURN(nRet);
// 尝试打开相机1
nRet = m_vrEyeDevice->OpenDevice(configResult.cameraList[0].ip.c_str(), &GrabBagPresenter::_StaticCameraNotify, this);
nRet = pDevice->OpenDevice(nullptr, &GrabBagPresenter::_StaticCameraNotify, this);
// 通过回调更新相机1状态
m_pStatus->OnCamera1StatusChanged(SUCCESS == nRet);
m_pStatus->OnStatusUpdate(SUCCESS == nRet ? "相机1连接成功" : "相机1连接失败");
bool camera1Connected = (SUCCESS == nRet);
if(camera1Connected)
{
m_vrEyeDeviceList.push_back(pDevice);
}
m_pStatus->OnCamera1StatusChanged(camera1Connected);
m_pStatus->OnStatusUpdate(camera1Connected ? "相机一连接成功" : "相机一连接失败");
m_bCameraConnected = camera1Connected;
}
else {
m_pStatus->OnCamera1StatusChanged(false);
}
m_pStatus->OnWorkStatusChanged(SUCCESS == nRet ? WorkStatus::Ready : WorkStatus::Error);
ERR_CODE_RETURN(nRet);
if (configResult.cameraList.size() >= 2) {
// 尝试打开相机2
nRet = m_vrEyeDevice->OpenDevice(configResult.cameraList[1].ip.c_str(), &GrabBagPresenter::_StaticCameraNotify, this);
// 通过回调更新相机2状态
m_pStatus->OnCamera2StatusChanged(SUCCESS == nRet);
m_pStatus->OnStatusUpdate(SUCCESS == nRet ? "相机2连接成功" : "相机2连接失败");
}
else {
// 如果只有一个相机则将相机2状态设为未连接
m_pStatus->OnCamera2StatusChanged(false);
}
ERR_CODE_RETURN(nRet);
m_bAlgoDetectThreadRunning = true;
std::thread algoDetectThread(&GrabBagPresenter::_AlgoDetectThread, this);
algoDetectThread.detach();
m_pStatus->OnStatusUpdate("设备初始化完成");
m_pStatus->OnWorkStatusChanged(SUCCESS == nRet ? WorkStatus::Ready : WorkStatus::Error);
return SUCCESS;
}
// 初始化机械臂协议
int GrabBagPresenter::InitRobotProtocol()
{
LOG_DEBUG("GrabBagPresenter::InitRobotProtocol - 开始初始化机械臂协议\n");
LOG_DEBUG("Start initializing robot protocol\n");
// 创建RobotProtocol实例
if(nullptr == m_pRobotProtocol){
@ -126,7 +170,7 @@ int GrabBagPresenter::InitRobotProtocol()
int nRet = m_pRobotProtocol->Initialize();
ERR_CODE_RETURN(nRet);
LOG_INFO("GrabBagPresenter::InitRobotProtocol - 机械臂协议初始化成功\n");
LOG_INFO("Robot protocol initialization successful\n");
return SUCCESS;
}
@ -134,17 +178,23 @@ int GrabBagPresenter::InitRobotProtocol()
// 机械臂协议回调函数实现
void GrabBagPresenter::OnRobotConnectionChanged(bool connected)
{
LOG_INFO("GrabBagPresenter::OnRobotConnectionChanged - 机械臂连接状态变化:%s\n", (connected ? "已连接" : "已断开"));
LOG_INFO("Robot connection status changed: %s\n", (connected ? "connected" : "disconnected"));
// 更新机械臂连接状态
m_bRobotConnected = connected;
if (m_pStatus) {
m_pStatus->OnRobotConnectionChanged(connected);
m_pStatus->OnStatusUpdate(connected ? "机械臂已连接" : "机械臂连接断开");
}
// 检查并更新工作状态
CheckAndUpdateWorkStatus();
}
void GrabBagPresenter::OnRobotWorkSignal(bool startWork)
{
LOG_INFO("GrabBagPresenter::OnRobotWorkSignal - 收到机械臂工作信号:%s\n", (startWork ? "开始工作" : "停止工作"));
LOG_INFO("Received robot work signal: %s\n", (startWork ? "start work" : "stop work"));
if (nullptr == m_pStatus) {
return;
@ -166,13 +216,233 @@ void GrabBagPresenter::SetStatusCallback(IYGrabBagStatus* status)
// 模拟检测函数,用于演示
int GrabBagPresenter::StartDetection()
{
LOG_INFO("GrabBagPresenter::StartDetection - 开始检测\n");
LOG_INFO("Start detection\n");
// 检查设备状态是否准备就绪
if (m_currentWorkStatus != WorkStatus::Ready) {
LOG_INFO("Device not ready, cannot start detection\n");
if (m_pStatus) {
m_pStatus->OnStatusUpdate("设备未准备就绪,无法开始检测");
}
return ERR_CODE(DEV_BUSY);
}
// 通知UI工作状态变更为"正在工作"
if (m_pStatus) {
m_currentWorkStatus = WorkStatus::Working;
m_pStatus->OnWorkStatusChanged(WorkStatus::Working);
}
if(m_vrEyeDeviceList.empty())
{
LOG_ERROR("No camera device found\n");
return ERR_CODE(DEV_NOT_FIND);
}
// 清空检测数据缓存
{
std::lock_guard<std::mutex> lock(m_detectionDataMutex);
m_detectionDataCache.clear();
}
// 启动所有相机的检测
for (size_t i = 0; i < m_vrEyeDeviceList.size(); ++i) {
IVrEyeDevice* pDevice = m_vrEyeDeviceList[i];
if (pDevice) {
int ret = pDevice->StartDetect(&GrabBagPresenter::_StaticDetectionCallback, this);
if (ret == 0) {
LOG_INFO("Camera %zu start detection successfully\n", i + 1);
} else {
LOG_WARNING("Camera %zu start detection failed, error code: %d\n", i + 1, ret);
}
}
}
return 0;
}
int GrabBagPresenter::StopDetection()
{
LOG_INFO("Stop detection\n");
// 停止所有相机的检测
for (size_t i = 0; i < m_vrEyeDeviceList.size(); ++i) {
IVrEyeDevice* pDevice = m_vrEyeDeviceList[i];
if (pDevice) {
int ret = pDevice->StopDetect();
if (ret == 0) {
LOG_INFO("Camera %zu stop detection successfully\n", i + 1);
} else {
LOG_WARNING("Camera %zu stop detection failed, error code: %d\n", i + 1, ret);
}
}
}
// 通知UI工作状态变更为"就绪"(如果设备连接正常)
if (m_pStatus) {
// 检查设备连接状态,决定停止后的状态
if (m_bCameraConnected && m_bRobotConnected) {
m_currentWorkStatus = WorkStatus::Ready;
m_pStatus->OnWorkStatusChanged(WorkStatus::Ready);
} else {
m_currentWorkStatus = WorkStatus::Error;
m_pStatus->OnWorkStatusChanged(WorkStatus::Error);
}
m_pStatus->OnStatusUpdate("检测已停止");
}
return 0;
}
IVrEyeDevice *GrabBagPresenter::GetEyeDevice(int index)
{
if(m_vrEyeDeviceList.size() <= index) return nullptr;
return m_vrEyeDeviceList[index];
}
// 静态回调函数实现
void GrabBagPresenter::_StaticCameraNotify(EVzDeviceWorkStatus eStatus, void* pExtData, unsigned int nDataLength, void* pInfoParam)
{
// 从pInfoParam获取this指针转换回GrabBagPresenter*类型
GrabBagPresenter* pThis = reinterpret_cast<GrabBagPresenter*>(pInfoParam);
if (pThis)
{
// 调用实例的非静态成员函数
pThis->_CameraNotify(eStatus, pExtData, nDataLength, pInfoParam);
}
}
void GrabBagPresenter::_CameraNotify(EVzDeviceWorkStatus eStatus, void *pExtData, unsigned int nDataLength, void *pInfoParam)
{
LOG_DEBUG("Camera notify received: status=%d, dataLength=%u\n", (int)eStatus, nDataLength);
switch (eStatus) {
case EVzDeviceWorkStatus::keDeviceWorkStatus_Offline:
{
LOG_WARNING("Camera device offline/disconnected\n");
// 更新相机连接状态
m_bCameraConnected = false;
// 通知UI相机状态变更
if (m_pStatus) {
// 这里需要判断是哪个相机离线暂时更新相机1状态
// 实际应用中可能需要通过pInfoParam或其他方式区分具体哪个相机
m_pStatus->OnCamera1StatusChanged(false);
m_pStatus->OnStatusUpdate("相机设备离线");
}
// 检查并更新工作状态
CheckAndUpdateWorkStatus();
break;
}
case EVzDeviceWorkStatus::keDeviceWorkStatus_Eye_Reconnect:
{
LOG_INFO("Camera device online/connected\n");
// 更新相机连接状态
m_bCameraConnected = true;
// 通知UI相机状态变更
if (m_pStatus) {
m_pStatus->OnCamera1StatusChanged(true);
m_pStatus->OnStatusUpdate("相机设备已连接");
}
// 检查并更新工作状态
CheckAndUpdateWorkStatus();
break;
}
case EVzDeviceWorkStatus::keDeviceWorkStatus_Device_Swing_Finish:
{
LOG_INFO("Received scan/trigger signal from camera\n");
// 如果当前状态为就绪,通知检测线程开始处理
if (m_currentWorkStatus == WorkStatus::Ready) {
LOG_INFO("Notifying detection thread to start processing\n");
// 通知算法检测线程
{
std::lock_guard<std::mutex> lock(m_algoDetectMutex);
// 这里可以设置一个标志位,或者直接通知条件变量
}
m_algoDetectCondition.notify_one();
if (m_pStatus) {
m_pStatus->OnStatusUpdate("收到扫描信号,开始检测处理");
}
} else {
LOG_WARNING("Received scan signal but device not ready, current status: %d\n", (int)m_currentWorkStatus);
}
break;
}
default:
LOG_DEBUG("Unhandled camera status: %d\n", (int)eStatus);
break;
}
}
// 检测数据回调函数静态版本
void GrabBagPresenter::_StaticDetectionCallback(EVzResultDataType eDataType, SVzLaserLineData* pLaserLinePoint, void* pUserData)
{
GrabBagPresenter* pThis = reinterpret_cast<GrabBagPresenter*>(pUserData);
if (pThis && pLaserLinePoint) {
pThis->_DetectionCallback(eDataType, pLaserLinePoint);
}
}
// 检测数据回调函数实例版本
void GrabBagPresenter::_DetectionCallback(EVzResultDataType eDataType, SVzLaserLineData* pLaserLinePoint)
{
if (!pLaserLinePoint) {
return;
}
// 将检测数据保存到缓存中
{
std::lock_guard<std::mutex> lock(m_detectionDataMutex);
m_detectionDataCache.push_back(pLaserLinePoint);
// LOG_DEBUG("Detection data cached: Frame %llu, Points: %d\n",
// pLaserLinePoint->sLineData.llFrameIdx,
// pLaserLinePoint->sLineData.nPointCount);
}
}
void GrabBagPresenter::CheckAndUpdateWorkStatus()
{
if (m_bCameraConnected && m_bRobotConnected) {
m_currentWorkStatus = WorkStatus::Ready;
m_pStatus->OnWorkStatusChanged(WorkStatus::Ready);
m_pStatus->OnStatusUpdate("设备已准备好");
} else {
m_currentWorkStatus = WorkStatus::Error;
m_pStatus->OnWorkStatusChanged(WorkStatus::Error);
m_pStatus->OnStatusUpdate("设备未准备好");
}
}
void GrabBagPresenter::_AlgoDetectThread()
{
while(m_bAlgoDetectThreadRunning)
{
std::unique_lock<std::mutex> lock(m_algoDetectMutex);
m_algoDetectCondition.wait(lock, [this]() {
return m_currentWorkStatus == WorkStatus::Ready;
});
// 检查设备状态是否准备就绪
_DetectTask();
}
}
int GrabBagPresenter::_DetectTask()
{
// 创建测试图像
QImage image(":/resource/result_image.jpg");
@ -229,6 +499,7 @@ int GrabBagPresenter::StartDetection()
// 检测完成后,将工作状态更新为"完成"
if (m_pStatus) {
m_currentWorkStatus = WorkStatus::Completed;
m_pStatus->OnWorkStatusChanged(WorkStatus::Completed);
}
@ -247,41 +518,11 @@ int GrabBagPresenter::StartDetection()
detectedCoord.rz = firstPos.yaw;
m_pRobotProtocol->SetRobotCoordinate(detectedCoord);
LOG_INFO("GrabBagPresenter::StartDetection - 更新检测结果坐标: X=%.2f, Y=%.2f, Z=%.2f\n",
LOG_INFO("Update detection result coordinates: X=%.2f, Y=%.2f, Z=%.2f\n",
detectedCoord.x, detectedCoord.y, detectedCoord.z);
}
}
}
return 0;
}
int GrabBagPresenter::StopDetection()
{
LOG_INFO("GrabBagPresenter::StopDetection - 停止检测\n");
// 通知UI工作状态变更为"就绪"
if (m_pStatus) {
m_pStatus->OnWorkStatusChanged(WorkStatus::Ready);
m_pStatus->OnStatusUpdate("检测已停止");
}
return 0;
}
// 静态回调函数实现
void GrabBagPresenter::_StaticCameraNotify(EVzDeviceWorkStatus eStatus, void* pExtData, unsigned int nDataLength, void* pInfoParam)
{
// 从pInfoParam获取this指针转换回GrabBagPresenter*类型
GrabBagPresenter* pThis = reinterpret_cast<GrabBagPresenter*>(pInfoParam);
if (pThis)
{
// 调用实例的非静态成员函数
pThis->_CameraNotify(eStatus, pExtData, nDataLength, pInfoParam);
}
}
void GrabBagPresenter::_CameraNotify(EVzDeviceWorkStatus eStatus, void *pExtData, unsigned int nDataLength, void *pInfoParam)
{
m_currentWorkStatus = WorkStatus::Ready;
return SUCCESS;
}

View File

@ -21,7 +21,7 @@ RobotProtocol::~RobotProtocol()
int RobotProtocol::Initialize(uint16_t port)
{
if (m_bServerRunning) {
LOG_WARNING("RobotProtocol::Initialize - 服务已经在运行中\n");
LOG_WARNING("Server is already running\n");
return SUCCESS;
}
@ -29,20 +29,40 @@ int RobotProtocol::Initialize(uint16_t port)
// 创建ModbusTCP服务器实例
bool bRet = IYModbusTCPServer::CreateInstance(&m_pModbusServer);
LOG_ERRO("RobotProtocol::%s - 创建ModbusTCP服务器%s \n", __func__, bRet ? "失败" : "成功");
LOG_ERRO("Create ModbusTCP server %s \n", bRet ? "success" : "failed");
m_bServerRunning = bRet;
ERR_CODE_RETURN(NET_ERR_CREAT_INIT);
// 设置ModbusTCP回调函数
if (m_pModbusServer) {
// 设置写线圈回调
m_pModbusServer->setWriteCoilsCallback([this](uint8_t unitId, uint16_t startAddress, uint16_t quantity, const uint8_t* values) {
return this->OnWriteCoils(unitId, startAddress, quantity, values);
});
// 设置写寄存器回调
m_pModbusServer->setWriteRegistersCallback([this](uint8_t unitId, uint16_t startAddress, uint16_t quantity, const uint16_t* values) {
return this->OnWriteRegisters(unitId, startAddress, quantity, values);
});
// 设置连接状态回调
m_pModbusServer->setConnectionStatusCallback([this](bool connected) {
this->OnModbusTCPConnectionChanged(connected);
});
}
int nRet = m_pModbusServer->start();
ERR_CODE_RETURN(nRet);
// 设置初始状态
m_robotStatus = STATUS_CONNECTED;
LOG_INFO("RobotProtocol::Initialize - ModbusTCP服务初始化完成\n");
return 0;
LOG_INFO("ModbusTCP service initialization completed\n");
return SUCCESS;
}
void RobotProtocol::Deinitialize()
{
LOG_DEBUG("RobotProtocol::Deinitialize - 停止ModbusTCP服务\n");
LOG_DEBUG("Stop ModbusTCP service\n");
// 停止ModbusTCP服务器
StopModbusTCPServer();
@ -51,14 +71,14 @@ void RobotProtocol::Deinitialize()
m_robotStatus = STATUS_DISCONNECTED;
m_bServerRunning = false;
LOG_INFO("RobotProtocol::Deinitialize - ModbusTCP服务已停止\n");
LOG_INFO("ModbusTCP service stopped\n");
}
int RobotProtocol::SetRobotCoordinate(const RobotCoordinate& coordinate)
{
LOG_DEBUG("RobotProtocol::SetRobotCoordinate - 设置机械臂坐标\n");
LOG_DEBUG("坐标: X=%.2f, Y=%.2f, Z=%.2f\n", coordinate.x, coordinate.y, coordinate.z);
LOG_DEBUG("旋转: RX=%.2f, RY=%.2f, RZ=%.2f\n", coordinate.rx, coordinate.ry, coordinate.rz);
LOG_DEBUG("Set robot arm coordinates\n");
LOG_DEBUG("Coordinates: X=%.2f, Y=%.2f, Z=%.2f\n", coordinate.x, coordinate.y, coordinate.z);
LOG_DEBUG("Rotation: RX=%.2f, RY=%.2f, RZ=%.2f\n", coordinate.rx, coordinate.ry, coordinate.rz);
m_robotCoordinate = coordinate;
@ -93,7 +113,7 @@ bool RobotProtocol::IsRunning() const
void RobotProtocol::StopModbusTCPServer()
{
LOG_DEBUG("RobotProtocol::StopModbusTCPServer - 停止ModbusTCP服务器\n");
LOG_DEBUG("Stop ModbusTCP server\n");
if (m_pModbusServer) {
// 释放资源
@ -102,22 +122,20 @@ void RobotProtocol::StopModbusTCPServer()
}
m_bServerRunning = false;
LOG_INFO("RobotProtocol::StopModbusTCPServer - ModbusTCP服务器已停止\n");
LOG_INFO("ModbusTCP server stopped\n");
}
IYModbusTCPServer::ErrorCode RobotProtocol::OnWriteCoils(uint8_t unitId, uint16_t startAddress,
uint16_t quantity, const uint8_t* values)
{
LOG_DEBUG("RobotProtocol::OnWriteCoils - 单元ID:%d, 起始地址:%d, 数量:%d\n",
unitId, startAddress, quantity);
LOG_DEBUG("Write coils - UnitID:%d, StartAddress:%d, Quantity:%d\n", unitId, startAddress, quantity);
// 处理工作信号线圈
if (startAddress <= WORK_SIGNAL_COIL && startAddress + quantity > WORK_SIGNAL_COIL) {
uint16_t coilIndex = WORK_SIGNAL_COIL - startAddress;
bool workSignal = (values[coilIndex / 8] >> (coilIndex % 8)) & 0x01;
LOG_INFO("RobotProtocol::OnWriteCoils - 收到工作信号:%s\n",
(workSignal ? "开始工作" : "停止工作"));
LOG_INFO("Received work signal: %s\n", (workSignal ? "start work" : "stop work"));
// 触发工作信号回调
if (m_workSignalCallback) {
@ -131,8 +149,7 @@ IYModbusTCPServer::ErrorCode RobotProtocol::OnWriteCoils(uint8_t unitId, uint16_
IYModbusTCPServer::ErrorCode RobotProtocol::OnWriteRegisters(uint8_t unitId, uint16_t startAddress,
uint16_t quantity, const uint16_t* values)
{
LOG_DEBUG("RobotProtocol::OnWriteRegisters - 单元ID:%d, 起始地址:%d, 数量:%d\n",
unitId, startAddress, quantity);
LOG_DEBUG("Write registers - UnitID:%d, StartAddress:%d, Quantity:%d\n", unitId, startAddress, quantity);
// 处理坐标寄存器更新
if (startAddress >= COORD_X_ADDR && startAddress < STATUS_ADDR) {
@ -168,7 +185,7 @@ IYModbusTCPServer::ErrorCode RobotProtocol::OnWriteRegisters(uint8_t unitId, uin
IYModbusTCPServer::ErrorCode RobotProtocol::OnReadHoldingRegisters(uint8_t unitId, uint16_t startAddress,
uint16_t quantity, uint16_t* values)
{
LOG_DEBUG("RobotProtocol::OnReadHoldingRegisters - 单元ID:%d, 起始地址:%d, 数量:%d\n",
LOG_DEBUG("Read holding registers - UnitID:%d, StartAddress:%d, Quantity:%d\n",
unitId, startAddress, quantity);
for (uint16_t i = 0; i < quantity; i++) {
@ -202,4 +219,20 @@ IYModbusTCPServer::ErrorCode RobotProtocol::OnReadHoldingRegisters(uint8_t unitI
}
return IYModbusTCPServer::ErrorCode::SUCCESS;
}
void RobotProtocol::OnModbusTCPConnectionChanged(bool connected)
{
if (connected) {
LOG_INFO("ModbusTCP connection established\n");
m_robotStatus = STATUS_CONNECTED;
} else {
LOG_INFO("ModbusTCP connection lost\n");
m_robotStatus = STATUS_DISCONNECTED;
}
// 触发上层连接状态回调
if (m_connectionCallback) {
m_connectionCallback(connected);
}
}

View File

@ -1,14 +1,165 @@
#include "dialogcamera.h"
#include "ui_dialogcamera.h"
#include <QMessageBox>
#include "VrSimpleLog.h"
DialogCamera::DialogCamera(QWidget *parent) :
DialogCamera::DialogCamera(IVrEyeDevice* pDevice, QWidget *parent) :
QDialog(parent),
ui(new Ui::DialogCamera)
ui(new Ui::DialogCamera),
m_pDevice(pDevice)
{
ui->setupUi(this);
// 检查设备是否有效
if (!m_pDevice) {
setWindowTitle("相机参数配置 - 设备错误");
// 禁用所有控件
setEnabled(false);
return;
} else {
setWindowTitle("相机参数配置");
}
// 初始化界面数据
InitCameraParameters();
}
DialogCamera::~DialogCamera()
{
delete ui;
}
void DialogCamera::on_btn_camer_ok_clicked()
{
if (!m_pDevice) {
QMessageBox::warning(this, "错误", "设备未初始化");
return;
}
// 应用参数配置
if (ApplyCameraParameters()) {
QMessageBox::information(this, "成功", "相机参数配置成功!");
accept(); // 关闭对话框并返回Accepted
} else {
QMessageBox::warning(this, "失败", "相机参数配置失败,请检查设备连接!");
}
}
void DialogCamera::on_btn_camer_cancel_clicked()
{
// 直接关闭窗口,不保存任何更改
reject();
}
void DialogCamera::InitCameraParameters()
{
if (!m_pDevice) return;
try {
// 获取曝光时间
unsigned int exposeTime = 0;
if (m_pDevice->GetEyeExpose(exposeTime) == 0) {
// 假设UI中有一个名为spinBox_expose的控件
ui->lineEdit_export->setText(QString::number(exposeTime));
LOG_DEBUG("Current expose time: %u\n", exposeTime);
}
// 获取增益
unsigned int gain = 0;
if (m_pDevice->GetEyeGain(gain) == 0) {
// 假设UI中有一个名为spinBox_gain的控件
ui->lineEdit_gain->setText(QString::number(gain));
LOG_DEBUG("Current gain: %u\n", gain);
}
// 获取帧率
int frame = 0;
if (m_pDevice->GetFrame(frame) == 0) {
// 假设UI中有一个名为spinBox_frame的控件
ui->lineEdit_frame->setText(QString::number(frame));
LOG_DEBUG("Current frame rate: %d\n", frame);
}
// 获取摆动速度
float swingSpeed = 0.0f;
if (m_pDevice->GetSwingSpeed(swingSpeed) == 0) {
// 假设UI中有一个名为doubleSpinBox_swing_speed的控件
ui->lineEdit_swing_speed->setText(QString::number(swingSpeed));
LOG_DEBUG("Swing speed: %.3f\n", swingSpeed);
}
// 获取工作角度
float minAngle = 0.0f, maxAngle = 0.0f;
if (m_pDevice->GetSwingAngle(minAngle, maxAngle) == 0) {
// 假设UI中有角度相关的控件
ui->lineEdit_swing_start->setText(QString::number(minAngle));
ui->lineEdit_swing_stop->setText(QString::number(maxAngle));
LOG_DEBUG("Swing angle range: %.3f to %.3f\n", minAngle, maxAngle);
}
} catch (...) {
QMessageBox::warning(this, "错误", "读取相机参数时发生异常");
}
}
bool DialogCamera::ApplyCameraParameters()
{
if (!m_pDevice) return false;
try {
bool success = true;
// 设置曝光时间
unsigned int exposeTime = ui->lineEdit_export->text().toUInt();
if (m_pDevice->SetEyeExpose(exposeTime) != 0) {
LOG_WARNING("Failed to set expose time: %u\n", exposeTime);
success = false;
} else {
LOG_INFO("Set expose time: %u\n", exposeTime);
}
// 设置增益
unsigned int gain = ui->lineEdit_gain->text().toUInt();
if (m_pDevice->SetEyeGain(gain) != 0) {
LOG_WARNING("Failed to set gain: %u\n", gain);
success = false;
} else {
LOG_INFO("Set gain: %u\n", gain);
}
// 设置帧率
int frame = ui->lineEdit_frame->text().toInt();
if (m_pDevice->SetFrame(frame) != 0) {
LOG_WARNING("Failed to set frame rate: %d\n", frame);
success = false;
} else {
LOG_INFO("Set frame rate: %d\n", frame);
}
// 设置摆动速度
float swingSpeed = ui->lineEdit_swing_speed->text().toFloat();
if (m_pDevice->SetSwingSpeed(swingSpeed) != 0) {
LOG_WARNING("Failed to set swing speed: %.3f\n", swingSpeed);
success = false;
} else {
LOG_INFO("Set swing speed: %.3f\n", swingSpeed);
}
// 设置工作角度
float minAngle = ui->lineEdit_swing_start->text().toFloat();
float maxAngle = ui->lineEdit_swing_stop->text().toFloat();
if (m_pDevice->SetSwingAngle(minAngle, maxAngle) != 0) {
LOG_WARNING("Failed to set swing angle: %.3f to %.3f\n", minAngle, maxAngle);
success = false;
} else {
LOG_INFO("Set swing angle: %.3f to %.3f\n", minAngle, maxAngle);
}
return success;
} catch (...) {
QMessageBox::warning(this, "错误", "应用相机参数时发生异常");
return false;
}
}

View File

@ -2,6 +2,7 @@
#define DIALOGCAMERA_H
#include <QDialog>
#include <IVrEyeDevice.h>
namespace Ui {
class DialogCamera;
@ -12,11 +13,23 @@ class DialogCamera : public QDialog
Q_OBJECT
public:
explicit DialogCamera(QWidget *parent = nullptr);
explicit DialogCamera(IVrEyeDevice* pDevice, QWidget *parent = nullptr);
~DialogCamera();
private slots:
void on_btn_camer_ok_clicked();
void on_btn_camer_cancel_clicked();
private:
// 初始化相机参数到界面
void InitCameraParameters();
// 应用界面参数到相机
bool ApplyCameraParameters();
private:
Ui::DialogCamera *ui;
IVrEyeDevice* m_pDevice = nullptr;
};
#endif // DIALOGCAMERA_H

View File

@ -13,7 +13,7 @@
<property name="windowTitle">
<string>相机配置</string>
</property>
<widget class="QLabel" name="label">
<widget class="QLabel" name="label_camera_title">
<property name="geometry">
<rect>
<x>30</x>
@ -51,7 +51,7 @@
<property name="title">
<string>基本参数</string>
</property>
<widget class="QWidget" name="">
<widget class="QWidget" name="layoutWidget">
<property name="geometry">
<rect>
<x>20</x>
@ -81,7 +81,7 @@
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit">
<widget class="QLineEdit" name="lineEdit_export">
<property name="font">
<font>
<pointsize>18</pointsize>
@ -106,7 +106,7 @@
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit_2">
<widget class="QLineEdit" name="lineEdit_gain">
<property name="font">
<font>
<pointsize>18</pointsize>
@ -131,7 +131,7 @@
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit_3">
<widget class="QLineEdit" name="lineEdit_frame">
<property name="font">
<font>
<pointsize>18</pointsize>
@ -191,7 +191,7 @@
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit_4">
<widget class="QLineEdit" name="lineEdit_swing_speed">
<property name="font">
<font>
<pointsize>18</pointsize>
@ -216,7 +216,7 @@
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit_5">
<widget class="QLineEdit" name="lineEdit_swing_start">
<property name="font">
<font>
<pointsize>18</pointsize>
@ -241,7 +241,7 @@
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit_6">
<widget class="QLineEdit" name="lineEdit_swing_stop">
<property name="font">
<font>
<pointsize>18</pointsize>
@ -254,7 +254,7 @@
</layout>
</widget>
</widget>
<widget class="QPushButton" name="pushButton">
<widget class="QPushButton" name="btn_camer_ok">
<property name="geometry">
<rect>
<x>120</x>
@ -272,7 +272,7 @@
<string>应用</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton_2">
<widget class="QPushButton" name="btn_camer_cancel">
<property name="geometry">
<rect>
<x>280</x>

View File

@ -17,8 +17,8 @@
<property name="geometry">
<rect>
<x>10</x>
<y>0</y>
<width>651</width>
<y>20</y>
<width>601</width>
<height>41</height>
</rect>
</property>
@ -28,7 +28,7 @@
</font>
</property>
<property name="text">
<string>区域定</string>
<string>区域定</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
@ -97,7 +97,7 @@
</font>
</property>
<property name="text">
<string>ms</string>
<string>mm</string>
</property>
</widget>
</item>
@ -134,7 +134,7 @@
</font>
</property>
<property name="text">
<string>ms</string>
<string>mm</string>
</property>
</widget>
</item>
@ -171,7 +171,7 @@
</font>
</property>
<property name="text">
<string>ms</string>
<string>mm</string>
</property>
</widget>
</item>
@ -243,7 +243,7 @@
</font>
</property>
<property name="text">
<string>ms</string>
<string>mm</string>
</property>
</widget>
</item>
@ -280,7 +280,7 @@
</font>
</property>
<property name="text">
<string>ms</string>
<string>mm</string>
</property>
</widget>
</item>
@ -317,7 +317,7 @@
</font>
</property>
<property name="text">
<string>ms</string>
<string>mm</string>
</property>
</widget>
</item>
@ -389,7 +389,7 @@
</font>
</property>
<property name="text">
<string>ms</string>
<string>mm</string>
</property>
</widget>
</item>
@ -426,7 +426,7 @@
</font>
</property>
<property name="text">
<string>ms</string>
<string>mm</string>
</property>
</widget>
</item>
@ -463,7 +463,7 @@
</font>
</property>
<property name="text">
<string>ms</string>
<string>mm</string>
</property>
</widget>
</item>

View File

@ -5,7 +5,7 @@
#include <QDebug>
#include <QPainter>
#include <QBrush>
#include <QMessageBox>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
@ -36,11 +36,17 @@ MainWindow::MainWindow(QWidget *parent)
setStatusDot(ui->label_camera_1_status, false); // 在线绿色
setStatusDot(ui->label_camera_2_status, false); // 在线绿色
setStatusDot(ui->label_robot_status, false); // 在线绿色
// 连接菜单信号
connect(ui->menu_camera, &QMenu::aboutToShow, this, &MainWindow::on_menu_camera_triggered);
connect(ui->menu_config, &QMenu::aboutToShow, this, &MainWindow::on_menu_config_triggered);
connect(ui->menu_camera_adjust, &QMenu::aboutToShow, this, &MainWindow::on_menu_camera_adjust_triggered);
// connect(ui->menu_camera, &QMenu::aboutToShow, this, &MainWindow::on_menu_camera_triggered);
// connect(ui->menu_config, &QMenu::aboutToShow, this, &MainWindow::on_menu_config_triggered);
// connect(ui->menu_camera_adjust, &QMenu::aboutToShow, this, &MainWindow::on_menu_camera_adjust_triggered);
// 连接工作状态更新信号槽
connect(this, &MainWindow::workStatusUpdateRequested, this, &MainWindow::updateWorkStatusLabel);
// 连接检测结果更新信号槽
connect(this, &MainWindow::detectionResultUpdateRequested, this, &MainWindow::updateDetectionResultDisplay);
updateStatusLog(tr("就绪"));
@ -140,10 +146,10 @@ void MainWindow::setStatusDot(QLabel* label, bool isOnline) {
void MainWindow::on_btn_camera_clicked()
{
if(nullptr == ui_dialogCamera){
ui_dialogCamera = new DialogCamera;
}
ui_dialogCamera->show();
// if(nullptr == ui_dialogCamera){
// ui_dialogCamera = new DialogCamera;
// }
// ui_dialogCamera->show();
}
void MainWindow::on_btn_config_clicked()
@ -154,16 +160,13 @@ void MainWindow::on_btn_config_clicked()
ui_dialogConfig->show();
}
void MainWindow::on_btn_flow_clicked()
{
// 机械臂连接/断开
static bool isConnected = false;
isConnected = !isConnected;
}
void MainWindow::on_btn_start_clicked()
{
// 使用Presenter启动检测
@ -172,7 +175,6 @@ void MainWindow::on_btn_start_clicked()
}
}
void MainWindow::on_btn_stop_clicked()
{
if (m_presenter) {
@ -180,25 +182,19 @@ void MainWindow::on_btn_stop_clicked()
}
}
void MainWindow::on_menu_camera_triggered()
{
qDebug() << __func__ ;
if(nullptr == ui_dialogCamera){
ui_dialogCamera = new DialogCamera(this);
}
ui_dialogCamera->show();
}
void MainWindow::on_menu_config_triggered()
{
qDebug() << __func__ ;
if(nullptr == ui_dialogConfig){
ui_dialogConfig = new DialogConfig(this);
}
ui_dialogConfig->show();
}
//void MainWindow::on_menu_camera_triggered()
//{
// qDebug() << __func__ ;
//}
//void MainWindow::on_menu_config_triggered()
//{
// qDebug() << __func__ ;
// if(nullptr == ui_dialogConfig){
// ui_dialogConfig = new DialogConfig(this);
// }
// ui_dialogConfig->show();
//}
void MainWindow::on_menu_camera_adjust_triggered()
{
@ -213,11 +209,8 @@ void MainWindow::OnStatusUpdate(const std::string& statusMessage)
void MainWindow::OnDetectionResult(const DetectionResult& result)
{
// 显示检测结果图像
displayImage(result.image);
// 添加检测结果到列表
addDetectionResult(result);
// 通过信号槽机制更新UI确保在主线程中执行
emit detectionResultUpdateRequested(result);
}
void MainWindow::OnCamera1StatusChanged(bool isConnected)
@ -226,7 +219,7 @@ void MainWindow::OnCamera1StatusChanged(bool isConnected)
setStatusDot(ui->label_camera_1_status, isConnected);
// 更新状态消息
QString statusMsg = isConnected ? tr("相机1已连接") : tr("相机1已断开");
QString statusMsg = isConnected ? tr("相机一已连接") : tr("相机一已断开");
ui->label_camera_1_txt->setText(statusMsg);
updateStatusLog(statusMsg);
}
@ -238,7 +231,7 @@ void MainWindow::OnCamera2StatusChanged(bool isConnected)
setStatusDot(ui->label_camera_2_status, isConnected);
// 更新状态消息
QString statusMsg = isConnected ? tr("相机2已连接") : tr("相机2已断开");
QString statusMsg = isConnected ? tr("相机二已连接") : tr("相机二已断开");
ui->label_camera_2_txt->setText(statusMsg);
updateStatusLog(statusMsg);
}
@ -272,11 +265,17 @@ void MainWindow::OnRobotConnectionChanged(bool isConnected)
// 更新状态消息
QString statusMsg = isConnected ? tr("机械臂已连接") : tr("机械臂已断开");
updateStatusLog(statusMsg);
updateStatusLog(statusMsg);
}
// 工作状态更新槽函数
void MainWindow::OnWorkStatusChanged(WorkStatus status)
{
// 通过信号槽机制更新UI确保在主线程中执行
emit workStatusUpdateRequested(status);
}
void MainWindow::updateWorkStatusLabel(WorkStatus status)
{
// 获取状态对应的显示文本
QString statusText = QString::fromStdString(WorkStatusToString(status));
@ -309,6 +308,40 @@ void MainWindow::OnWorkStatusChanged(WorkStatus status)
updateStatusLog(statusText);
}
void MainWindow::updateDetectionResultDisplay(const DetectionResult& result)
{
// 实现检测结果显示的逻辑
displayImage(result.image);
addDetectionResult(result);
}
void MainWindow::on_action_camera_1_triggered()
{
IVrEyeDevice* pDevice = m_presenter->GetEyeDevice(0);
if(nullptr == pDevice){
QMessageBox::warning(this, "设备错误", "相机设备未正确初始化!");
return;
}
if(nullptr == ui_dialogCamera){
ui_dialogCamera = new DialogCamera(pDevice, this);
}
ui_dialogCamera->show();
}
void MainWindow::on_action_camera_2_triggered()
{
IVrEyeDevice* pDevice = m_presenter->GetEyeDevice(1);
if(nullptr == pDevice){
QMessageBox::warning(this, "设备错误", "相机设备未正确初始化!");
return;
}
if(nullptr == ui_dialogCamera){
ui_dialogCamera = new DialogCamera(pDevice, this);
}
ui_dialogCamera->show();
}

View File

@ -1,4 +1,4 @@
#ifndef MAINWINDOW_H
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
@ -36,6 +36,13 @@ public:
virtual void OnCameraCountChanged(int cameraCount) override;
virtual void OnWorkStatusChanged(WorkStatus status) override;
signals:
// 工作状态更新信号
void workStatusUpdateRequested(WorkStatus status);
// 检测结果更新信号
void detectionResultUpdateRequested(const DetectionResult& result);
private slots:
// UI操作相关槽
void on_btn_camera_clicked();
@ -43,9 +50,19 @@ private slots:
void on_btn_flow_clicked();
void on_btn_start_clicked();
void on_btn_stop_clicked();
void on_menu_camera_triggered();
void on_menu_config_triggered();
// void on_menu_camera_triggered();
// void on_menu_config_triggered();
void on_menu_camera_adjust_triggered();
// 工作状态更新槽函数
void updateWorkStatusLabel(WorkStatus status);
// 检测结果更新槽函数
void updateDetectionResultDisplay(const DetectionResult& result);
void on_action_camera_1_triggered();
void on_action_camera_2_triggered();
private:
Ui::MainWindow *ui;

View File

@ -197,6 +197,8 @@
<property name="title">
<string>相机配置</string>
</property>
<addaction name="action_camera_1"/>
<addaction name="action_camera_2"/>
</widget>
<widget class="QMenu" name="menu_config">
<property name="title">
@ -219,6 +221,16 @@
<addaction name="menu_4"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<action name="action_camera_1">
<property name="text">
<string>相机一配置</string>
</property>
</action>
<action name="action_camera_2">
<property name="text">
<string>相机二配置</string>
</property>
</action>
</widget>
<resources/>
<connections/>

View File

@ -32,6 +32,9 @@ public:
// 写保持寄存器回调函数unitId, startAddress, quantity, values -> ErrorCode
using WriteRegistersCallback = std::function<ErrorCode(uint8_t, uint16_t, uint16_t, const uint16_t*)>;
// 连接状态回调函数isConnected -> void
using ConnectionStatusCallback = std::function<void(bool)>;
public:
virtual ~IYModbusTCPServer() = default;
@ -39,12 +42,13 @@ public:
static bool CreateInstance(IYModbusTCPServer** ppModbusTCPServer);
// 启动/停止服务器
virtual bool start(int port = 502, int maxConnections = 10) = 0;
virtual int start(int port = 502, int maxConnections = 10) = 0;
virtual void stop() = 0;
// 设置回调函数
virtual void setWriteCoilsCallback(WriteCoilsCallback callback) = 0;
virtual void setWriteRegistersCallback(WriteRegistersCallback callback) = 0;
virtual void setConnectionStatusCallback(ConnectionStatusCallback callback) = 0;
// 更新数据接口 - 线程安全
virtual void updateCoil(uint16_t address, bool value) = 0;

View File

@ -19,6 +19,10 @@ DEFINES += DLLBUILD
TEMPLATE = lib
CONFIG += staticlib
INCLUDEPATH += ../../VrCommon/Inc
INCLUDEPATH += ../../VrUtils/Inc
INCLUDEPATH += ./Inc
INCLUDEPATH += ./_Inc

View File

@ -3,6 +3,9 @@
#include <cstring>
#include <stdexcept>
#include "VrError.h"
#include "VrSimpleLog.h"
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
@ -32,11 +35,11 @@ ModbusTCPServer::~ModbusTCPServer()
stop();
}
bool ModbusTCPServer::start(int port, int maxConnections)
int ModbusTCPServer::start(int port, int maxConnections)
{
if (m_isRunning.load()) {
setLastError("服务器已在运行");
return true;
return SUCCESS;
}
m_port = port;
@ -46,7 +49,7 @@ bool ModbusTCPServer::start(int port, int maxConnections)
m_modbusCtx = modbus_new_tcp("0.0.0.0", port);
if (m_modbusCtx == nullptr) {
setLastError("创建Modbus TCP上下文失败");
return false;
return ERR_CODE(NET_ERR_CREAT_INIT);
}
// 创建数据映射 - 分配足够的空间
@ -56,7 +59,7 @@ bool ModbusTCPServer::start(int port, int maxConnections)
setLastError("创建数据映射失败");
modbus_free(m_modbusCtx);
m_modbusCtx = nullptr;
return false;
return ERR_CODE(NET_ERR_CONFIG);
}
// 监听连接
@ -67,7 +70,7 @@ bool ModbusTCPServer::start(int port, int maxConnections)
m_mapping = nullptr;
modbus_free(m_modbusCtx);
m_modbusCtx = nullptr;
return false;
return ERR_CODE(NET_ERR_CREAT_LISTEN);
}
m_isRunning.store(true);
@ -76,7 +79,12 @@ bool ModbusTCPServer::start(int port, int maxConnections)
// 启动服务器线程
m_serverThread = std::make_unique<std::thread>(&ModbusTCPServer::serverLoop, this);
return true;
// 初始状态:服务器启动但没有客户端连接
if (m_connectionStatusCallback) {
m_connectionStatusCallback(false);
}
return SUCCESS;
}
void ModbusTCPServer::stop()
@ -154,7 +162,7 @@ void ModbusTCPServer::serverLoop()
if (selectResult == -1) {
if (!m_shouldStop.load()) {
std::cerr << "select错误: " << strerror(errno) << std::endl;
LOG_WARNING("select error: %s\n", strerror(errno));
}
break;
}
@ -198,7 +206,7 @@ void ModbusTCPServer::handleNewConnection()
int clientSocket = modbus_tcp_accept(m_modbusCtx, &m_serverSocket);
if (clientSocket == -1) {
if (!m_shouldStop.load()) {
std::cerr << "接受连接失败: " << modbus_strerror(errno) << std::endl;
LOG_ERRO("Accept connection failed: %s\n", modbus_strerror(errno));
}
return;
}
@ -206,7 +214,7 @@ void ModbusTCPServer::handleNewConnection()
// 创建新的modbus context用于此客户端
modbus_t* clientCtx = modbus_new_tcp("0.0.0.0", m_port);
if (clientCtx == nullptr) {
std::cerr << "为客户端创建Modbus上下文失败" << std::endl;
LOG_ERRO("Create Modbus context for client failed\n");
#ifdef _WIN32
closesocket(clientSocket);
#else
@ -227,7 +235,12 @@ void ModbusTCPServer::handleNewConnection()
m_clients[clientSocket] = client;
}
std::cout << "新客户端连接: socket=" << clientSocket << std::endl;
LOG_INFO("New client connected: socket=%d\n", clientSocket);
// 触发连接状态回调
if (m_connectionStatusCallback) {
m_connectionStatusCallback(true);
}
}
void ModbusTCPServer::handleClientData(std::shared_ptr<ClientConnection> client)
@ -240,9 +253,9 @@ void ModbusTCPServer::handleClientData(std::shared_ptr<ClientConnection> client)
if (bytesReceived <= 0) {
// 连接断开或错误
if (bytesReceived == 0) {
std::cout << "客户端断开连接: socket=" << client->socket << std::endl;
LOG_VERBOSE("Client disconnected: socket=%d\n", client->socket);
} else {
std::cerr << "接收数据错误: " << strerror(errno) << std::endl;
LOG_ERRO("Receive data error: %s\n", strerror(errno));
}
throw std::runtime_error("客户端连接错误");
}
@ -256,8 +269,13 @@ void ModbusTCPServer::removeClient(int socket)
std::lock_guard<std::mutex> lock(m_clientsMutex);
auto it = m_clients.find(socket);
if (it != m_clients.end()) {
std::cout << "移除客户端连接: socket=" << socket << std::endl;
LOG_INFO("Remove client connection: socket=%d\n", socket);
m_clients.erase(it);
// 如果没有客户端连接了,触发断开回调
if (m_clients.empty() && m_connectionStatusCallback) {
m_connectionStatusCallback(false);
}
}
}
@ -268,42 +286,134 @@ void ModbusTCPServer::processModbusRequest(std::shared_ptr<ClientConnection> cli
int responseRc = modbus_reply(client->modbusCtx, query, queryLength, m_mapping);
if (responseRc == -1) {
std::cerr << "发送响应失败: " << modbus_strerror(errno) << std::endl;
LOG_WARNING("Send response failed: %s\n", modbus_strerror(errno));
throw std::runtime_error("发送响应失败");
}
// 检查是否是写操作,如果是则调用回调
if (queryLength >= 8) { // 确保有足够的字节
uint8_t function = query[7]; // 功能码在TCP ADU的第8字节
uint16_t address = (query[8] << 8) | query[9];
uint16_t quantity = (query[10] << 8) | query[11];
uint8_t unitId = query[6];
// 解析ModbusTCP ADU - 最小长度检查
if (queryLength < 8) {
LOG_DEBUG("Query too short: %d bytes\n", queryLength);
return;
}
switch (function) {
case MODBUS_FC_WRITE_SINGLE_COIL:
case MODBUS_FC_WRITE_MULTIPLE_COILS:
if (m_writeCoilsCallback) {
const uint8_t* values = &query[12]; // 数据从第13字节开始
ErrorCode result = m_writeCoilsCallback(unitId, address, quantity, values);
if (result != ErrorCode::SUCCESS) {
// 发送异常响应
modbus_reply_exception(client->modbusCtx, query, static_cast<unsigned int>(result));
// ModbusTCP ADU格式: [Transaction ID(2)] [Protocol ID(2)] [Length(2)] [Unit ID(1)] [Function Code(1)] [Data...]
uint16_t transactionId = (query[0] << 8) | query[1]; // Transaction ID
uint16_t protocolId = (query[2] << 8) | query[3]; // Protocol ID (should be 0 for ModbusTCP)
uint16_t length = (query[4] << 8) | query[5]; // Length field
uint8_t unitId = query[6]; // Unit ID
uint8_t function = query[7]; // Function Code
// 验证协议ID
if (protocolId != 0) {
LOG_DEBUG("Invalid protocol ID: %d\n", protocolId);
return;
}
// 验证长度字段
if (length != (queryLength - 6)) {
LOG_DEBUG("Length mismatch: expected %d, got %d\n", length, queryLength - 6);
return;
}
LOG_DEBUG("ModbusTCP request - TransID:%d, UnitID:%d, Function:0x%02X\n",
transactionId, unitId, function);
// 根据功能码解析数据
switch (function) {
case MODBUS_FC_WRITE_SINGLE_COIL:
{
if (queryLength >= 12) {
uint16_t address = (query[8] << 8) | query[9];
uint16_t value = (query[10] << 8) | query[11];
LOG_DEBUG("Write single coil - Address:%d, Value:%d\n", address, value);
if (m_writeCoilsCallback) {
uint8_t coilValue = (value == 0xFF00) ? 1 : 0;
ErrorCode result = m_writeCoilsCallback(unitId, address, 1, &coilValue);
if (result != ErrorCode::SUCCESS) {
LOG_DEBUG("Write coil callback returned error: %d\n", (int)result);
}
}
}
break;
case MODBUS_FC_WRITE_SINGLE_REGISTER:
case MODBUS_FC_WRITE_MULTIPLE_REGISTERS:
if (m_writeRegistersCallback) {
const uint16_t* values = reinterpret_cast<const uint16_t*>(&query[12]);
ErrorCode result = m_writeRegistersCallback(unitId, address, quantity, values);
if (result != ErrorCode::SUCCESS) {
// 发送异常响应
modbus_reply_exception(client->modbusCtx, query, static_cast<unsigned int>(result));
}
break;
case MODBUS_FC_WRITE_MULTIPLE_COILS:
{
if (queryLength >= 13) {
uint16_t address = (query[8] << 8) | query[9];
uint16_t quantity = (query[10] << 8) | query[11];
uint8_t byteCount = query[12];
if (queryLength >= (13 + byteCount)) {
LOG_DEBUG("Write multiple coils - Address:%d, Quantity:%d, Bytes:%d\n",
address, quantity, byteCount);
if (m_writeCoilsCallback) {
const uint8_t* values = &query[13];
ErrorCode result = m_writeCoilsCallback(unitId, address, quantity, values);
if (result != ErrorCode::SUCCESS) {
LOG_DEBUG("Write coils callback returned error: %d\n", (int)result);
}
}
}
}
break;
}
}
break;
case MODBUS_FC_WRITE_SINGLE_REGISTER:
{
if (queryLength >= 12) {
uint16_t address = (query[8] << 8) | query[9];
uint16_t value = (query[10] << 8) | query[11];
LOG_DEBUG("Write single register - Address:%d, Value:%d\n", address, value);
if (m_writeRegistersCallback) {
ErrorCode result = m_writeRegistersCallback(unitId, address, 1, &value);
if (result != ErrorCode::SUCCESS) {
LOG_DEBUG("Write register callback returned error: %d\n", (int)result);
}
}
}
}
break;
case MODBUS_FC_WRITE_MULTIPLE_REGISTERS:
{
if (queryLength >= 13) {
uint16_t address = (query[8] << 8) | query[9];
uint16_t quantity = (query[10] << 8) | query[11];
uint8_t byteCount = query[12];
if (queryLength >= (13 + byteCount) && byteCount == (quantity * 2)) {
LOG_DEBUG("Write multiple registers - Address:%d, Quantity:%d, Bytes:%d\n",
address, quantity, byteCount);
if (m_writeRegistersCallback) {
// 解析寄存器值(注意字节序)
std::vector<uint16_t> values;
values.reserve(quantity);
for (int i = 0; i < quantity; i++) {
uint16_t value = (query[13 + i*2] << 8) | query[13 + i*2 + 1];
values.push_back(value);
}
ErrorCode result = m_writeRegistersCallback(unitId, address, quantity, values.data());
if (result != ErrorCode::SUCCESS) {
LOG_DEBUG("Write registers callback returned error: %d\n", (int)result);
}
}
}
}
}
break;
default:
LOG_DEBUG("Unhandled function code: 0x%02X\n", function);
break;
}
}
@ -399,4 +509,4 @@ bool IYModbusTCPServer::CreateInstance(IYModbusTCPServer** ppModbusTCPServer)
*ppModbusTCPServer = new ModbusTCPServer();
return true;
}
}

View File

@ -47,13 +47,14 @@ public:
// 实现IYModbusTCPServer接口
// 启动/停止服务器
virtual bool start(int port = 502, int maxConnections = 10) override;
virtual int start(int port = 502, int maxConnections = 10) override;
virtual void stop() override;
bool isRunning() const { return m_isRunning.load(); }
// 设置回调函数
virtual void setWriteCoilsCallback(WriteCoilsCallback callback) override { m_writeCoilsCallback = callback; }
virtual void setWriteRegistersCallback(WriteRegistersCallback callback) override { m_writeRegistersCallback = callback; }
virtual void setConnectionStatusCallback(ConnectionStatusCallback callback) override { m_connectionStatusCallback = callback; }
// 数据更新接口 - 线程安全
virtual void updateCoil(uint16_t address, bool value) override;
@ -111,6 +112,7 @@ private:
// 回调函数
WriteCoilsCallback m_writeCoilsCallback;
WriteRegistersCallback m_writeRegistersCallback;
ConnectionStatusCallback m_connectionStatusCallback;
// 错误信息
mutable std::mutex m_errorMutex;
@ -120,4 +122,4 @@ private:
void setLastError(const std::string& error);
};
#endif // MODBUS_TCP_SERVER_H
#endif // MODBUS_TCP_SERVER_H

View File

@ -17,9 +17,14 @@ CVrEyeCommon* CVrEyeCommon::GetInstance()
int CVrEyeCommon::InitDevice()
{
int nErrCode = SUCCESS;
if(m_bInit) return nErrCode;
// 初始化SDK
SVzNLConfigParam sVzNlConfigParam;
nErrCode = VzNL_Init(&sVzNlConfigParam);
m_bInit = (SUCCESS == nErrCode);
return nErrCode;
}

View File

@ -1,6 +1,6 @@
#ifndef VREYECOMMON_H
#define VREYECOMMON_H
#include <atomic>
class CVrEyeCommon
{
@ -12,6 +12,9 @@ public:
int InitDevice();
private:
std::atomic<bool> m_bInit = false;
};
#endif // VREYECOMMON_H

View File

@ -54,7 +54,6 @@
#define _CRT_SECURE_NO_WARNINGS
////定义Log�
///******************************************************************************************************************/
#ifdef __ANDROID__
#include <android/log.h>
@ -65,28 +64,6 @@
#define LOG_ERRO(...) __android_log_print(ANDROID_LOG_ERROR, "VrAPPE", ##__VA_ARGS__)
#else
//#ifdef QT_CORE_LIB
//#define LOG_TIME do { \
//std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); \
// std::time_t timestamp = std::chrono::system_clock::to_time_t(now); \
// std::tm local_time; \
// localtime_s(&local_time, &timestamp); \
// long long milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count(); \
// char varTime[128] = { 0 }; \
// sprintf_s(varTime, "%d-%02d-%02d %02d:%02d:%02d.%03lld", local_time.tm_year + 1900 , local_time.tm_mon + 1, local_time.tm_mday, local_time.tm_hour, local_time.tm_min, local_time.tm_sec, milliseconds % 1000); \
// _LOG_OUTPUT << varTime; \
//} while(0)
//#define LOG_VERBOSE(level,fmt, ...) do { if(level <= 1) { _EchoLog( true, "V", logfilename(__FILE__), __LINE__, fmt ); }} while(0)
//#define LOG_DEBUG(level,fmt, ...) do { if(level <= 2) { _EchoLog( true, "D", logfilename(__FILE__), __LINE__, fmt ); }} while(0)
//#define LOG_DEBUG_NOLINE(level,fmt, ...) do { if(level <= 3) { _EchoLog( false, "D", logfilename(__FILE__), __LINE__, fmt ); }} while(0)
//#define LOG_INFO(level,fmt, ...) do { if(level <= 3) { _EchoLog( true, "I", logfilename(__FILE__), __LINE__, fmt ); }} while(0)
//#define LOG_WARNING(level,fmt, ...) do { if(level <= 4) { _EchoLog( true, "W", logfilename(__FILE__), __LINE__, fmt ); }} while(0)
//#define LOG_ERRO(level,fmt, ...) do { if(level <= 5) { _EchoLog( true, "E", logfilename(__FILE__), __LINE__, fmt ); }} while(0)
//#define LOG_ERR(level,fmt, ...) do { if(level <= 5) { _EchoLog( true, "E", logfilename(__FILE__), __LINE__, fmt ); }} while(0)
//#else
#if 0
#include <qdebug.h>
@ -105,48 +82,14 @@ std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
} while(0)
#define LOG_VERBOSE(fmt, ...) do { { LOG_TIME; _LOG_OUTPUT(" V[%s : %4u] " fmt"", logfilename(__FILE__), __LINE__ ,##__VA_ARGS__); }} while(0)
#define LOG_DEBUG(fmt, ...) do { { LOG_TIME; _LOG_OUTPUT(" D[%s : %4u] " fmt"", logfilename(__FILE__), __LINE__ ,##__VA_ARGS__); }} while(0)
#define LOG_DEBUG_NOLINE(fmt, ...) do { { printf(fmt, ##__VA_ARGS__); }} while(0)
#define LOG_INFO(fmt, ...) do { { LOG_TIME; _LOG_OUTPUT(" I[%s : %4u] " fmt"", logfilename(__FILE__), __LINE__ ,##__VA_ARGS__); }} while(0)
#define LOG_WARNING(fmt, ...) do { { LOG_TIME; _LOG_OUTPUT(" W[%s : %4u] " fmt"", logfilename(__FILE__), __LINE__ ,##__VA_ARGS__); }} while(0)
#define LOG_ERRO(fmt, ...) do { { LOG_TIME; _LOG_OUTPUT(" E[%s : %4u] " fmt"", logfilename(__FILE__), __LINE__ ,##__VA_ARGS__); }} while(0)
#define LOG_ERR(fmt, ...) do { { LOG_TIME; _LOG_OUTPUT(" E[%s : %4u] " fmt"", logfilename(__FILE__), __LINE__ ,##__VA_ARGS__); }} while(0)
//#endif
#define LOG_VERBOSE(fmt, ...) do { { LOG_TIME; _LOG_OUTPUT(" V[%20s : %4u] " fmt"", logfilename(__FILE__), __LINE__ ,##__VA_ARGS__); } fflush(stdout); } while(0)
#define LOG_DEBUG(fmt, ...) do { { LOG_TIME; _LOG_OUTPUT(" D[%20s : %4u] " fmt"", logfilename(__FILE__), __LINE__ ,##__VA_ARGS__); } fflush(stdout); } while(0)
#define LOG_DEBUG_NOLINE(fmt, ...) do { { printf(fmt, ##__VA_ARGS__); } fflush(stdout); } while(0)
#define LOG_INFO(fmt, ...) do { { LOG_TIME; _LOG_OUTPUT(" I[%20s : %4u] " fmt"", logfilename(__FILE__), __LINE__ ,##__VA_ARGS__); } fflush(stdout);} while(0)
#define LOG_WARNING(fmt, ...) do { { LOG_TIME; _LOG_OUTPUT(" W[%20s : %4u] " fmt"", logfilename(__FILE__), __LINE__ ,##__VA_ARGS__); } fflush(stdout); } while(0)
#define LOG_ERROR(fmt, ...) do { { LOG_TIME; _LOG_OUTPUT(" E[%20s : %4u] " fmt"", logfilename(__FILE__), __LINE__ ,##__VA_ARGS__); } fflush(stdout); } while(0)
#define LOG_ERRO(fmt, ...) do { { LOG_TIME; _LOG_OUTPUT(" E[%20s : %4u] " fmt"", logfilename(__FILE__), __LINE__ ,##__VA_ARGS__); } fflush(stdout); } while(0)
#define LOG_ERR(fmt, ...) do { { LOG_TIME; _LOG_OUTPUT(" E[%20s : %4u] " fmt"", logfilename(__FILE__), __LINE__ ,##__VA_ARGS__); } fflush(stdout); } while(0)
#endif
///******************************************************************************************************************/
#if 0
static void _EchoLog(const bool bLogHead, const char* sTag, const char* fileName, const int nLenNo, const char* sFormat, ...)
{
// load log info
va_list args;
va_start(args, sFormat);
char szLogInfo[1024] = { 0 };
#ifdef _WIN32
vsprintf_s(szLogInfo, sFormat, args);
#else
vsprintf(szLogInfo, sFormat, args);
#endif
va_end(args);
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
std::time_t timestamp = std::chrono::system_clock::to_time_t(now);
std::tm local_time;
localtime_s(&local_time, &timestamp);
long long milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
char varTime[128] = { 0 };
sprintf_s(varTime, "%d-%02d-%02d %02d:%02d:%02d.%03lld", local_time.tm_year + 1900 , local_time.tm_mon + 1, local_time.tm_mday, local_time.tm_hour, local_time.tm_min, local_time.tm_sec, milliseconds % 1000);
if(bLogHead)
{
_LOG_OUTPUT << varTime << "[" << sTag << fileName << ":" << nLenNo << "]" << szLogInfo;
}
else
{
_LOG_OUTPUT << szLogInfo;
}
}
#endif