diff --git a/IO_Modbus.cpp b/IO_Modbus.cpp index 4c7df51..7404b12 100644 --- a/IO_Modbus.cpp +++ b/IO_Modbus.cpp @@ -19,7 +19,468 @@ #include "IO_Modbus.h" #include "defines.h" +void ModbusADU::setTransactionId(uint16_t transactionId) { + _setRegister(tcp, 0, transactionId); +} +void ModbusADU::setProtocolId(uint16_t protocolId) { + _setRegister(tcp, 2, protocolId); +} + +void ModbusADU::setLength(uint16_t length) { + if (length < 3 || length > 254) _setRegister(tcp, 4, 0); + else _setRegister(tcp, 4, length); +} + +void ModbusADU::setUnitId(uint8_t unitId) { + tcp[6] = unitId; +} + +void ModbusADU::setFunctionCode(uint8_t functionCode) { + pdu[0] = functionCode; +} + +void ModbusADU::setDataRegister(uint8_t index, uint16_t value) { + _setRegister(data, index, value); +} + + + +void ModbusADU::setRtuLen(uint16_t rtuLen) { + setLength(rtuLen - 2); +} + +void ModbusADU::setTcpLen(uint16_t tcpLen) { + setLength(tcpLen - 6); +} + +void ModbusADU::setPduLen(uint16_t pduLen) { + setLength(pduLen + 1); +} + +void ModbusADU::setDataLen(uint16_t dataLen) { + setLength(dataLen + 2); +} + + + +uint16_t ModbusADU::getTransactionId() { + return _getRegister(tcp, 0); +} + +uint16_t ModbusADU::getProtocolId() { + return _getRegister(tcp, 2); +} + +uint16_t ModbusADU::getLength() { + uint16_t length = _getRegister(tcp, 4); + if (length < 3 || length > 254) return 0; + else return length; +} + +uint8_t ModbusADU::getUnitId() { + return tcp[6]; +} + +uint8_t ModbusADU::getFunctionCode() { + return pdu[0]; +} + +uint16_t ModbusADU::getDataRegister(uint8_t index) { + return _getRegister(data, index); +} + + + +uint16_t ModbusADU::getRtuLen() { + uint16_t len = getLength(); + if (len == 0) return 0; + else return len + 2; +} + +uint16_t ModbusADU::getTcpLen() { + uint16_t len = getLength(); + if (len == 0) return 0; + else return len + 6; +} + +uint16_t ModbusADU::getPduLen() { + uint16_t len = getLength(); + if (len == 0) return 0; + else return len - 1; +} + +uint16_t ModbusADU::getDataLen() { + uint16_t len = getLength(); + if (len == 0) return 0; + else return len - 2; +} + + + +void ModbusADU::updateCrc() { + uint16_t len = getLength(); + uint16_t crc = _calculateCrc(len); + rtu[len] = lowByte(crc); + rtu[len + 1] = highByte(crc); +} + +bool ModbusADU::crcGood() { + uint16_t len = getLength(); + uint16_t aduCrc = rtu[len] | (rtu[len + 1] << 8); + uint16_t calculatedCrc = _calculateCrc(len); + if (aduCrc == calculatedCrc) return true; + else return false; +} + + + +void ModbusADU::prepareExceptionResponse(uint8_t exceptionCode) { + pdu[0] |= 0x80; + pdu[1] = exceptionCode; + setPduLen(2); +} + + + +void ModbusADU::_setRegister(uint8_t *buf, uint16_t index, uint16_t value) { + buf[index] = highByte(value); + buf[index + 1] = lowByte(value); +} + +uint16_t ModbusADU::_getRegister(uint8_t *buf, uint16_t index) { + return (buf[index] << 8) | buf[index + 1]; +} + +uint16_t ModbusADU::_calculateCrc(uint16_t len) { + uint16_t value = 0xFFFF; + for (uint16_t i = 0; i < len; i++) { + value ^= (uint16_t)rtu[i]; + for (uint8_t j = 0; j < 8; j++) { + bool lsb = value & 1; + value >>= 1; + if (lsb == true) value ^= 0xA001; + } + } + return value; +} + + + +uint16_t div8RndUp(uint16_t value) { + return (value + 7) >> 3; +} + +ModbusRTUComm::ModbusRTUComm(Stream& serial, int8_t dePin, int8_t rePin) : _serial(serial) { + _dePin = dePin; + _rePin = rePin; +} + +void ModbusRTUComm::begin(unsigned long baud, uint32_t config) { + unsigned long bitsPerChar; + switch (config) { + case SERIAL_8E2: + case SERIAL_8O2: + bitsPerChar = 12; + break; + case SERIAL_8N2: + case SERIAL_8E1: + case SERIAL_8O1: + bitsPerChar = 11; + break; + case SERIAL_8N1: + default: + bitsPerChar = 10; + break; + } + if (baud <= 19200) { + _charTimeout = (bitsPerChar * 2500000) / baud; + _frameTimeout = (bitsPerChar * 4500000) / baud; + } + else { + _charTimeout = (bitsPerChar * 1000000) / baud + 750; + _frameTimeout = (bitsPerChar * 1000000) / baud + 1750; + } + #if defined(ARDUINO_UNOR4_MINIMA) || defined(ARDUINO_UNOR4_WIFI) || defined(ARDUINO_GIGA) || (defined(ARDUINO_NANO_RP2040_CONNECT) && defined(ARDUINO_ARCH_MBED)) + _postDelay = ((bitsPerChar * 1000000) / baud) + 2; + #endif + if (_dePin >= 0) { + pinMode(_dePin, OUTPUT); + digitalWrite(_dePin, LOW); + } + if (_rePin >= 0) { + pinMode(_rePin, OUTPUT); + digitalWrite(_rePin, LOW); + } + clearRxBuffer(); +} + +void ModbusRTUComm::setTimeout(unsigned long timeout) { + _readTimeout = timeout; +} + +ModbusRTUCommError ModbusRTUComm::readAdu(ModbusADU& adu) { + adu.setRtuLen(0); + unsigned long startMillis = millis(); + while (!_serial.available()) { + if (millis() - startMillis >= _readTimeout) return MODBUS_RTU_COMM_TIMEOUT; + } + uint16_t len = 0; + unsigned long startMicros = micros(); + do { + if (_serial.available()) { + startMicros = micros(); + adu.rtu[len] = _serial.read(); + len++; + } + } while (micros() - startMicros <= _charTimeout && len < 256); + adu.setRtuLen(len); + while (micros() - startMicros < _frameTimeout); + if (_serial.available()) { + adu.setRtuLen(0); + return MODBUS_RTU_COMM_FRAME_ERROR; + } + if (!adu.crcGood()) { + adu.setRtuLen(0); + return MODBUS_RTU_COMM_CRC_ERROR; + } + return MODBUS_RTU_COMM_SUCCESS; +} + +void ModbusRTUComm::writeAdu(ModbusADU& adu) { + adu.updateCrc(); + if (_dePin >= 0) digitalWrite(_dePin, HIGH); + if (_rePin >= 0) digitalWrite(_rePin, HIGH); + _serial.write(adu.rtu, adu.getRtuLen()); + _serial.flush(); + delayMicroseconds(_postDelay); + if (_dePin >= 0) digitalWrite(_dePin, LOW); + if (_rePin >= 0) digitalWrite(_rePin, LOW); +} + +void ModbusRTUComm::clearRxBuffer() { + unsigned long startMicros = micros(); + do { + if (_serial.available() > 0) { + startMicros = micros(); + _serial.read(); + } + } while (micros() - startMicros < _frameTimeout); +} + +ModbusRTUMaster::ModbusRTUMaster(Stream& serial, int8_t dePin, int8_t rePin) : _rtuComm(serial, dePin, rePin) { + _rtuComm.setTimeout(500); +} + +void ModbusRTUMaster::setTimeout(unsigned long timeout) { + _rtuComm.setTimeout(timeout); +} + +void ModbusRTUMaster::begin(unsigned long baud, uint32_t config) { + _rtuComm.begin(baud, config); +} + + + +ModbusRTUMasterError ModbusRTUMaster::readCoils(uint8_t id, uint16_t startAddress, bool buf[], uint16_t quantity) { + return _readValues(id, 1, startAddress, buf, quantity); +} + +ModbusRTUMasterError ModbusRTUMaster::readDiscreteInputs(uint8_t id, uint16_t startAddress, bool buf[], uint16_t quantity) { + return _readValues(id, 2, startAddress, buf, quantity); +} + +ModbusRTUMasterError ModbusRTUMaster::readHoldingRegisters(uint8_t id, uint16_t startAddress, uint16_t buf[], uint16_t quantity) { + return _readValues(id, 3, startAddress, buf, quantity); +} + +ModbusRTUMasterError ModbusRTUMaster::readInputRegisters(uint8_t id, uint16_t startAddress, uint16_t buf[], uint16_t quantity) { + return _readValues(id, 4, startAddress, buf, quantity); +} + + + +ModbusRTUMasterError ModbusRTUMaster::writeSingleCoil(uint8_t id, uint16_t address, bool value) { + return _writeSingleValue(id, 5, address, ((value) ? 0xFF00 : 0x0000)); +} + +ModbusRTUMasterError ModbusRTUMaster::writeSingleHoldingRegister(uint8_t id, uint16_t address, uint16_t value) { + return _writeSingleValue(id, 6, address, value); +} + + + +ModbusRTUMasterError ModbusRTUMaster::writeMultipleCoils(uint8_t id, uint16_t startAddress, bool buf[], uint16_t quantity) { + const uint8_t functionCode = 15; + if (id > 247) return MODBUS_RTU_MASTER_INVALID_ID; + if (!buf) return MODBUS_RTU_MASTER_INVALID_BUFFER; + if (quantity == 0 || quantity > 1968) return MODBUS_RTU_MASTER_INVALID_QUANTITY; + ModbusADU adu; + uint16_t byteCount = div8RndUp(quantity); + adu.setUnitId(id); + adu.setFunctionCode(functionCode); + adu.setDataRegister(0, startAddress); + adu.setDataRegister(2, quantity); + adu.data[4] = byteCount; + for (uint16_t i = 0; i < quantity; i++) { + bitWrite(adu.data[5 + (i >> 3)], i & 7, buf[i]); + } + for (uint16_t i = quantity; i < (byteCount * 8); i++) { + bitClear(adu.data[5 + (i >> 3)], i & 7); + } + adu.setDataLen(5 + byteCount); + _rtuComm.writeAdu(adu); + if (id == 0) return MODBUS_RTU_MASTER_SUCCESS; + ModbusRTUCommError commError = _rtuComm.readAdu(adu); + if (commError) return _translateCommError(commError); + if (adu.getUnitId() != id) return MODBUS_RTU_MASTER_UNEXPECTED_ID; + if (adu.getFunctionCode() == (functionCode + 0x80)) { + _exceptionResponse = adu.data[0]; + return MODBUS_RTU_MASTER_EXCEPTION_RESPONSE; + } + if (adu.getFunctionCode() != functionCode) return MODBUS_RTU_MASTER_UNEXPECTED_FUNCTION_CODE; + if (adu.getDataLen() != 4) return MODBUS_RTU_MASTER_UNEXPECTED_LENGTH; + if (adu.getDataRegister(0) != startAddress) return MODBUS_RTU_MASTER_UNEXPECTED_ADDRESS; + if (adu.getDataRegister(2) != quantity) return MODBUS_RTU_MASTER_UNEXPECTED_QUANTITY; + return MODBUS_RTU_MASTER_SUCCESS; +} + +ModbusRTUMasterError ModbusRTUMaster::writeMultipleHoldingRegisters(uint8_t id, uint16_t startAddress, uint16_t buf[], uint16_t quantity) { + uint8_t functionCode = 16; + if (id > 247) return MODBUS_RTU_MASTER_INVALID_ID; + if (!buf) return MODBUS_RTU_MASTER_INVALID_BUFFER; + if (quantity == 0 || quantity > 123) return MODBUS_RTU_MASTER_INVALID_QUANTITY; + uint16_t byteCount = quantity * 2; + ModbusADU adu; + adu.setUnitId(id); + adu.setFunctionCode(functionCode); + adu.setDataRegister(0, startAddress); + adu.setDataRegister(2, quantity); + adu.data[4] = byteCount; + for (uint16_t i = 0; i < quantity; i++) { + adu.setDataRegister(5 + (i * 2), buf[i]); + } + adu.setDataLen(5 + byteCount); + _rtuComm.writeAdu(adu); + if (id == 0) return MODBUS_RTU_MASTER_SUCCESS; + ModbusRTUCommError commError = _rtuComm.readAdu(adu); + if (commError) return _translateCommError(commError); + if (adu.getUnitId() != id) return MODBUS_RTU_MASTER_UNEXPECTED_ID; + if (adu.getFunctionCode() == (functionCode + 0x80)) { + _exceptionResponse = adu.data[0]; + return MODBUS_RTU_MASTER_EXCEPTION_RESPONSE; + } + if (adu.getFunctionCode() != functionCode) return MODBUS_RTU_MASTER_UNEXPECTED_FUNCTION_CODE; + if (adu.getDataLen() != 4) return MODBUS_RTU_MASTER_UNEXPECTED_LENGTH; + if (adu.getDataRegister(0) != startAddress) return MODBUS_RTU_MASTER_UNEXPECTED_ADDRESS; + if (adu.getDataRegister(2) != quantity) return MODBUS_RTU_MASTER_UNEXPECTED_QUANTITY; + return MODBUS_RTU_MASTER_SUCCESS; +} + + + +uint8_t ModbusRTUMaster::getExceptionResponse() { + return _exceptionResponse; +} + + + +ModbusRTUMasterError ModbusRTUMaster::_readValues(uint8_t id, uint8_t functionCode, uint16_t startAddress, bool buf[], uint16_t quantity) { + if (id < 1 || id > 247) return MODBUS_RTU_MASTER_INVALID_ID; + if (!buf) return MODBUS_RTU_MASTER_INVALID_BUFFER; + if (quantity == 0 || quantity > 2000) return MODBUS_RTU_MASTER_INVALID_QUANTITY; + ModbusADU adu; + adu.setUnitId(id); + adu.setFunctionCode(functionCode); + adu.setDataRegister(0, startAddress); + adu.setDataRegister(2, quantity); + adu.setDataLen(4); + _rtuComm.writeAdu(adu); + ModbusRTUCommError commError = _rtuComm.readAdu(adu); + if (commError) return _translateCommError(commError); + if (adu.getUnitId() != id) return MODBUS_RTU_MASTER_UNEXPECTED_ID; + if (adu.getFunctionCode() == (functionCode + 0x80)) { + _exceptionResponse = adu.data[0]; + return MODBUS_RTU_MASTER_EXCEPTION_RESPONSE; + } + if (adu.getFunctionCode() != functionCode) return MODBUS_RTU_MASTER_UNEXPECTED_FUNCTION_CODE; + uint16_t byteCount = div8RndUp(quantity); + if (adu.getDataLen() != (1 + byteCount)) return MODBUS_RTU_MASTER_UNEXPECTED_LENGTH; + if (adu.data[0] != byteCount) return MODBUS_RTU_MASTER_UNEXPECTED_BYTE_COUNT; + for (uint16_t i = 0; i < quantity; i++) { + buf[i] = bitRead(adu.data[1 + (i >> 3)], i & 7); + } + return MODBUS_RTU_MASTER_SUCCESS; +} + +ModbusRTUMasterError ModbusRTUMaster::_readValues(uint8_t id, uint8_t functionCode, uint16_t startAddress, uint16_t buf[], uint16_t quantity) { + if (id < 1 || id > 247) return MODBUS_RTU_MASTER_INVALID_ID; + if (!buf) return MODBUS_RTU_MASTER_INVALID_BUFFER; + if (quantity == 0 || quantity > 125) return MODBUS_RTU_MASTER_INVALID_QUANTITY; + ModbusADU adu; + adu.setUnitId(id); + adu.setFunctionCode(functionCode); + adu.setDataRegister(0, startAddress); + adu.setDataRegister(2, quantity); + adu.setDataLen(4); + _rtuComm.writeAdu(adu); + ModbusRTUCommError commError = _rtuComm.readAdu(adu); + if (commError) return _translateCommError(commError); + if (adu.getUnitId() != id) return MODBUS_RTU_MASTER_UNEXPECTED_ID; + if (adu.getFunctionCode() == (functionCode + 0x80)) { + _exceptionResponse = adu.data[0]; + return MODBUS_RTU_MASTER_EXCEPTION_RESPONSE; + } + if (adu.getFunctionCode() != functionCode) return MODBUS_RTU_MASTER_UNEXPECTED_FUNCTION_CODE; + uint16_t byteCount = quantity * 2; + if (adu.getDataLen() != (1 + byteCount)) return MODBUS_RTU_MASTER_UNEXPECTED_LENGTH; + if (adu.data[0] != byteCount) return MODBUS_RTU_MASTER_UNEXPECTED_BYTE_COUNT; + for (uint16_t i = 0; i < quantity; i++) { + buf[i] = adu.getDataRegister(1 + (i * 2)); + } + return MODBUS_RTU_MASTER_SUCCESS; +} + +ModbusRTUMasterError ModbusRTUMaster::_writeSingleValue(uint8_t id, uint8_t functionCode, uint16_t address, uint16_t value) { + if (id > 247) return MODBUS_RTU_MASTER_INVALID_ID; + ModbusADU adu; + adu.setUnitId(id); + adu.setFunctionCode(functionCode); + adu.setDataRegister(0, address); + adu.setDataRegister(2, value); + adu.setDataLen(4); + _rtuComm.writeAdu(adu); + if (id == 0) return MODBUS_RTU_MASTER_SUCCESS; + ModbusRTUCommError commError = _rtuComm.readAdu(adu); + if (commError) return _translateCommError(commError); + if (adu.getUnitId() != id) return MODBUS_RTU_MASTER_UNEXPECTED_ID; + if (adu.getFunctionCode() == (functionCode + 0x80)) { + _exceptionResponse = adu.data[0]; + return MODBUS_RTU_MASTER_EXCEPTION_RESPONSE; + } + if (adu.getFunctionCode() != functionCode) return MODBUS_RTU_MASTER_UNEXPECTED_FUNCTION_CODE; + if (adu.getDataLen() != 4) return MODBUS_RTU_MASTER_UNEXPECTED_LENGTH; + if (adu.getDataRegister(0) != address) return MODBUS_RTU_MASTER_UNEXPECTED_ADDRESS; + if (adu.getDataRegister(2) != value) return MODBUS_RTU_MASTER_UNEXPECTED_VALUE; + return MODBUS_RTU_MASTER_SUCCESS; +} + + + +ModbusRTUMasterError ModbusRTUMaster::_translateCommError(ModbusRTUCommError commError) { + switch (commError) { + case MODBUS_RTU_COMM_SUCCESS: + return MODBUS_RTU_MASTER_SUCCESS; + case MODBUS_RTU_COMM_TIMEOUT: + return MODBUS_RTU_MASTER_RESPONSE_TIMEOUT; + case MODBUS_RTU_COMM_FRAME_ERROR: + return MODBUS_RTU_MASTER_FRAME_ERROR; + case MODBUS_RTU_COMM_CRC_ERROR: + return MODBUS_RTU_MASTER_CRC_ERROR; + default: + return MODBUS_RTU_MASTER_UNKNOWN_COMM_ERROR; + } +} /************************************************************ * Modbus implementation diff --git a/IO_Modbus.h b/IO_Modbus.h index 4933eeb..be5b65b 100644 --- a/IO_Modbus.h +++ b/IO_Modbus.h @@ -52,7 +52,129 @@ #define IO_MODBUS_H #include "IODevice.h" -#include "ModbusRTUMaster.h" +class ModbusADU { + public: + uint8_t *rtu = _adu + 6; + uint8_t *tcp = _adu; + uint8_t *pdu = _adu + 7; + uint8_t *data = _adu + 8; + + void setTransactionId(uint16_t transactionId); + void setProtocolId(uint16_t protocolId); + void setLength(uint16_t length); + void setUnitId(uint8_t unitId); + void setFunctionCode(uint8_t functionCode); + void setDataRegister(uint8_t index, uint16_t value); + + void setRtuLen(uint16_t rtuLen); + void setTcpLen(uint16_t tcpLen); + void setPduLen(uint16_t pduLen); + void setDataLen(uint16_t dataLen); + + uint16_t getTransactionId(); + uint16_t getProtocolId(); + uint16_t getLength(); + uint8_t getUnitId(); + uint8_t getFunctionCode(); + uint16_t getDataRegister(uint8_t index); + + uint16_t getRtuLen(); + uint16_t getTcpLen(); + uint16_t getPduLen(); + uint16_t getDataLen(); + + void updateCrc(); + bool crcGood(); + + void prepareExceptionResponse(uint8_t exceptionCode); + + private: + uint8_t _adu[262]; + void _setRegister(uint8_t *buf, uint16_t index, uint16_t value); + uint16_t _getRegister(uint8_t *buf, uint16_t index); + uint16_t _calculateCrc(uint16_t len); + +}; + +uint16_t div8RndUp(uint16_t value); + +enum ModbusRTUCommError : uint8_t { + MODBUS_RTU_COMM_SUCCESS = 0, + MODBUS_RTU_COMM_TIMEOUT = 1, + MODBUS_RTU_COMM_FRAME_ERROR = 2, + MODBUS_RTU_COMM_CRC_ERROR = 3 +}; + +class ModbusRTUComm { + public: + ModbusRTUComm(Stream& serial, int8_t dePin = -1, int8_t rePin = -1); + void begin(unsigned long baud, uint32_t config = SERIAL_8N1); + void setTimeout(unsigned long timeout); + ModbusRTUCommError readAdu(ModbusADU& adu); + void writeAdu(ModbusADU& adu); + void clearRxBuffer(); + + private: + Stream& _serial; + int8_t _dePin; + int8_t _rePin; + unsigned long _charTimeout; + unsigned long _frameTimeout; + unsigned long _postDelay = 0; + unsigned long _readTimeout = 0; +}; + +enum ModbusRTUMasterError : uint8_t { + MODBUS_RTU_MASTER_SUCCESS = 0, + MODBUS_RTU_MASTER_INVALID_ID = 1, + MODBUS_RTU_MASTER_INVALID_BUFFER = 2, + MODBUS_RTU_MASTER_INVALID_QUANTITY = 3, + MODBUS_RTU_MASTER_RESPONSE_TIMEOUT = 4, + MODBUS_RTU_MASTER_FRAME_ERROR = 5, + MODBUS_RTU_MASTER_CRC_ERROR = 6, + MODBUS_RTU_MASTER_UNKNOWN_COMM_ERROR = 7, + MODBUS_RTU_MASTER_UNEXPECTED_ID = 8, + MODBUS_RTU_MASTER_EXCEPTION_RESPONSE = 9, + MODBUS_RTU_MASTER_UNEXPECTED_FUNCTION_CODE = 10, + MODBUS_RTU_MASTER_UNEXPECTED_LENGTH = 11, + MODBUS_RTU_MASTER_UNEXPECTED_BYTE_COUNT = 12, + MODBUS_RTU_MASTER_UNEXPECTED_ADDRESS = 13, + MODBUS_RTU_MASTER_UNEXPECTED_VALUE = 14, + MODBUS_RTU_MASTER_UNEXPECTED_QUANTITY = 15 +}; + +class ModbusRTUMaster { + public: + ModbusRTUMaster(Stream& serial, int8_t dePin = -1, int8_t rePin = -1); + void setTimeout(unsigned long timeout); + void begin(unsigned long baud, uint32_t config = SERIAL_8N1); + + ModbusRTUMasterError readCoils(uint8_t id, uint16_t startAddress, bool buf[], uint16_t quantity); + ModbusRTUMasterError readDiscreteInputs(uint8_t id, uint16_t startAddress, bool buf[], uint16_t quantity); + ModbusRTUMasterError readHoldingRegisters(uint8_t id, uint16_t startAddress, uint16_t buf[], uint16_t quantity); + ModbusRTUMasterError readInputRegisters(uint8_t id, uint16_t startAddress, uint16_t buf[], uint16_t quantity); + + ModbusRTUMasterError writeSingleCoil(uint8_t id, uint16_t address, bool value); + ModbusRTUMasterError writeSingleHoldingRegister(uint8_t id, uint16_t address, uint16_t value); + ModbusRTUMasterError writeMultipleCoils(uint8_t id, uint16_t startAddress, bool buf[], uint16_t quantity); + ModbusRTUMasterError writeMultipleHoldingRegisters(uint8_t id, uint16_t startAddress, uint16_t buf[], uint16_t quantity); + + uint8_t getExceptionResponse(); + + private: + ModbusRTUComm _rtuComm; + uint8_t _exceptionResponse = 0; + + ModbusRTUMasterError _readValues(uint8_t id, uint8_t functionCode, uint16_t startAddress, bool buf[], uint16_t quantity); + ModbusRTUMasterError _readValues(uint8_t id, uint8_t functionCode, uint16_t startAddress, uint16_t buf[], uint16_t quantity); + ModbusRTUMasterError _writeSingleValue(uint8_t id, uint8_t functionCode, uint16_t address, uint16_t value); + + ModbusRTUMasterError _translateCommError(ModbusRTUCommError commError); + +}; + + + /********************************************************************** * Modbusnode class * diff --git a/ModbusADU.cpp b/ModbusADU.cpp deleted file mode 100644 index b7752b2..0000000 --- a/ModbusADU.cpp +++ /dev/null @@ -1,153 +0,0 @@ -#include "ModbusADU.h" - -void ModbusADU::setTransactionId(uint16_t transactionId) { - _setRegister(tcp, 0, transactionId); -} - -void ModbusADU::setProtocolId(uint16_t protocolId) { - _setRegister(tcp, 2, protocolId); -} - -void ModbusADU::setLength(uint16_t length) { - if (length < 3 || length > 254) _setRegister(tcp, 4, 0); - else _setRegister(tcp, 4, length); -} - -void ModbusADU::setUnitId(uint8_t unitId) { - tcp[6] = unitId; -} - -void ModbusADU::setFunctionCode(uint8_t functionCode) { - pdu[0] = functionCode; -} - -void ModbusADU::setDataRegister(uint8_t index, uint16_t value) { - _setRegister(data, index, value); -} - - - -void ModbusADU::setRtuLen(uint16_t rtuLen) { - setLength(rtuLen - 2); -} - -void ModbusADU::setTcpLen(uint16_t tcpLen) { - setLength(tcpLen - 6); -} - -void ModbusADU::setPduLen(uint16_t pduLen) { - setLength(pduLen + 1); -} - -void ModbusADU::setDataLen(uint16_t dataLen) { - setLength(dataLen + 2); -} - - - -uint16_t ModbusADU::getTransactionId() { - return _getRegister(tcp, 0); -} - -uint16_t ModbusADU::getProtocolId() { - return _getRegister(tcp, 2); -} - -uint16_t ModbusADU::getLength() { - uint16_t length = _getRegister(tcp, 4); - if (length < 3 || length > 254) return 0; - else return length; -} - -uint8_t ModbusADU::getUnitId() { - return tcp[6]; -} - -uint8_t ModbusADU::getFunctionCode() { - return pdu[0]; -} - -uint16_t ModbusADU::getDataRegister(uint8_t index) { - return _getRegister(data, index); -} - - - -uint16_t ModbusADU::getRtuLen() { - uint16_t len = getLength(); - if (len == 0) return 0; - else return len + 2; -} - -uint16_t ModbusADU::getTcpLen() { - uint16_t len = getLength(); - if (len == 0) return 0; - else return len + 6; -} - -uint16_t ModbusADU::getPduLen() { - uint16_t len = getLength(); - if (len == 0) return 0; - else return len - 1; -} - -uint16_t ModbusADU::getDataLen() { - uint16_t len = getLength(); - if (len == 0) return 0; - else return len - 2; -} - - - -void ModbusADU::updateCrc() { - uint16_t len = getLength(); - uint16_t crc = _calculateCrc(len); - rtu[len] = lowByte(crc); - rtu[len + 1] = highByte(crc); -} - -bool ModbusADU::crcGood() { - uint16_t len = getLength(); - uint16_t aduCrc = rtu[len] | (rtu[len + 1] << 8); - uint16_t calculatedCrc = _calculateCrc(len); - if (aduCrc == calculatedCrc) return true; - else return false; -} - - - -void ModbusADU::prepareExceptionResponse(uint8_t exceptionCode) { - pdu[0] |= 0x80; - pdu[1] = exceptionCode; - setPduLen(2); -} - - - -void ModbusADU::_setRegister(uint8_t *buf, uint16_t index, uint16_t value) { - buf[index] = highByte(value); - buf[index + 1] = lowByte(value); -} - -uint16_t ModbusADU::_getRegister(uint8_t *buf, uint16_t index) { - return (buf[index] << 8) | buf[index + 1]; -} - -uint16_t ModbusADU::_calculateCrc(uint16_t len) { - uint16_t value = 0xFFFF; - for (uint16_t i = 0; i < len; i++) { - value ^= (uint16_t)rtu[i]; - for (uint8_t j = 0; j < 8; j++) { - bool lsb = value & 1; - value >>= 1; - if (lsb == true) value ^= 0xA001; - } - } - return value; -} - - - -uint16_t div8RndUp(uint16_t value) { - return (value + 7) >> 3; -} \ No newline at end of file diff --git a/ModbusADU.h b/ModbusADU.h deleted file mode 100644 index 2aa72d9..0000000 --- a/ModbusADU.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef ModbusADU_h -#define ModbusADU_h - -#include "Arduino.h" - -class ModbusADU { - public: - uint8_t *rtu = _adu + 6; - uint8_t *tcp = _adu; - uint8_t *pdu = _adu + 7; - uint8_t *data = _adu + 8; - - void setTransactionId(uint16_t transactionId); - void setProtocolId(uint16_t protocolId); - void setLength(uint16_t length); - void setUnitId(uint8_t unitId); - void setFunctionCode(uint8_t functionCode); - void setDataRegister(uint8_t index, uint16_t value); - - void setRtuLen(uint16_t rtuLen); - void setTcpLen(uint16_t tcpLen); - void setPduLen(uint16_t pduLen); - void setDataLen(uint16_t dataLen); - - uint16_t getTransactionId(); - uint16_t getProtocolId(); - uint16_t getLength(); - uint8_t getUnitId(); - uint8_t getFunctionCode(); - uint16_t getDataRegister(uint8_t index); - - uint16_t getRtuLen(); - uint16_t getTcpLen(); - uint16_t getPduLen(); - uint16_t getDataLen(); - - void updateCrc(); - bool crcGood(); - - void prepareExceptionResponse(uint8_t exceptionCode); - - private: - uint8_t _adu[262]; - void _setRegister(uint8_t *buf, uint16_t index, uint16_t value); - uint16_t _getRegister(uint8_t *buf, uint16_t index); - uint16_t _calculateCrc(uint16_t len); - -}; - -uint16_t div8RndUp(uint16_t value); - -#endif \ No newline at end of file diff --git a/ModbusRTUComm.cpp b/ModbusRTUComm.cpp deleted file mode 100644 index 2abbe96..0000000 --- a/ModbusRTUComm.cpp +++ /dev/null @@ -1,98 +0,0 @@ -#include "ModbusRTUComm.h" - -ModbusRTUComm::ModbusRTUComm(Stream& serial, int8_t dePin, int8_t rePin) : _serial(serial) { - _dePin = dePin; - _rePin = rePin; -} - -void ModbusRTUComm::begin(unsigned long baud, uint32_t config) { - unsigned long bitsPerChar; - switch (config) { - case SERIAL_8E2: - case SERIAL_8O2: - bitsPerChar = 12; - break; - case SERIAL_8N2: - case SERIAL_8E1: - case SERIAL_8O1: - bitsPerChar = 11; - break; - case SERIAL_8N1: - default: - bitsPerChar = 10; - break; - } - if (baud <= 19200) { - _charTimeout = (bitsPerChar * 2500000) / baud; - _frameTimeout = (bitsPerChar * 4500000) / baud; - } - else { - _charTimeout = (bitsPerChar * 1000000) / baud + 750; - _frameTimeout = (bitsPerChar * 1000000) / baud + 1750; - } - #if defined(ARDUINO_UNOR4_MINIMA) || defined(ARDUINO_UNOR4_WIFI) || defined(ARDUINO_GIGA) || (defined(ARDUINO_NANO_RP2040_CONNECT) && defined(ARDUINO_ARCH_MBED)) - _postDelay = ((bitsPerChar * 1000000) / baud) + 2; - #endif - if (_dePin >= 0) { - pinMode(_dePin, OUTPUT); - digitalWrite(_dePin, LOW); - } - if (_rePin >= 0) { - pinMode(_rePin, OUTPUT); - digitalWrite(_rePin, LOW); - } - clearRxBuffer(); -} - -void ModbusRTUComm::setTimeout(unsigned long timeout) { - _readTimeout = timeout; -} - -ModbusRTUCommError ModbusRTUComm::readAdu(ModbusADU& adu) { - adu.setRtuLen(0); - unsigned long startMillis = millis(); - while (!_serial.available()) { - if (millis() - startMillis >= _readTimeout) return MODBUS_RTU_COMM_TIMEOUT; - } - uint16_t len = 0; - unsigned long startMicros = micros(); - do { - if (_serial.available()) { - startMicros = micros(); - adu.rtu[len] = _serial.read(); - len++; - } - } while (micros() - startMicros <= _charTimeout && len < 256); - adu.setRtuLen(len); - while (micros() - startMicros < _frameTimeout); - if (_serial.available()) { - adu.setRtuLen(0); - return MODBUS_RTU_COMM_FRAME_ERROR; - } - if (!adu.crcGood()) { - adu.setRtuLen(0); - return MODBUS_RTU_COMM_CRC_ERROR; - } - return MODBUS_RTU_COMM_SUCCESS; -} - -void ModbusRTUComm::writeAdu(ModbusADU& adu) { - adu.updateCrc(); - if (_dePin >= 0) digitalWrite(_dePin, HIGH); - if (_rePin >= 0) digitalWrite(_rePin, HIGH); - _serial.write(adu.rtu, adu.getRtuLen()); - _serial.flush(); - delayMicroseconds(_postDelay); - if (_dePin >= 0) digitalWrite(_dePin, LOW); - if (_rePin >= 0) digitalWrite(_rePin, LOW); -} - -void ModbusRTUComm::clearRxBuffer() { - unsigned long startMicros = micros(); - do { - if (_serial.available() > 0) { - startMicros = micros(); - _serial.read(); - } - } while (micros() - startMicros < _frameTimeout); -} diff --git a/ModbusRTUComm.h b/ModbusRTUComm.h deleted file mode 100644 index cae7234..0000000 --- a/ModbusRTUComm.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef ModbusRTUComm_h -#define ModbusRTUComm_h - -#include "Arduino.h" -#include "ModbusADU.h" - -enum ModbusRTUCommError : uint8_t { - MODBUS_RTU_COMM_SUCCESS = 0, - MODBUS_RTU_COMM_TIMEOUT = 1, - MODBUS_RTU_COMM_FRAME_ERROR = 2, - MODBUS_RTU_COMM_CRC_ERROR = 3 -}; - -class ModbusRTUComm { - public: - ModbusRTUComm(Stream& serial, int8_t dePin = -1, int8_t rePin = -1); - void begin(unsigned long baud, uint32_t config = SERIAL_8N1); - void setTimeout(unsigned long timeout); - ModbusRTUCommError readAdu(ModbusADU& adu); - void writeAdu(ModbusADU& adu); - void clearRxBuffer(); - - private: - Stream& _serial; - int8_t _dePin; - int8_t _rePin; - unsigned long _charTimeout; - unsigned long _frameTimeout; - unsigned long _postDelay = 0; - unsigned long _readTimeout = 0; -}; - -#endif \ No newline at end of file diff --git a/ModbusRTUMaster.cpp b/ModbusRTUMaster.cpp deleted file mode 100644 index 897ce5a..0000000 --- a/ModbusRTUMaster.cpp +++ /dev/null @@ -1,216 +0,0 @@ -#include "ModbusRTUMaster.h" - -ModbusRTUMaster::ModbusRTUMaster(Stream& serial, int8_t dePin, int8_t rePin) : _rtuComm(serial, dePin, rePin) { - _rtuComm.setTimeout(500); -} - -void ModbusRTUMaster::setTimeout(unsigned long timeout) { - _rtuComm.setTimeout(timeout); -} - -void ModbusRTUMaster::begin(unsigned long baud, uint32_t config) { - _rtuComm.begin(baud, config); -} - - - -ModbusRTUMasterError ModbusRTUMaster::readCoils(uint8_t id, uint16_t startAddress, bool buf[], uint16_t quantity) { - return _readValues(id, 1, startAddress, buf, quantity); -} - -ModbusRTUMasterError ModbusRTUMaster::readDiscreteInputs(uint8_t id, uint16_t startAddress, bool buf[], uint16_t quantity) { - return _readValues(id, 2, startAddress, buf, quantity); -} - -ModbusRTUMasterError ModbusRTUMaster::readHoldingRegisters(uint8_t id, uint16_t startAddress, uint16_t buf[], uint16_t quantity) { - return _readValues(id, 3, startAddress, buf, quantity); -} - -ModbusRTUMasterError ModbusRTUMaster::readInputRegisters(uint8_t id, uint16_t startAddress, uint16_t buf[], uint16_t quantity) { - return _readValues(id, 4, startAddress, buf, quantity); -} - - - -ModbusRTUMasterError ModbusRTUMaster::writeSingleCoil(uint8_t id, uint16_t address, bool value) { - return _writeSingleValue(id, 5, address, ((value) ? 0xFF00 : 0x0000)); -} - -ModbusRTUMasterError ModbusRTUMaster::writeSingleHoldingRegister(uint8_t id, uint16_t address, uint16_t value) { - return _writeSingleValue(id, 6, address, value); -} - - - -ModbusRTUMasterError ModbusRTUMaster::writeMultipleCoils(uint8_t id, uint16_t startAddress, bool buf[], uint16_t quantity) { - const uint8_t functionCode = 15; - if (id > 247) return MODBUS_RTU_MASTER_INVALID_ID; - if (!buf) return MODBUS_RTU_MASTER_INVALID_BUFFER; - if (quantity == 0 || quantity > 1968) return MODBUS_RTU_MASTER_INVALID_QUANTITY; - ModbusADU adu; - uint16_t byteCount = div8RndUp(quantity); - adu.setUnitId(id); - adu.setFunctionCode(functionCode); - adu.setDataRegister(0, startAddress); - adu.setDataRegister(2, quantity); - adu.data[4] = byteCount; - for (uint16_t i = 0; i < quantity; i++) { - bitWrite(adu.data[5 + (i >> 3)], i & 7, buf[i]); - } - for (uint16_t i = quantity; i < (byteCount * 8); i++) { - bitClear(adu.data[5 + (i >> 3)], i & 7); - } - adu.setDataLen(5 + byteCount); - _rtuComm.writeAdu(adu); - if (id == 0) return MODBUS_RTU_MASTER_SUCCESS; - ModbusRTUCommError commError = _rtuComm.readAdu(adu); - if (commError) return _translateCommError(commError); - if (adu.getUnitId() != id) return MODBUS_RTU_MASTER_UNEXPECTED_ID; - if (adu.getFunctionCode() == (functionCode + 0x80)) { - _exceptionResponse = adu.data[0]; - return MODBUS_RTU_MASTER_EXCEPTION_RESPONSE; - } - if (adu.getFunctionCode() != functionCode) return MODBUS_RTU_MASTER_UNEXPECTED_FUNCTION_CODE; - if (adu.getDataLen() != 4) return MODBUS_RTU_MASTER_UNEXPECTED_LENGTH; - if (adu.getDataRegister(0) != startAddress) return MODBUS_RTU_MASTER_UNEXPECTED_ADDRESS; - if (adu.getDataRegister(2) != quantity) return MODBUS_RTU_MASTER_UNEXPECTED_QUANTITY; - return MODBUS_RTU_MASTER_SUCCESS; -} - -ModbusRTUMasterError ModbusRTUMaster::writeMultipleHoldingRegisters(uint8_t id, uint16_t startAddress, uint16_t buf[], uint16_t quantity) { - uint8_t functionCode = 16; - if (id > 247) return MODBUS_RTU_MASTER_INVALID_ID; - if (!buf) return MODBUS_RTU_MASTER_INVALID_BUFFER; - if (quantity == 0 || quantity > 123) return MODBUS_RTU_MASTER_INVALID_QUANTITY; - uint16_t byteCount = quantity * 2; - ModbusADU adu; - adu.setUnitId(id); - adu.setFunctionCode(functionCode); - adu.setDataRegister(0, startAddress); - adu.setDataRegister(2, quantity); - adu.data[4] = byteCount; - for (uint16_t i = 0; i < quantity; i++) { - adu.setDataRegister(5 + (i * 2), buf[i]); - } - adu.setDataLen(5 + byteCount); - _rtuComm.writeAdu(adu); - if (id == 0) return MODBUS_RTU_MASTER_SUCCESS; - ModbusRTUCommError commError = _rtuComm.readAdu(adu); - if (commError) return _translateCommError(commError); - if (adu.getUnitId() != id) return MODBUS_RTU_MASTER_UNEXPECTED_ID; - if (adu.getFunctionCode() == (functionCode + 0x80)) { - _exceptionResponse = adu.data[0]; - return MODBUS_RTU_MASTER_EXCEPTION_RESPONSE; - } - if (adu.getFunctionCode() != functionCode) return MODBUS_RTU_MASTER_UNEXPECTED_FUNCTION_CODE; - if (adu.getDataLen() != 4) return MODBUS_RTU_MASTER_UNEXPECTED_LENGTH; - if (adu.getDataRegister(0) != startAddress) return MODBUS_RTU_MASTER_UNEXPECTED_ADDRESS; - if (adu.getDataRegister(2) != quantity) return MODBUS_RTU_MASTER_UNEXPECTED_QUANTITY; - return MODBUS_RTU_MASTER_SUCCESS; -} - - - -uint8_t ModbusRTUMaster::getExceptionResponse() { - return _exceptionResponse; -} - - - -ModbusRTUMasterError ModbusRTUMaster::_readValues(uint8_t id, uint8_t functionCode, uint16_t startAddress, bool buf[], uint16_t quantity) { - if (id < 1 || id > 247) return MODBUS_RTU_MASTER_INVALID_ID; - if (!buf) return MODBUS_RTU_MASTER_INVALID_BUFFER; - if (quantity == 0 || quantity > 2000) return MODBUS_RTU_MASTER_INVALID_QUANTITY; - ModbusADU adu; - adu.setUnitId(id); - adu.setFunctionCode(functionCode); - adu.setDataRegister(0, startAddress); - adu.setDataRegister(2, quantity); - adu.setDataLen(4); - _rtuComm.writeAdu(adu); - ModbusRTUCommError commError = _rtuComm.readAdu(adu); - if (commError) return _translateCommError(commError); - if (adu.getUnitId() != id) return MODBUS_RTU_MASTER_UNEXPECTED_ID; - if (adu.getFunctionCode() == (functionCode + 0x80)) { - _exceptionResponse = adu.data[0]; - return MODBUS_RTU_MASTER_EXCEPTION_RESPONSE; - } - if (adu.getFunctionCode() != functionCode) return MODBUS_RTU_MASTER_UNEXPECTED_FUNCTION_CODE; - uint16_t byteCount = div8RndUp(quantity); - if (adu.getDataLen() != (1 + byteCount)) return MODBUS_RTU_MASTER_UNEXPECTED_LENGTH; - if (adu.data[0] != byteCount) return MODBUS_RTU_MASTER_UNEXPECTED_BYTE_COUNT; - for (uint16_t i = 0; i < quantity; i++) { - buf[i] = bitRead(adu.data[1 + (i >> 3)], i & 7); - } - return MODBUS_RTU_MASTER_SUCCESS; -} - -ModbusRTUMasterError ModbusRTUMaster::_readValues(uint8_t id, uint8_t functionCode, uint16_t startAddress, uint16_t buf[], uint16_t quantity) { - if (id < 1 || id > 247) return MODBUS_RTU_MASTER_INVALID_ID; - if (!buf) return MODBUS_RTU_MASTER_INVALID_BUFFER; - if (quantity == 0 || quantity > 125) return MODBUS_RTU_MASTER_INVALID_QUANTITY; - ModbusADU adu; - adu.setUnitId(id); - adu.setFunctionCode(functionCode); - adu.setDataRegister(0, startAddress); - adu.setDataRegister(2, quantity); - adu.setDataLen(4); - _rtuComm.writeAdu(adu); - ModbusRTUCommError commError = _rtuComm.readAdu(adu); - if (commError) return _translateCommError(commError); - if (adu.getUnitId() != id) return MODBUS_RTU_MASTER_UNEXPECTED_ID; - if (adu.getFunctionCode() == (functionCode + 0x80)) { - _exceptionResponse = adu.data[0]; - return MODBUS_RTU_MASTER_EXCEPTION_RESPONSE; - } - if (adu.getFunctionCode() != functionCode) return MODBUS_RTU_MASTER_UNEXPECTED_FUNCTION_CODE; - uint16_t byteCount = quantity * 2; - if (adu.getDataLen() != (1 + byteCount)) return MODBUS_RTU_MASTER_UNEXPECTED_LENGTH; - if (adu.data[0] != byteCount) return MODBUS_RTU_MASTER_UNEXPECTED_BYTE_COUNT; - for (uint16_t i = 0; i < quantity; i++) { - buf[i] = adu.getDataRegister(1 + (i * 2)); - } - return MODBUS_RTU_MASTER_SUCCESS; -} - -ModbusRTUMasterError ModbusRTUMaster::_writeSingleValue(uint8_t id, uint8_t functionCode, uint16_t address, uint16_t value) { - if (id > 247) return MODBUS_RTU_MASTER_INVALID_ID; - ModbusADU adu; - adu.setUnitId(id); - adu.setFunctionCode(functionCode); - adu.setDataRegister(0, address); - adu.setDataRegister(2, value); - adu.setDataLen(4); - _rtuComm.writeAdu(adu); - if (id == 0) return MODBUS_RTU_MASTER_SUCCESS; - ModbusRTUCommError commError = _rtuComm.readAdu(adu); - if (commError) return _translateCommError(commError); - if (adu.getUnitId() != id) return MODBUS_RTU_MASTER_UNEXPECTED_ID; - if (adu.getFunctionCode() == (functionCode + 0x80)) { - _exceptionResponse = adu.data[0]; - return MODBUS_RTU_MASTER_EXCEPTION_RESPONSE; - } - if (adu.getFunctionCode() != functionCode) return MODBUS_RTU_MASTER_UNEXPECTED_FUNCTION_CODE; - if (adu.getDataLen() != 4) return MODBUS_RTU_MASTER_UNEXPECTED_LENGTH; - if (adu.getDataRegister(0) != address) return MODBUS_RTU_MASTER_UNEXPECTED_ADDRESS; - if (adu.getDataRegister(2) != value) return MODBUS_RTU_MASTER_UNEXPECTED_VALUE; - return MODBUS_RTU_MASTER_SUCCESS; -} - - - -ModbusRTUMasterError ModbusRTUMaster::_translateCommError(ModbusRTUCommError commError) { - switch (commError) { - case MODBUS_RTU_COMM_SUCCESS: - return MODBUS_RTU_MASTER_SUCCESS; - case MODBUS_RTU_COMM_TIMEOUT: - return MODBUS_RTU_MASTER_RESPONSE_TIMEOUT; - case MODBUS_RTU_COMM_FRAME_ERROR: - return MODBUS_RTU_MASTER_FRAME_ERROR; - case MODBUS_RTU_COMM_CRC_ERROR: - return MODBUS_RTU_MASTER_CRC_ERROR; - default: - return MODBUS_RTU_MASTER_UNKNOWN_COMM_ERROR; - } -} - diff --git a/ModbusRTUMaster.h b/ModbusRTUMaster.h deleted file mode 100644 index d9193c3..0000000 --- a/ModbusRTUMaster.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef ModbusRTUMaster_h -#define ModbusRTUMaster_h - -#include "Arduino.h" -#include "ModbusADU.h" -#include "ModbusRTUComm.h" - -enum ModbusRTUMasterError : uint8_t { - MODBUS_RTU_MASTER_SUCCESS = 0, - MODBUS_RTU_MASTER_INVALID_ID = 1, - MODBUS_RTU_MASTER_INVALID_BUFFER = 2, - MODBUS_RTU_MASTER_INVALID_QUANTITY = 3, - MODBUS_RTU_MASTER_RESPONSE_TIMEOUT = 4, - MODBUS_RTU_MASTER_FRAME_ERROR = 5, - MODBUS_RTU_MASTER_CRC_ERROR = 6, - MODBUS_RTU_MASTER_UNKNOWN_COMM_ERROR = 7, - MODBUS_RTU_MASTER_UNEXPECTED_ID = 8, - MODBUS_RTU_MASTER_EXCEPTION_RESPONSE = 9, - MODBUS_RTU_MASTER_UNEXPECTED_FUNCTION_CODE = 10, - MODBUS_RTU_MASTER_UNEXPECTED_LENGTH = 11, - MODBUS_RTU_MASTER_UNEXPECTED_BYTE_COUNT = 12, - MODBUS_RTU_MASTER_UNEXPECTED_ADDRESS = 13, - MODBUS_RTU_MASTER_UNEXPECTED_VALUE = 14, - MODBUS_RTU_MASTER_UNEXPECTED_QUANTITY = 15 -}; - -class ModbusRTUMaster { - public: - ModbusRTUMaster(Stream& serial, int8_t dePin = -1, int8_t rePin = -1); - void setTimeout(unsigned long timeout); - void begin(unsigned long baud, uint32_t config = SERIAL_8N1); - - ModbusRTUMasterError readCoils(uint8_t id, uint16_t startAddress, bool buf[], uint16_t quantity); - ModbusRTUMasterError readDiscreteInputs(uint8_t id, uint16_t startAddress, bool buf[], uint16_t quantity); - ModbusRTUMasterError readHoldingRegisters(uint8_t id, uint16_t startAddress, uint16_t buf[], uint16_t quantity); - ModbusRTUMasterError readInputRegisters(uint8_t id, uint16_t startAddress, uint16_t buf[], uint16_t quantity); - - ModbusRTUMasterError writeSingleCoil(uint8_t id, uint16_t address, bool value); - ModbusRTUMasterError writeSingleHoldingRegister(uint8_t id, uint16_t address, uint16_t value); - ModbusRTUMasterError writeMultipleCoils(uint8_t id, uint16_t startAddress, bool buf[], uint16_t quantity); - ModbusRTUMasterError writeMultipleHoldingRegisters(uint8_t id, uint16_t startAddress, uint16_t buf[], uint16_t quantity); - - uint8_t getExceptionResponse(); - - private: - ModbusRTUComm _rtuComm; - uint8_t _exceptionResponse = 0; - - ModbusRTUMasterError _readValues(uint8_t id, uint8_t functionCode, uint16_t startAddress, bool buf[], uint16_t quantity); - ModbusRTUMasterError _readValues(uint8_t id, uint8_t functionCode, uint16_t startAddress, uint16_t buf[], uint16_t quantity); - ModbusRTUMasterError _writeSingleValue(uint8_t id, uint8_t functionCode, uint16_t address, uint16_t value); - - ModbusRTUMasterError _translateCommError(ModbusRTUCommError commError); - -}; - -#endif