From 4a429bfcc8c2bf0933b75ce014f1ce27191ae52a Mon Sep 17 00:00:00 2001 From: Andrey Klimov Date: Sun, 14 Jan 2018 23:25:30 +0300 Subject: [PATCH 1/9] Update ModbusMaster.cpp Add tolerance to random noise receiving after transmission in half-duplex mode (Invalid Slave 0xE1 error preventing) --- src/ModbusMaster.cpp | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/ModbusMaster.cpp b/src/ModbusMaster.cpp index 4169e58..575a20c 100644 --- a/src/ModbusMaster.cpp +++ b/src/ModbusMaster.cpp @@ -726,12 +726,16 @@ uint8_t ModbusMaster::ModbusMasterTransaction(uint8_t u8MBFunction) while (u8BytesLeft && !u8MBStatus) { if (_serial->available()) - { + { uint8_t ch; #if __MODBUSMASTER_DEBUG__ digitalWrite(__MODBUSMASTER_DEBUG_PIN_A__, true); #endif - u8ModbusADU[u8ModbusADUSize++] = _serial->read(); - u8BytesLeft--; + ch = _serial->read(); + if ((ch == _u8MBSlave) || u8ModbusADUSize) + { + u8ModbusADU[u8ModbusADUSize++]=ch; + u8BytesLeft--; + } #if __MODBUSMASTER_DEBUG__ digitalWrite(__MODBUSMASTER_DEBUG_PIN_A__, false); #endif @@ -753,13 +757,6 @@ uint8_t ModbusMaster::ModbusMasterTransaction(uint8_t u8MBFunction) // evaluate slave ID, function code once enough bytes have been read if (u8ModbusADUSize == 5) { - // verify response is for correct Modbus slave - if (u8ModbusADU[0] != _u8MBSlave) - { - u8MBStatus = ku8MBInvalidSlaveID; - break; - } - // verify response is for correct Modbus function code (mask exception bit 7) if ((u8ModbusADU[1] & 0x7F) != u8MBFunction) { From 916f9399038697f20f1477b205a51a8003af8f9a Mon Sep 17 00:00:00 2001 From: Andrey Klimov Date: Fri, 28 Sep 2018 03:20:11 +0300 Subject: [PATCH 2/9] Rename crc16.h to crc16_.h --- src/util/{crc16.h => crc16_.h} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/util/{crc16.h => crc16_.h} (100%) diff --git a/src/util/crc16.h b/src/util/crc16_.h similarity index 100% rename from src/util/crc16.h rename to src/util/crc16_.h From 41086aef35babc32f8b6218e7ba71beb361e2307 Mon Sep 17 00:00:00 2001 From: Andrey Klimov Date: Fri, 28 Sep 2018 03:22:24 +0300 Subject: [PATCH 3/9] Resolve Bridge.cpp compilation issue Resolve "Bridge.cpp:121:33: error: '_crc_ccitt_update' was not declared in this scope" --- src/ModbusMaster.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ModbusMaster.h b/src/ModbusMaster.h index 8c433e6..cad8572 100644 --- a/src/ModbusMaster.h +++ b/src/ModbusMaster.h @@ -55,7 +55,7 @@ Set to 1 to enable debugging features within class: /* _____PROJECT INCLUDES_____________________________________________________ */ // functions to calculate Modbus Application Data Unit CRC -#include "util/crc16.h" +#include "util/crc16_.h" // functions to manipulate words #include "util/word.h" From eccd5a9c9553747003fb82d29918dee9e3fa7e6a Mon Sep 17 00:00:00 2001 From: Andrey Klimov Date: Fri, 7 May 2021 20:20:03 +0300 Subject: [PATCH 4/9] MODBUS_DEBUG compilation option added --- src/ModbusMaster.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/ModbusMaster.cpp b/src/ModbusMaster.cpp index 575a20c..17efa24 100644 --- a/src/ModbusMaster.cpp +++ b/src/ModbusMaster.cpp @@ -709,11 +709,27 @@ uint8_t ModbusMaster::ModbusMasterTransaction(uint8_t u8MBFunction) { _preTransmission(); } + + #ifdef MODBUS_DEBUG + Serial.println(); + #endif + for (i = 0; i < u8ModbusADUSize; i++) { _serial->write(u8ModbusADU[i]); + + #ifdef MODBUS_DEBUG + if (u8ModbusADU[i]<10) Serial.print("0"); + Serial.print (u8ModbusADU[i],HEX); + Serial.print(">"); + #endif + } + #ifdef MODBUS_DEBUG + Serial.println(); + #endif + u8ModbusADUSize = 0; _serial->flush(); // flush transmit buffer if (_postTransmission) @@ -731,6 +747,14 @@ uint8_t ModbusMaster::ModbusMasterTransaction(uint8_t u8MBFunction) digitalWrite(__MODBUSMASTER_DEBUG_PIN_A__, true); #endif ch = _serial->read(); + +#ifdef MODBUS_DEBUG + if (ch<10) Serial.print("0"); + Serial.print (ch,HEX); + Serial.print("<"); +#endif + + if ((ch == _u8MBSlave) || u8ModbusADUSize) { u8ModbusADU[u8ModbusADUSize++]=ch; From 6e7968757e2f187fad820e66600734a3d5c28620 Mon Sep 17 00:00:00 2001 From: Andrey Klimov Date: Sat, 28 Aug 2021 17:12:57 +0300 Subject: [PATCH 5/9] debugSerialPort definition --- src/ModbusMaster.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/ModbusMaster.cpp b/src/ModbusMaster.cpp index 17efa24..137c314 100644 --- a/src/ModbusMaster.cpp +++ b/src/ModbusMaster.cpp @@ -48,6 +48,10 @@ ModbusMaster::ModbusMaster(void) _postTransmission = 0; } +#ifndef debugSerialPort +#define debugSerialPort Serial +#endif + /** Initialize class object. @@ -711,7 +715,7 @@ uint8_t ModbusMaster::ModbusMasterTransaction(uint8_t u8MBFunction) } #ifdef MODBUS_DEBUG - Serial.println(); + debugSerialPort.println(); #endif for (i = 0; i < u8ModbusADUSize; i++) @@ -719,15 +723,15 @@ uint8_t ModbusMaster::ModbusMasterTransaction(uint8_t u8MBFunction) _serial->write(u8ModbusADU[i]); #ifdef MODBUS_DEBUG - if (u8ModbusADU[i]<10) Serial.print("0"); - Serial.print (u8ModbusADU[i],HEX); - Serial.print(">"); + if (u8ModbusADU[i]<15) debugSerialPort.print("0"); + debugSerialPort.print (u8ModbusADU[i],HEX); + debugSerialPort.print(">"); #endif } #ifdef MODBUS_DEBUG - Serial.println(); + debugSerialPort.println(); #endif u8ModbusADUSize = 0; @@ -749,9 +753,9 @@ uint8_t ModbusMaster::ModbusMasterTransaction(uint8_t u8MBFunction) ch = _serial->read(); #ifdef MODBUS_DEBUG - if (ch<10) Serial.print("0"); - Serial.print (ch,HEX); - Serial.print("<"); + if (ch<15) debugSerialPort.print("0"); + debugSerialPort.print (ch,HEX); + debugSerialPort.print("<"); #endif From 5027aef7394817af97494e4e978a8b0cf6806870 Mon Sep 17 00:00:00 2001 From: Andrey Klimov Date: Sat, 31 Dec 2022 02:10:51 +0300 Subject: [PATCH 6/9] raw data transactions --- src/ModbusMaster.cpp | 146 +++++++++++++++++++++++++++++++++++++++++++ src/ModbusMaster.h | 1 + 2 files changed, 147 insertions(+) diff --git a/src/ModbusMaster.cpp b/src/ModbusMaster.cpp index 137c314..8ab3857 100644 --- a/src/ModbusMaster.cpp +++ b/src/ModbusMaster.cpp @@ -899,3 +899,149 @@ uint8_t ModbusMaster::ModbusMasterTransaction(uint8_t u8MBFunction) _u8ResponseBufferIndex = 0; return u8MBStatus; } + +/** +Modbus-like protocols transaction engine. +Sequence: + - calculate CRC + - transmit buffer over selected serial port + CRC + - wait for/retrieve response + - return status (success/exception) + +@param u8ModbusADU - pointer to buffer +@param u8ModbusADUSize - request size +@param u8BytesLeft - how many bytes to be collected back (include CRC) - should be less then buffer size +@return 0 on success; exception number on failure + +*/ +uint8_t ModbusMaster::ModbusRawTransaction(uint8_t *u8ModbusADU,uint8_t u8ModbusADUSize, uint8_t u8BytesLeft ) +{ + + uint16_t u16CRC; + uint32_t u32StartTime; + + uint8_t u8MBStatus = ku8MBSuccess; + + // calculate CRC + u16CRC = 0xFFFF; + for (uint8_t i = 0; i < u8ModbusADUSize; i++) + { + u16CRC = crc16_update(u16CRC, u8ModbusADU[i]); + } + + // flush receive buffer before transmitting request + while (_serial->read() != -1); + + // transmit request + if (_preTransmission) + { + _preTransmission(); + } + + #ifdef MODBUS_DEBUG + debugSerialPort.println(); + #endif + + for (uint8_t i = 0; i < u8ModbusADUSize; i++) + { + _serial->write(u8ModbusADU[i]); + + #ifdef MODBUS_DEBUG + if (u8ModbusADU[i]<15) debugSerialPort.print("0"); + debugSerialPort.print (u8ModbusADU[i],HEX); + debugSerialPort.print(">"); + #endif + + } + _serial->write(lowByte(u16CRC)); + _serial->write(highByte(u16CRC)); + + #ifdef MODBUS_DEBUG + if (lowByte(u16CRC)<15) debugSerialPort.print("0"); + debugSerialPort.print (lowByte(u16CRC),HEX); + + if (highByte(u16CRC)<15) debugSerialPort.print("0"); + debugSerialPort.print (highByte(u16CRC),HEX); + debugSerialPort.print(">"); + + debugSerialPort.println(); + #endif + + + u8ModbusADUSize = 0; + _serial->flush(); // flush transmit buffer + if (_postTransmission) + { + _postTransmission(); + } + + // loop until we run out of time or bytes, or an error occurs + u32StartTime = millis(); + while (u8BytesLeft && !u8MBStatus) + { + if (_serial->available()) + { uint8_t ch; +#if __MODBUSMASTER_DEBUG__ + digitalWrite(__MODBUSMASTER_DEBUG_PIN_A__, true); +#endif + ch = _serial->read(); + +#ifdef MODBUS_DEBUG + if (ch<15) debugSerialPort.print("0"); + debugSerialPort.print (ch,HEX); + debugSerialPort.print("<"); +#endif + + + if ((ch == _u8MBSlave) || u8ModbusADUSize) + { + u8ModbusADU[u8ModbusADUSize++]=ch; + u8BytesLeft--; + } +#if __MODBUSMASTER_DEBUG__ + digitalWrite(__MODBUSMASTER_DEBUG_PIN_A__, false); +#endif + } + else + { +#if __MODBUSMASTER_DEBUG__ + digitalWrite(__MODBUSMASTER_DEBUG_PIN_B__, true); +#endif + if (_idle) + { + _idle(); + } +#if __MODBUSMASTER_DEBUG__ + digitalWrite(__MODBUSMASTER_DEBUG_PIN_B__, false); +#endif + } + + if ((millis() - u32StartTime) > ku16MBResponseTimeout) + { + u8MBStatus = ku8MBResponseTimedOut; + } + } + + // verify response is large enough to inspect further + if (!u8MBStatus && u8ModbusADUSize >= 4) + { + // calculate CRC + u16CRC = 0xFFFF; + for (uint8_t i = 0; i < (u8ModbusADUSize - 2); i++) + { + u16CRC = crc16_update(u16CRC, u8ModbusADU[i]); + } + + // verify CRC + if (!u8MBStatus && (lowByte(u16CRC) != u8ModbusADU[u8ModbusADUSize - 2] || + highByte(u16CRC) != u8ModbusADU[u8ModbusADUSize - 1])) + { + u8MBStatus = ku8MBInvalidCRC; + } + } + + _u8TransmitBufferIndex = 0; + u16TransmitBufferLength = 0; + _u8ResponseBufferIndex = 0; + return u8MBStatus; +} diff --git a/src/ModbusMaster.h b/src/ModbusMaster.h index cad8572..ab4f68c 100644 --- a/src/ModbusMaster.h +++ b/src/ModbusMaster.h @@ -216,6 +216,7 @@ class ModbusMaster uint8_t maskWriteRegister(uint16_t, uint16_t, uint16_t); uint8_t readWriteMultipleRegisters(uint16_t, uint16_t, uint16_t, uint16_t); uint8_t readWriteMultipleRegisters(uint16_t, uint16_t); + uint8_t ModbusRawTransaction(uint8_t *u8ModbusADU,uint8_t u8ModbusADUSize, uint8_t u8BytesLeft); private: Stream* _serial; ///< reference to serial port object From f68d0813acc996282bc769fd357b7dacdfd4c436 Mon Sep 17 00:00:00 2001 From: Andrey Klimov Date: Mon, 2 Jan 2023 12:15:15 +0300 Subject: [PATCH 7/9] Raw transaction - adding device address in 1-st byte --- src/ModbusMaster.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ModbusMaster.cpp b/src/ModbusMaster.cpp index 8ab3857..43dcf23 100644 --- a/src/ModbusMaster.cpp +++ b/src/ModbusMaster.cpp @@ -921,7 +921,7 @@ uint8_t ModbusMaster::ModbusRawTransaction(uint8_t *u8ModbusADU,uint8_t u8Modbus uint32_t u32StartTime; uint8_t u8MBStatus = ku8MBSuccess; - + u8ModbusADU[0] = _u8MBSlave; // calculate CRC u16CRC = 0xFFFF; for (uint8_t i = 0; i < u8ModbusADUSize; i++) From a932c126e0104722b682d7d424667e3d8142295a Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 7 Nov 2023 19:39:33 +0300 Subject: [PATCH 8/9] re-check serial input after idle handler to prevent timeouts --- src/ModbusMaster.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/ModbusMaster.cpp b/src/ModbusMaster.cpp index 43dcf23..1e08f77 100644 --- a/src/ModbusMaster.cpp +++ b/src/ModbusMaster.cpp @@ -736,6 +736,11 @@ uint8_t ModbusMaster::ModbusMasterTransaction(uint8_t u8MBFunction) u8ModbusADUSize = 0; _serial->flush(); // flush transmit buffer + + /* while (_tx_buffer->_iHead != _tx_buffer->_iTail); //wait for transmit data to be sent + // Wait for transmission to complete + while ((_pUart->UART_SR & UART_SR_TXEMPTY) != UART_SR_TXEMPTY) + ;*/ if (_postTransmission) { _postTransmission(); @@ -776,6 +781,7 @@ uint8_t ModbusMaster::ModbusMasterTransaction(uint8_t u8MBFunction) if (_idle) { _idle(); + if (_serial->available()) continue; } #if __MODBUSMASTER_DEBUG__ digitalWrite(__MODBUSMASTER_DEBUG_PIN_B__, false); @@ -1010,6 +1016,7 @@ uint8_t ModbusMaster::ModbusRawTransaction(uint8_t *u8ModbusADU,uint8_t u8Modbus if (_idle) { _idle(); + if (_serial->available()) continue; } #if __MODBUSMASTER_DEBUG__ digitalWrite(__MODBUSMASTER_DEBUG_PIN_B__, false); From 93fe8b462a043e5b126ca88b204f044c65a2c92a Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 29 Jul 2024 00:14:41 +0300 Subject: [PATCH 9/9] methods to replace response buffer --- src/ModbusMaster.cpp | 23 +++++++++++++++++++---- src/ModbusMaster.h | 17 ++++++++++++----- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/src/ModbusMaster.cpp b/src/ModbusMaster.cpp index 1e08f77..afcca2c 100644 --- a/src/ModbusMaster.cpp +++ b/src/ModbusMaster.cpp @@ -46,6 +46,9 @@ ModbusMaster::ModbusMaster(void) _idle = 0; _preTransmission = 0; _postTransmission = 0; + ku8MaxBufferSize=ku8DefMaxBufferSize; + _u16ResponseBuffer=_u16DefResponseBuffer; + } #ifndef debugSerialPort @@ -104,7 +107,7 @@ uint8_t ModbusMaster::requestFrom(uint16_t address, uint16_t quantity) void ModbusMaster::sendBit(bool data) { uint8_t txBitIndex = u16TransmitBufferLength % 16; - if ((u16TransmitBufferLength >> 4) < ku8MaxBufferSize) + if ((u16TransmitBufferLength >> 4) < ku8DefMaxBufferSize) { if (0 == txBitIndex) { @@ -119,7 +122,7 @@ void ModbusMaster::sendBit(bool data) void ModbusMaster::send(uint16_t data) { - if (_u8TransmitBufferIndex < ku8MaxBufferSize) + if (_u8TransmitBufferIndex < ku8DefMaxBufferSize) { _u16TransmitBuffer[_u8TransmitBufferIndex++] = data; u16TransmitBufferLength = _u8TransmitBufferIndex << 4; @@ -270,7 +273,7 @@ Place data in transmit buffer. */ uint8_t ModbusMaster::setTransmitBuffer(uint8_t u8Index, uint16_t u16Value) { - if (u8Index < ku8MaxBufferSize) + if (u8Index < ku8DefMaxBufferSize) { _u16TransmitBuffer[u8Index] = u16Value; return ku8MBSuccess; @@ -292,7 +295,7 @@ void ModbusMaster::clearTransmitBuffer() { uint8_t i; - for (i = 0; i < ku8MaxBufferSize; i++) + for (i = 0; i < ku8DefMaxBufferSize; i++) { _u16TransmitBuffer[i] = 0; } @@ -1052,3 +1055,15 @@ uint8_t ModbusMaster::ModbusRawTransaction(uint8_t *u8ModbusADU,uint8_t u8Modbus _u8ResponseBufferIndex = 0; return u8MBStatus; } + void ModbusMaster::setResponseBuffer(uint16_t *bufPtr,size_t bufLen) + { + ku8MaxBufferSize=bufLen; + _u16ResponseBuffer=bufPtr; + + } + + void ModbusMaster::setDefaultResponseBuffer() + { + ku8MaxBufferSize=ku8DefMaxBufferSize; + _u16ResponseBuffer=_u16DefResponseBuffer; + } \ No newline at end of file diff --git a/src/ModbusMaster.h b/src/ModbusMaster.h index ab4f68c..c906ac6 100644 --- a/src/ModbusMaster.h +++ b/src/ModbusMaster.h @@ -217,17 +217,22 @@ class ModbusMaster uint8_t readWriteMultipleRegisters(uint16_t, uint16_t, uint16_t, uint16_t); uint8_t readWriteMultipleRegisters(uint16_t, uint16_t); uint8_t ModbusRawTransaction(uint8_t *u8ModbusADU,uint8_t u8ModbusADUSize, uint8_t u8BytesLeft); - + void setResponseBuffer(uint16_t *bufPtr,size_t bufLen); + void setDefaultResponseBuffer(); + private: Stream* _serial; ///< reference to serial port object uint8_t _u8MBSlave; ///< Modbus slave (1..255) initialized in begin() - static const uint8_t ku8MaxBufferSize = 64; ///< size of response/transmit buffers + + static const uint8_t ku8DefMaxBufferSize = 64; ///< size of response/transmit buffers + uint8_t ku8MaxBufferSize ; uint16_t _u16ReadAddress; ///< slave register from which to read uint16_t _u16ReadQty; ///< quantity of words to read - uint16_t _u16ResponseBuffer[ku8MaxBufferSize]; ///< buffer to store Modbus slave response; read via GetResponseBuffer() + uint16_t _u16DefResponseBuffer[ku8DefMaxBufferSize]; ///< buffer to store Modbus slave response; read via GetResponseBuffer() + uint16_t *_u16ResponseBuffer; uint16_t _u16WriteAddress; ///< slave register to which to write - uint16_t _u16WriteQty; ///< quantity of words to write - uint16_t _u16TransmitBuffer[ku8MaxBufferSize]; ///< buffer containing data to transmit to Modbus slave; set via SetTransmitBuffer() + uint16_t _u16WriteQty; //< quantity of words to write + uint16_t _u16TransmitBuffer[ku8DefMaxBufferSize]; ///< buffer containing data to transmit to Modbus slave; set via SetTransmitBuffer() uint16_t* txBuffer; // from Wire.h -- need to clean this up Rx uint8_t _u8TransmitBufferIndex; uint16_t u16TransmitBufferLength; @@ -261,6 +266,8 @@ class ModbusMaster void (*_preTransmission)(); // postTransmission callback function; gets called after a Modbus message has been sent void (*_postTransmission)(); + + }; #endif