Merge branch 'bugfix/fix_tcp_slave_start_destroy_sequence' into 'master'

modbus tcp master, slave fix start - destroy sequence

See merge request idf/esp-modbus!43
This commit is contained in:
Alex Lisitsyn
2023-09-29 21:17:36 +08:00
6 changed files with 127 additions and 108 deletions

View File

@@ -113,6 +113,14 @@
return ret_val; \ return ret_val; \
} }
// Macro to check if stack shutdown event is active
#define TCP_PORT_CHECK_SHDN(sema_ptr, callback_func) do { \
if (sema_ptr) { \
ESP_LOGD(TAG, "Shutdown stack from %s(%d)", __func__, __LINE__); \
callback_func(); \
} \
} while(0)
#ifdef __cplusplus #ifdef __cplusplus
PR_BEGIN_EXTERN_C PR_BEGIN_EXTERN_C
#endif /* __cplusplus */ #endif /* __cplusplus */

View File

@@ -181,7 +181,6 @@ static esp_err_t mbc_tcp_master_start(void)
return ESP_OK; return ESP_OK;
} }
// Modbus controller destroy function
static esp_err_t mbc_tcp_master_destroy(void) static esp_err_t mbc_tcp_master_destroy(void)
{ {
MB_MASTER_ASSERT(mbm_interface_ptr != NULL); MB_MASTER_ASSERT(mbm_interface_ptr != NULL);
@@ -189,17 +188,21 @@ static esp_err_t mbc_tcp_master_destroy(void)
MB_MASTER_CHECK((mbm_opts != NULL), ESP_ERR_INVALID_ARG, "mb incorrect options pointer."); MB_MASTER_CHECK((mbm_opts != NULL), ESP_ERR_INVALID_ARG, "mb incorrect options pointer.");
eMBErrorCode mb_error = MB_ENOERR; eMBErrorCode mb_error = MB_ENOERR;
// 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.");
mb_error = eMBMasterClose();
MB_MASTER_CHECK((mb_error == MB_ENOERR), ESP_ERR_INVALID_STATE,
"mb stack close failure returned (0x%x).", (int)mb_error);
// Stop polling by clearing correspondent bit in the event group // Stop polling by clearing correspondent bit in the event group
xEventGroupClearBits(mbm_opts->mbm_event_group, xEventGroupClearBits(mbm_opts->mbm_event_group,
(EventBits_t)MB_EVENT_STACK_STARTED); (EventBits_t)MB_EVENT_STACK_STARTED);
// Disable and then destroy the Modbus port
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)vTaskDelete(mbm_opts->mbm_task_handle);
mbm_opts->mbm_task_handle = NULL; mbm_opts->mbm_task_handle = NULL;
mb_error = eMBMasterClose();
MB_MASTER_CHECK((mb_error == MB_ENOERR), ESP_ERR_INVALID_STATE,
"mb stack close failure returned (0x%x).", (int)mb_error);
(void)vEventGroupDelete(mbm_opts->mbm_event_group); (void)vEventGroupDelete(mbm_opts->mbm_event_group);
mbm_opts->mbm_event_group = NULL; mbm_opts->mbm_event_group = NULL;
mbc_tcp_master_free_slave_list(); mbc_tcp_master_free_slave_list();

View File

@@ -68,6 +68,7 @@
#define MB_EVENT_REQ_ERR_MASK ( EV_MASTER_PROCESS_SUCCESS ) #define MB_EVENT_REQ_ERR_MASK ( EV_MASTER_PROCESS_SUCCESS )
#define MB_EVENT_WAIT_TOUT_MS ( 3000 ) #define MB_EVENT_WAIT_TOUT_MS ( 3000 )
#define MB_SHDN_WAIT_TOUT_MS ( 5000 )
#define MB_TCP_READ_TICK_MS ( 1 ) #define MB_TCP_READ_TICK_MS ( 1 )
#define MB_TCP_READ_BUF_RETRY_CNT ( 4 ) #define MB_TCP_READ_BUF_RETRY_CNT ( 4 )
@@ -80,7 +81,7 @@ void vMBPortEventClose(void);
static const char *TAG = "MB_TCP_MASTER_PORT"; static const char *TAG = "MB_TCP_MASTER_PORT";
static MbPortConfig_t xMbPortConfig; static MbPortConfig_t xMbPortConfig;
static EventGroupHandle_t xMasterEventHandle = NULL; static EventGroupHandle_t xMasterEventHandle = NULL;
static SemaphoreHandle_t xShutdownSemaphore = NULL; static SemaphoreHandle_t xShutdownSema = NULL;
static EventBits_t xMasterEvent = 0; static EventBits_t xMasterEvent = 0;
/* ----------------------- Static functions ---------------------------------*/ /* ----------------------- Static functions ---------------------------------*/
@@ -129,7 +130,7 @@ xMBMasterTCPPortInit( USHORT usTCPPort )
// Create task for packet processing // Create task for packet processing
BaseType_t xErr = xTaskCreatePinnedToCore(vMBTCPPortMasterTask, BaseType_t xErr = xTaskCreatePinnedToCore(vMBTCPPortMasterTask,
"tcp_master_task", "mbm_port_tcp_task",
MB_TCP_STACK_SIZE, MB_TCP_STACK_SIZE,
NULL, NULL,
MB_TCP_TASK_PRIO, MB_TCP_TASK_PRIO,
@@ -143,8 +144,6 @@ xMBMasterTCPPortInit( USHORT usTCPPort )
ESP_LOGI(TAG, "TCP master stack initialized."); ESP_LOGI(TAG, "TCP master stack initialized.");
bOkay = TRUE; bOkay = TRUE;
} }
vTaskSuspend(xMbPortConfig.xMbTcpTaskHandle);
return bOkay; return bOkay;
} }
@@ -217,15 +216,6 @@ static void vMBTCPPortMasterMStoTimeVal(USHORT usTimeoutMs, struct timeval *tv)
tv->tv_usec = (usTimeoutMs - (tv->tv_sec * 1000)) * 1000; 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) static BOOL xMBTCPPortMasterCloseConnection(MbSlaveInfo_t *pxInfo)
{ {
if (!pxInfo) { if (!pxInfo) {
@@ -243,6 +233,26 @@ static BOOL xMBTCPPortMasterCloseConnection(MbSlaveInfo_t *pxInfo)
return TRUE; return TRUE;
} }
static void xMBTCPPortMasterShutdown(void)
{
xSemaphoreGive(xShutdownSema);
vTaskDelete(NULL);
xMbPortConfig.xMbTcpTaskHandle = NULL;
for (USHORT ucCnt = 0; ucCnt < MB_TCP_PORT_MAX_CONN; ucCnt++) {
MbSlaveInfo_t* pxInfo = xMbPortConfig.pxMbSlaveInfo[ucCnt];
if (pxInfo) {
xMBTCPPortMasterCloseConnection(pxInfo);
if (pxInfo->pucRcvBuf) {
free(pxInfo->pucRcvBuf);
}
free(pxInfo);
xMbPortConfig.pxMbSlaveInfo[ucCnt] = NULL;
}
}
free(xMbPortConfig.pxMbSlaveInfo);
}
void vMBTCPPortMasterSetNetOpt(void *pvNetIf, eMBPortIpVer xIpVersion, eMBPortProto xProto) void vMBTCPPortMasterSetNetOpt(void *pvNetIf, eMBPortIpVer xIpVersion, eMBPortProto xProto)
{ {
xMbPortConfig.pvNetIface = pvNetIf; xMbPortConfig.pvNetIface = pvNetIf;
@@ -298,7 +308,7 @@ static int xMBTCPPortMasterGetBuf(MbSlaveInfo_t *pxInfo, UCHAR *pucDstBuf, USHOR
// Receive data from connected client // Receive data from connected client
while (usBytesLeft > 0) { while (usBytesLeft > 0) {
xMBTCPPortMasterCheckShutdown(); TCP_PORT_CHECK_SHDN(xShutdownSema, xMBTCPPortMasterShutdown);
xLength = recv(pxInfo->xSockId, pucBuf, usBytesLeft, 0); xLength = recv(pxInfo->xSockId, pucBuf, usBytesLeft, 0);
if (xLength < 0) { if (xLength < 0) {
if (errno == EAGAIN) { if (errno == EAGAIN) {
@@ -678,7 +688,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
while (1) { while (1) {
MbSlaveAddrInfo_t xSlaveAddrInfo = { 0 }; MbSlaveAddrInfo_t xSlaveAddrInfo = { 0 };
BaseType_t xStatus = xQueueReceive(xMbPortConfig.xConnectQueue, (void*)&xSlaveAddrInfo, pdMS_TO_TICKS(MB_EVENT_WAIT_TOUT_MS)); BaseType_t xStatus = xQueueReceive(xMbPortConfig.xConnectQueue, (void*)&xSlaveAddrInfo, pdMS_TO_TICKS(MB_EVENT_WAIT_TOUT_MS));
xMBTCPPortMasterCheckShutdown(); TCP_PORT_CHECK_SHDN(xShutdownSema, xMBTCPPortMasterShutdown);
if (xStatus != pdTRUE) { if (xStatus != pdTRUE) {
ESP_LOGE(TAG, "Fail to register slave IP."); ESP_LOGE(TAG, "Fail to register slave IP.");
} else { } else {
@@ -785,7 +795,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
if (pxInfo) { if (pxInfo) {
pxInfo->xError = xErr; pxInfo->xError = xErr;
} }
xMBTCPPortMasterCheckShutdown(); TCP_PORT_CHECK_SHDN(xShutdownSema, xMBTCPPortMasterShutdown);
} }
} }
ESP_LOGI(TAG, "Connected %u slaves, start polling...", (unsigned)usSlaveConnCnt); ESP_LOGI(TAG, "Connected %u slaves, start polling...", (unsigned)usSlaveConnCnt);
@@ -797,6 +807,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
xReadSet = xConnSet; xReadSet = xConnSet;
// Check transmission event to clear appropriate bit. // Check transmission event to clear appropriate bit.
xMBMasterPortFsmWaitConfirmation(EV_MASTER_FRAME_TRANSMIT, pdMS_TO_TICKS(MB_EVENT_WAIT_TOUT_MS)); xMBMasterPortFsmWaitConfirmation(EV_MASTER_FRAME_TRANSMIT, pdMS_TO_TICKS(MB_EVENT_WAIT_TOUT_MS));
TCP_PORT_CHECK_SHDN(xShutdownSema, xMBTCPPortMasterShutdown);
// Synchronize state machine with send packet event // Synchronize state machine with send packet event
if (xMBMasterPortFsmWaitConfirmation(EV_MASTER_FRAME_SENT, pdMS_TO_TICKS(MB_EVENT_WAIT_TOUT_MS))) { if (xMBMasterPortFsmWaitConfirmation(EV_MASTER_FRAME_SENT, pdMS_TO_TICKS(MB_EVENT_WAIT_TOUT_MS))) {
ESP_LOGD(TAG, "FSM Synchronized with sent event."); ESP_LOGD(TAG, "FSM Synchronized with sent event.");
@@ -807,7 +818,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
ESP_LOGE(TAG, "Incorrect connection options for slave index: %d.", ESP_LOGE(TAG, "Incorrect connection options for slave index: %d.",
(int)xMbPortConfig.ucCurSlaveIndex); (int)xMbPortConfig.ucCurSlaveIndex);
vMBTCPPortMasterStopPoll(); vMBTCPPortMasterStopPoll();
xMBTCPPortMasterCheckShutdown(); TCP_PORT_CHECK_SHDN(xShutdownSema, xMBTCPPortMasterShutdown);
break; // incorrect slave descriptor, reconnect. break; // incorrect slave descriptor, reconnect.
} }
xTime = xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo); xTime = xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo);
@@ -823,7 +834,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
xTime = xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo); xTime = xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo);
// Wait completion of last transaction // Wait completion of last transaction
xMBMasterPortFsmWaitConfirmation(MB_EVENT_REQ_DONE_MASK, pdMS_TO_TICKS(xTime + 1)); xMBMasterPortFsmWaitConfirmation(MB_EVENT_REQ_DONE_MASK, pdMS_TO_TICKS(xTime + 1));
xMBTCPPortMasterCheckShutdown(); TCP_PORT_CHECK_SHDN(xShutdownSema, xMBTCPPortMasterShutdown);
continue; continue;
} else if (xRes < 0) { } else if (xRes < 0) {
// Select error (slave connection or r/w failure). // Select error (slave connection or r/w failure).
@@ -834,7 +845,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
xMBMasterPortFsmWaitConfirmation(MB_EVENT_REQ_DONE_MASK, pdMS_TO_TICKS(xTime)); xMBMasterPortFsmWaitConfirmation(MB_EVENT_REQ_DONE_MASK, pdMS_TO_TICKS(xTime));
// Stop polling process // Stop polling process
vMBTCPPortMasterStopPoll(); vMBTCPPortMasterStopPoll();
xMBTCPPortMasterCheckShutdown(); TCP_PORT_CHECK_SHDN(xShutdownSema, xMBTCPPortMasterShutdown);
// Check disconnected slaves, do not need a result just to print information. // Check disconnected slaves, do not need a result just to print information.
xMBTCPPortMasterCheckConnState(&xConnSet); xMBTCPPortMasterCheckConnState(&xConnSet);
break; break;
@@ -868,7 +879,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
(int)pxCurrInfo->xIndex, (int)pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr, (int)xRet); (int)pxCurrInfo->xIndex, (int)pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr, (int)xRet);
// Stop polling process // Stop polling process
vMBTCPPortMasterStopPoll(); vMBTCPPortMasterStopPoll();
xMBTCPPortMasterCheckShutdown(); TCP_PORT_CHECK_SHDN(xShutdownSema, xMBTCPPortMasterShutdown);
// Check disconnected slaves, do not need a result just to print information. // Check disconnected slaves, do not need a result just to print information.
xMBTCPPortMasterCheckConnState(&xConnSet); xMBTCPPortMasterCheckConnState(&xConnSet);
break; break;
@@ -885,7 +896,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
(int)pxCurrInfo->xIndex, (int)pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr, xTime); (int)pxCurrInfo->xIndex, (int)pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr, xTime);
} }
} }
xMBTCPPortMasterCheckShutdown(); TCP_PORT_CHECK_SHDN(xShutdownSema, xMBTCPPortMasterShutdown);
} // while(usMbSlaveInfoCount) } // while(usMbSlaveInfoCount)
} // while (1) } // while (1)
vTaskDelete(NULL); vTaskDelete(NULL);
@@ -896,35 +907,23 @@ extern void vMBMasterPortTimerClose(void);
void vMBMasterTCPPortEnable(void) void vMBMasterTCPPortEnable(void)
{ {
vTaskResume(xMbPortConfig.xMbTcpTaskHandle);
} }
void vMBMasterTCPPortDisable(void) void vMBMasterTCPPortDisable(void)
{ {
// Try to exit the task gracefully, so select could release its internal callbacks // 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 // that were allocated on the stack of the task we're going to delete
xShutdownSemaphore = xSemaphoreCreateBinary(); xShutdownSema = xSemaphoreCreateBinary();
// if no semaphore (alloc issues) or couldn't acquire it, just delete the task // 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) { if (xShutdownSema == NULL || xSemaphoreTake(xShutdownSema, pdMS_TO_TICKS(MB_SHDN_WAIT_TOUT_MS)) != pdTRUE) {
ESP_LOGW(TAG, "Modbus port task couldn't exit gracefully within timeout -> abruptly deleting the task."); ESP_LOGW(TAG, "Modbus port task couldn't exit gracefully within timeout -> abruptly deleting the task.");
vTaskDelete(xMbPortConfig.xMbTcpTaskHandle); vTaskDelete(xMbPortConfig.xMbTcpTaskHandle);
} }
if (xShutdownSemaphore) { if (xShutdownSema) {
vSemaphoreDelete(xShutdownSemaphore); vSemaphoreDelete(xShutdownSema);
xShutdownSemaphore = NULL; xShutdownSema = NULL;
} }
for (USHORT ucCnt = 0; ucCnt < MB_TCP_PORT_MAX_CONN; ucCnt++) {
MbSlaveInfo_t* pxInfo = xMbPortConfig.pxMbSlaveInfo[ucCnt];
if (pxInfo) {
xMBTCPPortMasterCloseConnection(pxInfo);
if (pxInfo->pucRcvBuf) {
free(pxInfo->pucRcvBuf);
}
free(pxInfo);
xMbPortConfig.pxMbSlaveInfo[ucCnt] = NULL;
}
}
free(xMbPortConfig.pxMbSlaveInfo);
} }
void vMBMasterTCPPortClose(void) void vMBMasterTCPPortClose(void)

