Skip to content

Commit

Permalink
Merge branch 'bugfix/modbus_fix_stack_reinitialization_sequence_v43' …
Browse files Browse the repository at this point in the history
…into 'release/v4.3'

modbus: fix stack reinitialization sequence (backport v4.3)

See merge request espressif/esp-idf!15402
  • Loading branch information
suda-morris committed Oct 18, 2021
2 parents 2e8abdb + 5b52358 commit 5a0b570
Show file tree
Hide file tree
Showing 6 changed files with 374 additions and 159 deletions.
2 changes: 0 additions & 2 deletions components/freemodbus/modbus/tcp/mbtcp_m.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,6 @@ eMBMasterTCPStart( void )
void
eMBMasterTCPStop( void )
{
/* Make sure that no more clients are connected. */
vMBMasterTCPPortDisable( );
}

eMBErrorCode
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@

// 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)

static mb_master_interface_t* mbm_interface_ptr = NULL;

Expand Down Expand Up @@ -116,15 +117,23 @@ static esp_err_t mbc_tcp_master_start(void)
result = (BOOL)xMBTCPPortMasterAddSlaveIp(*comm_ip_table);
MB_MASTER_CHECK(result, ESP_ERR_INVALID_STATE, "mb stack add slave IP failed: %s.", *comm_ip_table);
}
// Add end of list condition
(void)xMBTCPPortMasterAddSlaveIp(NULL);
// Init polling event handlers and wait before start polling
xMBTCPPortMasterWaitEvent(mbm_opts->mbm_event_group, (EventBits_t)MB_EVENT_STACK_STARTED, 1);

status = eMBMasterEnable();
MB_MASTER_CHECK((status == MB_ENOERR), ESP_ERR_INVALID_STATE,
"mb stack set slave ID failure, eMBMasterEnable() returned (0x%x).", (uint32_t)status);

bool start = (bool)xMBTCPPortMasterWaitEvent(mbm_opts->mbm_event_group, (EventBits_t)MB_EVENT_STACK_STARTED);
MB_MASTER_CHECK((start), ESP_ERR_INVALID_STATE, "mb stack start failed.");
// Send end of list condition to start connection phase
(void)xMBTCPPortMasterAddSlaveIp(NULL);

// Wait for connection done event
bool start = (bool)xMBTCPPortMasterWaitEvent(mbm_opts->mbm_event_group,
(EventBits_t)MB_EVENT_STACK_STARTED, MB_TCP_CONNECTION_TOUT);
MB_MASTER_CHECK((start), ESP_ERR_INVALID_STATE,
"mb stack could not connect to slaves for %d seconds.",
CONFIG_FMB_TCP_CONNECTION_TOUT_SEC);

return ESP_OK;
}

Expand All @@ -136,17 +145,19 @@ static esp_err_t mbc_tcp_master_destroy(void)
MB_MASTER_CHECK((mbm_opts != NULL), ESP_ERR_INVALID_ARG, "mb incorrect options pointer.");
eMBErrorCode mb_error = MB_ENOERR;

// Stop polling by clearing correspondent bit in the event group
xEventGroupClearBits(mbm_opts->mbm_event_group,
(EventBits_t)MB_EVENT_STACK_STARTED);
// Disable and then destroy the Modbus stack
mb_error = eMBMasterDisable();
MB_MASTER_CHECK((mb_error == MB_ENOERR), ESP_ERR_INVALID_STATE, "mb stack disable failure.");
(void)vTaskDelete(mbm_opts->mbm_task_handle);
(void)vEventGroupDelete(mbm_opts->mbm_event_group);
mb_error = eMBMasterClose();
MB_MASTER_CHECK((mb_error == MB_ENOERR), ESP_ERR_INVALID_STATE,
"mb stack close failure returned (0x%x).", (uint32_t)mb_error);
// Stop polling by clearing correspondent bit in the event group
xEventGroupClearBits(mbm_opts->mbm_event_group,
(EventBits_t)MB_EVENT_STACK_STARTED);
(void)vTaskDelete(mbm_opts->mbm_task_handle);
mbm_opts->mbm_task_handle = NULL;
(void)vEventGroupDelete(mbm_opts->mbm_event_group);
mbm_opts->mbm_event_group = NULL;
free(mbm_interface_ptr); // free the memory allocated for options
vMBPortSetMode((UCHAR)MB_PORT_INACTIVE);
mbm_interface_ptr = NULL;
Expand Down
76 changes: 59 additions & 17 deletions components/freemodbus/tcp_master/port/port_tcp_master.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@

#define MB_EVENT_REQ_ERR_MASK ( EV_MASTER_PROCESS_SUCCESS )

#define MB_EVENT_WAIT_TOUT_MS ( 2000 )
#define MB_EVENT_WAIT_TOUT_MS ( 3000 )

