diff --git a/docs/conf_common.py b/docs/conf_common.py index 9f275b7..896d2c5 100644 --- a/docs/conf_common.py +++ b/docs/conf_common.py @@ -1,3 +1,14 @@ +# -*- coding: utf-8 -*- +# +# Common (non-language-specific) configuration for Sphinx +# + +# type: ignore +# pylint: disable=wildcard-import +# pylint: disable=undefined-variable + +from __future__ import print_function, unicode_literals + from esp_docs.conf_docs import * # noqa: F403,F401 extensions += ['sphinx_copybutton', @@ -12,8 +23,7 @@ github_repo = 'espressif/esp-modbus' # context used by sphinx_idf_theme html_context['github_user'] = 'espressif' html_context['github_repo'] = 'esp-modbus' - -html_static_path = ["../_static"] +html_static_path = ['../_static'] # Extra options required by sphinx_idf_theme project_slug = 'esp-modbus' diff --git a/freemodbus/modbus/ascii/mbascii.c b/freemodbus/modbus/ascii/mbascii.c index 4400c25..1b7636e 100644 --- a/freemodbus/modbus/ascii/mbascii.c +++ b/freemodbus/modbus/ascii/mbascii.c @@ -154,7 +154,7 @@ eMBASCIIReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLength ) UCHAR *pucMBASCIIFrame = ( UCHAR* ) ucASCIIBuf; USHORT usFrameLength = usRcvBufferPos; - if( xMBSerialPortGetRequest( &pucMBASCIIFrame, &usFrameLength ) == FALSE ) + if( xMBPortSerialGetRequest( &pucMBASCIIFrame, &usFrameLength ) == FALSE ) { return MB_EIO; } @@ -217,7 +217,7 @@ eMBASCIISend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLength ) eSndState = STATE_TX_START; EXIT_CRITICAL_SECTION( ); - if ( xMBSerialPortSendResponse( ( UCHAR * ) pucSndBufferCur, usSndBufferCount ) == FALSE ) + if ( xMBPortSerialSendResponse( ( UCHAR * ) pucSndBufferCur, usSndBufferCount ) == FALSE ) { eStatus = MB_EIO; } diff --git a/freemodbus/modbus/ascii/mbascii_m.c b/freemodbus/modbus/ascii/mbascii_m.c index a883a23..fae0506 100644 --- a/freemodbus/modbus/ascii/mbascii_m.c +++ b/freemodbus/modbus/ascii/mbascii_m.c @@ -157,7 +157,7 @@ eMBMasterASCIIReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLen UCHAR *pucMBASCIIFrame = ( UCHAR* ) ucMasterASCIIRcvBuf; USHORT usFrameLength = usMasterRcvBufferPos; - if( xMBMasterSerialPortGetResponse( &pucMBASCIIFrame, &usFrameLength ) == FALSE ) + if( xMBMasterPortSerialGetResponse( &pucMBASCIIFrame, &usFrameLength ) == FALSE ) { return MB_EIO; } @@ -181,8 +181,8 @@ eMBMasterASCIIReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLen /* Return the start of the Modbus PDU to the caller. */ *pucFrame = ( UCHAR * ) & pucMBASCIIFrame[MB_SER_PDU_PDU_OFF]; - } else { - eStatus = MB_EIO; + } else { + eStatus = MB_EIO; } EXIT_CRITICAL_SECTION( ); return eStatus; @@ -219,7 +219,7 @@ eMBMasterASCIISend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLengt eSndState = STATE_M_TX_START; EXIT_CRITICAL_SECTION( ); - if ( xMBMasterSerialPortSendRequest( ( UCHAR * ) pucMasterSndBufferCur, usMasterSndBufferCount ) == FALSE ) + if ( xMBMasterPortSerialSendRequest( ( UCHAR * ) pucMasterSndBufferCur, usMasterSndBufferCount ) == FALSE ) { eStatus = MB_EIO; } diff --git a/freemodbus/modbus/include/mb_m.h b/freemodbus/modbus/include/mb_m.h index 4eb7723..0b720a4 100644 --- a/freemodbus/modbus/include/mb_m.h +++ b/freemodbus/modbus/include/mb_m.h @@ -408,6 +408,7 @@ BOOL xMBMasterRequestIsBroadcast( void ); eMBMasterErrorEventType eMBMasterGetErrorType( void ); void vMBMasterSetErrorType( eMBMasterErrorEventType errorType ); eMBMasterReqErrCode eMBMasterWaitRequestFinish( void ); +eMBMode ucMBMasterGetCommMode( void ); /* ----------------------- Callback -----------------------------------------*/ diff --git a/freemodbus/modbus/include/mbport.h b/freemodbus/modbus/include/mbport.h index acaf908..aa9602a 100644 --- a/freemodbus/modbus/include/mbport.h +++ b/freemodbus/modbus/include/mbport.h @@ -145,9 +145,9 @@ BOOL xMBPortSerialGetByte( CHAR * pucByte ); BOOL xMBPortSerialPutByte( CHAR ucByte ); -BOOL xMBSerialPortGetRequest( UCHAR **ppucMBSerialFrame, USHORT * pusSerialLength ) __attribute__ ((weak)); +BOOL xMBPortSerialGetRequest( UCHAR **ppucMBSerialFrame, USHORT * pusSerialLength ) __attribute__ ((weak)); -BOOL xMBSerialPortSendResponse( UCHAR *pucMBSerialFrame, USHORT usSerialLength ) __attribute__ ((weak)); +BOOL xMBPortSerialSendResponse( UCHAR *pucMBSerialFrame, USHORT usSerialLength ) __attribute__ ((weak)); #if MB_MASTER_RTU_ENABLED || MB_MASTER_ASCII_ENABLED BOOL xMBMasterPortSerialInit( UCHAR ucPort, ULONG ulBaudRate, @@ -163,9 +163,11 @@ BOOL xMBMasterPortSerialGetByte( CHAR * pucByte ); BOOL xMBMasterPortSerialPutByte( CHAR ucByte ); -BOOL xMBMasterSerialPortGetResponse( UCHAR **ppucMBSerialFrame, USHORT * usSerialLength ); +BOOL xMBMasterPortSerialGetResponse( UCHAR **ppucMBSerialFrame, USHORT * usSerialLength ); -BOOL xMBMasterSerialPortSendRequest( UCHAR *pucMBSerialFrame, USHORT usSerialLength ); +BOOL xMBMasterPortSerialSendRequest( UCHAR *pucMBSerialFrame, USHORT usSerialLength ); + +void vMBMasterRxFlush( void ); #endif diff --git a/freemodbus/modbus/mb_m.c b/freemodbus/modbus/mb_m.c index 708aedc..fa3d386 100644 --- a/freemodbus/modbus/mb_m.c +++ b/freemodbus/modbus/mb_m.c @@ -310,11 +310,13 @@ eMBMasterDisable( void ) eMBErrorCode eMBMasterPoll( void ) { - static UCHAR *ucMBFrame = NULL; + static UCHAR *ucMBSendFrame = NULL; + static UCHAR *ucMBRcvFrame = NULL; static UCHAR ucRcvAddress; static UCHAR ucFunctionCode; static USHORT usLength; static eMBException eException; + static BOOL xTransactionIsActive = FALSE; int i; int j; eMBErrorCode eStatus = MB_ENOERR; @@ -340,49 +342,63 @@ eMBMasterPoll( void ) } else if ( MB_PORT_CHECK_EVENT( eEvent, EV_MASTER_FRAME_TRANSMIT ) ) { ESP_LOGD(MB_PORT_TAG, "%s:EV_MASTER_FRAME_TRANSMIT", __func__); /* Master is busy now. */ - vMBMasterGetPDUSndBuf( &ucMBFrame ); - ESP_LOG_BUFFER_HEX_LEVEL("POLL transmit buffer", (void*)ucMBFrame, usMBMasterGetPDUSndLength(), ESP_LOG_DEBUG); - eStatus = peMBMasterFrameSendCur( ucMBMasterGetDestAddress(), ucMBFrame, usMBMasterGetPDUSndLength() ); + 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) { + vMBMasterSetErrorType(EV_ERROR_RECEIVE_DATA); + ( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS ); ESP_LOGE( MB_PORT_TAG, "%s:Frame send error. %d", __func__, 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*)ucMBFrame, usMBMasterGetPDUSndLength(), ESP_LOG_DEBUG); + 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 ) ) { - eStatus = peMBMasterFrameReceiveCur( &ucRcvAddress, &ucMBFrame, &usLength); + if (xTransactionIsActive) { + eStatus = peMBMasterFrameReceiveCur( &ucRcvAddress, &ucMBRcvFrame, &usLength); + MB_PORT_CHECK(ucMBRcvFrame, MB_EILLSTATE, "Receive buffer initialization fail."); + 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() ) ) + { + 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__, eStatus); + ESP_LOG_BUFFER_HEX_LEVEL("POLL receive buffer", (void*)ucMBRcvFrame, (uint16_t)usLength, ESP_LOG_DEBUG); - // 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 ) ) ) - { - ( void ) xMBMasterPortEventPost( EV_MASTER_EXECUTE ); - ESP_LOGD(MB_PORT_TAG, "%s: Packet data received successfully (%u).", __func__, eStatus); - ESP_LOG_BUFFER_HEX_LEVEL("POLL receive buffer", (void*)ucMBFrame, (uint16_t)usLength, ESP_LOG_DEBUG); - } - 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__, ucRcvAddress, eStatus); + ( void ) xMBMasterPortEventPost( EV_MASTER_EXECUTE ); + } else { + ESP_LOGE( MB_PORT_TAG, "Drop incorrect frame, receive_func(%u) != send_func(%u)", + 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__, ucRcvAddress, 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."); } MB_PORT_CLEAR_EVENT( eEvent, EV_MASTER_FRAME_RECEIVED ); } else if ( MB_PORT_CHECK_EVENT( eEvent, EV_MASTER_EXECUTE ) ) { - if ( !ucMBFrame ) - { - return MB_EILLSTATE; - } + MB_PORT_CHECK(ucMBRcvFrame, MB_EILLSTATE, "receive buffer initialization fail."); ESP_LOGD(MB_PORT_TAG, "%s:EV_MASTER_EXECUTE", __func__); - ucFunctionCode = ucMBFrame[MB_PDU_FUNC_OFF]; + 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)ucMBFrame[MB_PDU_DATA_OFF]; + eException = (eMBException)ucMBRcvFrame[MB_PDU_DATA_OFF]; } else { for ( i = 0; i < MB_FUNC_HANDLERS_MAX; i++ ) { @@ -403,12 +419,12 @@ eMBMasterPoll( void ) for(j = 1; j <= MB_MASTER_TOTAL_SLAVE_NUM; j++) { vMBMasterSetDestAddress(j); - eException = xMasterFuncHandlers[i].pxHandler(ucMBFrame, &usLength); + eException = xMasterFuncHandlers[i].pxHandler(ucMBRcvFrame, &usLength); } } else { - eException = xMasterFuncHandlers[i].pxHandler( ucMBFrame, &usLength ); + eException = xMasterFuncHandlers[i].pxHandler( ucMBRcvFrame, &usLength ); } vMBMasterSetCBRunInMasterMode( FALSE ); break; @@ -434,20 +450,20 @@ eMBMasterPoll( void ) ESP_LOGD( MB_PORT_TAG, "%s:EV_MASTER_ERROR_PROCESS", __func__ ); /* Execute specified error process callback function. */ errorType = eMBMasterGetErrorType( ); - vMBMasterGetPDUSndBuf( &ucMBFrame ); + vMBMasterGetPDUSndBuf( &ucMBSendFrame ); switch ( errorType ) { case EV_ERROR_RESPOND_TIMEOUT: vMBMasterErrorCBRespondTimeout( ucMBMasterGetDestAddress( ), - ucMBFrame, usMBMasterGetPDUSndLength( ) ); + ucMBSendFrame, usMBMasterGetPDUSndLength( ) ); break; case EV_ERROR_RECEIVE_DATA: vMBMasterErrorCBReceiveData( ucMBMasterGetDestAddress( ), - ucMBFrame, usMBMasterGetPDUSndLength( ) ); + ucMBSendFrame, usMBMasterGetPDUSndLength( ) ); break; case EV_ERROR_EXECUTE_FUNCTION: vMBMasterErrorCBExecuteFunction( ucMBMasterGetDestAddress( ), - ucMBFrame, usMBMasterGetPDUSndLength( ) ); + ucMBSendFrame, usMBMasterGetPDUSndLength( ) ); break; case EV_ERROR_OK: vMBMasterCBRequestSuccess( ); @@ -456,6 +472,7 @@ eMBMasterPoll( void ) ESP_LOGE( MB_PORT_TAG, "%s: incorrect error type = %d.", __func__, errorType); break; } + vMBMasterPortTimersDisable( ); vMBMasterSetErrorType( EV_ERROR_INIT ); MB_PORT_CLEAR_EVENT( eEvent, EV_MASTER_ERROR_PROCESS ); vMBMasterRunResRelease( ); @@ -542,8 +559,15 @@ BOOL MB_PORT_ISR_ATTR xMBMasterRequestIsBroadcast( void ) } /* The master request is broadcast? */ -void vMBMasterRequestSetType( BOOL xIsBroadcast ){ +void vMBMasterRequestSetType( BOOL xIsBroadcast ) +{ xFrameIsBroadcast = xIsBroadcast; } +// Get Modbus Master communication mode. +eMBMode ucMBMasterGetCommMode(void) +{ + return eMBMasterCurrentMode; +} + #endif // MB_MASTER_RTU_ENABLED || MB_MASTER_ASCII_ENABLED || MB_MASTER_TCP_ENABLED diff --git a/freemodbus/modbus/rtu/mbrtu.c b/freemodbus/modbus/rtu/mbrtu.c index 144e208..77a2c2f 100644 --- a/freemodbus/modbus/rtu/mbrtu.c +++ b/freemodbus/modbus/rtu/mbrtu.c @@ -158,7 +158,7 @@ eMBRTUReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLength ) UCHAR *pucMBRTUFrame = ( UCHAR* ) ucRTUBuf; USHORT usFrameLength = usRcvBufferPos; - if( xMBSerialPortGetRequest( &pucMBRTUFrame, &usFrameLength ) == FALSE ) + if( xMBPortSerialGetRequest( &pucMBRTUFrame, &usFrameLength ) == FALSE ) { return MB_EIO; } @@ -222,7 +222,7 @@ eMBRTUSend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLength ) eSndState = STATE_TX_XMIT; EXIT_CRITICAL_SECTION( ); - if( xMBSerialPortSendResponse( ( UCHAR * ) pucSndBufferCur, usSndBufferCount ) == FALSE ) + if( xMBPortSerialSendResponse( ( UCHAR * ) pucSndBufferCur, usSndBufferCount ) == FALSE ) { eStatus = MB_EIO; } diff --git a/freemodbus/modbus/rtu/mbrtu_m.c b/freemodbus/modbus/rtu/mbrtu_m.c index 863b569..8e5271d 100644 --- a/freemodbus/modbus/rtu/mbrtu_m.c +++ b/freemodbus/modbus/rtu/mbrtu_m.c @@ -164,7 +164,7 @@ eMBMasterRTUReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLengt UCHAR *pucMBRTUFrame = ( UCHAR* ) ucMasterRTURcvBuf; USHORT usFrameLength = usMasterRcvBufferPos; - if( xMBMasterSerialPortGetResponse( &pucMBRTUFrame, &usFrameLength ) == FALSE ) + if( xMBMasterPortSerialGetResponse( &pucMBRTUFrame, &usFrameLength ) == FALSE ) { return MB_EIO; } @@ -231,7 +231,7 @@ eMBMasterRTUSend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLength /* Activate the transmitter. */ eSndState = STATE_M_TX_XMIT; - if ( xMBMasterSerialPortSendRequest( ( UCHAR * ) pucMasterSndBufferCur, usMasterSndBufferCount ) == FALSE ) + if ( xMBMasterPortSerialSendRequest( ( UCHAR * ) pucMasterSndBufferCur, usMasterSndBufferCount ) == FALSE ) { eStatus = MB_EIO; } diff --git a/freemodbus/port/port.c b/freemodbus/port/port.c index 4f672a9..6dca483 100644 --- a/freemodbus/port/port.c +++ b/freemodbus/port/port.c @@ -73,13 +73,61 @@ vMBPortSetMode( UCHAR ucMode ) EXIT_CRITICAL_SECTION(); } +#if MB_MASTER_RTU_ENABLED || MB_MASTER_ASCII_ENABLED || MB_SLAVE_RTU_ENABLED || MB_SLAVE_ASCII_ENABLED + BOOL xMBPortSerialWaitEvent(QueueHandle_t xMbUartQueue, uart_event_t* pxEvent, ULONG xTimeout) { BOOL xResult = (BaseType_t)xQueueReceive(xMbUartQueue, (void*)pxEvent, (TickType_t) xTimeout); - ESP_LOGD(__func__, "UART event: %d ", pxEvent->type); + ESP_LOGD(MB_PORT_TAG, "%s, UART event: %d ", __func__, pxEvent->type); return xResult; } +#endif + +#if MB_MASTER_RTU_ENABLED || MB_MASTER_ASCII_ENABLED + +/* + * The function is called from ASCII/RTU module to get processed data buffer. Sets the + * received buffer and its length using parameters. + */ +__attribute__ ((weak)) +BOOL xMBMasterPortSerialGetResponse( UCHAR **ppucMBSerialFrame, USHORT * usSerialLength ) +{ + ESP_LOGD(MB_PORT_TAG, " %s default", __func__); + return TRUE; +} + +/* + * The function is called from ASCII/RTU module to set processed data buffer + * to be sent in transmitter state machine. + */ +__attribute__ ((weak)) +BOOL xMBMasterPortSerialSendRequest( UCHAR *pucMBSerialFrame, USHORT usSerialLength ) +{ + ESP_LOGD(MB_PORT_TAG, "%s default", __func__); + return TRUE; +} + +#endif + +#if MB_SLAVE_RTU_ENABLED || MB_SLAVE_ASCII_ENABLED + +__attribute__ ((weak)) +BOOL xMBPortSerialGetRequest( UCHAR **ppucMBSerialFrame, USHORT * usSerialLength ) +{ + ESP_LOGD(MB_PORT_TAG, "%s default", __func__); + return TRUE; +} + +__attribute__ ((weak)) +BOOL xMBPortSerialSendResponse( UCHAR *pucMBSerialFrame, USHORT usSerialLength ) +{ + ESP_LOGD(MB_PORT_TAG, "%s default", __func__); + return TRUE; +} + +#endif + #if MB_TCP_DEBUG // This function is kept to realize legacy freemodbus frame logging functionality diff --git a/freemodbus/port/portserial.c b/freemodbus/port/portserial.c index aae45d9..dbc148d 100644 --- a/freemodbus/port/portserial.c +++ b/freemodbus/port/portserial.c @@ -260,17 +260,6 @@ BOOL xMBPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, return TRUE; } -BOOL xMBSerialPortGetRequest( UCHAR **ppucMBSerialFrame, USHORT * usSerialLength ) -{ - BOOL eStatus = TRUE; - return eStatus; -} - -BOOL xMBSerialPortSendResponse( UCHAR *pucMBSerialFrame, USHORT usSerialLength ) -{ - return TRUE; -} - void vMBPortSerialClose(void) { (void)vTaskSuspend(xMbTaskHandle); diff --git a/freemodbus/port/portserial_m.c b/freemodbus/port/portserial_m.c index db5f13d..cc37f51 100644 --- a/freemodbus/port/portserial_m.c +++ b/freemodbus/port/portserial_m.c @@ -52,6 +52,9 @@ #include "port_serial_master.h" /* ----------------------- Defines ------------------------------------------*/ +#define MB_SERIAL_RX_SEMA_TOUT_MS (1000) +#define MB_SERIAL_RX_SEMA_TOUT (pdMS_TO_TICKS(MB_SERIAL_RX_SEMA_TOUT_MS)) +#define MB_SERIAL_RX_FLUSH_RETRY (2) /* ----------------------- Static variables ---------------------------------*/ static const CHAR *TAG = "MB_MASTER_SERIAL"; @@ -66,16 +69,67 @@ static UCHAR ucUartNumber = UART_NUM_MAX - 1; static BOOL bRxStateEnabled = FALSE; // Receiver enabled flag static BOOL bTxStateEnabled = FALSE; // Transmitter enabled flag +static SemaphoreHandle_t xMasterSemaRxHandle; // Rx blocking semaphore handle + +static BOOL xMBMasterPortRxSemaInit( void ) +{ + xMasterSemaRxHandle = xSemaphoreCreateBinary(); + MB_PORT_CHECK((xMasterSemaRxHandle != NULL), FALSE , "%s: RX semaphore create failure.", __func__); + return TRUE; +} + +static BOOL xMBMasterPortRxSemaTake( LONG lTimeOut ) +{ + BaseType_t xStatus = pdTRUE; + xStatus = xSemaphoreTake(xMasterSemaRxHandle, lTimeOut ); + MB_PORT_CHECK((xStatus == pdTRUE), FALSE , "%s: RX semaphore take failure.", __func__); + ESP_LOGV(MB_PORT_TAG,"%s:Take RX semaphore (%lu ticks).", __func__, lTimeOut); + return TRUE; +} + +static void vMBMasterRxSemaRelease( void ) +{ + BaseType_t xStatus = pdFALSE; + xStatus = xSemaphoreGive(xMasterSemaRxHandle); + if (xStatus != pdTRUE) { + ESP_LOGD(MB_PORT_TAG,"%s:RX semaphore is free.", __func__); + } +} + +static BOOL vMBMasterRxSemaIsBusy( void ) +{ + BaseType_t xStatus = pdFALSE; + xStatus = (uxSemaphoreGetCount(xMasterSemaRxHandle) == 0) ? TRUE : FALSE; + return xStatus; +} + +void vMBMasterRxFlush( void ) +{ + size_t xSize = 1; + esp_err_t xErr = ESP_OK; + for (int xCount = 0; (xCount < MB_SERIAL_RX_FLUSH_RETRY) && xSize; xCount++) { + xErr = uart_get_buffered_data_len(ucUartNumber, &xSize); + MB_PORT_CHECK((xErr == ESP_OK), ; , "mb flush serial fail, error = 0x%x.", xErr); + BaseType_t xStatus = xQueueReset(xMbUartQueue); + if (xStatus) { + xErr = uart_flush_input(ucUartNumber); + MB_PORT_CHECK((xErr == ESP_OK), ; , "mb flush serial fail, error = 0x%x.", xErr); + } + } +} + void vMBMasterPortSerialEnable(BOOL bRxEnable, BOOL bTxEnable) { // This function can be called from xMBRTUTransmitFSM() of different task if (bTxEnable) { + vMBMasterRxFlush(); bTxStateEnabled = TRUE; } else { bTxStateEnabled = FALSE; } if (bRxEnable) { bRxStateEnabled = TRUE; + vMBMasterRxSemaRelease(); vTaskResume(xMbTaskHandle); // Resume receiver task } else { vTaskSuspend(xMbTaskHandle); // Block receiver task @@ -88,12 +142,12 @@ static USHORT usMBMasterPortSerialRxPoll(size_t xEventSize) BOOL xStatus = TRUE; USHORT usCnt = 0; - if (bRxStateEnabled) { + xStatus = xMBMasterPortRxSemaTake(MB_SERIAL_RX_SEMA_TOUT); + if (xStatus) { while(xStatus && (usCnt++ <= xEventSize)) { // Call the Modbus stack callback function and let it fill the stack buffers. xStatus = pxMBMasterFrameCBByteReceived(); // callback to receive FSM } - // The buffer is transferred into Modbus stack and is not needed here any more uart_flush_input(ucUartNumber); ESP_LOGD(TAG, "Received data: %d(bytes in buffer)\n", (uint32_t)usCnt); @@ -147,13 +201,17 @@ static void vUartTask(void* pvParameters) // This flag set in the event means that no more // data received during configured timeout and UART TOUT feature is triggered if (xEvent.timeout_flag) { + // Response is received but previous packet processing is pending + // Do not wait completion of processing and just discard received data as incorrect + if (vMBMasterRxSemaIsBusy()) { + vMBMasterRxFlush(); + break; + } // Get buffered data length ESP_ERROR_CHECK(uart_get_buffered_data_len(ucUartNumber, &xEvent.size)); // Read received data and send it to modbus stack usResult = usMBMasterPortSerialRxPoll(xEvent.size); ESP_LOGD(TAG,"Timeout occured, processed: %d bytes", usResult); - // Block receiver task until data is not processed - vTaskSuspend(NULL); } break; //Event of HW FIFO overflow detected @@ -253,7 +311,8 @@ BOOL xMBMasterPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, // Set always timeout flag to trigger timeout interrupt even after rx fifo full uart_set_always_rx_timeout(ucUartNumber, true); - + MB_PORT_CHECK((xMBMasterPortRxSemaInit()), FALSE, + "mb serial RX semaphore create fail."); // Create a task to handle UART events BaseType_t xStatus = xTaskCreatePinnedToCore(vUartTask, "uart_queue_task", MB_SERIAL_TASK_STACK_SIZE, @@ -272,24 +331,6 @@ BOOL xMBMasterPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, return TRUE; } -/* - * The function is called from ASCII/RTU module to get processed data buffer. Sets the - * received buffer and its length using parameters. - */ -BOOL xMBMasterSerialPortGetResponse( UCHAR **ppucMBSerialFrame, USHORT * usSerialLength ) -{ - return TRUE; -} - -/* - * The function is called from ASCII/RTU module to set processed data buffer - * to be sent in transmitter state machine. - */ -BOOL xMBMasterSerialPortSendRequest( UCHAR *pucMBSerialFrame, USHORT usSerialLength ) -{ - return TRUE; -} - void vMBMasterPortSerialClose(void) { (void)vTaskDelete(xMbTaskHandle); diff --git a/idf_component.yml b/idf_component.yml index 7b3fefd..dbe4eb2 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -1,4 +1,4 @@ -version: "1.0.5" +version: "1.0.6" description: ESP-MODBUS is the official Modbus library for Espressif SoCs. url: https://github.com/espressif/esp-modbus dependencies: