136 lines
5.5 KiB
C++
136 lines
5.5 KiB
C++
#ifndef MODBUS_TCP_CLIENT_H
|
||
#define MODBUS_TCP_CLIENT_H
|
||
|
||
#include <stdint.h>
|
||
#include <stdio.h>
|
||
#include <unistd.h>
|
||
#include <fcntl.h>
|
||
#include <arpa/inet.h>
|
||
#include <sys/socket.h>
|
||
#include <sys/select.h>
|
||
#include <pthread.h> // Use mutexes
|
||
|
||
// Enum class for MODBUS function codes
|
||
enum class ModbusFunction : uint8_t {
|
||
READ_COIL = 0x01,
|
||
READ_DISCRETE_INPUT = 0x02,
|
||
READ_HOLDING_REGISTER = 0x03,
|
||
READ_INPUT_REGISTER = 0x04,
|
||
WRITE_SINGLE_COIL = 0x05,
|
||
WRITE_SINGLE_HOLDING_REGISTER = 0x06,
|
||
WRITE_MULTIPLE_COILS = 0x0F,
|
||
WRITE_MULTIPLE_HOLDING_REGISTERS = 0x10
|
||
};
|
||
|
||
// Enum class for error codes
|
||
enum class ModbusError {
|
||
NONE = 0,
|
||
TIMEOUT,
|
||
INVALID_RESPONSE,
|
||
CONNECTION_LOST,
|
||
EXCEPTION_RESPONSE,
|
||
INVALID_REQUEST
|
||
};
|
||
|
||
class ModbusTCPClient {
|
||
public:
|
||
// Constructor that allocates dynamic buffers based on provided counts and start addresses.
|
||
ModbusTCPClient(const char* ip, int port, int numCoils, int numDI, int numIR, int numHR,
|
||
int startCoils = 0, int startDI = 0, int startIR = 0, int startHR = 0);
|
||
// Simpler constructor for manual MODBUS function calls (without readAll/writeAll)
|
||
ModbusTCPClient(const char* ip, int port);
|
||
~ModbusTCPClient();
|
||
|
||
// Set start addresses for each type.
|
||
void setStartAddresses(int startCoils, int startDI, int startIR, int startHR);
|
||
|
||
// Connection functions
|
||
bool connectServer();
|
||
void disconnectServer();
|
||
bool isConnected() const;
|
||
bool reconnectServer();
|
||
|
||
// Set the timeout (in milliseconds) for receiving responses.
|
||
void setTimeout(int milliseconds);
|
||
|
||
// Getters and setters for data values (if using the automatic mode).
|
||
void setCoil(int address, bool value);
|
||
void setHoldingRegister(int address, uint16_t value);
|
||
|
||
bool getDiscreteInput(int address) const;
|
||
bool getCoil(int address) const;
|
||
bool getDesiredCoil(int address) const;
|
||
uint16_t getInputRegister(int address) const;
|
||
uint16_t getHoldingRegister(int address) const;
|
||
uint16_t getDesiredHoldingRegister(int address) const;
|
||
|
||
ModbusError getMultipleCoils(int startAddress, int count, bool* destination) const;
|
||
ModbusError getMultipleDiscreteInputs(int startAddress, int count, bool* destination) const;
|
||
ModbusError getMultipleInputRegisters(int startAddress, int count, uint16_t* destination) const;
|
||
ModbusError getMultipleHoldingRegisters(int startAddress, int count, uint16_t* destination) const;
|
||
|
||
// High-level functions: readAll and writeAll update the internal buffers.
|
||
ModbusError readAll();
|
||
ModbusError writeAll();
|
||
|
||
// Low-level MODBUS functions (manual calls)
|
||
ModbusError readCoil(int address, bool &coilState);
|
||
ModbusError readMultipleCoils(int address, int count, bool coilStates[]);
|
||
ModbusError readDiscreteInput(int address, bool &discreteInput);
|
||
ModbusError readMultipleDiscreteInputs(int address, int count, bool discreteInputs[]);
|
||
ModbusError readHoldingRegister(int address, uint16_t &holdingRegister);
|
||
ModbusError readMultipleHoldingRegisters(int address, int count, uint16_t holdingRegisters[]);
|
||
ModbusError readInputRegister(int address, uint16_t &inputRegister);
|
||
ModbusError readMultipleInputRegisters(int address, int count, uint16_t inputRegisters[]);
|
||
|
||
ModbusError writeCoil(int address, bool value);
|
||
ModbusError writeMultipleCoils(int address, int count, const bool values[]);
|
||
ModbusError writeHoldingRegister(int address, uint16_t value);
|
||
ModbusError writeMultipleHoldingRegisters(int address, int count, const uint16_t values[]);
|
||
|
||
private:
|
||
// TCP settings
|
||
const char* serverIP;
|
||
int serverPort;
|
||
int socketFD;
|
||
uint16_t transactionID;
|
||
int timeoutMilliseconds = 2000; // Default 2-second timeout
|
||
|
||
// Start addresses for each data type
|
||
int startCoils, startDiscreteInputs, startInputRegisters, startHoldingRegisters;
|
||
// Number of items for each type
|
||
int numCoils, numDiscreteInputs, numInputRegisters, numHoldingRegisters;
|
||
|
||
// Internal storage for automatic readAll()/writeAll() mode
|
||
bool* coilsRead; // Actual state from PLC
|
||
bool* coilsWrite; // Desired state to write
|
||
bool* discreteInputs; // Only read
|
||
uint16_t* inputRegisters; // Only read
|
||
uint16_t* holdingRegistersRead; // Actual values from PLC
|
||
uint16_t* holdingRegistersWrite; // Desired values to write
|
||
|
||
// --- Communication buffers (shared for both reading and writing)
|
||
uint8_t* commRequestBuffer; // Preallocated request buffer
|
||
uint8_t* commResponseBuffer; // Preallocated response buffer
|
||
int commRequestBufferSize; // Maximum request size needed
|
||
int commResponseBufferSize; // Maximum response size needed
|
||
|
||
// Global mutex to protect the TCP socket and communication buffers.
|
||
pthread_mutex_t socketMutex;
|
||
|
||
// Low-level communication functions using the shared buffers.
|
||
bool sendRequest(uint8_t* request, int requestSize);
|
||
bool receiveResponse(uint8_t* response, int expectedSize);
|
||
|
||
// Message building functions – they write into a provided buffer.
|
||
void buildReadRequest(uint8_t* buffer, ModbusFunction functionCode, uint16_t startAddr, uint16_t quantity);
|
||
void buildWriteSingleRequest(uint8_t* buffer, ModbusFunction functionCode, uint16_t address, uint16_t value);
|
||
void buildWriteMultipleRequest(uint8_t* buffer, ModbusFunction functionCode, uint16_t address, uint16_t count, const void* values, uint8_t byteCount);
|
||
|
||
// Helper functions to compute maximum buffer sizes.
|
||
int computeMaxReadResponseSize() const;
|
||
int computeMaxWriteRequestSize() const;
|
||
};
|
||
|
||
#endif // MODBUS_TCP_CLIENT_H
|