#define MB_TCP_READ_TICK_MS ( 1 )
#define MB_TCP_READ_BUF_RETRY_CNT ( 4 )
Expand All @@ -76,6 +76,7 @@ void vMBPortEventClose( void );
/* ----------------------- Static variables ---------------------------------*/
static MbPortConfig_t xMbPortConfig;
static EventGroupHandle_t xMasterEventHandle = NULL;
static SemaphoreHandle_t xShutdownSemaphore = NULL;
static EventBits_t xMasterEvent = 0;

/* ----------------------- Static functions ---------------------------------*/
Expand All @@ -84,15 +85,15 @@ static void vMBTCPPortMasterTask(void *pvParameters);
/* ----------------------- Begin implementation -----------------------------*/

// Waits for stack start event to start Modbus event processing
BOOL xMBTCPPortMasterWaitEvent(EventGroupHandle_t xEventHandle, EventBits_t xEvent)
BOOL xMBTCPPortMasterWaitEvent(EventGroupHandle_t xEventHandle, EventBits_t xEvent, USHORT usTimeout)
{
xMasterEventHandle = xEventHandle;
xMasterEvent = xEvent;
BaseType_t status = xEventGroupWaitBits(xMasterEventHandle,
(BaseType_t)(xEvent),
pdFALSE, // do not clear start bit
pdFALSE,
portMAX_DELAY);
usTimeout);
return (BOOL)(status & xEvent);
}

Expand Down Expand Up @@ -156,6 +157,8 @@ static void vMBTCPPortMasterStartPoll(void)
if (!(xFlags & xMasterEvent)) {
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Fail to start TCP stack.");
}
} else {
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Fail to start polling. Incorrect event handle...");
}
}

Expand All @@ -169,6 +172,8 @@ static void vMBTCPPortMasterStopPoll(void)
if (!(xFlags & xMasterEvent)) {
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Fail to stop polling.");
}
} else {
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Fail to stop polling. Incorrect event handle...");
}
}

Expand All @@ -185,6 +190,14 @@ static void vMBTCPPortMasterMStoTimeVal(USHORT usTimeoutMs, struct timeval *tv)
tv->tv_usec = (usTimeoutMs - (tv->tv_sec * 1000)) * 1000;
}

static void xMBTCPPortMasterCheckShutdown(void) {
// First check if the task is not flagged for shutdown
if (xShutdownSemaphore) {
xSemaphoreGive(xShutdownSemaphore);
vTaskDelete(NULL);
}
}

static BOOL xMBTCPPortMasterCloseConnection(MbSlaveInfo_t* pxInfo)
{
if (!pxInfo) {
Expand Down Expand Up @@ -256,6 +269,7 @@ static int xMBTCPPortMasterGetBuf(MbSlaveInfo_t* pxInfo, UCHAR* pucDstBuf, USHOR

// Receive data from connected client
while (usBytesLeft > 0) {
xMBTCPPortMasterCheckShutdown();
// none blocking read from socket with timeout
xLength = recv(pxInfo->xSockId, pucBuf, usBytesLeft, MSG_DONTWAIT);
if (xLength < 0) {
Expand Down Expand Up @@ -341,6 +355,9 @@ static int vMBTCPPortMasterReadPacket(MbSlaveInfo_t* pxInfo)

static err_t xMBTCPPortMasterSetNonBlocking(MbSlaveInfo_t* pxInfo)
{
if (!pxInfo) {
return ERR_CONN;
}
// Set non blocking attribute for socket
ULONG ulFlags = fcntl(pxInfo->xSockId, F_GETFL);
if (fcntl(pxInfo->xSockId, F_SETFL, ulFlags | O_NONBLOCK) == -1) {
Expand Down Expand Up @@ -465,6 +482,10 @@ BOOL xMBTCPPortMasterAddSlaveIp(const CHAR* pcIpStr)
// Unblocking connect function
static err_t xMBTCPPortMasterConnect(MbSlaveInfo_t* pxInfo)
{
if (!pxInfo) {
return ERR_CONN;
}

err_t xErr = ERR_OK;
CHAR cStr[128];
CHAR* pcStr = NULL;
Expand Down Expand Up @@ -623,7 +644,8 @@ static void vMBTCPPortMasterTask(void *pvParameters)

// Register each slave in the connection info structure
while (1) {
BaseType_t xStatus = xQueueReceive(xMbPortConfig.xConnectQueue, (void*)&pcAddrStr, portMAX_DELAY);
BaseType_t xStatus = xQueueReceive(xMbPortConfig.xConnectQueue, (void*)&pcAddrStr, pdMS_TO_TICKS(MB_EVENT_WAIT_TOUT_MS));
xMBTCPPortMasterCheckShutdown();
if (xStatus != pdTRUE) {
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Fail to register slave IP.");
} else {
Expand Down Expand Up @@ -724,10 +746,14 @@ static void vMBTCPPortMasterTask(void *pvParameters)
pxInfo->pcIpAddr, xErr);
break;
}
pxInfo->xError = xErr;
if (pxInfo) {
pxInfo->xError = xErr;
}
xMBTCPPortMasterCheckShutdown();
}
}
ESP_LOGI(MB_TCP_MASTER_PORT_TAG, "Connected %d slaves, start polling...", usSlaveConnCnt);

vMBTCPPortMasterStartPoll(); // Send event to start stack

// Slave receive data loop
Expand All @@ -745,6 +771,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Incorrect connection options for slave index: %d.",
xMbPortConfig.ucCurSlaveIndex);
vMBTCPPortMasterStopPoll();
xMBTCPPortMasterCheckShutdown();
break; // incorrect slave descriptor, reconnect.
}
xTime = xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo);
Expand All @@ -760,6 +787,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
xTime = xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo);
// Wait completion of last transaction
xMBMasterPortFsmWaitConfirmation(MB_EVENT_REQ_DONE_MASK, pdMS_TO_TICKS(xTime + 1));
xMBTCPPortMasterCheckShutdown();
continue;
} else if (xRes < 0) {
// Select error (slave connection or r/w failure).
Expand All @@ -770,6 +798,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
xMBMasterPortFsmWaitConfirmation(MB_EVENT_REQ_DONE_MASK, pdMS_TO_TICKS(xTime));
// Stop polling process
vMBTCPPortMasterStopPoll();
xMBTCPPortMasterCheckShutdown();
// Check disconnected slaves, do not need a result just to print information.
xMBTCPPortMasterCheckConnState(&xConnSet);
break;
Expand Down Expand Up @@ -802,6 +831,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr, xErr);
// Stop polling process
vMBTCPPortMasterStopPoll();
xMBTCPPortMasterCheckShutdown();
// Check disconnected slaves, do not need a result just to print information.
xMBTCPPortMasterCheckConnState(&xConnSet);
break;
Expand All @@ -818,6 +848,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr, xTime);
}
}
xMBTCPPortMasterCheckShutdown();
} // while(usMbSlaveInfoCount)
} // while (1)
vTaskDelete(NULL);
Expand All @@ -826,18 +857,6 @@ static void vMBTCPPortMasterTask(void *pvParameters)
extern void vMBMasterPortEventClose(void);
extern void vMBMasterPortTimerClose(void);

