Merge branch 'bugfix/freemodbus_multiple_poll_event_processing' into 'master'

freemodbus: fix multiple event processing

See merge request espressif/esp-idf!6675
This commit is contained in:
Angus Gratton 2019-12-10 14:27:09 +08:00
commit 671fea5c58
10 changed files with 100 additions and 99 deletions

View File

@ -71,7 +71,9 @@ PR_BEGIN_EXTERN_C
/*! \ingroup modbus
* \brief Use the default Modbus TCP port (502)
*/
#define MB_TCP_PORT_USE_DEFAULT 0
#define MB_TCP_PORT_USE_DEFAULT 0
#define MB_FUNC_CODE_MAX 127
/* ----------------------- Type definitions ---------------------------------*/
#ifndef _MB_M_H

View File

@ -376,7 +376,8 @@ eMBPoll( void )
if ( !ucMBFrame ) {
return MB_EILLSTATE;
}
ESP_LOGD(MB_PORT_TAG, "%s:EV_EXECUTE", __func__); ucFunctionCode = ucMBFrame[MB_PDU_FUNC_OFF];
ESP_LOGD(MB_PORT_TAG, "%s:EV_EXECUTE", __func__);
ucFunctionCode = ucMBFrame[MB_PDU_FUNC_OFF];
eException = MB_EX_ILLEGAL_FUNCTION;
for( i = 0; i < MB_FUNC_HANDLERS_MAX; i++ )
{
@ -385,7 +386,7 @@ eMBPoll( void )
{
break;
}
else if( xFuncHandlers[i].ucFunctionCode == ucFunctionCode )
if( xFuncHandlers[i].ucFunctionCode == ucFunctionCode )
{
eException = xFuncHandlers[i].pxHandler( ucMBFrame, &usLength );
break;
@ -418,7 +419,7 @@ eMBPoll( void )
case EV_FRAME_SENT:
ESP_LOGD(MB_PORT_TAG, "%s:EV_FRAME_SENT", __func__);
break;
default:
break;
}

View File

@ -269,7 +269,6 @@ eMBMasterPoll( void )
static UCHAR ucFunctionCode;
static USHORT usLength;
static eMBException eException;
int i;
int j;
eMBErrorCode eStatus = MB_ENOERR;
@ -284,46 +283,31 @@ eMBMasterPoll( void )
/* Check if there is a event available. If not return control to caller.
* Otherwise we will handle the event. */
if( xMBMasterPortEventGet( &eEvent ) == TRUE )
if ( xMBMasterPortEventGet( &eEvent ) == TRUE )
{
switch ( eEvent )
{
case EV_MASTER_NO_EVENT:
ESP_LOGD(MB_PORT_TAG, "%s:EV_MASTER_NO_EVENT", __func__);
// Something went wrong and task unblocked but there are no any events set
assert(0);
break;
case EV_MASTER_PROCESS_SUCCESS:
ESP_LOGD(MB_PORT_TAG, "%s:EV_MASTER_PROCESS_SUCCESS", __func__);
break;
case EV_MASTER_ERROR_RESPOND_TIMEOUT:
ESP_LOGD(MB_PORT_TAG, "%s:EV_MASTER_ERROR_RESPOND_TIMEOUT", __func__);
break;
case EV_MASTER_ERROR_RECEIVE_DATA:
ESP_LOGD(MB_PORT_TAG, "%s:EV_MASTER_ERROR_RECEIVE_DATA", __func__);
break;
case EV_MASTER_ERROR_EXECUTE_FUNCTION:
ESP_LOGD(MB_PORT_TAG, "%s:EV_MASTER_ERROR_EXECUTE_FUNCTION", __func__);
break;
case EV_MASTER_READY:
// 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__);
break;
case EV_MASTER_FRAME_RECEIVED:
eStatus = peMBMasterFrameReceiveCur( &ucRcvAddress, &ucMBFrame, &usLength );
MB_PORT_CLEAR_EVENT( eEvent, EV_MASTER_READY );
} else if ( MB_PORT_CHECK_EVENT( eEvent, EV_MASTER_FRAME_RECEIVED ) ) {
eStatus = peMBMasterFrameReceiveCur( &ucRcvAddress, &ucMBFrame, &usLength);
ESP_LOG_BUFFER_HEX_LEVEL("POLL RCV buffer:", (void*)ucMBFrame, (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() ) )
{
ESP_LOGD(MB_PORT_TAG, "%s: Packet data received successfully (%u).", __func__, eStatus);
( void ) xMBMasterPortEventPost( EV_MASTER_EXECUTE );
}
}
else
{
vMBMasterSetErrorType(EV_ERROR_RECEIVE_DATA);
ESP_LOGD(MB_PORT_TAG, "%s: Packet data receive failed (addr=%u)(%u).", __func__, ucRcvAddress, eStatus);
ESP_LOGD( MB_PORT_TAG, "%s: Packet data receive failed (addr=%u)(%u).",
__func__, ucRcvAddress, eStatus);
( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS );
}
break;
case EV_MASTER_EXECUTE:
MB_PORT_CLEAR_EVENT( eEvent, EV_MASTER_FRAME_RECEIVED );
} else if ( MB_PORT_CHECK_EVENT( eEvent, EV_MASTER_EXECUTE ) ) {
if ( !ucMBFrame )
{
return MB_EILLSTATE;
@ -335,10 +319,8 @@ eMBMasterPoll( void )
if (ucFunctionCode & MB_FUNC_ERROR)
{
eException = (eMBException)ucMBFrame[MB_PDU_DATA_OFF];
}
else
{
for (i = 0; i < MB_FUNC_HANDLERS_MAX; i++)
} else {
for ( i = 0; i < MB_FUNC_HANDLERS_MAX; i++ )
{
/* No more function handlers registered. Abort. */
if (xMasterFuncHandlers[i].ucFunctionCode == 0)
@ -362,9 +344,9 @@ eMBMasterPoll( void )
}
else
{
eException = xMasterFuncHandlers[i].pxHandler(ucMBFrame, &usLength);
eException = xMasterFuncHandlers[i].pxHandler( ucMBFrame, &usLength );
}
vMBMasterSetCBRunInMasterMode(FALSE);
vMBMasterSetCBRunInMasterMode( FALSE );
break;
}
}
@ -380,54 +362,58 @@ eMBMasterPoll( void )
vMBMasterCBRequestSuccess( );
vMBMasterRunResRelease( );
}
break;
case EV_MASTER_FRAME_TRANSMIT:
MB_PORT_CLEAR_EVENT( eEvent, EV_MASTER_EXECUTE );
} 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 );
eStatus = peMBMasterFrameSendCur( ucMBMasterGetDestAddress(), ucMBFrame, usMBMasterGetPDUSndLength() );
if (eStatus != MB_ENOERR)
{
ESP_LOGD(MB_PORT_TAG, "%s:Frame send error. %d", __func__, eStatus);
ESP_LOGE( MB_PORT_TAG, "%s:Frame send error. %d", __func__, eStatus );
}
break;
case EV_MASTER_FRAME_SENT:
ESP_LOGD(MB_PORT_TAG, "%s:EV_MASTER_FRAME_SENT", __func__);
break;
case EV_MASTER_ERROR_PROCESS:
ESP_LOGD(MB_PORT_TAG, "%s:EV_MASTER_ERROR_PROCESS", __func__);
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__ );
MB_PORT_CLEAR_EVENT( eEvent, EV_MASTER_FRAME_SENT );
} 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();
errorType = eMBMasterGetErrorType( );
vMBMasterGetPDUSndBuf( &ucMBFrame );
switch (errorType)
switch ( errorType )
{
case EV_ERROR_RESPOND_TIMEOUT:
vMBMasterErrorCBRespondTimeout(ucMBMasterGetDestAddress(),
ucMBFrame, usMBMasterGetPDUSndLength());
break;
case EV_ERROR_RECEIVE_DATA:
vMBMasterErrorCBReceiveData(ucMBMasterGetDestAddress(),
ucMBFrame, usMBMasterGetPDUSndLength());
break;
case EV_ERROR_EXECUTE_FUNCTION:
vMBMasterErrorCBExecuteFunction(ucMBMasterGetDestAddress(),
ucMBFrame, usMBMasterGetPDUSndLength());
break;
default:
ESP_LOGD(MB_PORT_TAG, "%s: incorrect error type.", __func__);
break;
case EV_ERROR_RESPOND_TIMEOUT:
vMBMasterErrorCBRespondTimeout( ucMBMasterGetDestAddress( ),
ucMBFrame, usMBMasterGetPDUSndLength( ) );
break;
case EV_ERROR_RECEIVE_DATA:
vMBMasterErrorCBReceiveData( ucMBMasterGetDestAddress( ),
ucMBFrame, usMBMasterGetPDUSndLength( ) );
break;
case EV_ERROR_EXECUTE_FUNCTION:
vMBMasterErrorCBExecuteFunction( ucMBMasterGetDestAddress( ),
ucMBFrame, usMBMasterGetPDUSndLength( ) );
break;
default:
ESP_LOGE( MB_PORT_TAG, "%s: incorrect error type = %d.", __func__, errorType);
break;
}
vMBMasterRunResRelease();
break;
default:
ESP_LOGD(MB_PORT_TAG, "%s: incorrect event triggered = %d.", __func__, eEvent);
break;
vMBMasterRunResRelease( );
MB_PORT_CLEAR_EVENT( eEvent, EV_MASTER_ERROR_PROCESS );
}
if ( eEvent ) {
// Event processing is done, but some poll events still set then
// postpone its processing for next poll cycle (rare case).
ESP_LOGW( MB_PORT_TAG, "%s: Unprocessed event %d.", __func__, eEvent );
( void ) xMBMasterPortEventPost( eEvent );
}
} else {
// xMBMasterPortEventGet has unbloked the task but the event bits are not set
ESP_LOGD(MB_PORT_TAG, "%s: task event wait failure.", __func__);
// Something went wrong and task unblocked but there are no any correct events set
ESP_LOGE( MB_PORT_TAG, "%s: Unexpected event triggered %d.", __func__, eEvent );
eStatus = MB_EILLSTATE;
}
return MB_ENOERR;
return eStatus;
}
// Get whether the Modbus Master is run in master mode.
@ -497,7 +483,8 @@ eMBMasterTimerMode MB_PORT_ISR_ATTR xMBMasterGetCurTimerMode( void )
}
/* The master request is broadcast? */
BOOL MB_PORT_ISR_ATTR xMBMasterRequestIsBroadcast( void ){
BOOL MB_PORT_ISR_ATTR xMBMasterRequestIsBroadcast( void )
{
return xFrameIsBroadcast;
}

View File

@ -31,6 +31,7 @@
#define MB_SERIAL_TX_TOUT_MS (100)
#define MB_SERIAL_TX_TOUT_TICKS pdMS_TO_TICKS(MB_SERIAL_TX_TOUT_MS) // timeout for transmission
#define MB_SERIAL_RX_TOUT_TICKS pdMS_TO_TICKS(1) // timeout for rx from buffer
#define MB_SERIAL_RESP_LEN_MIN (4)
#define MB_PORT_CHECK(a, ret_val, str, ...) \
if (!(a)) { \
@ -70,6 +71,9 @@ void vMBPortExitCritical(void);
#define EXIT_CRITICAL_SECTION( ) { vMBPortExitCritical(); \
ESP_LOGD(MB_PORT_TAG,"%s: Port exit critical", __func__); }
#define MB_PORT_CHECK_EVENT( event, mask ) ( event & mask )
#define MB_PORT_CLEAR_EVENT( event, mask ) do { event &= ~mask; } while(0)
#ifdef __cplusplus
PR_END_EXTERN_C
#endif /* __cplusplus */

View File

@ -62,7 +62,6 @@
EV_MASTER_ERROR_RECEIVE_DATA | \
EV_MASTER_ERROR_EXECUTE_FUNCTION )
#define MB_CHECK_EVENT(event, mask) (event & mask)
/* ----------------------- Variables ----------------------------------------*/
static SemaphoreHandle_t xSemaphorMasterHdl;
@ -118,19 +117,19 @@ xMBMasterPortEventGet( eMBMasterEventType * eEvent)
{
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.
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 (uxBits & MB_EVENT_POLL_MASK) {
*eEvent = (eMBMasterEventType)(uxBits);
if (MB_PORT_CHECK_EVENT(uxBits, MB_EVENT_POLL_MASK)) {
*eEvent = (eMBMasterEventType)(uxBits & MB_EVENT_POLL_MASK);
xEventHappened = TRUE;
} else {
ESP_LOGE(MB_PORT_TAG,"%s: Incorrect event triggered = %d.", __func__, uxBits);
*eEvent = (eMBMasterEventType)uxBits;
xEventHappened = FALSE;
}
return xEventHappened;
@ -258,16 +257,16 @@ eMBMasterReqErrCode eMBMasterWaitRequestFinish( void ) {
if (xRecvedEvent) {
ESP_LOGD(MB_PORT_TAG,"%s: returned event = 0x%x", __func__, xRecvedEvent);
if (!(xRecvedEvent & MB_EVENT_REQ_MASK)) {
// if we wait for certain event bits but get other then set in mask
// if we wait for certain event bits but get from poll subset
ESP_LOGE(MB_PORT_TAG,"%s: incorrect event set = 0x%x", __func__, xRecvedEvent);
}
if MB_CHECK_EVENT(xRecvedEvent, EV_MASTER_PROCESS_SUCCESS) {
if (MB_PORT_CHECK_EVENT(xRecvedEvent, EV_MASTER_PROCESS_SUCCESS)) {
eErrStatus = MB_MRE_NO_ERR;
} else if MB_CHECK_EVENT(xRecvedEvent, EV_MASTER_ERROR_RESPOND_TIMEOUT){
} else if (MB_PORT_CHECK_EVENT(xRecvedEvent, EV_MASTER_ERROR_RESPOND_TIMEOUT)) {
eErrStatus = MB_MRE_TIMEDOUT;
} else if MB_CHECK_EVENT(xRecvedEvent, EV_MASTER_ERROR_RECEIVE_DATA){
} else if (MB_PORT_CHECK_EVENT(xRecvedEvent, EV_MASTER_ERROR_RECEIVE_DATA)) {
eErrStatus = MB_MRE_REV_DATA;
} else if MB_CHECK_EVENT(xRecvedEvent, EV_MASTER_ERROR_EXECUTE_FUNCTION){
} else if (MB_PORT_CHECK_EVENT(xRecvedEvent, EV_MASTER_ERROR_EXECUTE_FUNCTION)) {
eErrStatus = MB_MRE_EXE_FUN;
}
} else {

View File

@ -109,7 +109,7 @@ static void vMBPortSerialRxPoll(size_t xEventSize)
USHORT usCnt = 0;
if (bRxStateEnabled) {
if (xEventSize > 0) {
if (xEventSize > MB_SERIAL_RESP_LEN_MIN) {
xEventSize = (xEventSize > MB_SERIAL_BUF_SIZE) ? MB_SERIAL_BUF_SIZE : xEventSize;
// Get received packet into Rx buffer
for(usCnt = 0; xReadStatus && (usCnt < xEventSize); usCnt++ ) {

View File

@ -76,6 +76,9 @@ static UCHAR ucUartNumber = UART_NUM_MAX - 1;
static BOOL bRxStateEnabled = FALSE; // Receiver enabled flag
static BOOL bTxStateEnabled = FALSE; // Transmitter enabled flag
static UCHAR ucBuffer[MB_SERIAL_BUF_SIZE]; // Temporary buffer to transfer received data to modbus stack
static USHORT uiRxBufferPos = 0; // position in the receiver buffer
void vMBMasterPortSerialEnable(BOOL bRxEnable, BOOL bTxEnable)
{
// This function can be called from xMBRTUTransmitFSM() of different task
@ -99,12 +102,14 @@ static void vMBMasterPortSerialRxPoll(size_t xEventSize)
USHORT usCnt = 0;
if (bRxStateEnabled) {
if (xEventSize > 0) {
if (xEventSize > MB_SERIAL_RESP_LEN_MIN) {
xEventSize = (xEventSize > MB_SERIAL_BUF_SIZE) ? MB_SERIAL_BUF_SIZE : xEventSize;
// Get received packet into Rx buffer
for(usCnt = 0; xReadStatus && (usCnt < xEventSize); usCnt++ ) {
USHORT usLength = uart_read_bytes(ucUartNumber, &ucBuffer[0], xEventSize, portMAX_DELAY);
uiRxBufferPos = 0;
for(usCnt = 0; xReadStatus && (usCnt < usLength); usCnt++ ) {
// Call the Modbus stack callback function and let it fill the stack buffers.
xReadStatus = pxMBMasterFrameCBByteReceived(); // calls callback xMBRTUReceiveFSM()
xReadStatus = pxMBMasterFrameCBByteReceived(); // callback to receive FSM state machine
}
// The buffer is transferred into Modbus stack and is not needed here any more
uart_flush_input(ucUartNumber);
@ -124,7 +129,7 @@ BOOL xMBMasterPortSerialTxPoll(void)
// Continue while all response bytes put in buffer or out of buffer
while((bNeedPoll) && (usCount++ < MB_SERIAL_BUF_SIZE)) {
// Calls the modbus stack callback function to let it fill the UART transmit buffer.
bNeedPoll = pxMBMasterFrameCBTransmitterEmpty( ); // calls callback xMBRTUTransmitFSM();
bNeedPoll = pxMBMasterFrameCBTransmitterEmpty( ); // callback to transmit FSM state machine
}
ESP_LOGD(TAG, "MB_TX_buffer sent: (%d) bytes.", (uint16_t)(usCount - 1));
// Waits while UART sending the packet
@ -254,6 +259,7 @@ BOOL xMBMasterPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits,
} else {
vTaskSuspend(xMbTaskHandle); // Suspend serial task while stack is not started
}
uiRxBufferPos = 0;
ESP_LOGD(MB_PORT_TAG,"%s Init serial.", __func__);
return TRUE;
}
@ -276,6 +282,9 @@ BOOL xMBMasterPortSerialPutByte(CHAR ucByte)
BOOL xMBMasterPortSerialGetByte(CHAR* pucByte)
{
assert(pucByte != NULL);
USHORT usLength = uart_read_bytes(ucUartNumber, (uint8_t*)pucByte, 1, MB_SERIAL_RX_TOUT_TICKS);
return (usLength == 1);
MB_PORT_CHECK((uiRxBufferPos < MB_SERIAL_BUF_SIZE),
FALSE, "mb stack serial get byte failure.");
*pucByte = ucBuffer[uiRxBufferPos];
uiRxBufferPos++;
return TRUE;
}

View File

@ -145,7 +145,6 @@ static BOOL xMBMasterPortTimersEnable(USHORT usTimerTics50us)
MB_PORT_CHECK((xErr == ESP_OK), FALSE,
"timer start failure, timer_start() returned (0x%x).",
(uint32_t)xErr);
ESP_LOGD(MB_PORT_TAG,"%s Init timer.", __func__);
return TRUE;
}
@ -198,4 +197,4 @@ void vMBMasterPortTimerClose(void)
ESP_ERROR_CHECK(timer_pause(usTimerGroupIndex, usTimerIndex));
ESP_ERROR_CHECK(timer_disable_intr(usTimerGroupIndex, usTimerIndex));
ESP_ERROR_CHECK(esp_intr_free(xTimerIntHandle));
}
}

View File

@ -165,7 +165,7 @@ def test_check_mode(dut=None, mode_str=None, value=None):
return False
@ttfw_idf.idf_example_test(env_tag='Example_T2_RS485')
@ttfw_idf.idf_example_test(env_tag='UT_T2_RS485')
def test_modbus_communication(env, comm_mode):
global logger

View File

@ -276,7 +276,7 @@ example_test_011:
extends: .example_debug_template
tags:
- ESP32
- Example_T2_RS485
- UT_T2_RS485
artifacts:
when: always
expire_in: 1 week