diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 429a1b0..b887798 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -118,12 +118,6 @@ build_idf_v4.3:
variables:
TEST_TARGETS: "esp32 esp32s2 esp32c3"
-build_idf_v4.2:
- extends: .build_pytest_template
- image: espressif/idf:release-v4.2
- variables:
- TEST_TARGETS: "esp32 esp32s2"
-
.target_test_template:
image: $TARGET_TEST_ENV_IMAGE
stage: target_test
@@ -200,7 +194,7 @@ build_docs:
script:
- cd docs
- pip install -r requirements.txt
- - build-docs -l en -t esp32
+ - ./generate_docs
.deploy_docs_template:
stage: deploy
diff --git a/Kconfig b/Kconfig
index 4c7eed8..134bad0 100644
--- a/Kconfig
+++ b/Kconfig
@@ -57,8 +57,8 @@ menu "Modbus configuration"
config FMB_MASTER_TIMEOUT_MS_RESPOND
int "Slave respond timeout (Milliseconds)"
- default 150
- range 50 3000
+ default 3000
+ range 150 15000
help
If master sends a frame which is not broadcast, it has to wait sometime for slave response.
if slave is not respond in this time, the master will process timeout error.
@@ -66,7 +66,7 @@ menu "Modbus configuration"
config FMB_MASTER_DELAY_MS_CONVERT
int "Slave conversion delay (Milliseconds)"
default 200
- range 50 400
+ range 150 2000
help
If master sends a broadcast frame, it has to wait conversion time to delay,
then master can send next frame.
@@ -107,7 +107,7 @@ menu "Modbus configuration"
config FMB_SERIAL_ASCII_TIMEOUT_RESPOND_MS
int "Response timeout for ASCII communication mode (ms)"
default 1000
- range 300 2000
+ range 200 5000
depends on FMB_COMM_MODE_ASCII_EN
help
This option defines response timeout of slave in milliseconds for ASCII communication mode.
diff --git a/docs/_static/modbus_docs_versions.js b/docs/_static/modbus_docs_versions.js
index 2827286..37a2cda 100644
--- a/docs/_static/modbus_docs_versions.js
+++ b/docs/_static/modbus_docs_versions.js
@@ -1,16 +1,14 @@
var DOCUMENTATION_VERSIONS = {
- DEFAULTS: { has_targets: true,
- supported_targets: [ "esp32", "esp32s2", "esp32s3", "esp32c3" ]
- },
VERSIONS: [
- { name: "latest" },
- { name: "v1.0.1", old:false },
- { name: "v1.0.0", old:true }
+ { name: "latest", has_targets: true, supported_targets: [ "esp32", "esp32s2", "esp32s3", "esp32c2", "esp32c3", "esp32c6", "esp32h2" ] },
],
IDF_TARGETS: [
{ text: "ESP32", value: "esp32"},
{ text: "ESP32-S2", value: "esp32s2"},
{ text: "ESP32-S3", value: "esp32s3"},
- { text: "ESP32-C3", value: "esp32c3"}
+ { text: "ESP32-C2", value: "esp32c2"},
+ { text: "ESP32-C3", value: "esp32c3"},
+ { text: "ESP32-C6", value: "esp32c6"},
+ { text: "ESP32-H2", value: "esp32h2"}
]
};
diff --git a/docs/conf_common.py b/docs/conf_common.py
index 896d2c5..9e090d1 100644
--- a/docs/conf_common.py
+++ b/docs/conf_common.py
@@ -29,5 +29,5 @@ html_static_path = ['../_static']
project_slug = 'esp-modbus'
versions_url = './_static/modbus_docs_versions.js'
-idf_targets = ['esp32', 'esp32s2', 'esp32c3']
+idf_targets = [ 'esp32' ]
languages = ['en']
diff --git a/docs/generate_docs b/docs/generate_docs
new file mode 100755
index 0000000..d9af465
--- /dev/null
+++ b/docs/generate_docs
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+rm -rf docs
+build-docs --target esp32 --language en
+
+# Modifes target field of html files
+ELEMENT=""
+
+FILES=$(find . -path "*/_build/en/esp32/html/*.html")
+
+for FILE in ${FILES}
+ do
+ echo ${ELEMENT} >> "${FILE}"
+ done
+
+
diff --git a/freemodbus/modbus/functions/mbfunccoils_m.c b/freemodbus/modbus/functions/mbfunccoils_m.c
index cbd5e3c..8399d2f 100644
--- a/freemodbus/modbus/functions/mbfunccoils_m.c
+++ b/freemodbus/modbus/functions/mbfunccoils_m.c
@@ -110,7 +110,7 @@ eMBMasterReqReadCoils( UCHAR ucSndAddr, USHORT usCoilAddr, USHORT usNCoils, LONG
ucMBFrame[MB_PDU_REQ_READ_COILCNT_OFF ] = usNCoils >> 8;
ucMBFrame[MB_PDU_REQ_READ_COILCNT_OFF + 1] = usNCoils;
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_READ_SIZE );
- ( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT );
+ ( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT | EV_MASTER_TRANS_START );
eErrStatus = eMBMasterWaitRequestFinish( );
}
@@ -217,7 +217,7 @@ eMBMasterReqWriteCoil( UCHAR ucSndAddr, USHORT usCoilAddr, USHORT usCoilData, LO
ucMBFrame[MB_PDU_REQ_WRITE_VALUE_OFF ] = usCoilData >> 8;
ucMBFrame[MB_PDU_REQ_WRITE_VALUE_OFF + 1] = usCoilData;
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_WRITE_SIZE );
- ( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT );
+ ( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT | EV_MASTER_TRANS_START );
eErrStatus = eMBMasterWaitRequestFinish( );
}
return eErrStatus;
@@ -327,7 +327,7 @@ eMBMasterReqWriteMultipleCoils( UCHAR ucSndAddr,
*ucMBFrame++ = pucDataBuffer[usRegIndex++];
}
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_WRITE_MUL_SIZE_MIN + ucByteCount );
- ( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT );
+ ( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT | EV_MASTER_TRANS_START );
eErrStatus = eMBMasterWaitRequestFinish( );
}
return eErrStatus;
diff --git a/freemodbus/modbus/functions/mbfuncdisc_m.c b/freemodbus/modbus/functions/mbfuncdisc_m.c
index 3a079ba..0af1169 100644
--- a/freemodbus/modbus/functions/mbfuncdisc_m.c
+++ b/freemodbus/modbus/functions/mbfuncdisc_m.c
@@ -92,7 +92,7 @@ eMBMasterReqReadDiscreteInputs( UCHAR ucSndAddr, USHORT usDiscreteAddr, USHORT u
ucMBFrame[MB_PDU_REQ_READ_DISCCNT_OFF ] = usNDiscreteIn >> 8;
ucMBFrame[MB_PDU_REQ_READ_DISCCNT_OFF + 1] = usNDiscreteIn;
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_READ_SIZE );
- ( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT );
+ ( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT | EV_MASTER_TRANS_START );
eErrStatus = eMBMasterWaitRequestFinish( );
}
return eErrStatus;
diff --git a/freemodbus/modbus/functions/mbfuncholding_m.c b/freemodbus/modbus/functions/mbfuncholding_m.c
index 48b7c7b..840d499 100644
--- a/freemodbus/modbus/functions/mbfuncholding_m.c
+++ b/freemodbus/modbus/functions/mbfuncholding_m.c
@@ -122,7 +122,7 @@ eMBMasterReqWriteHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usRe
ucMBFrame[MB_PDU_REQ_WRITE_VALUE_OFF] = usRegData >> 8;
ucMBFrame[MB_PDU_REQ_WRITE_VALUE_OFF + 1] = usRegData ;
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_WRITE_SIZE );
- ( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT );
+ ( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT | EV_MASTER_TRANS_START );
eErrStatus = eMBMasterWaitRequestFinish( );
}
return eErrStatus;
@@ -200,7 +200,7 @@ eMBMasterReqWriteMultipleHoldingRegister( UCHAR ucSndAddr,
*ucMBFrame++ = pusDataBuffer[usRegIndex++] ;
}
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_WRITE_MUL_SIZE_MIN + 2*usNRegs );
- ( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT );
+ ( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT | EV_MASTER_TRANS_START );
eErrStatus = eMBMasterWaitRequestFinish( );
}
return eErrStatus;
@@ -286,7 +286,7 @@ eMBMasterReqReadHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usNRe
ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF] = usNRegs >> 8;
ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF + 1] = usNRegs;
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_READ_SIZE );
- ( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT );
+ ( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT | EV_MASTER_TRANS_START );
eErrStatus = eMBMasterWaitRequestFinish( );
}
return eErrStatus;
@@ -392,7 +392,7 @@ eMBMasterReqReadWriteMultipleHoldingRegister( UCHAR ucSndAddr,
*ucMBFrame++ = pusDataBuffer[usRegIndex++] ;
}
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_READWRITE_SIZE_MIN + 2*usNWriteRegs );
- ( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT );
+ ( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT | EV_MASTER_TRANS_START );
eErrStatus = eMBMasterWaitRequestFinish( );
}
return eErrStatus;
diff --git a/freemodbus/modbus/functions/mbfuncinput_m.c b/freemodbus/modbus/functions/mbfuncinput_m.c
index 2db16d6..7fb3126 100644
--- a/freemodbus/modbus/functions/mbfuncinput_m.c
+++ b/freemodbus/modbus/functions/mbfuncinput_m.c
@@ -93,7 +93,7 @@ eMBMasterReqReadInputRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usNRegs
ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF] = usNRegs >> 8;
ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF + 1] = usNRegs;
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_READ_SIZE );
- ( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT );
+ ( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_TRANSMIT | EV_MASTER_TRANS_START );
eErrStatus = eMBMasterWaitRequestFinish( );
}
return eErrStatus;
diff --git a/freemodbus/modbus/include/mb_m.h b/freemodbus/modbus/include/mb_m.h
index 0b720a4..9201dea 100644
--- a/freemodbus/modbus/include/mb_m.h
+++ b/freemodbus/modbus/include/mb_m.h
@@ -103,7 +103,7 @@ typedef enum
MB_TMODE_T35, /*!< Master receive frame T3.5 timeout. */
MB_TMODE_RESPOND_TIMEOUT, /*!< Master wait respond for slave. */
MB_TMODE_CONVERT_DELAY /*!< Master sent broadcast ,then delay sometime.*/
-}eMBMasterTimerMode;
+} eMBMasterTimerMode;
/* ----------------------- Function prototypes ------------------------------*/
/*! \ingroup modbus
diff --git a/freemodbus/modbus/include/mbconfig.h b/freemodbus/modbus/include/mbconfig.h
index cd5b405..6dbb9ca 100644
--- a/freemodbus/modbus/include/mbconfig.h
+++ b/freemodbus/modbus/include/mbconfig.h
@@ -99,6 +99,9 @@ PR_BEGIN_EXTERN_C
#define MB_ASCII_BITS_PER_SYMB ( CONFIG_FMB_SERIAL_ASCII_BITS_PER_SYMB )
#endif
+#define MB_EVENT_QUEUE_SIZE ( CONFIG_FMB_CONTROLLER_NOTIFY_QUEUE_SIZE )
+#define MB_EVENT_QUEUE_TIMEOUT ( pdMS_TO_TICKS( CONFIG_FMB_EVENT_QUEUE_TIMEOUT ) )
+
/*! \brief The character timeout value for Modbus ASCII.
*
* The character timeout value is not fixed for Modbus ASCII and is therefore
diff --git a/freemodbus/modbus/include/mbport.h b/freemodbus/modbus/include/mbport.h
index affc5d4..c5e9ff2 100644
--- a/freemodbus/modbus/include/mbport.h
+++ b/freemodbus/modbus/include/mbport.h
@@ -70,17 +70,18 @@ typedef enum
#if MB_MASTER_RTU_ENABLED || MB_MASTER_ASCII_ENABLED || MB_MASTER_TCP_ENABLED
typedef enum {
EV_MASTER_NO_EVENT = 0x0000,
- EV_MASTER_READY = 0x0001, /*!< Startup finished. */
- EV_MASTER_FRAME_RECEIVED = 0x0002, /*!< Frame received. */
- EV_MASTER_EXECUTE = 0x0004, /*!< Execute function. */
- EV_MASTER_FRAME_SENT = 0x0008, /*!< Frame sent. */
- EV_MASTER_FRAME_TRANSMIT = 0x0010, /*!< Frame transmission. */
- EV_MASTER_ERROR_PROCESS = 0x0020, /*!< Frame error process. */
- EV_MASTER_PROCESS_SUCCESS = 0x0040, /*!< Request process success. */
- EV_MASTER_ERROR_RESPOND_TIMEOUT = 0x0080, /*!< Request respond timeout. */
- EV_MASTER_ERROR_RECEIVE_DATA = 0x0100, /*!< Request receive data error. */
- EV_MASTER_ERROR_EXECUTE_FUNCTION = 0x0200 /*!< Request execute function error. */
-} eMBMasterEventType;
+ EV_MASTER_TRANS_START = 0x0001, /*!< Transaction start flag */
+ EV_MASTER_READY = 0x0002, /*!< Startup finished. */
+ EV_MASTER_FRAME_RECEIVED = 0x0004, /*!< Frame received. */
+ EV_MASTER_EXECUTE = 0x0008, /*!< Execute function. */
+ EV_MASTER_FRAME_SENT = 0x0010, /*!< Frame sent. */
+ EV_MASTER_FRAME_TRANSMIT = 0x0020, /*!< Frame transmission. */
+ EV_MASTER_ERROR_PROCESS = 0x0040, /*!< Frame error process. */
+ EV_MASTER_PROCESS_SUCCESS = 0x0080, /*!< Request process success. */
+ EV_MASTER_ERROR_RESPOND_TIMEOUT = 0x0100, /*!< Request respond timeout. */
+ EV_MASTER_ERROR_RECEIVE_DATA = 0x0200, /*!< Request receive data error. */
+ EV_MASTER_ERROR_EXECUTE_FUNCTION = 0x0400 /*!< Request execute function error. */
+} eMBMasterEventEnum;
typedef enum {
EV_ERROR_INIT, /*!< No error, initial state. */
@@ -89,6 +90,14 @@ typedef enum {
EV_ERROR_EXECUTE_FUNCTION, /*!< Execute function error. */
EV_ERROR_OK /*!< No error, processing completed. */
} eMBMasterErrorEventType;
+
+typedef struct _MbEventType {
+ eMBMasterEventEnum eEvent; /*!< event itself. */
+ uint64_t xTransactionId; /*!< ID of the transaction */
+ uint64_t xPostTimestamp; /*!< timestamp of event posted */
+ uint64_t xGetTimestamp; /*!< timestamp of event get */
+} xMBMasterEventType;
+
#endif
/*! \ingroup modbus
@@ -115,18 +124,21 @@ BOOL xMBPortEventGet( /*@out@ */ eMBEventType * eEvent );
#if MB_MASTER_RTU_ENABLED || MB_MASTER_ASCII_ENABLED || MB_MASTER_TCP_ENABLED
BOOL xMBMasterPortEventInit( void );
-BOOL xMBMasterPortEventPost( eMBMasterEventType eEvent );
+BOOL xMBMasterPortEventPost( eMBMasterEventEnum eEvent );
-BOOL xMBMasterPortEventGet( /*@out@ */ eMBMasterEventType * eEvent );
+BOOL xMBMasterPortEventGet( /*@out@ */ xMBMasterEventType * eEvent );
-eMBMasterEventType
- xMBMasterPortFsmWaitConfirmation( eMBMasterEventType eEventMask, ULONG ulTimeout);
+eMBMasterEventEnum
+ xMBMasterPortFsmWaitConfirmation( eMBMasterEventEnum eEventMask, ULONG ulTimeout);
void vMBMasterOsResInit( void );
BOOL xMBMasterRunResTake( LONG time );
void vMBMasterRunResRelease( void );
+
+uint64_t xMBMasterPortGetTransactionId( void );
+
#endif // MB_MASTER_RTU_ENABLED || MB_MASTER_ASCII_ENABLED || MB_MASTER_TCP_ENABLED
/* ----------------------- Serial port functions ----------------------------*/
diff --git a/freemodbus/modbus/include/mbproto.h b/freemodbus/modbus/include/mbproto.h
index da303a6..6d02c18 100644
--- a/freemodbus/modbus/include/mbproto.h
+++ b/freemodbus/modbus/include/mbproto.h
@@ -62,7 +62,7 @@ PR_BEGIN_EXTERN_C
#define MB_FUNC_OTHER_REPORT_SLAVEID ( 17 )
#define MB_FUNC_ERROR ( 128u )
/* ----------------------- Type definitions ---------------------------------*/
- typedef enum
+typedef enum
{
MB_EX_NONE = 0x00,
MB_EX_ILLEGAL_FUNCTION = 0x01,
diff --git a/freemodbus/modbus/mb_m.c b/freemodbus/modbus/mb_m.c
index ca17676..24c51d6 100644
--- a/freemodbus/modbus/mb_m.c
+++ b/freemodbus/modbus/mb_m.c
@@ -36,8 +36,9 @@
*/
/* ----------------------- System includes ----------------------------------*/
-#include "stdlib.h"
-#include "string.h"
+#include
+#include
+#include
/* ----------------------- Platform includes --------------------------------*/
#include "port.h"
@@ -316,171 +317,171 @@ eMBMasterPoll( void )
static UCHAR ucFunctionCode;
static USHORT usLength;
static eMBException eException;
- static BOOL xTransactionIsActive = FALSE;
+ static uint64_t xCurTransactionId = 0;
int i;
int j;
eMBErrorCode eStatus = MB_ENOERR;
- eMBMasterEventType eEvent;
+ xMBMasterEventType xEvent;
eMBMasterErrorEventType errorType;
/* Check if the protocol stack is ready. */
- if( eMBState != STATE_ENABLED )
- {
+ if( eMBState != STATE_ENABLED ) {
return MB_EILLSTATE;
}
/* Check if there is a event available. If not return control to caller.
* Otherwise we will handle the event. */
- if ( xMBMasterPortEventGet( &eEvent ) == TRUE )
- {
- while( eEvent ) {
+ if ( xMBMasterPortEventGet( &xEvent ) == TRUE ) {
+ switch( xEvent.eEvent ) {
// In some cases it is possible that more than one event set
// together (even from one subset mask) than process them consistently
- if ( MB_PORT_CHECK_EVENT( eEvent, EV_MASTER_READY ) ) {
- ESP_LOGD(MB_PORT_TAG, "%s:EV_MASTER_READY", __func__);
+ case EV_MASTER_READY:
+ ESP_LOGD(MB_PORT_TAG, "%" PRIu64 ":EV_MASTER_READY", xEvent.xTransactionId);
vMBMasterSetErrorType( EV_ERROR_INIT );
vMBMasterRunResRelease( );
- MB_PORT_CLEAR_EVENT( eEvent, EV_MASTER_READY );
- } else if ( MB_PORT_CHECK_EVENT( eEvent, EV_MASTER_FRAME_TRANSMIT ) ) {
- ESP_LOGD(MB_PORT_TAG, "%s:EV_MASTER_FRAME_TRANSMIT", __func__);
+ break;
+ case EV_MASTER_FRAME_TRANSMIT:
+ ESP_LOGD(MB_PORT_TAG, "%" PRIu64 ":EV_MASTER_FRAME_TRANSMIT", xEvent.xTransactionId);
/* Master is busy now. */
vMBMasterGetPDUSndBuf( &ucMBSendFrame );
ESP_LOG_BUFFER_HEX_LEVEL("POLL transmit buffer", (void*)ucMBSendFrame, usMBMasterGetPDUSndLength(), ESP_LOG_DEBUG);
eStatus = peMBMasterFrameSendCur( ucMBMasterGetDestAddress(), ucMBSendFrame, usMBMasterGetPDUSndLength() );
- if (eStatus != MB_ENOERR)
- {
+ if (eStatus != MB_ENOERR) {
vMBMasterSetErrorType(EV_ERROR_RECEIVE_DATA);
( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS );
- ESP_LOGE( MB_PORT_TAG, "%s:Frame send error. %u", __func__, (unsigned)eStatus );
+ ESP_LOGE( MB_PORT_TAG, "%" PRIu64 ":Frame send error = %d", xEvent.xTransactionId, (unsigned)eStatus );
}
- MB_PORT_CLEAR_EVENT( eEvent, EV_MASTER_FRAME_TRANSMIT );
- } else if ( MB_PORT_CHECK_EVENT( eEvent, EV_MASTER_FRAME_SENT ) ) {
- ESP_LOGD( MB_PORT_TAG, "%s:EV_MASTER_FRAME_SENT", __func__ );
- ESP_LOG_BUFFER_HEX_LEVEL("POLL sent buffer", (void*)ucMBSendFrame, usMBMasterGetPDUSndLength(), ESP_LOG_DEBUG);
- xTransactionIsActive = TRUE;
- MB_PORT_CLEAR_EVENT( eEvent, EV_MASTER_FRAME_SENT );
- } else if ( MB_PORT_CHECK_EVENT( eEvent, EV_MASTER_FRAME_RECEIVED ) ) {
- if (xTransactionIsActive) {
- ESP_LOGD( MB_PORT_TAG, "%s:EV_MASTER_FRAME_RECEIVED", __func__ );
- eStatus = peMBMasterFrameReceiveCur( &ucRcvAddress, &ucMBRcvFrame, &usLength);
+ xCurTransactionId = xEvent.xTransactionId;
+ break;
+ case EV_MASTER_FRAME_SENT:
+ if (xCurTransactionId == xEvent.xTransactionId) {
+ ESP_LOGD( MB_PORT_TAG, "%" PRIu64 ":EV_MASTER_FRAME_SENT", xEvent.xTransactionId );
+ ESP_LOG_BUFFER_HEX_LEVEL("POLL sent buffer", (void*)ucMBSendFrame, usMBMasterGetPDUSndLength(), ESP_LOG_DEBUG);
+ }
+ break;
+ case EV_MASTER_FRAME_RECEIVED:
+ ESP_LOGD( MB_PORT_TAG, "%" PRIu64 ":EV_MASTER_FRAME_RECEIVED", xEvent.xTransactionId );
+ eStatus = peMBMasterFrameReceiveCur( &ucRcvAddress, &ucMBRcvFrame, &usLength);
+ if (xCurTransactionId == xEvent.xTransactionId) {
MB_PORT_CHECK(ucMBSendFrame, MB_EILLSTATE, "Send buffer initialization fail.");
// Check if the frame is for us. If not ,send an error process event.
if ( ( eStatus == MB_ENOERR ) && ( ( ucRcvAddress == ucMBMasterGetDestAddress() )
|| ( ucRcvAddress == MB_TCP_PSEUDO_ADDRESS) ) ) {
if ( ( ucMBRcvFrame[MB_PDU_FUNC_OFF] & ~MB_FUNC_ERROR ) == ( ucMBSendFrame[MB_PDU_FUNC_OFF] ) ) {
- ESP_LOGD(MB_PORT_TAG, "%s: Packet data received successfully (%u).", __func__, (unsigned)eStatus);
- ESP_LOG_BUFFER_HEX_LEVEL("POLL receive buffer", (void*)ucMBRcvFrame, (unsigned)usLength, ESP_LOG_DEBUG);
-
+ ESP_LOGD(MB_PORT_TAG, "%" PRIu64 ": Packet data received successfully (%u).", xEvent.xTransactionId, (unsigned)eStatus);
+ ESP_LOG_BUFFER_HEX_LEVEL("POLL receive buffer", (void*)ucMBRcvFrame, (uint16_t)usLength, ESP_LOG_DEBUG);
( void ) xMBMasterPortEventPost( EV_MASTER_EXECUTE );
} else {
ESP_LOGE( MB_PORT_TAG, "Drop incorrect frame, receive_func(%u) != send_func(%u)",
- (UCHAR)ucMBRcvFrame[MB_PDU_FUNC_OFF], (UCHAR)ucMBSendFrame[MB_PDU_FUNC_OFF]);
+ ucMBRcvFrame[MB_PDU_FUNC_OFF], ucMBSendFrame[MB_PDU_FUNC_OFF]);
vMBMasterSetErrorType(EV_ERROR_RECEIVE_DATA);
( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS );
}
} else {
vMBMasterSetErrorType(EV_ERROR_RECEIVE_DATA);
( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS );
- ESP_LOGD( MB_PORT_TAG, "%s: Packet data receive failed (addr=%u)(%u).",
- __func__, (unsigned)ucRcvAddress, (unsigned)eStatus);
+ ESP_LOGD( MB_PORT_TAG, "%" PRIu64 ": Packet data receive failed (addr=%u)(%u).",
+ xEvent.xTransactionId, (unsigned)ucRcvAddress, (unsigned)eStatus);
}
} else {
// Ignore the `EV_MASTER_FRAME_RECEIVED` event because the respond timeout occurred
// and this is likely respond to previous transaction
- ESP_LOGE( MB_PORT_TAG, "Drop data received outside of transaction.");
+ ESP_LOGE( MB_PORT_TAG, "Drop data received outside of transaction (%" PRIu64 ")", xEvent.xTransactionId );
}
- MB_PORT_CLEAR_EVENT( eEvent, EV_MASTER_FRAME_RECEIVED );
- } else if ( MB_PORT_CHECK_EVENT( eEvent, EV_MASTER_EXECUTE ) ) {
- MB_PORT_CHECK(ucMBRcvFrame, MB_EILLSTATE, "receive buffer initialization fail.");
- ESP_LOGD(MB_PORT_TAG, "%s:EV_MASTER_EXECUTE", __func__);
- ucFunctionCode = ucMBRcvFrame[MB_PDU_FUNC_OFF];
- eException = MB_EX_ILLEGAL_FUNCTION;
- /* If receive frame has exception. The receive function code highest bit is 1.*/
- if (ucFunctionCode & MB_FUNC_ERROR)
- {
- eException = (eMBException)ucMBRcvFrame[MB_PDU_DATA_OFF];
- } else {
- for ( i = 0; i < MB_FUNC_HANDLERS_MAX; i++ )
- {
- /* No more function handlers registered. Abort. */
- if (xMasterFuncHandlers[i].ucFunctionCode == 0)
+ break;
+ case EV_MASTER_EXECUTE:
+ if (xCurTransactionId == xEvent.xTransactionId) {
+ MB_PORT_CHECK(ucMBRcvFrame, MB_EILLSTATE, "receive buffer initialization fail.");
+ ESP_LOGD(MB_PORT_TAG, "%" PRIu64 ":EV_MASTER_EXECUTE", xEvent.xTransactionId);
+ ucFunctionCode = ucMBRcvFrame[MB_PDU_FUNC_OFF];
+ eException = MB_EX_ILLEGAL_FUNCTION;
+ /* If receive frame has exception. The receive function code highest bit is 1.*/
+ if (ucFunctionCode & MB_FUNC_ERROR) {
+ eException = (eMBException)ucMBRcvFrame[MB_PDU_DATA_OFF];
+ } else {
+ for ( i = 0; i < MB_FUNC_HANDLERS_MAX; i++ )
{
- break;
- }
- if (xMasterFuncHandlers[i].ucFunctionCode == ucFunctionCode)
- {
- vMBMasterSetCBRunInMasterMode(TRUE);
- /* If master request is broadcast,
- * the master need execute function for all slave.
- */
- if ( xMBMasterRequestIsBroadcast() )
- {
- usLength = usMBMasterGetPDUSndLength();
- for(j = 1; j <= MB_MASTER_TOTAL_SLAVE_NUM; j++)
- {
- vMBMasterSetDestAddress(j);
- eException = xMasterFuncHandlers[i].pxHandler(ucMBRcvFrame, &usLength);
+ /* No more function handlers registered. Abort. */
+ if (xMasterFuncHandlers[i].ucFunctionCode == 0) {
+ break;
+ }
+ if (xMasterFuncHandlers[i].ucFunctionCode == ucFunctionCode) {
+ vMBMasterSetCBRunInMasterMode(TRUE);
+ /* If master request is broadcast,
+ * the master need execute function for all slave.
+ */
+ if ( xMBMasterRequestIsBroadcast() ) {
+ usLength = usMBMasterGetPDUSndLength();
+ for(j = 1; j <= MB_MASTER_TOTAL_SLAVE_NUM; j++)
+ {
+ vMBMasterSetDestAddress(j);
+ eException = xMasterFuncHandlers[i].pxHandler(ucMBRcvFrame, &usLength);
+ }
+ } else {
+ eException = xMasterFuncHandlers[i].pxHandler( ucMBRcvFrame, &usLength );
}
+ vMBMasterSetCBRunInMasterMode( FALSE );
+ break;
}
- else
- {
- eException = xMasterFuncHandlers[i].pxHandler( ucMBRcvFrame, &usLength );
- }
- vMBMasterSetCBRunInMasterMode( FALSE );
- break;
}
}
- }
- /* If master has exception, will send error process event. Otherwise the master is idle.*/
- if ( eException != MB_EX_NONE )
- {
- vMBMasterSetErrorType( EV_ERROR_EXECUTE_FUNCTION );
- ( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS );
- }
- else
- {
- if ( eMBMasterGetErrorType( ) == EV_ERROR_INIT ) {
- vMBMasterSetErrorType(EV_ERROR_OK);
- ESP_LOGD( MB_PORT_TAG, "%s: set event EV_ERROR_OK", __func__ );
+ /* If master has exception, will send error process event. Otherwise the master is idle.*/
+ if ( eException != MB_EX_NONE ) {
+ vMBMasterSetErrorType( EV_ERROR_EXECUTE_FUNCTION );
( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS );
+ } else {
+ if ( eMBMasterGetErrorType( ) == EV_ERROR_INIT ) {
+ vMBMasterSetErrorType(EV_ERROR_OK);
+ ESP_LOGD( MB_PORT_TAG, "%" PRIu64 ":set event EV_ERROR_OK", xEvent.xTransactionId );
+ ( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS );
+ }
}
+ } else {
+ ESP_LOGD( MB_PORT_TAG, "%" PRIu64 ":EV_MASTER_EXECUTE is expired", xEvent.xTransactionId );
}
- MB_PORT_CLEAR_EVENT( eEvent, EV_MASTER_EXECUTE );
- } else if ( MB_PORT_CHECK_EVENT( eEvent, EV_MASTER_ERROR_PROCESS ) ) {
- ESP_LOGD( MB_PORT_TAG, "%s:EV_MASTER_ERROR_PROCESS", __func__ );
- /* Execute specified error process callback function. */
- errorType = eMBMasterGetErrorType( );
- vMBMasterGetPDUSndBuf( &ucMBSendFrame );
- switch ( errorType )
- {
- case EV_ERROR_RESPOND_TIMEOUT:
- vMBMasterErrorCBRespondTimeout( ucMBMasterGetDestAddress( ),
- ucMBSendFrame, usMBMasterGetPDUSndLength( ) );
- break;
- case EV_ERROR_RECEIVE_DATA:
- vMBMasterErrorCBReceiveData( ucMBMasterGetDestAddress( ),
- ucMBSendFrame, usMBMasterGetPDUSndLength( ) );
- break;
- case EV_ERROR_EXECUTE_FUNCTION:
- vMBMasterErrorCBExecuteFunction( ucMBMasterGetDestAddress( ),
- ucMBSendFrame, usMBMasterGetPDUSndLength( ) );
- break;
- case EV_ERROR_OK:
- vMBMasterCBRequestSuccess( );
- break;
- default:
- ESP_LOGE( MB_PORT_TAG, "%s: incorrect error type = %u.", __func__, (unsigned)errorType);
- break;
+ break;
+ case EV_MASTER_ERROR_PROCESS:
+ if (xCurTransactionId == xEvent.xTransactionId) {
+ ESP_LOGD( MB_PORT_TAG, "%" PRIu64 ":EV_MASTER_ERROR_PROCESS", xEvent.xTransactionId);
+ /* Execute specified error process callback function. */
+ errorType = eMBMasterGetErrorType( );
+ vMBMasterGetPDUSndBuf( &ucMBSendFrame );
+ switch ( errorType )
+ {
+ case EV_ERROR_RESPOND_TIMEOUT:
+ vMBMasterErrorCBRespondTimeout( ucMBMasterGetDestAddress( ),
+ ucMBSendFrame, usMBMasterGetPDUSndLength( ) );
+ break;
+ case EV_ERROR_RECEIVE_DATA:
+ vMBMasterErrorCBReceiveData( ucMBMasterGetDestAddress( ),
+ ucMBSendFrame, usMBMasterGetPDUSndLength( ) );
+ break;
+ case EV_ERROR_EXECUTE_FUNCTION:
+ vMBMasterErrorCBExecuteFunction( ucMBMasterGetDestAddress( ),
+ ucMBSendFrame, usMBMasterGetPDUSndLength( ) );
+ break;
+ case EV_ERROR_OK:
+ vMBMasterCBRequestSuccess( );
+ break;
+ default:
+ ESP_LOGE( MB_PORT_TAG, "%" PRIu64 ":incorrect error type = %d.", xEvent.xTransactionId, (int)errorType);
+ break;
+ }
}
vMBMasterPortTimersDisable( );
+ uint64_t xProcTime = xCurTransactionId ? ( xEvent.xPostTimestamp - xCurTransactionId ) : 0;
+ ESP_LOGD( MB_PORT_TAG, "Transaction (%" PRIu64 "), processing time(us) = %" PRId64, xCurTransactionId, xProcTime );
+ xCurTransactionId = 0;
vMBMasterSetErrorType( EV_ERROR_INIT );
- MB_PORT_CLEAR_EVENT( eEvent, EV_MASTER_ERROR_PROCESS );
vMBMasterRunResRelease( );
- }
+ break;
+ default:
+ ESP_LOGE( MB_PORT_TAG, "%" PRIu64 ":Unexpected event triggered 0x%02x.", xEvent.xTransactionId, (int)xEvent.eEvent );
+ break;
}
} else {
// Something went wrong and task unblocked but there are no any correct events set
- ESP_LOGE( MB_PORT_TAG, "%s: Unexpected event triggered 0x%02x.", __func__, (int)eEvent );
+ ESP_LOGE( MB_PORT_TAG, "%" PRIu64 ": Unexpected event triggered 0x%02x.", xEvent.xTransactionId, (int)xEvent.eEvent );
eStatus = MB_EILLSTATE;
}
return eStatus;
@@ -489,37 +490,37 @@ eMBMasterPoll( void )
// Get whether the Modbus Master is run in master mode.
BOOL xMBMasterGetCBRunInMasterMode( void )
{
- return xMBRunInMasterMode;
+ return atomic_load(&xMBRunInMasterMode);
}
// Set whether the Modbus Master is run in master mode.
void vMBMasterSetCBRunInMasterMode( BOOL IsMasterMode )
{
- xMBRunInMasterMode = IsMasterMode;
+ atomic_store(&(xMBRunInMasterMode), IsMasterMode);
}
// Get Modbus Master send destination address.
UCHAR ucMBMasterGetDestAddress( void )
{
- return ucMBMasterDestAddress;
+ return atomic_load(&ucMBMasterDestAddress);
}
// Set Modbus Master send destination address.
void vMBMasterSetDestAddress( UCHAR Address )
{
- ucMBMasterDestAddress = Address;
+ atomic_store(&(ucMBMasterDestAddress), Address);
}
// Get Modbus Master current error event type.
eMBMasterErrorEventType inline eMBMasterGetErrorType( void )
{
- return eMBMasterCurErrorType;
+ return atomic_load(&eMBMasterCurErrorType);
}
// Set Modbus Master current error event type.
void IRAM_ATTR vMBMasterSetErrorType( eMBMasterErrorEventType errorType )
{
- eMBMasterCurErrorType = errorType;
+ atomic_store(&(eMBMasterCurErrorType), errorType);
}
/* Get Modbus Master send PDU's buffer address pointer.*/
@@ -531,25 +532,25 @@ void vMBMasterGetPDUSndBuf( UCHAR ** pucFrame )
/* Set Modbus Master send PDU's buffer length.*/
void vMBMasterSetPDUSndLength( USHORT SendPDULength )
{
- usMasterSendPDULength = SendPDULength;
+ atomic_store(&(usMasterSendPDULength), SendPDULength);
}
/* Get Modbus Master send PDU's buffer length.*/
USHORT usMBMasterGetPDUSndLength( void )
{
- return usMasterSendPDULength;
+ return atomic_load(&usMasterSendPDULength);
}
/* Set Modbus Master current timer mode.*/
void vMBMasterSetCurTimerMode( eMBMasterTimerMode eMBTimerMode )
{
- eMasterCurTimerMode = eMBTimerMode;
+ atomic_store(&(eMasterCurTimerMode), eMBTimerMode);
}
/* Get Modbus Master current timer mode.*/
eMBMasterTimerMode MB_PORT_ISR_ATTR xMBMasterGetCurTimerMode( void )
{
- return eMasterCurTimerMode;
+ return atomic_load(&eMasterCurTimerMode);
}
/* The master request is broadcast? */
@@ -561,7 +562,7 @@ BOOL MB_PORT_ISR_ATTR xMBMasterRequestIsBroadcast( void )
/* The master request is broadcast? */
void vMBMasterRequestSetType( BOOL xIsBroadcast )
{
- xFrameIsBroadcast = xIsBroadcast;
+ atomic_store(&(xFrameIsBroadcast), xIsBroadcast);
}
// Get Modbus Master communication mode.
diff --git a/freemodbus/modbus/rtu/mbrtu_m.c b/freemodbus/modbus/rtu/mbrtu_m.c
index 5fa585d..4b3739d 100644
--- a/freemodbus/modbus/rtu/mbrtu_m.c
+++ b/freemodbus/modbus/rtu/mbrtu_m.c
@@ -252,7 +252,9 @@ xMBMasterRTUReceiveFSM( void )
BOOL xStatus = FALSE;
UCHAR ucByte;
- assert(( eSndState == STATE_M_TX_IDLE ) || ( eSndState == STATE_M_TX_XFWR ));
+ if ( ( eSndState != STATE_M_TX_IDLE ) && ( eSndState != STATE_M_TX_XFWR ) ) {
+ return FALSE;
+ }
/* Always read the character. */
xStatus = xMBMasterPortSerialGetByte( ( CHAR * ) & ucByte );
@@ -328,7 +330,9 @@ xMBMasterRTUTransmitFSM( void )
BOOL xNeedPoll = TRUE;
BOOL xFrameIsBroadcast = FALSE;
- assert( eRcvState == STATE_M_RX_IDLE );
+ if ( eRcvState != STATE_M_RX_IDLE ) {
+ return FALSE;
+ }
switch ( eSndState )
{
diff --git a/freemodbus/port/port.h b/freemodbus/port/port.h
index b5d8858..ffdb3b5 100644
--- a/freemodbus/port/port.h
+++ b/freemodbus/port/port.h
@@ -91,6 +91,10 @@
#define MB_TCP_SEND_TIMEOUT (pdMS_TO_TICKS(MB_TCP_SEND_TIMEOUT_MS))
#define MB_TCP_PORT_MAX_CONN (CONFIG_FMB_TCP_PORT_MAX_CONN)
+// Set the API unlock time to maximum response time
+// The actual release time will be dependent on the timer time
+#define MB_MAX_RESPONSE_TIME_MS (5000)
+
#define MB_TCP_FRAME_LOG_BUFSIZE (256)
#define MB_PORT_HAS_CLOSE (1) // Define to explicitly close port on destroy
diff --git a/freemodbus/port/portevent.c b/freemodbus/port/portevent.c
index 7837959..a19b809 100644
--- a/freemodbus/port/portevent.c
+++ b/freemodbus/port/portevent.c
@@ -44,14 +44,11 @@
#include "mb.h"
#include "mbport.h"
#include "port.h"
-#include "sdkconfig.h"
+#include "mbconfig.h"
#include "port_serial_slave.h"
/* ----------------------- Variables ----------------------------------------*/
static QueueHandle_t xQueueHdl;
-#define MB_EVENT_QUEUE_SIZE (6)
-#define MB_EVENT_QUEUE_TIMEOUT (pdMS_TO_TICKS(CONFIG_FMB_EVENT_QUEUE_TIMEOUT))
-
/* ----------------------- Start implementation -----------------------------*/
BOOL
xMBPortEventInit( void )
diff --git a/freemodbus/port/portevent_m.c b/freemodbus/port/portevent_m.c
index 9ec12e4..d7a807f 100644
--- a/freemodbus/port/portevent_m.c
+++ b/freemodbus/port/portevent_m.c
@@ -35,26 +35,24 @@
*/
/* ----------------------- Modbus includes ----------------------------------*/
-#include "mb_m.h"
-#include "mbport.h"
-#include "mbconfig.h"
+
+#include
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
+#include "freertos/semphr.h"
+
+#include "mb_m.h"
+#include "mbport.h"
+#include "mbconfig.h"
+
#include "port.h"
#include "mbport.h"
#include "freertos/semphr.h"
#if MB_MASTER_RTU_ENABLED || MB_MASTER_ASCII_ENABLED || MB_MASTER_TCP_ENABLED
/* ----------------------- Defines ------------------------------------------*/
-// Event bit mask for xMBMasterPortEventGet()
-#define MB_EVENT_POLL_MASK (EventBits_t)( EV_MASTER_READY | \
- EV_MASTER_FRAME_RECEIVED | \
- EV_MASTER_EXECUTE | \
- EV_MASTER_FRAME_SENT | \
- EV_MASTER_FRAME_TRANSMIT | \
- EV_MASTER_ERROR_PROCESS )
// Event bit mask for eMBMasterWaitRequestFinish()
#define MB_EVENT_REQ_MASK (EventBits_t)( EV_MASTER_PROCESS_SUCCESS | \
@@ -62,12 +60,13 @@
EV_MASTER_ERROR_RECEIVE_DATA | \
EV_MASTER_ERROR_EXECUTE_FUNCTION )
-#define MB_EVENT_RESOURCE (EventBits_t)( 0x0080 )
-
/* ----------------------- Variables ----------------------------------------*/
-static EventGroupHandle_t xResourceMasterHdl;
+static SemaphoreHandle_t xResourceMasterHdl;
static EventGroupHandle_t xEventGroupMasterHdl;
static EventGroupHandle_t xEventGroupMasterConfirmHdl;
+static QueueHandle_t xQueueMasterHdl;
+
+static uint64_t xTransactionID = 0;
/* ----------------------- Start implementation -----------------------------*/
@@ -78,45 +77,60 @@ xMBMasterPortEventInit( void )
xEventGroupMasterConfirmHdl = xEventGroupCreate();
MB_PORT_CHECK((xEventGroupMasterHdl != NULL) && (xEventGroupMasterConfirmHdl != NULL),
FALSE, "mb stack event group creation error.");
+ xQueueMasterHdl = xQueueCreate(MB_EVENT_QUEUE_SIZE, sizeof(xMBMasterEventType));
+ MB_PORT_CHECK(xQueueMasterHdl, FALSE, "mb stack event group creation error.");
+ vQueueAddToRegistry(xQueueMasterHdl, "MbMasterPortEventQueue");
+ xTransactionID = 0;
return TRUE;
}
BOOL MB_PORT_ISR_ATTR
-xMBMasterPortEventPost( eMBMasterEventType eEvent )
+xMBMasterPortEventPost( eMBMasterEventEnum eEvent)
{
- BOOL bStatus = FALSE;
- eMBMasterEventType eTempEvent = eEvent;
+ BaseType_t xStatus, xHigherPriorityTaskWoken = pdFALSE;
+ assert(xQueueMasterHdl != NULL);
+ xMBMasterEventType xEvent;
+ xEvent.xPostTimestamp = esp_timer_get_time();
+
+ if (eEvent & EV_MASTER_TRANS_START) {
+ atomic_store(&(xTransactionID), xEvent.xPostTimestamp);
+ }
+ xEvent.eEvent = (eEvent & ~EV_MASTER_TRANS_START);
- if( (BOOL)xPortInIsrContext() == TRUE )
- {
- BaseType_t xHigherPriorityTaskWoken = pdFALSE;
- BaseType_t xResult = xEventGroupSetBitsFromISR( xEventGroupMasterHdl,
- (EventBits_t) eTempEvent,
- &xHigherPriorityTaskWoken );
- // Was the message posted successfully?
- if( xResult == pdPASS ) {
- // If xHigherPriorityTaskWoken is now set to pdTRUE
- // then a context switch should be requested.
- if (xHigherPriorityTaskWoken) portYIELD_FROM_ISR();
- bStatus = TRUE;
- } else {
- bStatus = FALSE;
+ if( (BOOL)xPortInIsrContext() == TRUE ) {
+ xStatus = xQueueSendFromISR(xQueueMasterHdl, (const void*)&xEvent, &xHigherPriorityTaskWoken);
+ if ( xHigherPriorityTaskWoken ) {
+ portYIELD_FROM_ISR();
}
+ if (xStatus != pdTRUE) {
+ ESP_EARLY_LOGV(MB_PORT_TAG, "%s: Post message failure = %d.", __func__, xStatus);
+ return FALSE;
+ }
+ } else {
+ xStatus = xQueueSend(xQueueMasterHdl, (const void*)&xEvent, MB_EVENT_QUEUE_TIMEOUT);
+ MB_PORT_CHECK((xStatus == pdTRUE), FALSE, "%s: Post message failure.", __func__);
}
- else
- {
- // Set event bits if the function is called from task
- // The return result is not checked here because
- // It might be that event bit was cleared automatically as a
- // task that was waiting for the bit was removed from the Blocked state.
- (void) xEventGroupSetBits( xEventGroupMasterHdl, (EventBits_t)eTempEvent );
- bStatus = TRUE;
- }
- return bStatus;
+ return TRUE;
}
-eMBMasterEventType
-xMBMasterPortFsmWaitConfirmation( eMBMasterEventType eEventMask, ULONG ulTimeout)
+BOOL
+xMBMasterPortEventGet(xMBMasterEventType *peEvent)
+{
+ assert(xQueueMasterHdl != NULL);
+ BOOL xEventHappened = FALSE;
+
+ if (xQueueReceive(xQueueMasterHdl, peEvent, portMAX_DELAY) == pdTRUE) {
+ peEvent->xTransactionId = atomic_load(&xTransactionID);
+ // Set event bits in confirmation group (for synchronization with port task)
+ xEventGroupSetBits(xEventGroupMasterConfirmHdl, peEvent->eEvent);
+ peEvent->xGetTimestamp = esp_timer_get_time();
+ xEventHappened = TRUE;
+ }
+ return xEventHappened;
+}
+
+eMBMasterEventEnum
+xMBMasterPortFsmWaitConfirmation( eMBMasterEventEnum eEventMask, ULONG ulTimeout)
{
EventBits_t uxBits;
uxBits = xEventGroupWaitBits( xEventGroupMasterConfirmHdl, // The event group being tested.
@@ -128,38 +142,19 @@ xMBMasterPortFsmWaitConfirmation( eMBMasterEventType eEventMask, ULONG ulTimeout
// Clear confirmation events that where set in the mask
xEventGroupClearBits( xEventGroupMasterConfirmHdl, (uxBits & eEventMask) );
}
- return (eMBMasterEventType)(uxBits & eEventMask);
+ return (eMBMasterEventEnum)(uxBits & eEventMask);
}
-BOOL
-xMBMasterPortEventGet( eMBMasterEventType* eEvent )
+uint64_t xMBMasterPortGetTransactionId( )
{
- EventBits_t uxBits;
- BOOL xEventHappened = FALSE;
- uxBits = xEventGroupWaitBits( xEventGroupMasterHdl, // The event group being tested.
- MB_EVENT_POLL_MASK, // The bits within the event group to wait for.
- pdTRUE, // Masked bits should be cleared before returning.
- pdFALSE, // Don't wait for both bits, either bit will do.
- portMAX_DELAY); // Wait forever for either bit to be set.
- // Check if poll event is correct
- if (MB_PORT_CHECK_EVENT(uxBits, MB_EVENT_POLL_MASK)) {
- *eEvent = (eMBMasterEventType)(uxBits & MB_EVENT_POLL_MASK);
- // Set event bits in confirmation group (for synchronization with port task)
- xEventGroupSetBits( xEventGroupMasterConfirmHdl, *eEvent );
- xEventHappened = TRUE;
- } else {
- ESP_LOGE(MB_PORT_TAG,"%s: Incorrect event triggered = %u.", __func__, (unsigned)uxBits);
- *eEvent = (eMBMasterEventType)uxBits;
- xEventHappened = FALSE;
- }
- return xEventHappened;
+ return atomic_load(&xTransactionID);
}
// This function is initialize the OS resource for modbus master.
void vMBMasterOsResInit( void )
{
- xResourceMasterHdl = xEventGroupCreate();
- MB_PORT_CHECK((xResourceMasterHdl != NULL), ; , "Resource create error.");
+ xResourceMasterHdl = xSemaphoreCreateBinary();
+ MB_PORT_CHECK((xResourceMasterHdl != NULL), ; , "%s: Resource create error.", __func__);
}
/**
@@ -172,14 +167,10 @@ void vMBMasterOsResInit( void )
*/
BOOL xMBMasterRunResTake( LONG lTimeOut )
{
- EventBits_t uxBits;
- uxBits = xEventGroupWaitBits( xResourceMasterHdl, // The event group being tested.
- MB_EVENT_RESOURCE, // The bits within the event group to wait for.
- pdTRUE, // Masked bits should be cleared before returning.
- pdFALSE, // Don't wait for both bits, either bit will do.
- lTimeOut); // Resource wait timeout.
- MB_PORT_CHECK((uxBits == MB_EVENT_RESOURCE), FALSE , "Take resource failure.");
- ESP_LOGD(MB_PORT_TAG,"%s:Take resource (%" PRIx32 ") (%" PRIu32 " ticks).", __func__, (uint32_t)uxBits, (uint32_t)lTimeOut);
+ BaseType_t xStatus = pdTRUE;
+ xStatus = xSemaphoreTake( xResourceMasterHdl, lTimeOut );
+ MB_PORT_CHECK((xStatus == pdTRUE), FALSE , "%s: Resource take failure.", __func__);
+ ESP_LOGD(MB_PORT_TAG,"%s:Take MB resource (%lu ticks).", __func__, lTimeOut);
return TRUE;
}
@@ -189,11 +180,10 @@ BOOL xMBMasterRunResTake( LONG lTimeOut )
*/
void vMBMasterRunResRelease( void )
{
- EventBits_t uxBits = xEventGroupSetBits( xResourceMasterHdl, MB_EVENT_RESOURCE );
- if (uxBits != MB_EVENT_RESOURCE) {
- // The returned resource mask may be = 0, if the task waiting for it is unblocked.
- // This is not an error but expected behavior.
- ESP_LOGD(MB_PORT_TAG,"%s: Release resource (%" PRIx32 ") fail.", __func__, (uint32_t)uxBits);
+ BaseType_t xStatus = pdFALSE;
+ xStatus = xSemaphoreGive( xResourceMasterHdl );
+ if (xStatus != pdTRUE) {
+ ESP_LOGD(MB_PORT_TAG,"%s: Release resource fail.", __func__);
}
}
@@ -208,8 +198,7 @@ void vMBMasterRunResRelease( void )
*/
void vMBMasterErrorCBRespondTimeout(UCHAR ucDestAddress, const UCHAR* pucPDUData, USHORT ucPDULength)
{
- BOOL ret = xMBMasterPortEventPost(EV_MASTER_ERROR_RESPOND_TIMEOUT);
- MB_PORT_CHECK((ret == TRUE), ; , "%s: Post event 'EV_MASTER_ERROR_RESPOND_TIMEOUT' failed!", __func__);
+ (void)xEventGroupSetBits( xEventGroupMasterHdl, EV_MASTER_ERROR_RESPOND_TIMEOUT );
ESP_LOGD(MB_PORT_TAG,"%s:Callback respond timeout.", __func__);
}
@@ -223,8 +212,7 @@ void vMBMasterErrorCBRespondTimeout(UCHAR ucDestAddress, const UCHAR* pucPDUData
*/
void vMBMasterErrorCBReceiveData(UCHAR ucDestAddress, const UCHAR* pucPDUData, USHORT ucPDULength)
{
- BOOL ret = xMBMasterPortEventPost(EV_MASTER_ERROR_RECEIVE_DATA);
- MB_PORT_CHECK((ret == TRUE), ; , "%s: Post event 'EV_MASTER_ERROR_RECEIVE_DATA' failed!", __func__);
+ (void)xEventGroupSetBits( xEventGroupMasterHdl, EV_MASTER_ERROR_RECEIVE_DATA );
ESP_LOGD(MB_PORT_TAG,"%s:Callback receive data timeout failure.", __func__);
ESP_LOG_BUFFER_HEX_LEVEL("Err rcv buf", (void *)pucPDUData, (USHORT)ucPDULength, ESP_LOG_DEBUG);
}
@@ -241,8 +229,7 @@ void vMBMasterErrorCBReceiveData(UCHAR ucDestAddress, const UCHAR* pucPDUData, U
*/
void vMBMasterErrorCBExecuteFunction(UCHAR ucDestAddress, const UCHAR* pucPDUData, USHORT ucPDULength)
{
- BOOL ret = xMBMasterPortEventPost(EV_MASTER_ERROR_EXECUTE_FUNCTION);
- MB_PORT_CHECK((ret == TRUE), ; , "%s: Post event 'EV_MASTER_ERROR_EXECUTE_FUNCTION' failed!", __func__);
+ xEventGroupSetBits( xEventGroupMasterHdl, EV_MASTER_ERROR_EXECUTE_FUNCTION );
ESP_LOGD(MB_PORT_TAG,"%s:Callback execute data handler failure.", __func__);
ESP_LOG_BUFFER_HEX_LEVEL("Exec func buf", (void*)pucPDUData, (USHORT)ucPDULength, ESP_LOG_DEBUG);
}
@@ -252,13 +239,9 @@ void vMBMasterErrorCBExecuteFunction(UCHAR ucDestAddress, const UCHAR* pucPDUDat
* @note There functions will block modbus master poll while execute OS waiting.
* So,for real-time of system. Do not execute too much waiting process.
*/
-void vMBMasterCBRequestSuccess( void ) {
- /**
- * @note This code is use OS's event mechanism for modbus master protocol stack.
- * If you don't use OS, you can change it.
- */
- BOOL ret = xMBMasterPortEventPost(EV_MASTER_PROCESS_SUCCESS);
- MB_PORT_CHECK((ret == TRUE), ; , "%s: Post event 'EV_MASTER_PROCESS_SUCCESS' failed!", __func__);
+void vMBMasterCBRequestSuccess( void )
+{
+ (void)xEventGroupSetBits( xEventGroupMasterHdl, EV_MASTER_PROCESS_SUCCESS );
ESP_LOGD(MB_PORT_TAG,"%s: Callback request success.", __func__);
}
@@ -273,14 +256,14 @@ void vMBMasterCBRequestSuccess( void ) {
*/
eMBMasterReqErrCode eMBMasterWaitRequestFinish( void ) {
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
- eMBMasterEventType xRecvedEvent;
+ eMBMasterEventEnum xRecvedEvent;
EventBits_t uxBits = xEventGroupWaitBits( xEventGroupMasterHdl, // The event group being tested.
MB_EVENT_REQ_MASK, // The bits within the event group to wait for.
pdTRUE, // Masked bits should be cleared before returning.
pdFALSE, // Don't wait for both bits, either bit will do.
portMAX_DELAY ); // Wait forever for either bit to be set.
- xRecvedEvent = (eMBMasterEventType)(uxBits);
+ xRecvedEvent = (eMBMasterEventEnum)(uxBits);
if (xRecvedEvent) {
ESP_LOGD(MB_PORT_TAG,"%s: returned event = 0x%x", __func__, (int)xRecvedEvent);
if (!(xRecvedEvent & MB_EVENT_REQ_MASK)) {
@@ -298,7 +281,7 @@ eMBMasterReqErrCode eMBMasterWaitRequestFinish( void ) {
eErrStatus = MB_MRE_EXE_FUN;
}
} else {
- ESP_LOGE(MB_PORT_TAG,"%s: Incorrect event or timeout xRecvedEvent = 0x%" PRIx32 "", __func__, (uint32_t)uxBits);
+ ESP_LOGE(MB_PORT_TAG,"%s: Incorrect event or timeout xRecvedEvent = 0x%x", __func__, (int)uxBits);
// https://github.com/espressif/esp-idf/issues/5275
// if a no event is received, that means vMBMasterPortEventClose()
// has been closed, so event group has been deleted by FreeRTOS, which
@@ -311,9 +294,22 @@ eMBMasterReqErrCode eMBMasterWaitRequestFinish( void ) {
void vMBMasterPortEventClose(void)
{
- vEventGroupDelete(xEventGroupMasterHdl);
- vEventGroupDelete(xEventGroupMasterConfirmHdl);
- vEventGroupDelete(xResourceMasterHdl);
+ if (xQueueMasterHdl) {
+ vEventGroupDelete(xEventGroupMasterHdl);
+ xQueueMasterHdl = NULL;
+ }
+ if (xQueueMasterHdl) {
+ vQueueDelete(xQueueMasterHdl);
+ xQueueMasterHdl = NULL;
+ }
+ if (xEventGroupMasterConfirmHdl) {
+ vEventGroupDelete(xEventGroupMasterConfirmHdl);
+ xEventGroupMasterConfirmHdl = NULL;
+ }
+ if (xResourceMasterHdl) {
+ vSemaphoreDelete(xResourceMasterHdl);
+ xResourceMasterHdl = NULL;
+ }
}
#endif
diff --git a/freemodbus/serial_master/modbus_controller/mbc_serial_master.c b/freemodbus/serial_master/modbus_controller/mbc_serial_master.c
index 7d9e716..ae24e04 100644
--- a/freemodbus/serial_master/modbus_controller/mbc_serial_master.c
+++ b/freemodbus/serial_master/modbus_controller/mbc_serial_master.c
@@ -27,8 +27,8 @@
extern BOOL xMBMasterPortSerialTxPoll(void);
/*-----------------------Master mode use these variables----------------------*/
-#define MB_RESPONSE_TICS pdMS_TO_TICKS(CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND + 10)
-
+// Actual wait time depends on the response timer
+#define MB_SERIAL_API_RESP_TICS (pdMS_TO_TICKS(MB_MAX_RESPONSE_TIME_MS))
static mb_master_interface_t* mbm_interface_ptr = NULL;
static const char *TAG = "MB_CONTROLLER_MASTER";
@@ -176,7 +176,7 @@ static esp_err_t mbc_serial_master_send_request(mb_param_request_t* request, voi
eMBMasterReqErrCode mb_error = MB_MRE_MASTER_BUSY;
esp_err_t error = ESP_FAIL;
- if (xMBMasterRunResTake(MB_RESPONSE_TICS)) {
+ if (xMBMasterRunResTake(MB_SERIAL_API_RESP_TICS)) {
uint8_t mb_slave_addr = request->slave_addr;
uint8_t mb_command = request->command;
@@ -194,43 +194,43 @@ static esp_err_t mbc_serial_master_send_request(mb_param_request_t* request, voi
{
case MB_FUNC_READ_COILS:
mb_error = eMBMasterReqReadCoils((UCHAR)mb_slave_addr, (USHORT)mb_offset,
- (USHORT)mb_size , (LONG)MB_RESPONSE_TICS );
+ (USHORT)mb_size , (LONG)MB_SERIAL_API_RESP_TICS );
break;
case MB_FUNC_WRITE_SINGLE_COIL:
mb_error = eMBMasterReqWriteCoil((UCHAR)mb_slave_addr, (USHORT)mb_offset,
- *(USHORT*)data_ptr, (LONG)MB_RESPONSE_TICS );
+ *(USHORT*)data_ptr, (LONG)MB_SERIAL_API_RESP_TICS );
break;
case MB_FUNC_WRITE_MULTIPLE_COILS:
mb_error = eMBMasterReqWriteMultipleCoils((UCHAR)mb_slave_addr, (USHORT)mb_offset,
- (USHORT)mb_size, (UCHAR*)data_ptr, (LONG)MB_RESPONSE_TICS);
+ (USHORT)mb_size, (UCHAR*)data_ptr, (LONG)MB_SERIAL_API_RESP_TICS);
break;
case MB_FUNC_READ_DISCRETE_INPUTS:
mb_error = eMBMasterReqReadDiscreteInputs((UCHAR)mb_slave_addr, (USHORT)mb_offset,
- (USHORT)mb_size, (LONG)MB_RESPONSE_TICS );
+ (USHORT)mb_size, (LONG)MB_SERIAL_API_RESP_TICS );
break;
case MB_FUNC_READ_HOLDING_REGISTER:
mb_error = eMBMasterReqReadHoldingRegister((UCHAR)mb_slave_addr, (USHORT)mb_offset,
- (USHORT)mb_size, (LONG)MB_RESPONSE_TICS );
+ (USHORT)mb_size, (LONG)MB_SERIAL_API_RESP_TICS );
break;
case MB_FUNC_WRITE_REGISTER:
mb_error = eMBMasterReqWriteHoldingRegister( (UCHAR)mb_slave_addr, (USHORT)mb_offset,
- *(USHORT*)data_ptr, (LONG)MB_RESPONSE_TICS );
+ *(USHORT*)data_ptr, (LONG)MB_SERIAL_API_RESP_TICS );
break;
case MB_FUNC_WRITE_MULTIPLE_REGISTERS:
mb_error = eMBMasterReqWriteMultipleHoldingRegister( (UCHAR)mb_slave_addr,
(USHORT)mb_offset, (USHORT)mb_size,
- (USHORT*)data_ptr, (LONG)MB_RESPONSE_TICS );
+ (USHORT*)data_ptr, (LONG)MB_SERIAL_API_RESP_TICS );
break;
case MB_FUNC_READWRITE_MULTIPLE_REGISTERS:
mb_error = eMBMasterReqReadWriteMultipleHoldingRegister( (UCHAR)mb_slave_addr, (USHORT)mb_offset,
(USHORT)mb_size, (USHORT*)data_ptr,
(USHORT)mb_offset, (USHORT)mb_size,
- (LONG)MB_RESPONSE_TICS );
+ (LONG)MB_SERIAL_API_RESP_TICS );
break;
case MB_FUNC_READ_INPUT_REGISTER:
mb_error = eMBMasterReqReadInputRegister( (UCHAR)mb_slave_addr, (USHORT)mb_offset,
- (USHORT)mb_size, (LONG) MB_RESPONSE_TICS );
+ (USHORT)mb_size, (LONG) MB_SERIAL_API_RESP_TICS );
break;
default:
ESP_LOGE(TAG, "%s: Incorrect function in request (%u) ", __FUNCTION__, (unsigned)mb_command);
diff --git a/freemodbus/tcp_master/modbus_controller/mbc_tcp_master.c b/freemodbus/tcp_master/modbus_controller/mbc_tcp_master.c
index c03e5e8..7e297bf 100644
--- a/freemodbus/tcp_master/modbus_controller/mbc_tcp_master.c
+++ b/freemodbus/tcp_master/modbus_controller/mbc_tcp_master.c
@@ -29,9 +29,10 @@
/*-----------------------Master mode use these variables----------------------*/
-// The response time is average processing time + data transmission
-#define MB_RESPONSE_TIMEOUT pdMS_TO_TICKS(CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND)
-#define MB_TCP_CONNECTION_TOUT pdMS_TO_TICKS(CONFIG_FMB_TCP_CONNECTION_TOUT_SEC * 1000)
+#define MB_TCP_CONNECTION_TOUT (pdMS_TO_TICKS(CONFIG_FMB_TCP_CONNECTION_TOUT_SEC * 1000))
+
+// Actual wait time depends on the response timer
+#define MB_TCP_API_RESP_TICS (pdMS_TO_TICKS(MB_MAX_RESPONSE_TIME_MS))
static mb_master_interface_t* mbm_interface_ptr = NULL;
static const char *TAG = "MB_CONTROLLER_MASTER";
@@ -257,7 +258,7 @@ static esp_err_t mbc_tcp_master_send_request(mb_param_request_t* request, void*
eMBMasterReqErrCode mb_error = MB_MRE_MASTER_BUSY;
esp_err_t error = ESP_FAIL;
- if (xMBMasterRunResTake(MB_RESPONSE_TIMEOUT)) {
+ if (xMBMasterRunResTake(MB_TCP_API_RESP_TICS)) {
uint8_t mb_slave_addr = request->slave_addr;
uint8_t mb_command = request->command;
@@ -275,44 +276,44 @@ static esp_err_t mbc_tcp_master_send_request(mb_param_request_t* request, void*
{
case MB_FUNC_READ_COILS:
mb_error = eMBMasterReqReadCoils((UCHAR)mb_slave_addr, (USHORT)mb_offset,
- (USHORT)mb_size, (LONG)MB_RESPONSE_TIMEOUT);
+ (USHORT)mb_size, (LONG)MB_TCP_API_RESP_TICS);
break;
case MB_FUNC_WRITE_SINGLE_COIL:
mb_error = eMBMasterReqWriteCoil((UCHAR)mb_slave_addr, (USHORT)mb_offset,
- *(USHORT *)data_ptr, (LONG)MB_RESPONSE_TIMEOUT);
+ *(USHORT *)data_ptr, (LONG)MB_TCP_API_RESP_TICS);
break;
case MB_FUNC_WRITE_MULTIPLE_COILS:
mb_error = eMBMasterReqWriteMultipleCoils((UCHAR)mb_slave_addr, (USHORT)mb_offset,
(USHORT)mb_size, (UCHAR *)data_ptr,
- (LONG)MB_RESPONSE_TIMEOUT);
+ (LONG)MB_TCP_API_RESP_TICS);
break;
case MB_FUNC_READ_DISCRETE_INPUTS:
mb_error = eMBMasterReqReadDiscreteInputs((UCHAR)mb_slave_addr, (USHORT)mb_offset,
- (USHORT)mb_size, (LONG)MB_RESPONSE_TIMEOUT);
+ (USHORT)mb_size, (LONG)MB_TCP_API_RESP_TICS);
break;
case MB_FUNC_READ_HOLDING_REGISTER:
mb_error = eMBMasterReqReadHoldingRegister((UCHAR)mb_slave_addr, (USHORT)mb_offset,
- (USHORT)mb_size, (LONG)MB_RESPONSE_TIMEOUT);
+ (USHORT)mb_size, (LONG)MB_TCP_API_RESP_TICS);
break;
case MB_FUNC_WRITE_REGISTER:
mb_error = eMBMasterReqWriteHoldingRegister((UCHAR)mb_slave_addr, (USHORT)mb_offset,
- *(USHORT *)data_ptr, (LONG)MB_RESPONSE_TIMEOUT);
+ *(USHORT *)data_ptr, (LONG)MB_TCP_API_RESP_TICS);
break;
case MB_FUNC_WRITE_MULTIPLE_REGISTERS:
mb_error = eMBMasterReqWriteMultipleHoldingRegister((UCHAR)mb_slave_addr,
(USHORT)mb_offset, (USHORT)mb_size,
- (USHORT *)data_ptr, (LONG)MB_RESPONSE_TIMEOUT);
+ (USHORT *)data_ptr, (LONG)MB_TCP_API_RESP_TICS);
break;
case MB_FUNC_READWRITE_MULTIPLE_REGISTERS:
mb_error = eMBMasterReqReadWriteMultipleHoldingRegister((UCHAR)mb_slave_addr, (USHORT)mb_offset,
(USHORT)mb_size, (USHORT *)data_ptr,
(USHORT)mb_offset, (USHORT)mb_size,
- (LONG)MB_RESPONSE_TIMEOUT);
+ (LONG)MB_TCP_API_RESP_TICS);
break;
case MB_FUNC_READ_INPUT_REGISTER:
mb_error = eMBMasterReqReadInputRegister((UCHAR)mb_slave_addr, (USHORT)mb_offset,
- (USHORT)mb_size, (LONG)MB_RESPONSE_TIMEOUT);
+ (USHORT)mb_size, (LONG)MB_TCP_API_RESP_TICS);
break;
default:
ESP_LOGE(TAG, "%s: Incorrect function in request (%u) ", __FUNCTION__, (unsigned)mb_command);
@@ -507,7 +508,6 @@ static esp_err_t mbc_tcp_master_get_parameter(uint16_t cid, char* name, uint8_t*
} else {
ESP_LOGD(TAG, "%s: Bad response to get cid(%u) = %s",
__FUNCTION__, (unsigned)reg_info.cid, (char*)esp_err_to_name(error));
- error = ESP_ERR_INVALID_RESPONSE;
}
free(pdata);
// Set the type of parameter found in the table
diff --git a/freemodbus/tcp_master/port/port_tcp_master.c b/freemodbus/tcp_master/port/port_tcp_master.c
index 2ccadd2..5632807 100644
--- a/freemodbus/tcp_master/port/port_tcp_master.c
+++ b/freemodbus/tcp_master/port/port_tcp_master.c
@@ -655,7 +655,7 @@ static int xMBTCPPortMasterCheckConnState(fd_set *pxFdSet)
return xCount;
}
-static void xMBTCPPortMasterFsmSetError(eMBMasterErrorEventType xErrType, eMBMasterEventType xPostEvent)
+static void xMBTCPPortMasterFsmSetError(eMBMasterErrorEventType xErrType, eMBMasterEventEnum xPostEvent)
{
vMBMasterPortTimersDisable();
vMBMasterSetErrorType(xErrType);
@@ -861,7 +861,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
} else if (xRet == ERR_BUF) {
// After retries a response with incorrect TID received, process failure.
xMBTCPPortMasterFsmSetError(EV_ERROR_RECEIVE_DATA, EV_MASTER_ERROR_PROCESS);
- ESP_LOGW(TAG, MB_SLAVE_FMT(", frame error."),
+ ESP_LOGD(TAG, MB_SLAVE_FMT(", frame error."),
(int)pxCurrInfo->xIndex, (int)pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr);
} else {
ESP_LOGE(TAG, MB_SLAVE_FMT(", critical error=%d."),
diff --git a/idf_component.yml b/idf_component.yml
index bf3e8e5..444d15a 100644
--- a/idf_component.yml
+++ b/idf_component.yml
@@ -1,8 +1,8 @@
-version: "1.0.10"
+version: "1.0.11"
description: ESP-MODBUS is the official Modbus library for Espressif SoCs.
url: https://github.com/espressif/esp-modbus
dependencies:
- idf: ">=4.1"
+ idf: ">=4.3"
files:
exclude:
- "docs/**/*"