void
vMBMasterTCPPortClose(void)
{
(void)vTaskDelete(xMbPortConfig.xMbTcpTaskHandle);
(void)vMBMasterTCPPortDisable();
free(xMbPortConfig.pxMbSlaveInfo);
vQueueDelete(xMbPortConfig.xConnectQueue);
vMBMasterPortTimerClose();
// Release resources for the event queue.
vMBMasterPortEventClose();
}

void
vMBMasterTCPPortDisable(void)
{
Expand All @@ -854,6 +873,29 @@ vMBMasterTCPPortDisable(void)
}
}

void
vMBMasterTCPPortClose(void)
{
// Try to exit the task gracefully, so select could release its internal callbacks
// that were allocated on the stack of the task we're going to delete
xShutdownSemaphore = xSemaphoreCreateBinary();
// if no semaphore (alloc issues) or couldn't acquire it, just delete the task
if (xShutdownSemaphore == NULL || xSemaphoreTake(xShutdownSemaphore, pdMS_TO_TICKS(MB_EVENT_WAIT_TOUT_MS)) != pdTRUE) {
ESP_LOGW(MB_TCP_MASTER_PORT_TAG, "Modbus port task couldn't exit gracefully within timeout -> abruptly deleting the task.");
vTaskDelete(xMbPortConfig.xMbTcpTaskHandle);
}
if (xShutdownSemaphore) {
vSemaphoreDelete(xShutdownSemaphore);
xShutdownSemaphore = NULL;
}
vMBMasterTCPPortDisable();
free(xMbPortConfig.pxMbSlaveInfo);
vQueueDelete(xMbPortConfig.xConnectQueue);
vMBMasterPortTimerClose();
// Release resources for the event queue.
vMBMasterPortEventClose();
}

BOOL
xMBMasterTCPPortGetRequest( UCHAR ** ppucMBTCPFrame, USHORT * usTCPLength )
{
Expand Down
3 changes: 2 additions & 1 deletion components/freemodbus/tcp_master/port/port_tcp_master.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,11 @@ BOOL xMBTCPPortMasterAddSlaveIp(const CHAR* pcIpStr);
*
* @param xEventHandle Master event handle
* @param xEvent event mask to start Modbus stack FSM
* @param usTimeout - timeout in ticks to wait for stack to start
*
* @return TRUE if stack started, else FALSE
*/
BOOL xMBTCPPortMasterWaitEvent(EventGroupHandle_t xEventHandle, EventBits_t xEvent);
BOOL xMBTCPPortMasterWaitEvent(EventGroupHandle_t xEventHandle, EventBits_t xEvent, USHORT usTimeout);

/**
* Set network options for Master port
Expand Down
Loading

0 comments on commit 5a0b570

Please sign in to comment.