View File

@@ -179,7 +179,7 @@ esp_err_t mbc_tcp_slave_create(void** handler)
ESP_ERR_NO_MEM, "mb notify queue creation error."); ESP_ERR_NO_MEM, "mb notify queue creation error.");
// Create Modbus controller task // Create Modbus controller task
status = xTaskCreatePinnedToCore((void*)&modbus_tcp_slave_task, status = xTaskCreatePinnedToCore((void*)&modbus_tcp_slave_task,
"modbus_tcp_slave_task", "mbs_port_tcp_task",
MB_CONTROLLER_STACK_SIZE, MB_CONTROLLER_STACK_SIZE,
NULL, NULL,
MB_CONTROLLER_PRIORITY, MB_CONTROLLER_PRIORITY,

View File

@@ -70,7 +70,7 @@ void vMBPortEventClose( void );
/* ----------------------- Static variables ---------------------------------*/ /* ----------------------- Static variables ---------------------------------*/
static const char *TAG = "MB_TCP_SLAVE_PORT"; static const char *TAG = "MB_TCP_SLAVE_PORT";
static int xListenSock = -1; static int xListenSock = -1;
static SemaphoreHandle_t xShutdownSemaphore = NULL; static SemaphoreHandle_t xShutdownSema = NULL;
static MbSlavePortConfig_t xConfig = { 0 }; static MbSlavePortConfig_t xConfig = { 0 };
/* ----------------------- Static functions ---------------------------------*/ /* ----------------------- Static functions ---------------------------------*/
@@ -158,7 +158,6 @@ xMBTCPPortInit( USHORT usTCPPort )
MB_TCP_TASK_PRIO, MB_TCP_TASK_PRIO,
&xConfig.xMbTcpTaskHandle, &xConfig.xMbTcpTaskHandle,
MB_PORT_TASK_AFFINITY); MB_PORT_TASK_AFFINITY);
vTaskSuspend(xConfig.xMbTcpTaskHandle);
if (xErr != pdTRUE) if (xErr != pdTRUE)
{ {
ESP_LOGE(TAG, "Server task creation failure."); ESP_LOGE(TAG, "Server task creation failure.");
@@ -229,7 +228,12 @@ static BOOL xMBTCPPortCloseConnection(MbClientInfo_t* pxInfo)
ESP_LOGE(TAG, "Wrong socket info or disconnected socket: %d.", (int)pxInfo->xSockId); ESP_LOGE(TAG, "Wrong socket info or disconnected socket: %d.", (int)pxInfo->xSockId);
return FALSE; return FALSE;
} }
if (shutdown(pxInfo->xSockId, SHUT_RDWR) == -1) {
// Empty tcp buffer before shutdown
(void)recv(pxInfo->xSockId, &pxInfo->pucTCPBuf[0], MB_PDU_SIZE_MAX, MSG_DONTWAIT);
if (shutdown(pxInfo->xSockId, SHUT_RDWR) == -1)
{
ESP_LOGE(TAG, "Socket (#%d), shutdown failed: errno %u", (int)pxInfo->xSockId, (unsigned)errno); ESP_LOGE(TAG, "Socket (#%d), shutdown failed: errno %u", (int)pxInfo->xSockId, (unsigned)errno);
} }
close(pxInfo->xSockId); close(pxInfo->xSockId);
@@ -242,6 +246,36 @@ static BOOL xMBTCPPortCloseConnection(MbClientInfo_t* pxInfo)
return TRUE; return TRUE;
} }
static void vMBTCPPortFreeClientInfo(MbClientInfo_t *pxClientInfo)
{
if (pxClientInfo) {
if (pxClientInfo->pucTCPBuf) {
free((void *)pxClientInfo->pucTCPBuf);
}
if (pxClientInfo->pcIpAddr) {
free((void *)pxClientInfo->pcIpAddr);
}
free((void *)pxClientInfo);
}
}
static void vMBTCPPortShutdown(void)
{
xSemaphoreGive(xShutdownSema);
vTaskDelete(NULL);
xConfig.xMbTcpTaskHandle = NULL;
for (int i = 0; i < MB_TCP_PORT_MAX_CONN; i++) {
MbClientInfo_t *pxClientInfo = xConfig.pxMbClientInfo[i];
if ((pxClientInfo != NULL) && (pxClientInfo->xSockId > 0)) {
xMBTCPPortCloseConnection(pxClientInfo);
vMBTCPPortFreeClientInfo(pxClientInfo);
xConfig.pxMbClientInfo[i] = NULL;
}
}
free(xConfig.pxMbClientInfo);
}
static int xMBTCPPortRxPoll(MbClientInfo_t *pxClientInfo, ULONG xTimeoutMs) static int xMBTCPPortRxPoll(MbClientInfo_t *pxClientInfo, ULONG xTimeoutMs)
{ {
int xRet = ERR_CLSD; int xRet = ERR_CLSD;
@@ -263,12 +297,14 @@ static int xMBTCPPortRxPoll(MbClientInfo_t* pxClientInfo, ULONG xTimeoutMs)
{ {
// If select an error occurred // If select an error occurred
xRet = ERR_CLSD; xRet = ERR_CLSD;
TCP_PORT_CHECK_SHDN(xShutdownSema, vMBTCPPortShutdown);
break; break;
} else if (xRet == 0) { } else if (xRet == 0) {
// timeout occurred // timeout occurred
if ((xStartTimeStamp + xTimeoutMs * 1000) > xMBTCPGetTimeStamp()) { if ((xStartTimeStamp + xTimeoutMs * 1000) > xMBTCPGetTimeStamp()) {
ESP_LOGD(TAG, "Socket (#%d) Read timeout.", (int)pxClientInfo->xSockId); ESP_LOGD(TAG, "Socket (#%d) Read timeout.", (int)pxClientInfo->xSockId);
xRet = ERR_TIMEOUT; xRet = ERR_TIMEOUT;
TCP_PORT_CHECK_SHDN(xShutdownSema, vMBTCPPortShutdown);
break; break;
} }
} }
@@ -414,21 +450,6 @@ vMBTCPPortBindAddr(const CHAR* pcBindIp)
return(xListenSockFd); return(xListenSockFd);
} }
static void
vMBTCPPortFreeClientInfo(MbClientInfo_t* pxClientInfo)
{
if (pxClientInfo) {
if (pxClientInfo->pucTCPBuf) {
free((void*)pxClientInfo->pucTCPBuf);
}
if (pxClientInfo->pcIpAddr) {
free((void*)pxClientInfo->pcIpAddr);
}
free((void*)pxClientInfo);
}
}
static void vMBTCPPortServerTask(void *pvParameters) static void vMBTCPPortServerTask(void *pvParameters)
{ {
int xErr = 0; int xErr = 0;
@@ -442,6 +463,7 @@ static void vMBTCPPortServerTask(void *pvParameters)
// Create listen socket // Create listen socket
xListenSock = vMBTCPPortBindAddr(xConfig.pcBindAddr); xListenSock = vMBTCPPortBindAddr(xConfig.pcBindAddr);
if (xListenSock < 0) { if (xListenSock < 0) {
TCP_PORT_CHECK_SHDN(xShutdownSema, vMBTCPPortShutdown);
continue; continue;
} }
@@ -458,6 +480,7 @@ static void vMBTCPPortServerTask(void *pvParameters)
// Initialize read set and file descriptor according to // Initialize read set and file descriptor according to
// all registered connected clients // all registered connected clients
for (i = 0; i < MB_TCP_PORT_MAX_CONN; i++) { for (i = 0; i < MB_TCP_PORT_MAX_CONN; i++) {
TCP_PORT_CHECK_SHDN(xShutdownSema, vMBTCPPortShutdown);
if ((xConfig.pxMbClientInfo[i] != NULL) && (xConfig.pxMbClientInfo[i]->xSockId > 0)) { if ((xConfig.pxMbClientInfo[i] != NULL) && (xConfig.pxMbClientInfo[i]->xSockId > 0)) {
// calculate max file descriptor for select // calculate max file descriptor for select
xMaxSd = (xConfig.pxMbClientInfo[i]->xSockId > xMaxSd) ? xMaxSd = (xConfig.pxMbClientInfo[i]->xSockId > xMaxSd) ?
@@ -467,20 +490,19 @@ static void vMBTCPPortServerTask(void *pvParameters)
} }
} }
// Wait for an activity on one of the sockets, timeout is NULL, so wait indefinitely vxMBTCPPortMStoTimeVal(MB_TCP_RESP_TIMEOUT_MS, &xTimeVal);
xErr = select(xMaxSd + 1 , &xReadSet , NULL , NULL , NULL);
// Wait for an activity on one of the sockets during timeout
xErr = select(xMaxSd + 1, &xReadSet, NULL, NULL, &xTimeVal);
if ((xErr < 0) && (errno != EINTR)) { if ((xErr < 0) && (errno != EINTR)) {
// First check if the task is not flagged for shutdown
if (xListenSock == -1 && xShutdownSemaphore) {
xSemaphoreGive(xShutdownSemaphore);
vTaskDelete(NULL);
}
// error occurred during wait for read // error occurred during wait for read
ESP_LOGE(TAG, "select() errno = %u.", (unsigned)errno); ESP_LOGE(TAG, "select() errno = %u.", (unsigned)errno);
TCP_PORT_CHECK_SHDN(xShutdownSema, vMBTCPPortShutdown);
continue; continue;
} else if (xErr == 0) { } else if (xErr == 0) {
// If timeout happened, something is wrong // If timeout happened, something is wrong
ESP_LOGE(TAG, "select() timeout, errno = %u.", (unsigned)errno); ESP_LOGD(TAG, "select() timeout, errno = %u.", (unsigned)errno);
TCP_PORT_CHECK_SHDN(xShutdownSema, vMBTCPPortShutdown);
} }
// If something happened on the master socket, then its an incoming connection. // If something happened on the master socket, then its an incoming connection.
@@ -567,10 +589,7 @@ static void vMBTCPPortServerTask(void *pvParameters)
break; break;
} }
if (xShutdownSemaphore) { TCP_PORT_CHECK_SHDN(xShutdownSema, vMBTCPPortShutdown);
xSemaphoreGive(xShutdownSemaphore);
vTaskDelete(NULL);
}
// Close client connection // Close client connection
xMBTCPPortCloseConnection(pxClientInfo); xMBTCPPortCloseConnection(pxClientInfo);
@@ -644,46 +663,36 @@ static void vMBTCPPortServerTask(void *pvParameters)
void void
vMBTCPPortClose( ) vMBTCPPortClose( )
{ {
// Release resources for the event queue.
// Try to exit the task gracefully, so select could release its internal callbacks // 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 // that were allocated on the stack of the task we're going to delete
xShutdownSemaphore = xSemaphoreCreateBinary(); xShutdownSema = xSemaphoreCreateBinary();
vTaskResume(xConfig.xMbTcpTaskHandle); if (xShutdownSema == NULL || // if no semaphore (alloc issues) or couldn't acquire it, just delete the task
if (xShutdownSemaphore == NULL || // if no semaphore (alloc issues) or couldn't acquire it, just delete the task xSemaphoreTake(xShutdownSema, 2 * pdMS_TO_TICKS(CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND)) != pdTRUE) {
xSemaphoreTake(xShutdownSemaphore, 2*pdMS_TO_TICKS(CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND)) != pdTRUE) {
ESP_LOGE(TAG, "Task couldn't exit gracefully within timeout -> abruptly deleting the task"); ESP_LOGE(TAG, "Task couldn't exit gracefully within timeout -> abruptly deleting the task");
vTaskDelete(xConfig.xMbTcpTaskHandle); vTaskDelete(xConfig.xMbTcpTaskHandle);
} }
if (xShutdownSemaphore) {
vSemaphoreDelete(xShutdownSemaphore);
xShutdownSemaphore = NULL;
}
close(xListenSock);
xListenSock = -1;
vMBTCPPortRespQueueDelete(xConfig.xRespQueueHandle);
if (xShutdownSema) {
vSemaphoreDelete(xShutdownSema);
xShutdownSema = NULL;
}
vMBPortEventClose(); vMBPortEventClose();
} }
void vMBTCPPortEnable( void ) void vMBTCPPortEnable( void )
{ {
vTaskResume(xConfig.xMbTcpTaskHandle);
} }
void void
vMBTCPPortDisable( void ) vMBTCPPortDisable( void )
{ {
vTaskSuspend(xConfig.xMbTcpTaskHandle);
for (int i = 0; i < MB_TCP_PORT_MAX_CONN; i++) {
MbClientInfo_t* pxClientInfo = xConfig.pxMbClientInfo[i];
if ((pxClientInfo != NULL) && (pxClientInfo->xSockId > 0)) {
xMBTCPPortCloseConnection(pxClientInfo);
vMBTCPPortFreeClientInfo(pxClientInfo);
xConfig.pxMbClientInfo[i] = NULL;
}
}
free(xConfig.pxMbClientInfo);
close(xListenSock);
xListenSock = -1;
vMBTCPPortRespQueueDelete(xConfig.xRespQueueHandle);
} }
BOOL BOOL

