261 lines
8.6 KiB
C++
Raw Permalink 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 "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 SUCCESS;
}
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;
}
void RobotProtocol::SetSystemControlCallback(const std::function<void(uint16_t)>& callback)
{
m_systemControlCallback = 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 ERR_CODE(DEV_NO_OPEN);
}
// 更新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 SUCCESS;
}
int RobotProtocol::ClearDetectionData()
{
LOG_INFO("Clearing detection result data in Modbus registers\n");
if (!m_pModbusServer) {
LOG_ERROR("ModbusTCP server not initialized\n");
return ERR_CODE(DEV_NO_OPEN);
}
// 清空检测结果数据区域地址1-80共5个撕裂信息每个16个寄存器
// 总共需要清空 5 * 16 = 80 个寄存器
std::vector<uint16_t> clearData(80, 0); // 创建80个值为0的寄存器
m_pModbusServer->updateHoldingRegisters(DETECT_RESULT_ADDR, clearData);
LOG_INFO("Detection result data cleared (registers 1-80)\n");
return SUCCESS;
}
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)
{
// 只允许写入地址0系统状态寄存器
if (startAddress != STATUS_ADDR) {
LOG_WARNING("Attempt to write to read-only address: %d\n", startAddress);
return IYModbusTCPServer::ErrorCode::ILLEGAL_DATA_ADDRESS;
}
// 只允许写入单个寄存器
if (quantity != 1) {
LOG_WARNING("Invalid quantity for status register write: %d\n", quantity);
return IYModbusTCPServer::ErrorCode::ILLEGAL_DATA_VALUE;
}
if (!values) {
LOG_ERROR("Null values pointer in write registers\n");
return IYModbusTCPServer::ErrorCode::SERVER_FAILURE;
}
uint16_t command = values[0];
// 验证命令值是否有效0-停止, 1-开始, 2-复位)
if (command > 2) {
LOG_WARNING("Invalid system control command: %d\n", command);
return IYModbusTCPServer::ErrorCode::ILLEGAL_DATA_VALUE;
}
LOG_INFO("Received system control command via ModbusTCP: %d\n", command);
// 调用系统控制回调
if (m_systemControlCallback) {
m_systemControlCallback(command);
LOG_DEBUG("System control callback executed for command: %d\n", command);
} else {
LOG_WARNING("System control callback not set\n");
}
return IYModbusTCPServer::ErrorCode::SUCCESS;
}
void RobotProtocol::OnModbusTCPConnectionChanged(bool connected)
{
}