#ifndef MODBUS_TCP_CLIENT_H #define MODBUS_TCP_CLIENT_H #include #include #include #include #include #include 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; // 数据变化回调函数类型(用于监控数据变化) using DataChangeCallback = std::function& 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& values); /** * @brief 读取离散输入 (功能码0x02) * @param startAddress 起始地址 * @param quantity 数量 (1-2000) * @param values 输出值数组 * @return 操作结果 */ Result ReadDiscreteInputs(int startAddress, int quantity, std::vector& values); /** * @brief 读取保持寄存器 (功能码0x03) * @param startAddress 起始地址 * @param quantity 数量 (1-125) * @param values 输出值数组 * @return 操作结果 */ Result ReadHoldingRegisters(int startAddress, int quantity, std::vector& values); /** * @brief 读取输入寄存器 (功能码0x04) * @param startAddress 起始地址 * @param quantity 数量 (1-125) * @param values 输出值数组 * @return 操作结果 */ Result ReadInputRegisters(int startAddress, int quantity, std::vector& 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& values); /** * @brief 写多个保持寄存器 (功能码0x10) * @param startAddress 起始地址 * @param values 值数组 * @return 操作结果 */ Result WriteMultipleRegisters(int startAddress, const std::vector& 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& writeValues, std::vector& 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 m_connectionState; ///< 连接状态 ConnectionStateCallback m_stateCallback; ///< 状态变化回调 mutable std::mutex m_mutex; ///< 互斥锁 std::string m_lastError; ///< 最后错误信息 }; #endif // MODBUS_TCP_CLIENT_H