2026-02-02 23:24:24 +08:00

160 lines
5.2 KiB
C++
Raw 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.

#ifndef PLC_MODBUS_CLIENT_H
#define PLC_MODBUS_CLIENT_H
#include <thread>
#include <mutex>
#include <functional>
#include <vector>
#include <atomic>
#include <string>
#include "IYModbusTCPClient.h"
/**
* @brief PLC Modbus 通信客户端(纯 std::thread 实现,无 Qt 依赖)
*
* 协议流程:
* 1. 轮询读取 PLC D1000 寄存器,=1 时触发拍照
* 2. 拍照执行后,写 0 到 D1000
* 3. 拍照完成,输出坐标数据到 D2000 开始
* 4. 坐标数据输出完成,写 1 到 D1002
*
* 线程模型:
* - 单一轮询线程:连接检测、自动重连、寄存器读取
* - 回调在轮询线程执行,调用方需注意线程安全
*
* 锁策略:
* - m_mutex: 保护 m_plcClient
* - m_callbackMutex: 保护回调函数指针
* - 回调通知时先复制回调再释放锁,避免死锁
*/
class PLCModbusClient
{
public:
// PLC 寄存器地址默认值(汇川 PLC D寄存器映射
static constexpr int DEFAULT_ADDR_PHOTO_REQUEST = 1001; // D1000
static constexpr int DEFAULT_ADDR_DATA_COMPLETE = 1003; // D1002
static constexpr int DEFAULT_ADDR_COORD_DATA_START = 2001; // D2000
struct RegisterConfig {
int addrPhotoRequest = 1001; // D1000
int addrDataComplete = 1003; // D1002
int addrCoordDataStart = 2001; // D2000
};
struct CoordinateData {
float x = 0.0f;
float y = 0.0f;
float z = 0.0f;
float roll = 0.0f;
float pitch = 0.0f;
float yaw = 0.0f;
};
static constexpr int REGS_PER_POINT = 12;
static constexpr int MAX_POINTS = 10;
// 回调类型
using PhotoTriggerCallback = std::function<void(int cameraIndex)>;
using ConnectionStateCallback = std::function<void(bool connected)>;
using ErrorCallback = std::function<void(const std::string& errorMsg)>;
using ReconnectingCallback = std::function<void(const std::string& device, int attempt)>;
public:
PLCModbusClient();
~PLCModbusClient();
// 禁止拷贝和移动
PLCModbusClient(const PLCModbusClient&) = delete;
PLCModbusClient& operator=(const PLCModbusClient&) = delete;
PLCModbusClient(PLCModbusClient&&) = delete;
PLCModbusClient& operator=(PLCModbusClient&&) = delete;
// ========== 生命周期 ==========
bool Initialize(const std::string& plcIP, int plcPort = 502);
bool Initialize(const std::string& plcIP, int plcPort,
const RegisterConfig& regConfig);
void Shutdown();
void StartPolling(int intervalMs = 100);
void StopPolling();
// ========== 回调设置 ==========
void SetPhotoTriggerCallback(PhotoTriggerCallback callback);
void SetConnectionStateCallback(ConnectionStateCallback callback);
void SetErrorCallback(ErrorCallback callback);
void SetReconnectingCallback(ReconnectingCallback callback);
// ========== 配置 ==========
void SetReconnectInterval(int intervalMs);
void SetAutoReconnect(bool enable);
// ========== PLC 操作 ==========
bool SendCoordinateToPLC(const CoordinateData& coord, int pointIndex = 0);
bool SendCoordinatesToPLC(const std::vector<CoordinateData>& coords);
bool NotifyDataComplete();
bool ClearPhotoRequest();
// ========== 轮询控制 ==========
void PausePhotoRequestPolling(); // 暂停读取拍照请求(检测期间调用)
void ResumePhotoRequestPolling(); // 恢复读取拍照请求(检测完成后调用)
bool IsPhotoRequestPollingPaused() const;
// ========== 状态查询 ==========
bool IsPLCConnected() const;
private:
// 轮询线程
void pollThreadFunc();
// 连接管理
bool checkConnection();
bool tryConnectPLC();
void disconnectPLC(); // 主动断开连接(用于触发重连)
// 寄存器操作
int readPhotoRequest();
void floatToRegisters(float value, uint16_t& high, uint16_t& low);
// 安全的回调通知(先复制回调,释放锁后再调用)
void notifyConnectionStateChanged(bool connected);
void notifyError(const std::string& errorMsg);
void notifyPhotoRequested(int cameraIndex);
void notifyReconnecting(const std::string& device, int attempt);
private:
// PLC 客户端
IYModbusTCPClient* m_plcClient;
// 回调函数
PhotoTriggerCallback m_photoCallback;
ConnectionStateCallback m_connectionStateCallback;
ErrorCallback m_errorCallback;
ReconnectingCallback m_reconnectingCallback;
// 连接配置
std::string m_plcIP;
int m_plcPort;
RegisterConfig m_registerConfig;
// 状态
bool m_lastPhotoRequestState;
bool m_lastConnectedState;
// 线程控制
std::thread m_pollThread;
std::atomic<bool> m_pollRunning;
std::atomic<bool> m_photoRequestPaused; // 暂停拍照请求轮询标志
int m_pollIntervalMs;
// 重连控制
std::atomic<bool> m_shutdownRequested;
std::atomic<bool> m_autoReconnect;
int m_reconnectInterval;
int m_plcReconnectAttempts;
// 互斥锁
mutable std::mutex m_mutex;
std::mutex m_callbackMutex;
};
#endif // PLC_MODBUS_CLIENT_H