View File

@@ -106,7 +106,7 @@ const mb_parameter_descriptor_t device_parameters[] = {
{ CID_INP_DATA_0, STR("Data_channel_0"), STR("Volts"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0, 2, { CID_INP_DATA_0, STR("Data_channel_0"), STR("Volts"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0, 2,
INPUT_OFFSET(input_data0), PARAM_TYPE_FLOAT, 4, OPTS( -10, 10, 1 ), PAR_PERMS_READ_WRITE_TRIGGER }, INPUT_OFFSET(input_data0), PARAM_TYPE_FLOAT, 4, OPTS( -10, 10, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
{ CID_HOLD_DATA_0, STR("Humidity_1"), STR("%rH"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0, 2, { CID_HOLD_DATA_0, STR("Humidity_1"), STR("%rH"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0, 2,
HOLD_OFFSET(holding_data0), PARAM_TYPE_FLOAT, 4, OPTS( 0, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER }, HOLD_OFFSET(holding_data0), PARAM_TYPE_FLOAT, 4, OPTS( 0, 1000, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
{ CID_INP_DATA_1, STR("Temperature_1"), STR("C"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 2, 2, { CID_INP_DATA_1, STR("Temperature_1"), STR("C"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 2, 2,
INPUT_OFFSET(input_data1), PARAM_TYPE_FLOAT, 4, OPTS( -40, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER }, INPUT_OFFSET(input_data1), PARAM_TYPE_FLOAT, 4, OPTS( -40, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
{ CID_HOLD_DATA_1, STR("Humidity_2"), STR("%rH"), MB_DEVICE_ADDR2, MB_PARAM_HOLDING, 2, 2, { CID_HOLD_DATA_1, STR("Humidity_2"), STR("%rH"), MB_DEVICE_ADDR2, MB_PARAM_HOLDING, 2, 2,