303 lines
7.9 KiB
C++
303 lines
7.9 KiB
C++
#ifndef MODBUS_TCP_CLIENT_H
|
||
#define MODBUS_TCP_CLIENT_H
|
||
|
||
#include <memory>
|
||
#include <string>
|
||
#include <vector>
|
||
#include <functional>
|
||
#include <mutex>
|
||
#include <atomic>
|
||
|
||
extern "C" {
|
||
#include "modbus.h"
|
||
}
|
||
|
||
/**
|
||
* @brief Modbus TCP客户端类,基于libmodbus库实现
|
||
*
|
||
* 提供完整的Modbus TCP客户端功能,包括:
|
||
* - 连接管理
|
||
* - 所有标准Modbus功能码支持
|
||
* - 异步操作支持
|
||
* - 错误处理和重连机制
|
||
* - 数据类型转换
|
||
*/
|
||
class ModbusTCPClient {
|
||
public:
|
||
// 连接状态枚举
|
||
enum ConnectionState {
|
||
DISCONNECTED = 0, ///< 已断开连接
|
||
CONNECTING, ///< 正在连接
|
||
CONNECTED, ///< 已连接
|
||
ERROR_STATE ///< 错误状态
|
||
};
|
||
|
||
// 操作结果枚举
|
||
enum Result {
|
||
SUCCESS = 0, ///< 操作成功
|
||
ERROR_CONNECTION = -1, ///< 连接错误
|
||
ERROR_INVALID_PARAM = -2, ///< 参数错误
|
||
ERROR_TIMEOUT = -3, ///< 超时错误
|
||
ERROR_DEVICE = -4, ///< 设备错误
|
||
ERROR_PROTOCOL = -5, ///< 协议错误
|
||
ERROR_UNKNOWN = -6 ///< 未知错误
|
||
};
|
||
|
||
// 连接状态变化回调函数类型
|
||
using ConnectionStateCallback = std::function<void(ConnectionState oldState, ConnectionState newState, const std::string& message)>;
|
||
|
||
// 数据变化回调函数类型(用于监控数据变化)
|
||
using DataChangeCallback = std::function<void(int address, const std::vector<uint16_t>& values)>;
|
||
|
||
public:
|
||
/**
|
||
* @brief 构造函数
|
||
* @param serverIP 服务器IP地址
|
||
* @param serverPort 服务器端口,默认502
|
||
*/
|
||
ModbusTCPClient(const std::string& serverIP, int serverPort = 502);
|
||
|
||
/**
|
||
* @brief 析构函数
|
||
*/
|
||
~ModbusTCPClient();
|
||
|
||
// 禁用拷贝构造和赋值
|
||
ModbusTCPClient(const ModbusTCPClient&) = delete;
|
||
ModbusTCPClient& operator=(const ModbusTCPClient&) = delete;
|
||
|
||
/**
|
||
* @brief 设置连接参数
|
||
* @param serverIP 服务器IP地址
|
||
* @param serverPort 服务器端口
|
||
* @return 设置是否成功
|
||
*/
|
||
bool SetConnectionParams(const std::string& serverIP, int serverPort);
|
||
|
||
/**
|
||
* @brief 设置从站ID
|
||
* @param slaveId 从站ID (1-247)
|
||
* @return 设置是否成功
|
||
*/
|
||
bool SetSlaveId(int slaveId);
|
||
|
||
/**
|
||
* @brief 设置响应超时时间
|
||
* @param timeoutMs 超时时间(毫秒)
|
||
* @return 设置是否成功
|
||
*/
|
||
bool SetTimeout(int timeoutMs);
|
||
|
||
/**
|
||
* @brief 设置连接状态变化回调
|
||
* @param callback 回调函数
|
||
*/
|
||
void SetConnectionStateCallback(ConnectionStateCallback callback);
|
||
|
||
/**
|
||
* @brief 连接到服务器
|
||
* @return 连接结果
|
||
*/
|
||
Result Connect();
|
||
|
||
/**
|
||
* @brief 断开连接
|
||
*/
|
||
void Disconnect();
|
||
|
||
/**
|
||
* @brief 获取连接状态
|
||
* @return 当前连接状态
|
||
*/
|
||
ConnectionState GetConnectionState() const;
|
||
|
||
/**
|
||
* @brief 检查是否已连接
|
||
* @return 是否已连接
|
||
*/
|
||
bool IsConnected() const;
|
||
|
||
// === 读操作 ===
|
||
|
||
/**
|
||
* @brief 读取线圈状态 (功能码0x01)
|
||
* @param startAddress 起始地址
|
||
* @param quantity 数量 (1-2000)
|
||
* @param values 输出值数组
|
||
* @return 操作结果
|
||
*/
|
||
Result ReadCoils(int startAddress, int quantity, std::vector<bool>& values);
|
||
|
||
/**
|
||
* @brief 读取离散输入 (功能码0x02)
|
||
* @param startAddress 起始地址
|
||
* @param quantity 数量 (1-2000)
|
||
* @param values 输出值数组
|
||
* @return 操作结果
|
||
*/
|
||
Result ReadDiscreteInputs(int startAddress, int quantity, std::vector<bool>& values);
|
||
|
||
/**
|
||
* @brief 读取保持寄存器 (功能码0x03)
|
||
* @param startAddress 起始地址
|
||
* @param quantity 数量 (1-125)
|
||
* @param values 输出值数组
|
||
* @return 操作结果
|
||
*/
|
||
Result ReadHoldingRegisters(int startAddress, int quantity, std::vector<uint16_t>& values);
|
||
|
||
/**
|
||
* @brief 读取输入寄存器 (功能码0x04)
|
||
* @param startAddress 起始地址
|
||
* @param quantity 数量 (1-125)
|
||
* @param values 输出值数组
|
||
* @return 操作结果
|
||
*/
|
||
Result ReadInputRegisters(int startAddress, int quantity, std::vector<uint16_t>& values);
|
||
|
||
// === 写操作 ===
|
||
|
||
/**
|
||
* @brief 写单个线圈 (功能码0x05)
|
||
* @param address 地址
|
||
* @param value 值
|
||
* @return 操作结果
|
||
*/
|
||
Result WriteSingleCoil(int address, bool value);
|
||
|
||
/**
|
||
* @brief 写单个保持寄存器 (功能码0x06)
|
||
* @param address 地址
|
||
* @param value 值
|
||
* @return 操作结果
|
||
*/
|
||
Result WriteSingleRegister(int address, uint16_t value);
|
||
|
||
/**
|
||
* @brief 写多个线圈 (功能码0x0F)
|
||
* @param startAddress 起始地址
|
||
* @param values 值数组
|
||
* @return 操作结果
|
||
*/
|
||
Result WriteMultipleCoils(int startAddress, const std::vector<bool>& values);
|
||
|
||
/**
|
||
* @brief 写多个保持寄存器 (功能码0x10)
|
||
* @param startAddress 起始地址
|
||
* @param values 值数组
|
||
* @return 操作结果
|
||
*/
|
||
Result WriteMultipleRegisters(int startAddress, const std::vector<uint16_t>& values);
|
||
|
||
// === 组合操作 ===
|
||
|
||
/**
|
||
* @brief 读写多个寄存器 (功能码0x17)
|
||
* @param readStartAddress 读起始地址
|
||
* @param readQuantity 读数量
|
||
* @param writeStartAddress 写起始地址
|
||
* @param writeValues 写值数组
|
||
* @param readValues 读取的值数组(输出)
|
||
* @return 操作结果
|
||
*/
|
||
Result ReadWriteMultipleRegisters(int readStartAddress, int readQuantity,
|
||
int writeStartAddress, const std::vector<uint16_t>& writeValues,
|
||
std::vector<uint16_t>& readValues);
|
||
|
||
// === 数据类型转换辅助函数 ===
|
||
|
||
/**
|
||
* @brief 将两个16位寄存器合并为32位整数
|
||
* @param high 高位寄存器
|
||
* @param low 低位寄存器
|
||
* @return 32位整数值
|
||
*/
|
||
static uint32_t RegistersToUInt32(uint16_t high, uint16_t low);
|
||
|
||
/**
|
||
* @brief 将32位整数分解为两个16位寄存器
|
||
* @param value 32位整数值
|
||
* @param high 高位寄存器(输出)
|
||
* @param low 低位寄存器(输出)
|
||
*/
|
||
static void UInt32ToRegisters(uint32_t value, uint16_t& high, uint16_t& low);
|
||
|
||
/**
|
||
* @brief 将两个16位寄存器合并为32位浮点数
|
||
* @param high 高位寄存器
|
||
* @param low 低位寄存器
|
||
* @return 32位浮点数值
|
||
*/
|
||
static float RegistersToFloat(uint16_t high, uint16_t low);
|
||
|
||
/**
|
||
* @brief 将32位浮点数分解为两个16位寄存器
|
||
* @param value 32位浮点数值
|
||
* @param high 高位寄存器(输出)
|
||
* @param low 低位寄存器(输出)
|
||
*/
|
||
static void FloatToRegisters(float value, uint16_t& high, uint16_t& low);
|
||
|
||
// === 错误处理 ===
|
||
|
||
/**
|
||
* @brief 获取最后一次错误信息
|
||
* @return 错误信息字符串
|
||
*/
|
||
std::string GetLastError() const;
|
||
|
||
/**
|
||
* @brief 将Result转换为字符串
|
||
* @param result 结果枚举
|
||
* @return 结果描述字符串
|
||
*/
|
||
static std::string ResultToString(Result result);
|
||
|
||
/**
|
||
* @brief 将ConnectionState转换为字符串
|
||
* @param state 状态枚举
|
||
* @return 状态描述字符串
|
||
*/
|
||
static std::string ConnectionStateToString(ConnectionState state);
|
||
|
||
private:
|
||
/**
|
||
* @brief 设置连接状态
|
||
* @param newState 新状态
|
||
* @param message 状态变化消息
|
||
*/
|
||
void SetConnectionState(ConnectionState newState, const std::string& message = "");
|
||
|
||
/**
|
||
* @brief 检查modbus上下文是否有效
|
||
* @return 是否有效
|
||
*/
|
||
bool IsModbusContextValid() const;
|
||
|
||
/**
|
||
* @brief 将libmodbus错误转换为Result
|
||
* @return 转换后的结果
|
||
*/
|
||
Result ConvertLibmodbusError() const;
|
||
|
||
/**
|
||
* @brief 设置最后错误信息
|
||
* @param error 错误信息
|
||
*/
|
||
void SetLastError(const std::string& error);
|
||
|
||
private:
|
||
modbus_t* m_modbusContext; ///< libmodbus上下文
|
||
std::string m_serverIP; ///< 服务器IP地址
|
||
int m_serverPort; ///< 服务器端口
|
||
int m_slaveId; ///< 从站ID
|
||
int m_timeoutMs; ///< 超时时间(毫秒)
|
||
|
||
std::atomic<ConnectionState> m_connectionState; ///< 连接状态
|
||
ConnectionStateCallback m_stateCallback; ///< 状态变化回调
|
||
|
||
mutable std::mutex m_mutex; ///< 互斥锁
|
||
std::string m_lastError; ///< 最后错误信息
|
||
};
|
||
|
||
#endif // MODBUS_TCP_CLIENT_H
|