2026-02-23 18:22:38 +08:00

174 lines
5.7 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 依赖)
*
* 协议流程0-based 地址):
* 1. 轮询读取地址0触发寄存器边沿 0→1 时触发工作
* 2. 触发后写 0 到地址0清除触发
* 3. 写 0 到地址1工作状态=正在工作)
* 4. 工作完成输出坐标数据到地址2开始
* 5. 写 1 到地址1工作状态=完成正常),或写 2错误
*
* 线程模型:
* - 单一轮询线程:连接检测、自动重连、寄存器读取
* - 回调在轮询线程执行,调用方需注意线程安全
*
* 锁策略:
* - m_mutex: 保护 m_plcClient
* - m_callbackMutex: 保护回调函数指针
* - 回调通知时先复制回调再释放锁,避免死锁
*/
class PLCModbusClient
{
public:
// 寄存器地址默认值0-based 协议)
static constexpr int DEFAULT_ADDR_TRIGGER = 0; // 触发寄存器
static constexpr int DEFAULT_ADDR_WORK_STATUS = 1; // 工作状态寄存器
static constexpr int DEFAULT_ADDR_COORD_DATA_START = 2; // 坐标数据起始
// 工作状态值枚举
enum WorkStatusValue {
WORK_STATUS_WORKING = 0, // 正在工作
WORK_STATUS_COMPLETE_OK = 1, // 完成正常
WORK_STATUS_ERROR = 2 // 错误
};
// 数据字节序枚举
enum ByteOrder {
BIG_ENDIAN_ORDER = 0, // 大端序 (ABCD) - 高字节在前
LITTLE_ENDIAN_ORDER = 1 // 小端序 (DCBA) - 低字节在前
};
struct RegisterConfig {
int addrTrigger = 0; // 触发寄存器地址
int addrWorkStatus = 1; // 工作状态寄存器地址
int addrCoordDataStart = 2; // 坐标数据起始地址
int byteOrder = BIG_ENDIAN_ORDER; // 数据字节序,默认大端序
};
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 WriteWorkStatus(WorkStatusValue status);
bool ClearTrigger();
// ========== 轮询控制 ==========
void PauseTriggerPolling(); // 暂停读取触发寄存器(检测期间调用)
void ResumeTriggerPolling(); // 恢复读取触发寄存器(检测完成后调用)
bool IsTriggerPollingPaused() const;
// ========== 状态查询 ==========
bool IsPLCConnected() const;
private:
// 轮询线程
void pollThreadFunc();
// 连接管理
bool checkConnection();
bool tryConnectPLC();
void disconnectPLC(); // 主动断开连接(用于触发重连)
// 寄存器操作
int readTriggerRegister();
void floatToRegisters(float value, uint16_t& high, uint16_t& low);
// 安全的回调通知(先复制回调,释放锁后再调用)
void notifyConnectionStateChanged(bool connected);
void notifyError(const std::string& errorMsg);
void notifyTriggerRequested(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_lastTriggerState;
bool m_lastConnectedState;
// 线程控制
std::thread m_pollThread;
std::atomic<bool> m_pollRunning;
std::atomic<bool> m_triggerPollingPaused; // 暂停触发寄存器轮询标志
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