GrabBag/Module/ModbusTCPClient/Inc/ModbusTCPClient.h

303 lines
8.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 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