2026-04-17 10:18:03 +08:00

280 lines
7.9 KiB
C++

/**
* @file TCPServerMethods.cpp
* @brief ScrewPositionPresenter TCP/Modbus communication methods
*/
#include "ScrewPositionPresenter.h"
#include "DetectionOutputConverter.h"
#include "VrLog.h"
#include <array>
#include <cstdio>
#include <cstring>
namespace {
constexpr uint16_t kModbusTriggerAddress = 0;
constexpr uint16_t kModbusWorkStatusAddress = 1;
constexpr uint16_t kModbusRobotPoseAddress = 2;
constexpr uint16_t kModbusRobotPoseRegisterCount = 12;
constexpr uint16_t kModbusResultStartAddress = 14;
constexpr uint16_t kModbusResultRegisterCount = 12;
constexpr int kPoseOutputRxRyRz = 0;
constexpr int kPoseOutputRxRzRy = 1;
constexpr int kPoseOutputRyRxRz = 2;
constexpr int kPoseOutputRyRzRx = 3;
constexpr int kPoseOutputRzRxRy = 4;
constexpr int kPoseOutputRzRyRx = 5;
void FloatToRegisters(float value, uint16_t& high, uint16_t& low)
{
uint32_t raw = 0;
static_assert(sizeof(raw) == sizeof(value), "float size mismatch");
std::memcpy(&raw, &value, sizeof(value));
high = static_cast<uint16_t>((raw >> 16) & 0xFFFF);
low = static_cast<uint16_t>(raw & 0xFFFF);
}
void ReorderPoseAngles(double roll,
double pitch,
double yaw,
int poseOutputOrder,
double& angle1,
double& angle2,
double& angle3)
{
switch (poseOutputOrder) {
case kPoseOutputRxRzRy:
angle1 = roll;
angle2 = yaw;
angle3 = pitch;
break;
case kPoseOutputRyRxRz:
angle1 = pitch;
angle2 = roll;
angle3 = yaw;
break;
case kPoseOutputRyRzRx:
angle1 = pitch;
angle2 = yaw;
angle3 = roll;
break;
case kPoseOutputRzRxRy:
angle1 = yaw;
angle2 = roll;
angle3 = pitch;
break;
case kPoseOutputRzRyRx:
angle1 = yaw;
angle2 = pitch;
angle3 = roll;
break;
case kPoseOutputRxRyRz:
default:
angle1 = roll;
angle2 = pitch;
angle3 = yaw;
break;
}
}
template<typename PoseT>
void FillPoseRegisters(const PoseT& pose,
int poseOutputOrder,
std::array<uint16_t, kModbusResultRegisterCount>& registers)
{
double angle1 = 0.0;
double angle2 = 0.0;
double angle3 = 0.0;
ReorderPoseAngles(pose.roll, pose.pitch, pose.yaw, poseOutputOrder, angle1, angle2, angle3);
const float values[6] = {
static_cast<float>(pose.x),
static_cast<float>(pose.y),
static_cast<float>(pose.z),
static_cast<float>(angle1),
static_cast<float>(angle2),
static_cast<float>(angle3)
};
for (size_t i = 0; i < 6; ++i) {
FloatToRegisters(values[i], registers[i * 2], registers[i * 2 + 1]);
}
}
} // namespace
void ScrewPositionPresenter::_SendDetectionResultToTCP(const DetectionResult& result, int cameraIndex)
{
if (!m_pTCPServer || !m_pTCPServer->IsRunning()) {
LOG_WARNING("TCP protocol not running, skip sending result\n");
return;
}
(void)cameraIndex;
int poseOutputOrder = 0;
if (m_pConfigManager) {
poseOutputOrder = m_pConfigManager->GetConfigResult().poseOutputOrder;
}
int count = static_cast<int>(result.positions.size());
std::string resultText = std::to_string(count);
for (const auto& pos : result.positions) {
double angle1 = 0.0;
double angle2 = 0.0;
double angle3 = 0.0;
ReorderPoseAngles(pos.roll, pos.pitch, pos.yaw, poseOutputOrder, angle1, angle2, angle3);
char buf[256];
std::snprintf(buf, sizeof(buf), "_%.2f_%.2f_%.2f_%.2f_%.2f_%.2f/",
pos.x, pos.y, pos.z, angle1, angle2, angle3);
resultText += buf;
}
LOG_INFO("TCP result text: %s\n", resultText.c_str());
const int ret = m_pTCPServer->SendTextResult(resultText);
if (ret != 0) {
LOG_ERROR("Failed to send detection result via TCP, error: %d\n", ret);
}
}
void ScrewPositionPresenter::_PublishDetectionResultToModbus(const DetectionResult& result)
{
if (!IsModbusServerRunning()) {
return;
}
std::array<uint16_t, kModbusResultRegisterCount> registers{};
bool hasPose = false;
int poseOutputOrder = 0;
if (m_pConfigManager) {
poseOutputOrder = m_pConfigManager->GetConfigResult().poseOutputOrder;
}
if (!result.positions.empty()) {
FillPoseRegisters(result.positions.front(), poseOutputOrder, registers);
hasPose = true;
}
WriteModbusRegisters(kModbusResultStartAddress, registers.data(), kModbusResultRegisterCount);
LOG_DEBUG("Published Modbus pose registers, hasPose=%d\n", hasPose ? 1 : 0);
_UpdateModbusWorkStatus(result.success ? 2 : 3);
}
void ScrewPositionPresenter::_ResetModbusResultRegisters()
{
if (!IsModbusServerRunning()) {
return;
}
std::array<uint16_t, kModbusResultRegisterCount> zeros{};
WriteModbusRegisters(kModbusResultStartAddress, zeros.data(), kModbusResultRegisterCount);
}
void ScrewPositionPresenter::_UpdateModbusWorkStatus(uint16_t statusValue)
{
if (!IsModbusServerRunning()) {
m_modbusWorkStatus = statusValue;
return;
}
m_modbusWorkStatus = statusValue;
WriteModbusRegisters(kModbusWorkStatusAddress, &statusValue, 1);
}
void ScrewPositionPresenter::_InitializeModbusRegisters()
{
if (m_modbusRegistersInitialized || !IsModbusServerRunning()) {
return;
}
const uint16_t zero = 0;
WriteModbusRegisters(kModbusTriggerAddress, &zero, 1);
std::array<uint16_t, kModbusRobotPoseRegisterCount> robotZeros{};
WriteModbusRegisters(kModbusRobotPoseAddress, robotZeros.data(), kModbusRobotPoseRegisterCount);
_ResetModbusResultRegisters();
_UpdateModbusWorkStatus(0);
m_modbusRegistersInitialized = true;
}
RobotPose6D ScrewPositionPresenter::_ReadRobotPoseFromModbus()
{
RobotPose6D pose;
return pose;
}
int ScrewPositionPresenter::InitTCPServer()
{
if (m_pTCPServer) {
LOG_WARNING("TCP server already initialized\n");
return 0;
}
m_pTCPServer = new ScrewPositionTCPProtocol();
m_pTCPServer->SetConnectionCallback([this](bool connected) {
OnTCPConnectionChanged(connected);
});
m_pTCPServer->SetDetectionTriggerCallback(
[this](int cameraIndex, DetectionType detectionType, const RobotPose6D& robotPose) -> bool {
LOG_DEBUG("TCP triggered detection, cameraIndex: %d, type: %d\n",
cameraIndex, static_cast<int>(detectionType));
return TriggerDetection(cameraIndex, detectionType, robotPose);
});
uint16_t port = 7800;
if (m_pConfigManager) {
const ConfigResult configResult = m_pConfigManager->GetConfigResult();
port = configResult.tcpPort;
}
const int ret = m_pTCPServer->Initialize(port);
if (ret != 0) {
LOG_ERROR("Failed to initialize TCP protocol on port %d, error: %d\n", port, ret);
delete m_pTCPServer;
m_pTCPServer = nullptr;
return ret;
}
LOG_DEBUG("TCP text protocol initialized on port %d\n", port);
return 0;
}
void ScrewPositionPresenter::stopServer()
{
if (m_pTCPServer) {
m_pTCPServer->Deinitialize();
delete m_pTCPServer;
m_pTCPServer = nullptr;
m_bTCPConnected = false;
LOG_DEBUG("TCP server stopped\n");
}
}
void ScrewPositionPresenter::OnTCPConnectionChanged(bool connected)
{
m_bTCPConnected = connected;
LOG_DEBUG("TCP connection changed: %s\n", connected ? "connected" : "disconnected");
if (auto pStatus = GetStatusCallback<IYScrewPositionStatus>()) {
pStatus->OnRobotConnectionChanged(connected);
pStatus->OnStatusUpdate(connected ? "TCP连接成功" : "TCP连接失败");
}
CheckAndUpdateWorkStatus();
}
void ScrewPositionPresenter::SendDetectionResultToClient(const DetectionResult& result)
{
_SendDetectionResultToTCP(result, result.cameraIndex);
}