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/**/*"