/** * @file TCPServerMethods.cpp * @brief ScrewPositionPresenter TCP/Modbus communication methods */ #include "ScrewPositionPresenter.h" #include "DetectionOutputConverter.h" #include "VrLog.h" #include #include #include 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((raw >> 16) & 0xFFFF); low = static_cast(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 void FillPoseRegisters(const PoseT& pose, int poseOutputOrder, std::array& 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(pose.x), static_cast(pose.y), static_cast(pose.z), static_cast(angle1), static_cast(angle2), static_cast(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(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 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 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 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(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()) { pStatus->OnRobotConnectionChanged(connected); pStatus->OnStatusUpdate(connected ? "TCP连接成功" : "TCP连接失败"); } CheckAndUpdateWorkStatus(); } void ScrewPositionPresenter::SendDetectionResultToClient(const DetectionResult& result) { _SendDetectionResultToTCP(result, result.cameraIndex); }