202 lines
6.5 KiB
C++
202 lines
6.5 KiB
C++
|
|
#include "RobotProtocol.h"
|
|||
|
|
#include "VrLog.h"
|
|||
|
|
#include "VrError.h"
|
|||
|
|
#include "IYModbusTCPServer.h"
|
|||
|
|
#include <cstring>
|
|||
|
|
#include <algorithm>
|
|||
|
|
|
|||
|
|
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) {
|
|||
|
|
LOG_WARNING("Server is already running\n");
|
|||
|
|
return SUCCESS;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
m_nPort = port;
|
|||
|
|
|
|||
|
|
// 创建ModbusTCP服务器实例
|
|||
|
|
bool bRet = IYModbusTCPServer::CreateInstance(&m_pModbusServer);
|
|||
|
|
LOG_DEBUG("Create ModbusTCP server %s \n", bRet ? "success" : "failed");
|
|||
|
|
m_bServerRunning = bRet;
|
|||
|
|
|
|||
|
|
// 设置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(m_nPort);
|
|||
|
|
ERR_CODE_RETURN(nRet);
|
|||
|
|
|
|||
|
|
// 设置初始状态
|
|||
|
|
m_robotStatus = STATUS_CONNECTED;
|
|||
|
|
|
|||
|
|
// 设置初始工作状态为空闲
|
|||
|
|
SetWorkStatus(WORK_STATUS_IDLE);
|
|||
|
|
|
|||
|
|
LOG_INFO("ModbusTCP service initialization completed\n");
|
|||
|
|
return SUCCESS;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void RobotProtocol::Deinitialize()
|
|||
|
|
{
|
|||
|
|
LOG_DEBUG("Stop ModbusTCP service\n");
|
|||
|
|
|
|||
|
|
// 停止ModbusTCP服务器
|
|||
|
|
StopModbusTCPServer();
|
|||
|
|
|
|||
|
|
// 重置状态
|
|||
|
|
m_robotStatus = STATUS_DISCONNECTED;
|
|||
|
|
m_bServerRunning = false;
|
|||
|
|
|
|||
|
|
LOG_INFO("ModbusTCP service stopped\n");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int RobotProtocol::SetMultiTargetData(const MultiTargetData& multiTargetData)
|
|||
|
|
{
|
|||
|
|
// 数据格式: count + 每个目标的{id,status,width,depth}数据(每个数据占2个寄存器)
|
|||
|
|
std::vector<uint16_t> data;
|
|||
|
|
// 限制最大目标数量
|
|||
|
|
size_t actualCount = multiTargetData.targets.size() > 5 ? 5 : multiTargetData.targets.size();
|
|||
|
|
data.resize(actualCount * 16);
|
|||
|
|
memset(data.data(), 0, data.size() * sizeof(uint16_t));
|
|||
|
|
|
|||
|
|
// 定义一个辅助函数来转换uint32_t到ModbusTCP寄存器顺序大端格式
|
|||
|
|
auto uint32ToBigEndian = [&](uint16_t addr, uint32_t value) {
|
|||
|
|
// ModbusTCP寄存器顺序大端:高16位寄存器在前,低16位寄存器在后
|
|||
|
|
data[addr] = (value >> 16) & 0xFFFF; // 高16位寄存器
|
|||
|
|
data[addr+1] = value & 0xFFFF; // 低16位寄存器
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 定义一个辅助函数来转换float到ModbusTCP寄存器顺序大端格式
|
|||
|
|
auto floatToBigEndian = [&](uint16_t addr, float value) {
|
|||
|
|
uint32_t intValue;
|
|||
|
|
memcpy(&intValue, &value, sizeof(float));
|
|||
|
|
// ModbusTCP寄存器顺序大端:高16位寄存器在前,低16位寄存器在后
|
|||
|
|
data[addr] = (intValue >> 16) & 0xFFFF; // 高16位寄存器
|
|||
|
|
data[addr+1] = intValue & 0xFFFF; // 低16位寄存器
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 定义一个辅助函数来转换uint16_t到ModbusTCP寄存器
|
|||
|
|
auto uint16ToBigEndian = [&](uint16_t addr, uint16_t value) {
|
|||
|
|
data[addr] = value; // uint16_t直接存储
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 从第二个寄存器开始存储目标数据 count [{id,status,width,depth}, {id,status,width,depth}]
|
|||
|
|
for (size_t i = 0; i < actualCount; i++) {
|
|||
|
|
uint16_t addr = i * RESULT_OFFSET_ADDR;
|
|||
|
|
const TargetResult& target = multiTargetData.targets[i];
|
|||
|
|
|
|||
|
|
// 按照 id, status, width, depth 的顺序存储每个目标的数据
|
|||
|
|
uint32ToBigEndian(addr, target.id); // ID (2个寄存器)
|
|||
|
|
uint16ToBigEndian(addr+2, target.status); // Status (1个寄存器)
|
|||
|
|
floatToBigEndian(addr+3, target.width); // Width (2个寄存器)
|
|||
|
|
floatToBigEndian(addr+5, target.depth); // Depth (2个寄存器)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
m_pModbusServer->updateHoldingRegisters(DETECT_RESULT_ADDR, data);
|
|||
|
|
|
|||
|
|
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;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
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_WORKING: statusStr = "工作中"; break;
|
|||
|
|
case WORK_STATUS_BUSY: statusStr = "忙碌"; break;
|
|||
|
|
default: statusStr = "未知状态"; break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
LOG_INFO("Work status updated to: %d (%s)\n", status, statusStr);
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void RobotProtocol::StopModbusTCPServer()
|
|||
|
|
{
|
|||
|
|
LOG_DEBUG("Stop ModbusTCP server\n");
|
|||
|
|
|
|||
|
|
if (m_pModbusServer) {
|
|||
|
|
// 释放资源
|
|||
|
|
delete m_pModbusServer;
|
|||
|
|
m_pModbusServer = nullptr;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
m_bServerRunning = false;
|
|||
|
|
LOG_INFO("ModbusTCP server stopped\n");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
IYModbusTCPServer::ErrorCode RobotProtocol::OnWriteCoils(uint8_t unitId, uint16_t startAddress, uint16_t quantity, const uint8_t* values)
|
|||
|
|
{
|
|||
|
|
return IYModbusTCPServer::ErrorCode::ILLEGAL_FUNCTION;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
IYModbusTCPServer::ErrorCode RobotProtocol::OnWriteRegisters(uint8_t unitId, uint16_t startAddress, uint16_t quantity, const uint16_t* values)
|
|||
|
|
{
|
|||
|
|
return IYModbusTCPServer::ErrorCode::ILLEGAL_FUNCTION;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void RobotProtocol::OnModbusTCPConnectionChanged(bool connected)
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
}
|