GrabBag/Module/ModbusTCPClient/Inc/ModbusTCPClient.h

303 lines
7.9 KiB
C
Raw Normal View History

2025-06-08 12:48:04 +08:00
#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<EFBFBD>ͻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>libmodbus<EFBFBD><EFBFBD>ʵ<EFBFBD><EFBFBD>
*
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Modbus TCP<EFBFBD>ͻ<EFBFBD><EFBFBD>˹<EFBFBD><EFBFBD>ܣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* - <EFBFBD><EFBFBD><EFBFBD>ӹ<EFBFBD><EFBFBD><EFBFBD>
* - <EFBFBD><EFBFBD><EFBFBD>б<EFBFBD>׼Modbus<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֧<EFBFBD><EFBFBD>
* - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֧<EFBFBD><EFBFBD>
* - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD><EFBFBD>
*/
class ModbusTCPClient {
public:
// <20><><EFBFBD><EFBFBD>״̬ö<CCAC><C3B6>
enum ConnectionState {
DISCONNECTED = 0, ///< <20>ѶϿ<D1B6><CFBF><EFBFBD><EFBFBD><EFBFBD>
CONNECTING, ///< <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
CONNECTED, ///< <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
ERROR_STATE ///< <20><><EFBFBD><EFBFBD>״̬
};
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ö<EFBFBD><C3B6>
enum Result {
SUCCESS = 0, ///< <20><><EFBFBD><EFBFBD><EFBFBD>ɹ<EFBFBD>
ERROR_CONNECTION = -1, ///< <20><><EFBFBD>Ӵ<EFBFBD><D3B4><EFBFBD>
ERROR_INVALID_PARAM = -2, ///< <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
ERROR_TIMEOUT = -3, ///< <20><>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD>
ERROR_DEVICE = -4, ///< <20><EFBFBD><E8B1B8><EFBFBD><EFBFBD>
ERROR_PROTOCOL = -5, ///< Э<><D0AD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
ERROR_UNKNOWN = -6 ///< δ֪<CEB4><D6AA><EFBFBD><EFBFBD>
};
// <20><><EFBFBD><EFBFBD>״̬<D7B4><EFBFBD>ص<EFBFBD><D8B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
using ConnectionStateCallback = std::function<void(ConnectionState oldState, ConnectionState newState, const std::string& message)>;
// <20><><EFBFBD>ݱ仯<DDB1>ص<EFBFBD><D8B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͣ<EFBFBD><CDA3><EFBFBD><EFBFBD>ڼ<EFBFBD><DABC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݱ仯<DDB1><E4BBAF>
using DataChangeCallback = std::function<void(int address, const std::vector<uint16_t>& values)>;
public:
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param serverIP <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>IP<EFBFBD><EFBFBD>ַ
* @param serverPort <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˿ڣ<EFBFBD>Ĭ<EFBFBD><EFBFBD>502
*/
ModbusTCPClient(const std::string& serverIP, int serverPort = 502);
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*/
~ModbusTCPClient();
// <20><><EFBFBD>ÿ<EFBFBD><C3BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͸<EFBFBD>ֵ
ModbusTCPClient(const ModbusTCPClient&) = delete;
ModbusTCPClient& operator=(const ModbusTCPClient&) = delete;
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӳ<EFBFBD><EFBFBD><EFBFBD>
* @param serverIP <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>IP<EFBFBD><EFBFBD>ַ
* @param serverPort <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˿<EFBFBD>
* @return <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><EFBFBD>ɹ<EFBFBD>
*/
bool SetConnectionParams(const std::string& serverIP, int serverPort);
/**
* @brief <EFBFBD><EFBFBD><EFBFBD>ô<EFBFBD>վID
* @param slaveId <EFBFBD><EFBFBD>վID (1-247)
* @return <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><EFBFBD>ɹ<EFBFBD>
*/
bool SetSlaveId(int slaveId);
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӧ<EFBFBD><EFBFBD>ʱʱ<EFBFBD><EFBFBD>
* @param timeoutMs <EFBFBD><EFBFBD>ʱʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @return <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><EFBFBD>ɹ<EFBFBD>
*/
bool SetTimeout(int timeoutMs);
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>״̬<EFBFBD><EFBFBD>ص<EFBFBD>
* @param callback <EFBFBD>ص<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*/
void SetConnectionStateCallback(ConnectionStateCallback callback);
/**
* @brief <EFBFBD><EFBFBD><EFBFBD>ӵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @return <EFBFBD><EFBFBD><EFBFBD>ӽ<EFBFBD><EFBFBD><EFBFBD>
*/
Result Connect();
/**
* @brief <EFBFBD>Ͽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*/
void Disconnect();
/**
* @brief <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>״̬
* @return <EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>״̬
*/
ConnectionState GetConnectionState() const;
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @return <EFBFBD>Ƿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*/
bool IsConnected() const;
// === <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ===
/**
* @brief <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD>Ȧ״̬ (<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>0x01)
* @param startAddress <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>ַ
* @param quantity <EFBFBD><EFBFBD><EFBFBD><EFBFBD> (1-2000)
* @param values <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @return <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*/
Result ReadCoils(int startAddress, int quantity, std::vector<bool>& values);
/**
* @brief <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD>ɢ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> (<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>0x02)
* @param startAddress <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>ַ
* @param quantity <EFBFBD><EFBFBD><EFBFBD><EFBFBD> (1-2000)
* @param values <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @return <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*/
Result ReadDiscreteInputs(int startAddress, int quantity, std::vector<bool>& values);
/**
* @brief <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD>ּĴ<EFBFBD><EFBFBD><EFBFBD> (<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>0x03)
* @param startAddress <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>ַ
* @param quantity <EFBFBD><EFBFBD><EFBFBD><EFBFBD> (1-125)
* @param values <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @return <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*/
Result ReadHoldingRegisters(int startAddress, int quantity, std::vector<uint16_t>& values);
/**
* @brief <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD> (<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>0x04)
* @param startAddress <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>ַ
* @param quantity <EFBFBD><EFBFBD><EFBFBD><EFBFBD> (1-125)
* @param values <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @return <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*/
Result ReadInputRegisters(int startAddress, int quantity, std::vector<uint16_t>& values);
// === д<><D0B4><EFBFBD><EFBFBD> ===
/**
* @brief д<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȧ (<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>0x05)
* @param address <EFBFBD><EFBFBD>ַ
* @param value ֵ
* @return <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*/
Result WriteSingleCoil(int address, bool value);
/**
* @brief д<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ּĴ<EFBFBD><EFBFBD><EFBFBD> (<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>0x06)
* @param address <EFBFBD><EFBFBD>ַ
* @param value ֵ
* @return <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*/
Result WriteSingleRegister(int address, uint16_t value);
/**
* @brief д<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȧ (<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>0x0F)
* @param startAddress <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>ַ
* @param values ֵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @return <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*/
Result WriteMultipleCoils(int startAddress, const std::vector<bool>& values);
/**
* @brief д<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ּĴ<EFBFBD><EFBFBD><EFBFBD> (<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>0x10)
* @param startAddress <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>ַ
* @param values ֵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @return <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*/
Result WriteMultipleRegisters(int startAddress, const std::vector<uint16_t>& values);
// === <20><><EFBFBD>ϲ<EFBFBD><CFB2><EFBFBD> ===
/**
* @brief <EFBFBD><EFBFBD>д<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD> (<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>0x17)
* @param readStartAddress <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>ַ
* @param readQuantity <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param writeStartAddress д<EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>ַ
* @param writeValues дֵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param readValues <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD>ֵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @return <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*/
Result ReadWriteMultipleRegisters(int readStartAddress, int readQuantity,
int writeStartAddress, const std::vector<uint16_t>& writeValues,
std::vector<uint16_t>& readValues);
// === <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD><D7AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ===
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>16λ<EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϲ<EFBFBD>Ϊ32λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param high <EFBFBD><EFBFBD>λ<EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD>
* @param low <EFBFBD><EFBFBD>λ<EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD>
* @return 32λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
*/
static uint32_t RegistersToUInt32(uint16_t high, uint16_t low);
/**
* @brief <EFBFBD><EFBFBD>32λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֽ<EFBFBD>Ϊ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>16λ<EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD>
* @param value 32λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
* @param high <EFBFBD><EFBFBD>λ<EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param low <EFBFBD><EFBFBD>λ<EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*/
static void UInt32ToRegisters(uint32_t value, uint16_t& high, uint16_t& low);
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>16λ<EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϲ<EFBFBD>Ϊ32λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param high <EFBFBD><EFBFBD>λ<EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD>
* @param low <EFBFBD><EFBFBD>λ<EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD>
* @return 32λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
*/
static float RegistersToFloat(uint16_t high, uint16_t low);
/**
* @brief <EFBFBD><EFBFBD>32λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֽ<EFBFBD>Ϊ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>16λ<EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD>
* @param value 32λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
* @param high <EFBFBD><EFBFBD>λ<EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param low <EFBFBD><EFBFBD>λ<EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*/
static void FloatToRegisters(float value, uint16_t& high, uint16_t& low);
// === <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ===
/**
* @brief <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD>δ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϣ
* @return <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϣ<EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD>
*/
std::string GetLastError() const;
/**
* @brief <EFBFBD><EFBFBD>Resultת<EFBFBD><EFBFBD>Ϊ<EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD>
* @param result <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ö<EFBFBD><EFBFBD>
* @return <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD>
*/
static std::string ResultToString(Result result);
/**
* @brief <EFBFBD><EFBFBD>ConnectionStateת<EFBFBD><EFBFBD>Ϊ<EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD>
* @param state ״̬ö<EFBFBD><EFBFBD>
* @return ״̬<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD>
*/
static std::string ConnectionStateToString(ConnectionState state);
private:
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>״̬
* @param newState <EFBFBD><EFBFBD>״̬
* @param message ״̬<EFBFBD><EFBFBD><EFBFBD>Ϣ
*/
void SetConnectionState(ConnectionState newState, const std::string& message = "");
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>modbus<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><EFBFBD><EFBFBD>Ч
* @return <EFBFBD>Ƿ<EFBFBD><EFBFBD><EFBFBD>Ч
*/
bool IsModbusContextValid() const;
/**
* @brief <EFBFBD><EFBFBD>libmodbus<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD><EFBFBD>ΪResult
* @return ת<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ľ<EFBFBD><EFBFBD><EFBFBD>
*/
Result ConvertLibmodbusError() const;
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϣ
* @param error <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϣ
*/
void SetLastError(const std::string& error);
private:
modbus_t* m_modbusContext; ///< libmodbus<75><73><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
std::string m_serverIP; ///< <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>IP<49><50>ַ
int m_serverPort; ///< <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˿<EFBFBD>
int m_slaveId; ///< <20><>վID
int m_timeoutMs; ///< <20><>ʱʱ<CAB1><EFBFBD><E4A3A8><EFBFBD>
std::atomic<ConnectionState> m_connectionState; ///< <20><><EFBFBD><EFBFBD>״̬
ConnectionStateCallback m_stateCallback; ///< ״̬<D7B4><EFBFBD>ص<EFBFBD>
mutable std::mutex m_mutex; ///< <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
std::string m_lastError; ///< <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϣ
};
#endif // MODBUS_TCP_CLIENT_H