#ifndef MODBUS_TCP_CLIENT_H #define MODBUS_TCP_CLIENT_H #include #include #include #include #include #include #include #include // 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