2025-06-08 12:48:04 +08:00
|
|
|
|
#include "RobotProtocol.h"
|
2025-06-17 00:37:05 +08:00
|
|
|
|
#include "VrLog.h"
|
2025-06-08 12:48:04 +08:00
|
|
|
|
#include "VrError.h"
|
|
|
|
|
|
#include <cstring>
|
2025-06-22 14:08:15 +08:00
|
|
|
|
#include <algorithm>
|
2025-06-08 12:48:04 +08:00
|
|
|
|
|
|
|
|
|
|
RobotProtocol::RobotProtocol()
|
|
|
|
|
|
: m_pModbusServer(nullptr)
|
|
|
|
|
|
, m_bServerRunning(false)
|
|
|
|
|
|
, m_nPort(502)
|
|
|
|
|
|
, m_robotStatus(STATUS_DISCONNECTED)
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RobotProtocol::~RobotProtocol()
|
|
|
|
|
|
{
|
|
|
|
|
|
Deinitialize();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int RobotProtocol::Initialize(uint16_t port)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (m_bServerRunning) {
|
2025-06-08 23:51:48 +08:00
|
|
|
|
LOG_WARNING("Server is already running\n");
|
2025-06-08 12:48:04 +08:00
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
m_nPort = port;
|
|
|
|
|
|
|
|
|
|
|
|
// 创建ModbusTCP服务器实例
|
|
|
|
|
|
bool bRet = IYModbusTCPServer::CreateInstance(&m_pModbusServer);
|
2025-06-17 00:37:05 +08:00
|
|
|
|
LOG_DEBUG("Create ModbusTCP server %s \n", bRet ? "success" : "failed");
|
2025-06-08 12:48:04 +08:00
|
|
|
|
m_bServerRunning = bRet;
|
2025-06-08 23:51:48 +08:00
|
|
|
|
|
|
|
|
|
|
// 设置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);
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-06-22 14:08:15 +08:00
|
|
|
|
int nRet = m_pModbusServer->start(m_nPort);
|
2025-06-08 23:51:48 +08:00
|
|
|
|
ERR_CODE_RETURN(nRet);
|
|
|
|
|
|
|
2025-06-08 12:48:04 +08:00
|
|
|
|
// 设置初始状态
|
|
|
|
|
|
m_robotStatus = STATUS_CONNECTED;
|
2025-06-22 14:08:15 +08:00
|
|
|
|
|
|
|
|
|
|
// 设置初始工作状态为空闲
|
|
|
|
|
|
SetWorkStatus(WORK_STATUS_IDLE);
|
2025-06-08 12:48:04 +08:00
|
|
|
|
|
2025-06-08 23:51:48 +08:00
|
|
|
|
LOG_INFO("ModbusTCP service initialization completed\n");
|
|
|
|
|
|
return SUCCESS;
|
2025-06-08 12:48:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RobotProtocol::Deinitialize()
|
|
|
|
|
|
{
|
2025-06-08 23:51:48 +08:00
|
|
|
|
LOG_DEBUG("Stop ModbusTCP service\n");
|
2025-06-08 12:48:04 +08:00
|
|
|
|
|
|
|
|
|
|
// 停止ModbusTCP服务器
|
|
|
|
|
|
StopModbusTCPServer();
|
|
|
|
|
|
|
|
|
|
|
|
// 重置状态
|
|
|
|
|
|
m_robotStatus = STATUS_DISCONNECTED;
|
|
|
|
|
|
m_bServerRunning = false;
|
|
|
|
|
|
|
2025-06-08 23:51:48 +08:00
|
|
|
|
LOG_INFO("ModbusTCP service stopped\n");
|
2025-06-08 12:48:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-06-22 14:08:15 +08:00
|
|
|
|
int RobotProtocol::SetMultiTargetData(const MultiTargetData& multiTargetData, uint16_t cameraId)
|
2025-06-08 12:48:04 +08:00
|
|
|
|
{
|
2025-06-22 14:08:15 +08:00
|
|
|
|
LOG_DEBUG("Set multi-target data, count: %d, camera ID: %d\n", multiTargetData.count, cameraId);
|
|
|
|
|
|
|
|
|
|
|
|
// 验证相机ID有效性(从1开始编号:1,2,...)
|
|
|
|
|
|
if (cameraId < 1 || cameraId > 2) {
|
|
|
|
|
|
LOG_ERROR("Invalid camera ID: %d, valid range is 1-2\n", cameraId);
|
|
|
|
|
|
return -1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 数据格式: count + 每个目标的{x,y,z,rz}坐标(每个坐标占2个寄存器)
|
|
|
|
|
|
std::vector<uint16_t> data;
|
|
|
|
|
|
data.resize(multiTargetData.count * 8 + 1);
|
2025-06-08 12:48:04 +08:00
|
|
|
|
|
2025-06-22 14:08:15 +08:00
|
|
|
|
// 限制最大目标数量
|
|
|
|
|
|
uint16_t actualCount = multiTargetData.count;
|
2025-06-08 12:48:04 +08:00
|
|
|
|
|
2025-06-22 14:08:15 +08:00
|
|
|
|
// 根据相机ID确定起始地址(cameraId: 1->COORD_ONE, 2->COORD_TWO)
|
|
|
|
|
|
uint16_t startAddr = (cameraId == 1) ? COORD_ONE_START_ADDR : COORD_TWO_START_ADDR;
|
|
|
|
|
|
|
|
|
|
|
|
// 设置目标数量
|
|
|
|
|
|
data[0] = actualCount;
|
2025-06-08 12:48:04 +08:00
|
|
|
|
|
2025-06-22 14:08:15 +08:00
|
|
|
|
// 从第二个寄存器开始存储坐标数据 count [{x,y,z,rz}, {x,y,z,rz}]
|
|
|
|
|
|
uint16_t dataIndex = 2;
|
|
|
|
|
|
|
|
|
|
|
|
// 定义一个辅助函数来转换float到ModbusTCP寄存器顺序大端格式
|
|
|
|
|
|
auto floatToBigEndian = [&](float value) {
|
|
|
|
|
|
uint32_t intValue;
|
|
|
|
|
|
memcpy(&intValue, &value, sizeof(float));
|
|
|
|
|
|
// ModbusTCP寄存器顺序大端:高16位寄存器在前,低16位寄存器在后
|
|
|
|
|
|
// 每个寄存器内部保持主机字节序
|
|
|
|
|
|
data[dataIndex++] = (intValue >> 16) & 0xFFFF; // 高16位寄存器
|
|
|
|
|
|
data[dataIndex++] = intValue & 0xFFFF; // 低16位寄存器
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
for (uint16_t i = 0; i < actualCount; i++) {
|
|
|
|
|
|
const TargetPosition& target = multiTargetData.targets[i];
|
|
|
|
|
|
|
|
|
|
|
|
// 按照 x, y, z, rz 的顺序存储每个目标的坐标
|
|
|
|
|
|
floatToBigEndian(target.x); // X坐标 (2个寄存器)
|
|
|
|
|
|
floatToBigEndian(target.y); // Y坐标 (2个寄存器)
|
|
|
|
|
|
floatToBigEndian(target.z); // Z坐标 (2个寄存器)
|
|
|
|
|
|
floatToBigEndian(target.rz); // RZ坐标 (2个寄存器)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
m_pModbusServer->updateHoldingRegisters(startAddr, data);
|
|
|
|
|
|
|
2025-06-08 12:48:04 +08:00
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RobotProtocol::RobotStatus RobotProtocol::GetDetectionStatus() const
|
|
|
|
|
|
{
|
|
|
|
|
|
return m_robotStatus;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RobotProtocol::SetConnectionCallback(const ConnectionCallback& callback)
|
|
|
|
|
|
{
|
|
|
|
|
|
m_connectionCallback = callback;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RobotProtocol::SetWorkSignalCallback(const WorkSignalCallback& callback)
|
|
|
|
|
|
{
|
|
|
|
|
|
m_workSignalCallback = callback;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool RobotProtocol::IsRunning() const
|
|
|
|
|
|
{
|
|
|
|
|
|
return m_bServerRunning;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-06-22 14:08:15 +08:00
|
|
|
|
int RobotProtocol::SetWorkStatus(uint16_t status)
|
|
|
|
|
|
{
|
|
|
|
|
|
LOG_DEBUG("Set work status to: %d\n", status);
|
|
|
|
|
|
|
|
|
|
|
|
if (!m_pModbusServer) {
|
|
|
|
|
|
LOG_ERROR("ModbusTCP server not initialized\n");
|
|
|
|
|
|
return -1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新STATUS_ADDR地址的寄存器值
|
|
|
|
|
|
std::vector<uint16_t> statusData;
|
|
|
|
|
|
statusData.push_back(status);
|
|
|
|
|
|
|
|
|
|
|
|
m_pModbusServer->updateHoldingRegisters(STATUS_ADDR, statusData);
|
|
|
|
|
|
|
|
|
|
|
|
const char* statusStr = "";
|
|
|
|
|
|
switch(status) {
|
|
|
|
|
|
case WORK_STATUS_IDLE: statusStr = "空闲"; break;
|
|
|
|
|
|
case WORK_STATUS_CAMERA1_DONE: statusStr = "相机1工作完成"; break;
|
|
|
|
|
|
case WORK_STATUS_CAMERA2_DONE: statusStr = "相机2工作完成"; break;
|
|
|
|
|
|
case WORK_STATUS_BUSY: statusStr = "忙碌"; break;
|
|
|
|
|
|
default: statusStr = "未知状态"; break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LOG_INFO("Work status updated to: %d (%s)\n", status, statusStr);
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-06-08 12:48:04 +08:00
|
|
|
|
void RobotProtocol::StopModbusTCPServer()
|
|
|
|
|
|
{
|
2025-06-08 23:51:48 +08:00
|
|
|
|
LOG_DEBUG("Stop ModbusTCP server\n");
|
2025-06-08 12:48:04 +08:00
|
|
|
|
|
|
|
|
|
|
if (m_pModbusServer) {
|
|
|
|
|
|
// 释放资源
|
|
|
|
|
|
delete m_pModbusServer;
|
|
|
|
|
|
m_pModbusServer = nullptr;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
m_bServerRunning = false;
|
2025-06-08 23:51:48 +08:00
|
|
|
|
LOG_INFO("ModbusTCP server stopped\n");
|
2025-06-08 12:48:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-06-20 01:28:00 +08:00
|
|
|
|
IYModbusTCPServer::ErrorCode RobotProtocol::OnWriteCoils(uint8_t unitId, uint16_t startAddress, uint16_t quantity, const uint8_t* values)
|
2025-06-08 12:48:04 +08:00
|
|
|
|
{
|
2025-06-08 23:51:48 +08:00
|
|
|
|
LOG_DEBUG("Write coils - UnitID:%d, StartAddress:%d, Quantity:%d\n", unitId, startAddress, quantity);
|
2025-06-08 12:48:04 +08:00
|
|
|
|
|
|
|
|
|
|
// 处理工作信号线圈
|
2025-06-22 14:08:15 +08:00
|
|
|
|
if (startAddress == WORK_SIGNAL_ADDR) {
|
|
|
|
|
|
bool workSignal = (values[0] >> 0) & 0x01;
|
|
|
|
|
|
|
|
|
|
|
|
LOG_INFO("Received work signal: %s (coil address: %d)\n",
|
|
|
|
|
|
(workSignal ? "start work" : "stop work"), startAddress);
|
|
|
|
|
|
|
|
|
|
|
|
// 触发工作信号回调(使用相机ID 1作为默认值)
|
|
|
|
|
|
if (m_workSignalCallback) {
|
|
|
|
|
|
m_workSignalCallback(workSignal, 1); // 默认相机ID为1
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
LOG_WARNING("Unknown coil address: %d\n", startAddress);
|
|
|
|
|
|
return IYModbusTCPServer::ErrorCode::ILLEGAL_DATA_ADDRESS;
|
2025-06-08 12:48:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return IYModbusTCPServer::ErrorCode::SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-06-20 01:28:00 +08:00
|
|
|
|
IYModbusTCPServer::ErrorCode RobotProtocol::OnWriteRegisters(uint8_t unitId, uint16_t startAddress, uint16_t quantity, const uint16_t* values)
|
2025-06-08 12:48:04 +08:00
|
|
|
|
{
|
2025-06-08 23:51:48 +08:00
|
|
|
|
LOG_DEBUG("Write registers - UnitID:%d, StartAddress:%d, Quantity:%d\n", unitId, startAddress, quantity);
|
2025-06-08 12:48:04 +08:00
|
|
|
|
|
|
|
|
|
|
// 处理坐标寄存器更新
|
2025-06-20 01:28:00 +08:00
|
|
|
|
if(quantity > 1) return IYModbusTCPServer::ErrorCode::ILLEGAL_DATA_VALUE;
|
|
|
|
|
|
|
2025-06-22 14:08:15 +08:00
|
|
|
|
if(nullptr == m_workSignalCallback) return IYModbusTCPServer::ErrorCode::GATEWAY_TARGET_FAILED;
|
|
|
|
|
|
|
2025-06-20 01:28:00 +08:00
|
|
|
|
IYModbusTCPServer::ErrorCode eResult = IYModbusTCPServer::ErrorCode::SUCCESS;
|
2025-06-22 14:08:15 +08:00
|
|
|
|
|
2025-06-20 01:28:00 +08:00
|
|
|
|
switch (startAddress) {
|
2025-06-22 14:08:15 +08:00
|
|
|
|
case WORK_SIGNAL_ADDR:
|
|
|
|
|
|
// 解析工作信号寄存器
|
|
|
|
|
|
if(!m_workSignalCallback(true, (int)values[0])){
|
|
|
|
|
|
eResult = IYModbusTCPServer::ErrorCode::SERVER_FAILURE;
|
2025-06-08 12:48:04 +08:00
|
|
|
|
}
|
2025-06-20 01:28:00 +08:00
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
eResult = IYModbusTCPServer::ErrorCode::ILLEGAL_FUNCTION;
|
|
|
|
|
|
break;
|
2025-06-08 12:48:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-06-20 01:28:00 +08:00
|
|
|
|
return eResult;
|
2025-06-08 12:48:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-06-08 23:51:48 +08:00
|
|
|
|
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);
|
|
|
|
|
|
}
|
2025-06-08 12:48:04 +08:00
|
|
|
|
}
|