From 9ea75ab79332ce7ee78077b44ba8fa5c8daa6105 Mon Sep 17 00:00:00 2001 From: aleks Date: Thu, 12 May 2022 15:48:55 +0200 Subject: [PATCH] modbus serial fix events misalingnment --- freemodbus/modbus/ascii/mbascii.c | 4 +- freemodbus/modbus/ascii/mbascii_m.c | 8 +-- freemodbus/modbus/include/mbport.h | 8 +-- freemodbus/modbus/rtu/mbrtu.c | 4 +- freemodbus/modbus/rtu/mbrtu_m.c | 4 +- freemodbus/port/port.c | 50 ++++++++++++++++- freemodbus/port/portserial.c | 11 ---- freemodbus/port/portserial_m.c | 86 +++++++++++++++++++++-------- 8 files changed, 127 insertions(+), 48 deletions(-) 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 849ab65..1cfe0e6 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/mbport.h b/freemodbus/modbus/include/mbport.h index acaf908..e453b59 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,9 @@ 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 ); #endif 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 65ac4b7..65f194b 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 777eee8..1be6b8a 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; +} + +static 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,7 +142,8 @@ static USHORT usMBMasterPortSerialRxPoll(size_t xEventSize) BOOL xReadStatus = TRUE; USHORT usCnt = 0; - if (bRxStateEnabled) { + xReadStatus = xMBMasterPortRxSemaTake(MB_SERIAL_RX_SEMA_TOUT); + if (xReadStatus) { while(xReadStatus && (usCnt++ <= xEventSize)) { // Call the Modbus stack callback function and let it fill the stack buffers. xReadStatus = pxMBMasterFrameCBByteReceived(); // callback to receive FSM @@ -143,13 +198,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 @@ -249,7 +308,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, @@ -268,24 +328,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);