ソースを参照

Merge branch 'bugfix/modbus_fix_stack_reinitialization_sequence' into 'master'

freemodbus: fix TCP stack/examples reinitialization sequence

Closes IDFGH-4432

See merge request espressif/esp-idf!12123
Alex Lisitsyn 4 年 前
コミット
cd27a44107

+ 0 - 2
components/freemodbus/modbus/tcp/mbtcp_m.c

@@ -91,8 +91,6 @@ eMBMasterTCPStart( void )
 void
 void
 eMBMasterTCPStop( void )
 eMBMasterTCPStop( void )
 {
 {
-    /* Make sure that no more clients are connected. */
-    vMBMasterTCPPortDisable( );
 }
 }
 
 
 eMBErrorCode
 eMBErrorCode

+ 20 - 9
components/freemodbus/tcp_master/modbus_controller/mbc_tcp_master.c

@@ -39,6 +39,7 @@
 
 
 // The response time is average processing time + data transmission
 // The response time is average processing time + data transmission
 #define MB_RESPONSE_TIMEOUT pdMS_TO_TICKS(CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND)
 #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;
 static mb_master_interface_t* mbm_interface_ptr = NULL;
 
 
@@ -118,15 +119,23 @@ static esp_err_t mbc_tcp_master_start(void)
         result = (BOOL)xMBTCPPortMasterAddSlaveIp(*comm_ip_table);
         result = (BOOL)xMBTCPPortMasterAddSlaveIp(*comm_ip_table);
         MB_MASTER_CHECK(result, ESP_ERR_INVALID_STATE, "mb stack add slave IP failed: %s.", *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();
     status = eMBMasterEnable();
     MB_MASTER_CHECK((status == MB_ENOERR), ESP_ERR_INVALID_STATE,
     MB_MASTER_CHECK((status == MB_ENOERR), ESP_ERR_INVALID_STATE,
             "mb stack set slave ID failure, eMBMasterEnable() returned (0x%x).", (uint32_t)status);
             "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;
     return ESP_OK;
 }
 }
 
 
@@ -138,17 +147,19 @@ 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;
 
 
-    // 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
     // Disable and then destroy the Modbus stack
     mb_error = eMBMasterDisable();
     mb_error = eMBMasterDisable();
     MB_MASTER_CHECK((mb_error == MB_ENOERR), ESP_ERR_INVALID_STATE, "mb stack disable failure.");
     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_error = eMBMasterClose();
     MB_MASTER_CHECK((mb_error == MB_ENOERR), ESP_ERR_INVALID_STATE,
     MB_MASTER_CHECK((mb_error == MB_ENOERR), ESP_ERR_INVALID_STATE,
             "mb stack close failure returned (0x%x).", (uint32_t)mb_error);
             "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
     free(mbm_interface_ptr); // free the memory allocated for options
     vMBPortSetMode((UCHAR)MB_PORT_INACTIVE);
     vMBPortSetMode((UCHAR)MB_PORT_INACTIVE);
     mbm_interface_ptr = NULL;
     mbm_interface_ptr = NULL;

+ 59 - 17
components/freemodbus/tcp_master/port/port_tcp_master.c

@@ -66,7 +66,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           ( 2000 )
+#define MB_EVENT_WAIT_TOUT_MS           ( 3000 )
 
 
 #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 )
@@ -78,6 +78,7 @@ void vMBPortEventClose( void );
 /* ----------------------- Static variables ---------------------------------*/
 /* ----------------------- Static variables ---------------------------------*/
 static MbPortConfig_t xMbPortConfig;
 static MbPortConfig_t xMbPortConfig;
 static EventGroupHandle_t xMasterEventHandle = NULL;
 static EventGroupHandle_t xMasterEventHandle = NULL;
+static SemaphoreHandle_t xShutdownSemaphore = NULL;
 static EventBits_t xMasterEvent = 0;
 static EventBits_t xMasterEvent = 0;
 
 
 /* ----------------------- Static functions ---------------------------------*/
 /* ----------------------- Static functions ---------------------------------*/
@@ -86,7 +87,7 @@ static void vMBTCPPortMasterTask(void *pvParameters);
 /* ----------------------- Begin implementation -----------------------------*/
 /* ----------------------- Begin implementation -----------------------------*/
 
 
 // Waits for stack start event to start Modbus event processing
 // 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;
     xMasterEventHandle = xEventHandle;
     xMasterEvent = xEvent;
     xMasterEvent = xEvent;
@@ -94,7 +95,7 @@ BOOL xMBTCPPortMasterWaitEvent(EventGroupHandle_t xEventHandle, EventBits_t xEve
                                                (BaseType_t)(xEvent),
                                                (BaseType_t)(xEvent),
                                                pdFALSE, // do not clear start bit
                                                pdFALSE, // do not clear start bit
                                                pdFALSE,
                                                pdFALSE,
-                                               portMAX_DELAY);
+                                               usTimeout);
     return (BOOL)(status & xEvent);
     return (BOOL)(status & xEvent);
 }
 }
 
 
@@ -159,6 +160,8 @@ static void vMBTCPPortMasterStartPoll(void)
         if (!(xFlags & xMasterEvent)) {
         if (!(xFlags & xMasterEvent)) {
             ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Fail to start TCP stack.");
             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...");
     }
     }
 }
 }
 
 
@@ -172,6 +175,8 @@ static void vMBTCPPortMasterStopPoll(void)
         if (!(xFlags & xMasterEvent)) {
         if (!(xFlags & xMasterEvent)) {
             ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Fail to stop polling.");
             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...");
     }
     }
 }
 }
 
 
@@ -188,6 +193,14 @@ 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) {
@@ -259,6 +272,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();
         // none blocking read from socket with timeout
         // none blocking read from socket with timeout
         xLength = recv(pxInfo->xSockId, pucBuf, usBytesLeft, MSG_DONTWAIT);
         xLength = recv(pxInfo->xSockId, pucBuf, usBytesLeft, MSG_DONTWAIT);
         if (xLength < 0) {
         if (xLength < 0) {
@@ -344,6 +358,9 @@ static int vMBTCPPortMasterReadPacket(MbSlaveInfo_t* pxInfo)
 
 
 static err_t xMBTCPPortMasterSetNonBlocking(MbSlaveInfo_t* pxInfo)
 static err_t xMBTCPPortMasterSetNonBlocking(MbSlaveInfo_t* pxInfo)
 {
 {
+    if (!pxInfo) {
+        return ERR_CONN;
+    }
     // Set non blocking attribute for socket
     // Set non blocking attribute for socket
     ULONG ulFlags = fcntl(pxInfo->xSockId, F_GETFL);
     ULONG ulFlags = fcntl(pxInfo->xSockId, F_GETFL);
     if (fcntl(pxInfo->xSockId, F_SETFL, ulFlags | O_NONBLOCK) == -1) {
     if (fcntl(pxInfo->xSockId, F_SETFL, ulFlags | O_NONBLOCK) == -1) {
@@ -468,6 +485,10 @@ BOOL xMBTCPPortMasterAddSlaveIp(const CHAR* pcIpStr)
 // Unblocking connect function
 // Unblocking connect function
 static err_t xMBTCPPortMasterConnect(MbSlaveInfo_t* pxInfo)
 static err_t xMBTCPPortMasterConnect(MbSlaveInfo_t* pxInfo)
 {
 {
+    if (!pxInfo) {
+        return ERR_CONN;
+    }
+
     err_t xErr = ERR_OK;
     err_t xErr = ERR_OK;
     CHAR cStr[128];
     CHAR cStr[128];
     CHAR* pcStr = NULL;
     CHAR* pcStr = NULL;
@@ -626,7 +647,8 @@ static void vMBTCPPortMasterTask(void *pvParameters)
 
 
     // Register each slave in the connection info structure
     // Register each slave in the connection info structure
     while (1) {
     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) {
         if (xStatus != pdTRUE) {
             ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Fail to register slave IP.");
             ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Fail to register slave IP.");
         } else {
         } else {
@@ -727,10 +749,14 @@ static void vMBTCPPortMasterTask(void *pvParameters)
                                                             pxInfo->pcIpAddr, xErr);
                                                             pxInfo->pcIpAddr, xErr);
                         break;
                         break;
                 }
                 }
-                pxInfo->xError = xErr;
+                if (pxInfo) {
+                    pxInfo->xError = xErr;
+                }
+                xMBTCPPortMasterCheckShutdown();
             }
             }
         }
         }
         ESP_LOGI(MB_TCP_MASTER_PORT_TAG, "Connected %d slaves, start polling...", usSlaveConnCnt);
         ESP_LOGI(MB_TCP_MASTER_PORT_TAG, "Connected %d slaves, start polling...", usSlaveConnCnt);
+
         vMBTCPPortMasterStartPoll(); // Send event to start stack
         vMBTCPPortMasterStartPoll(); // Send event to start stack
 
 
         // Slave receive data loop
         // Slave receive data loop
@@ -748,6 +774,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
                 ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Incorrect connection options for slave index: %d.",
                 ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Incorrect connection options for slave index: %d.",
                                             xMbPortConfig.ucCurSlaveIndex);
                                             xMbPortConfig.ucCurSlaveIndex);
                 vMBTCPPortMasterStopPoll();
                 vMBTCPPortMasterStopPoll();
+                xMBTCPPortMasterCheckShutdown();
                 break; // incorrect slave descriptor, reconnect.
                 break; // incorrect slave descriptor, reconnect.
             }
             }
             xTime = xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo);
             xTime = xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo);
@@ -763,6 +790,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();
                 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).
@@ -773,6 +801,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();
                 // 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;
@@ -805,6 +834,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
                                     pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr, xErr);
                                     pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr, xErr);
                         // Stop polling process
                         // Stop polling process
                         vMBTCPPortMasterStopPoll();
                         vMBTCPPortMasterStopPoll();
+                        xMBTCPPortMasterCheckShutdown();
                         // 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;
@@ -821,6 +851,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
                                                     pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr, xTime);
                                                     pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr, xTime);
                 }
                 }
             }
             }
+            xMBTCPPortMasterCheckShutdown();
         } // while(usMbSlaveInfoCount)
         } // while(usMbSlaveInfoCount)
     } // while (1)
     } // while (1)
     vTaskDelete(NULL);
     vTaskDelete(NULL);
@@ -829,18 +860,6 @@ static void vMBTCPPortMasterTask(void *pvParameters)
 extern void vMBMasterPortEventClose(void);
 extern void vMBMasterPortEventClose(void);
 extern void vMBMasterPortTimerClose(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
 void
 vMBMasterTCPPortDisable(void)
 vMBMasterTCPPortDisable(void)
 {
 {
@@ -857,6 +876,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
 BOOL
 xMBMasterTCPPortGetRequest( UCHAR ** ppucMBTCPFrame, USHORT * usTCPLength )
 xMBMasterTCPPortGetRequest( UCHAR ** ppucMBTCPFrame, USHORT * usTCPLength )
 {
 {

+ 2 - 1
components/freemodbus/tcp_master/port/port_tcp_master.h

@@ -104,10 +104,11 @@ BOOL xMBTCPPortMasterAddSlaveIp(const CHAR* pcIpStr);
  *
  *
  * @param xEventHandle Master event handle
  * @param xEventHandle Master event handle
  * @param xEvent event mask to start Modbus stack FSM
  * @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
  * @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
  * Set network options for Master port

+ 105 - 42
examples/protocols/modbus/tcp/mb_tcp_master/main/tcp_master.c

@@ -14,6 +14,7 @@
 
 
 #include "string.h"
 #include "string.h"
 #include "esp_log.h"
 #include "esp_log.h"
+#include "esp_check.h"
 #include "esp_system.h"
 #include "esp_system.h"
 #include "esp_wifi.h"
 #include "esp_wifi.h"
 #include "esp_event.h"
 #include "esp_event.h"
@@ -46,12 +47,6 @@
 
 
 #define MASTER_TAG "MASTER_TEST"
 #define MASTER_TAG "MASTER_TEST"
 
 
-#define MASTER_CHECK(a, ret_val, str, ...) \
-    if (!(a)) { \
-        ESP_LOGE(MASTER_TAG, "%s(%u): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
-        return (ret_val); \
-    }
-
 // The macro to get offset for parameter in the appropriate structure
 // The macro to get offset for parameter in the appropriate structure
 #define HOLD_OFFSET(field) ((uint16_t)(offsetof(holding_reg_params_t, field) + 1))
 #define HOLD_OFFSET(field) ((uint16_t)(offsetof(holding_reg_params_t, field) + 1))
 #define INPUT_OFFSET(field) ((uint16_t)(offsetof(input_reg_params_t, field) + 1))
 #define INPUT_OFFSET(field) ((uint16_t)(offsetof(input_reg_params_t, field) + 1))
@@ -365,6 +360,7 @@ static void master_destroy_slave_list(char** table)
     for (int i = 0; ((i < MB_DEVICE_COUNT) && table[i] != NULL); i++) {
     for (int i = 0; ((i < MB_DEVICE_COUNT) && table[i] != NULL); i++) {
         if (table[i]) {
         if (table[i]) {
             free(table[i]);
             free(table[i]);
+            table[i] = NULL;
         }
         }
     }
     }
 }
 }
@@ -500,48 +496,52 @@ static void master_operation_func(void *arg)
     }
     }
     ESP_LOGI(MASTER_TAG, "Destroy master...");
     ESP_LOGI(MASTER_TAG, "Destroy master...");
     vTaskDelay(100);
     vTaskDelay(100);
-    ESP_ERROR_CHECK(mbc_master_destroy());
 }
 }
 
 
-// Modbus master initialization
-static esp_err_t master_init(void)
+static esp_err_t init_services(mb_tcp_addr_type_t ip_addr_type)
 {
 {
     esp_err_t result = nvs_flash_init();
     esp_err_t result = nvs_flash_init();
     if (result == ESP_ERR_NVS_NO_FREE_PAGES || result == ESP_ERR_NVS_NEW_VERSION_FOUND) {
     if (result == ESP_ERR_NVS_NO_FREE_PAGES || result == ESP_ERR_NVS_NEW_VERSION_FOUND) {
       ESP_ERROR_CHECK(nvs_flash_erase());
       ESP_ERROR_CHECK(nvs_flash_erase());
       result = nvs_flash_init();
       result = nvs_flash_init();
     }
     }
-    ESP_ERROR_CHECK(result);
-    esp_netif_init();
-    ESP_ERROR_CHECK(esp_event_loop_create_default());
-
+    ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
+                            MASTER_TAG,
+                            "nvs_flash_init fail, returns(0x%x).",
+                            (uint32_t)result);
+    result = esp_netif_init();
+    ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
+                            MASTER_TAG,
+                            "esp_netif_init fail, returns(0x%x).",
+                            (uint32_t)result);
+    result = esp_event_loop_create_default();
+    ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
+                            MASTER_TAG,
+                            "esp_event_loop_create_default fail, returns(0x%x).",
+                            (uint32_t)result);
 #if CONFIG_MB_MDNS_IP_RESOLVER
 #if CONFIG_MB_MDNS_IP_RESOLVER
     // Start mdns service and register device
     // Start mdns service and register device
     master_start_mdns_service();
     master_start_mdns_service();
 #endif
 #endif
-
     // This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
     // This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
     // Read "Establishing Wi-Fi or Ethernet Connection" section in
     // Read "Establishing Wi-Fi or Ethernet Connection" section in
     // examples/protocols/README.md for more information about this function.
     // examples/protocols/README.md for more information about this function.
-    ESP_ERROR_CHECK(example_connect());
-
-    ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE));
-
-    mb_communication_info_t comm_info = { 0 };
-    comm_info.ip_port = MB_TCP_PORT;
-#if !CONFIG_EXAMPLE_CONNECT_IPV6
-    comm_info.ip_addr_type = MB_IPV4;
-#else
-    comm_info.ip_addr_type = MB_IPV6;
+    result = example_connect();
+    ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
+                                MASTER_TAG,
+                                "example_connect fail, returns(0x%x).",
+                                (uint32_t)result);
+#if CONFIG_EXAMPLE_CONNECT_WIFI
+   result = esp_wifi_set_ps(WIFI_PS_NONE);
+   ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
+                                   MASTER_TAG,
+                                   "esp_wifi_set_ps fail, returns(0x%x).",
+                                   (uint32_t)result);
 #endif
 #endif
-    comm_info.ip_mode = MB_MODE_TCP;
-    comm_info.ip_addr = (void*)slave_ip_address_table;
-    comm_info.ip_netif_ptr = (void*)get_example_netif();
-
 #if CONFIG_MB_MDNS_IP_RESOLVER
 #if CONFIG_MB_MDNS_IP_RESOLVER
     int res = 0;
     int res = 0;
     for (int retry = 0; (res < num_device_parameters) && (retry < 10); retry++) {
     for (int retry = 0; (res < num_device_parameters) && (retry < 10); retry++) {
-        res = master_query_slave_service("_modbus", "_tcp", comm_info.ip_addr_type);
+        res = master_query_slave_service("_modbus", "_tcp", ip_addr_type);
     }
     }
     if (res < num_device_parameters) {
     if (res < num_device_parameters) {
         ESP_LOGE(MASTER_TAG, "Could not resolve one or more slave IP addresses, resolved: %d out of %d.", res, num_device_parameters );
         ESP_LOGE(MASTER_TAG, "Could not resolve one or more slave IP addresses, resolved: %d out of %d.", res, num_device_parameters );
@@ -555,46 +555,109 @@ static esp_err_t master_init(void)
         ESP_LOGI(MASTER_TAG, "Configured %d IP addresse(s).", ip_cnt);
         ESP_LOGI(MASTER_TAG, "Configured %d IP addresse(s).", ip_cnt);
     } else {
     } else {
         ESP_LOGE(MASTER_TAG, "Fail to get IP address from stdin. Continue.");
         ESP_LOGE(MASTER_TAG, "Fail to get IP address from stdin. Continue.");
+        return ESP_ERR_NOT_FOUND;
     }
     }
 #endif
 #endif
+    return ESP_OK;
+}
 
 
+static esp_err_t destroy_services(void)
+{
+    esp_err_t err = ESP_OK;
+#if CONFIG_MB_MDNS_IP_RESOLVER
+    master_destroy_slave_list(slave_ip_address_table);
+#endif
+    err = example_disconnect();
+    ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
+                                   MASTER_TAG,
+                                   "example_disconnect fail, returns(0x%x).",
+                                   (uint32_t)err);
+    err = esp_event_loop_delete_default();
+    ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
+                                       MASTER_TAG,
+                                       "esp_event_loop_delete_default fail, returns(0x%x).",
+                                       (uint32_t)err);
+    err = esp_netif_deinit();
+    ESP_RETURN_ON_FALSE((err == ESP_OK || err == ESP_ERR_NOT_SUPPORTED), ESP_ERR_INVALID_STATE,
+                                        MASTER_TAG,
+                                        "esp_netif_deinit fail, returns(0x%x).",
+                                        (uint32_t)err);
+    err = nvs_flash_deinit();
+    ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
+                                MASTER_TAG,
+                                "nvs_flash_deinit fail, returns(0x%x).",
+                                (uint32_t)err);
+    return err;
+}
+
+// Modbus master initialization
+static esp_err_t master_init(mb_communication_info_t* comm_info)
+{
     void* master_handler = NULL;
     void* master_handler = NULL;
 
 
     esp_err_t err = mbc_master_init_tcp(&master_handler);
     esp_err_t err = mbc_master_init_tcp(&master_handler);
-    MASTER_CHECK((master_handler != NULL), ESP_ERR_INVALID_STATE,
+    ESP_RETURN_ON_FALSE((master_handler != NULL), ESP_ERR_INVALID_STATE,
+                                MASTER_TAG,
                                 "mb controller initialization fail.");
                                 "mb controller initialization fail.");
-    MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
+    ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
+                            MASTER_TAG,
                             "mb controller initialization fail, returns(0x%x).",
                             "mb controller initialization fail, returns(0x%x).",
                             (uint32_t)err);
                             (uint32_t)err);
 
 
-    err = mbc_master_setup((void*)&comm_info);
-    MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
+    err = mbc_master_setup((void*)comm_info);
+    ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
+                            MASTER_TAG,
                             "mb controller setup fail, returns(0x%x).",
                             "mb controller setup fail, returns(0x%x).",
                             (uint32_t)err);
                             (uint32_t)err);
 
 
     err = mbc_master_set_descriptor(&device_parameters[0], num_device_parameters);
     err = mbc_master_set_descriptor(&device_parameters[0], num_device_parameters);
-    MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
+    ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
+                                MASTER_TAG,
                                 "mb controller set descriptor fail, returns(0x%x).",
                                 "mb controller set descriptor fail, returns(0x%x).",
                                 (uint32_t)err);
                                 (uint32_t)err);
     ESP_LOGI(MASTER_TAG, "Modbus master stack initialized...");
     ESP_LOGI(MASTER_TAG, "Modbus master stack initialized...");
 
 
     err = mbc_master_start();
     err = mbc_master_start();
-    MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
+    ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
+                            MASTER_TAG,
                             "mb controller start fail, returns(0x%x).",
                             "mb controller start fail, returns(0x%x).",
                             (uint32_t)err);
                             (uint32_t)err);
     vTaskDelay(5);
     vTaskDelay(5);
     return err;
     return err;
 }
 }
 
 
-void app_main(void)
+static esp_err_t master_destroy(void)
 {
 {
-    // Initialization of device peripheral and objects
-    ESP_ERROR_CHECK(master_init());
-    vTaskDelay(10);
+    esp_err_t err = mbc_master_destroy();
+    ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
+                                MASTER_TAG,
+                                "mbc_master_destroy fail, returns(0x%x).",
+                                (uint32_t)err);
+    ESP_LOGI(MASTER_TAG, "Modbus master stack destroy...");
+    return err;
+}
 
 
-    master_operation_func(NULL);
-#if CONFIG_MB_MDNS_IP_RESOLVER
-    master_destroy_slave_list(slave_ip_address_table);
+void app_main(void)
+{
+    mb_tcp_addr_type_t ip_addr_type;
+#if !CONFIG_EXAMPLE_CONNECT_IPV6
+    ip_addr_type = MB_IPV4;
+#else
+    ip_addr_type = MB_IPV6;
 #endif
 #endif
+    ESP_ERROR_CHECK(init_services(ip_addr_type));
 
 
+    mb_communication_info_t comm_info = { 0 };
+    comm_info.ip_port = MB_TCP_PORT;
+    comm_info.ip_addr_type = ip_addr_type;
+    comm_info.ip_mode = MB_MODE_TCP;
+    comm_info.ip_addr = (void*)slave_ip_address_table;
+    comm_info.ip_netif_ptr = (void*)get_example_netif();
+
+    ESP_ERROR_CHECK(master_init(&comm_info));
+    vTaskDelay(50);
+
+    master_operation_func(NULL);
+    ESP_ERROR_CHECK(master_destroy());
+    ESP_ERROR_CHECK(destroy_services());
 }
 }

+ 223 - 100
examples/protocols/modbus/tcp/mb_tcp_slave/main/tcp_slave.c

@@ -8,7 +8,7 @@
 #include "esp_err.h"
 #include "esp_err.h"
 #include "sdkconfig.h"
 #include "sdkconfig.h"
 #include "esp_log.h"
 #include "esp_log.h"
-
+#include "esp_check.h"
 #include "esp_system.h"
 #include "esp_system.h"
 #include "esp_wifi.h"
 #include "esp_wifi.h"
 #include "esp_event.h"
 #include "esp_event.h"
@@ -87,7 +87,7 @@ static inline char* gen_host_name_str(char* service_name, char* name)
     return name;
     return name;
 }
 }
 
 
-static void start_mdns_service()
+static void start_mdns_service(void)
 {
 {
     char temp_str[32] = {0};
     char temp_str[32] = {0};
     uint8_t sta_mac[6] = {0};
     uint8_t sta_mac[6] = {0};
@@ -115,6 +115,11 @@ static void start_mdns_service()
     ESP_ERROR_CHECK( mdns_service_txt_item_set("_modbus", "_tcp", "mb_id", gen_id_str("\0", temp_str)));
     ESP_ERROR_CHECK( mdns_service_txt_item_set("_modbus", "_tcp", "mb_id", gen_id_str("\0", temp_str)));
 }
 }
 
 
+static void stop_mdns_service(void)
+{
+    mdns_free();
+}
+
 #endif
 #endif
 
 
 // Set register values into known state
 // Set register values into known state
@@ -152,104 +157,9 @@ static void setup_reg_data(void)
     input_reg_params.input_data7 = 4.78;
     input_reg_params.input_data7 = 4.78;
 }
 }
 
 
-// An example application of Modbus slave. It is based on freemodbus stack.
-// See deviceparams.h file for more information about assigned Modbus parameters.
-// These parameters can be accessed from main application and also can be changed
-// by external Modbus master host.
-void app_main(void)
+static void slave_operation_func(void *arg)
 {
 {
-    esp_err_t result = nvs_flash_init();
-    if (result == ESP_ERR_NVS_NO_FREE_PAGES || result == ESP_ERR_NVS_NEW_VERSION_FOUND) {
-      ESP_ERROR_CHECK(nvs_flash_erase());
-      result = nvs_flash_init();
-    }
-    ESP_ERROR_CHECK(result);
-    esp_netif_init();
-    ESP_ERROR_CHECK(esp_event_loop_create_default());
-
-#if CONFIG_MB_MDNS_IP_RESOLVER
-    start_mdns_service();
-#endif
-
-    /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
-     * Read "Establishing Wi-Fi or Ethernet Connection" section in
-     * examples/protocols/README.md for more information about this function.
-     */
-    ESP_ERROR_CHECK(example_connect());
-
-    ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE));
-
-    // Set UART log level
-    esp_log_level_set(SLAVE_TAG, ESP_LOG_INFO);
-    void* mbc_slave_handler = NULL;
-
-    ESP_ERROR_CHECK(mbc_slave_init_tcp(&mbc_slave_handler)); // Initialization of Modbus controller
-
     mb_param_info_t reg_info; // keeps the Modbus registers access information
     mb_param_info_t reg_info; // keeps the Modbus registers access information
-    mb_register_area_descriptor_t reg_area; // Modbus register area descriptor structure
-
-    mb_communication_info_t comm_info = { 0 };
-    comm_info.ip_port = MB_TCP_PORT_NUMBER;
-#if !CONFIG_EXAMPLE_CONNECT_IPV6
-    comm_info.ip_addr_type = MB_IPV4;
-#else
-    comm_info.ip_addr_type = MB_IPV6;
-#endif
-    comm_info.ip_mode = MB_MODE_TCP;
-    comm_info.ip_addr = NULL;
-    comm_info.ip_netif_ptr = (void*)get_example_netif();
-    // Setup communication parameters and start stack
-    ESP_ERROR_CHECK(mbc_slave_setup((void*)&comm_info));
-
-    // The code below initializes Modbus register area descriptors
-    // for Modbus Holding Registers, Input Registers, Coils and Discrete Inputs
-    // Initialization should be done for each supported Modbus register area according to register map.
-    // When external master trying to access the register in the area that is not initialized
-    // by mbc_slave_set_descriptor() API call then Modbus stack
-    // will send exception response for this register area.
-    reg_area.type = MB_PARAM_HOLDING; // Set type of register area
-    reg_area.start_offset = MB_REG_HOLDING_START_AREA0; // Offset of register area in Modbus protocol
-    reg_area.address = (void*)&holding_reg_params.holding_data0; // Set pointer to storage instance
-    reg_area.size = sizeof(float) << 2; // Set the size of register storage instance
-    ESP_ERROR_CHECK(mbc_slave_set_descriptor(reg_area));
-
-    reg_area.type = MB_PARAM_HOLDING; // Set type of register area
-    reg_area.start_offset = MB_REG_HOLDING_START_AREA1; // Offset of register area in Modbus protocol
-    reg_area.address = (void*)&holding_reg_params.holding_data4; // Set pointer to storage instance
-    reg_area.size = sizeof(float) << 2; // Set the size of register storage instance
-    ESP_ERROR_CHECK(mbc_slave_set_descriptor(reg_area));
-
-    // Initialization of Input Registers area
-    reg_area.type = MB_PARAM_INPUT;
-    reg_area.start_offset = MB_REG_INPUT_START_AREA0;
-    reg_area.address = (void*)&input_reg_params.input_data0;
-    reg_area.size = sizeof(float) << 2;
-    ESP_ERROR_CHECK(mbc_slave_set_descriptor(reg_area));
-    // Initialization of Input Registers area
-    reg_area.type = MB_PARAM_INPUT;
-    reg_area.start_offset = MB_REG_INPUT_START_AREA1;
-    reg_area.address = (void*)&input_reg_params.input_data4;
-    reg_area.size = sizeof(float) << 2;
-    ESP_ERROR_CHECK(mbc_slave_set_descriptor(reg_area));
-
-    // Initialization of Coils register area
-    reg_area.type = MB_PARAM_COIL;
-    reg_area.start_offset = MB_REG_COILS_START;
-    reg_area.address = (void*)&coil_reg_params;
-    reg_area.size = sizeof(coil_reg_params);
-    ESP_ERROR_CHECK(mbc_slave_set_descriptor(reg_area));
-
-    // Initialization of Discrete Inputs register area
-    reg_area.type = MB_PARAM_DISCRETE;
-    reg_area.start_offset = MB_REG_DISCRETE_INPUT_START;
-    reg_area.address = (void*)&discrete_reg_params;
-    reg_area.size = sizeof(discrete_reg_params);
-    ESP_ERROR_CHECK(mbc_slave_set_descriptor(reg_area));
-
-    setup_reg_data(); // Set values into known state
-
-    // Starts of modbus controller and stack
-    ESP_ERROR_CHECK(mbc_slave_start());
 
 
     ESP_LOGI(SLAVE_TAG, "Modbus slave stack initialized.");
     ESP_LOGI(SLAVE_TAG, "Modbus slave stack initialized.");
     ESP_LOGI(SLAVE_TAG, "Start modbus test...");
     ESP_LOGI(SLAVE_TAG, "Start modbus test...");
@@ -310,8 +220,221 @@ void app_main(void)
     // Destroy of Modbus controller on alarm
     // Destroy of Modbus controller on alarm
     ESP_LOGI(SLAVE_TAG,"Modbus controller destroyed.");
     ESP_LOGI(SLAVE_TAG,"Modbus controller destroyed.");
     vTaskDelay(100);
     vTaskDelay(100);
-    ESP_ERROR_CHECK(mbc_slave_destroy());
+}
+
+static esp_err_t init_services(void)
+{
+    esp_err_t result = nvs_flash_init();
+    if (result == ESP_ERR_NVS_NO_FREE_PAGES || result == ESP_ERR_NVS_NEW_VERSION_FOUND) {
+      ESP_ERROR_CHECK(nvs_flash_erase());
+      result = nvs_flash_init();
+    }
+    ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
+                            SLAVE_TAG,
+                            "nvs_flash_init fail, returns(0x%x).",
+                            (uint32_t)result);
+    result = esp_netif_init();
+    ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
+                            SLAVE_TAG,
+                            "esp_netif_init fail, returns(0x%x).",
+                            (uint32_t)result);
+    result = esp_event_loop_create_default();
+    ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
+                            SLAVE_TAG,
+                            "esp_event_loop_create_default fail, returns(0x%x).",
+                            (uint32_t)result);
 #if CONFIG_MB_MDNS_IP_RESOLVER
 #if CONFIG_MB_MDNS_IP_RESOLVER
-    mdns_free();
+    // Start mdns service and register device
+    start_mdns_service();
+#endif
+    // This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
+    // Read "Establishing Wi-Fi or Ethernet Connection" section in
+    // examples/protocols/README.md for more information about this function.
+    result = example_connect();
+    ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
+                                SLAVE_TAG,
+                                "example_connect fail, returns(0x%x).",
+                                (uint32_t)result);
+#if CONFIG_EXAMPLE_CONNECT_WIFI
+    result = esp_wifi_set_ps(WIFI_PS_NONE);
+    ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
+                                   SLAVE_TAG,
+                                   "esp_wifi_set_ps fail, returns(0x%x).",
+                                   (uint32_t)result);
+#endif
+    return ESP_OK;
+}
+
+static esp_err_t destroy_services(void)
+{
+    esp_err_t err = ESP_OK;
+
+    err = example_disconnect();
+    ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
+                                   SLAVE_TAG,
+                                   "example_disconnect fail, returns(0x%x).",
+                                   (uint32_t)err);
+    err = esp_event_loop_delete_default();
+    ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
+                                       SLAVE_TAG,
+                                       "esp_event_loop_delete_default fail, returns(0x%x).",
+                                       (uint32_t)err);
+    err = esp_netif_deinit();
+    ESP_RETURN_ON_FALSE((err == ESP_OK || err == ESP_ERR_NOT_SUPPORTED), ESP_ERR_INVALID_STATE,
+                                        SLAVE_TAG,
+                                        "esp_netif_deinit fail, returns(0x%x).",
+                                        (uint32_t)err);
+    err = nvs_flash_deinit();
+    ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
+                                SLAVE_TAG,
+                                "nvs_flash_deinit fail, returns(0x%x).",
+                                (uint32_t)err);
+#if CONFIG_MB_MDNS_IP_RESOLVER
+    stop_mdns_service();
+#endif
+    return err;
+}
+
+// Modbus slave initialization
+static esp_err_t slave_init(mb_communication_info_t* comm_info)
+{
+    mb_register_area_descriptor_t reg_area; // Modbus register area descriptor structure
+
+    void* slave_handler = NULL;
+
+    // Initialization of Modbus controller
+    esp_err_t err = mbc_slave_init_tcp(&slave_handler);
+    ESP_RETURN_ON_FALSE((err == ESP_OK && slave_handler != NULL), ESP_ERR_INVALID_STATE,
+                                SLAVE_TAG,
+                                "mb controller initialization fail.");
+
+    comm_info->ip_addr = NULL; // Bind to any address
+    comm_info->ip_netif_ptr = (void*)get_example_netif();
+
+    // Setup communication parameters and start stack
+    err = mbc_slave_setup((void*)comm_info);
+    ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
+                                        SLAVE_TAG,
+                                        "mbc_slave_setup fail, returns(0x%x).",
+                                        (uint32_t)err);
+
+    // The code below initializes Modbus register area descriptors
+    // for Modbus Holding Registers, Input Registers, Coils and Discrete Inputs
+    // Initialization should be done for each supported Modbus register area according to register map.
+    // When external master trying to access the register in the area that is not initialized
+    // by mbc_slave_set_descriptor() API call then Modbus stack
+    // will send exception response for this register area.
+    reg_area.type = MB_PARAM_HOLDING; // Set type of register area
+    reg_area.start_offset = MB_REG_HOLDING_START_AREA0; // Offset of register area in Modbus protocol
+    reg_area.address = (void*)&holding_reg_params.holding_data0; // Set pointer to storage instance
+    reg_area.size = sizeof(float) << 2; // Set the size of register storage instance
+    err = mbc_slave_set_descriptor(reg_area);
+    ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
+                                    SLAVE_TAG,
+                                    "mbc_slave_set_descriptor fail, returns(0x%x).",
+                                    (uint32_t)err);
+
+    reg_area.type = MB_PARAM_HOLDING; // Set type of register area
+    reg_area.start_offset = MB_REG_HOLDING_START_AREA1; // Offset of register area in Modbus protocol
+    reg_area.address = (void*)&holding_reg_params.holding_data4; // Set pointer to storage instance
+    reg_area.size = sizeof(float) << 2; // Set the size of register storage instance
+    err = mbc_slave_set_descriptor(reg_area);
+    ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
+                                    SLAVE_TAG,
+                                    "mbc_slave_set_descriptor fail, returns(0x%x).",
+                                    (uint32_t)err);
+
+    // Initialization of Input Registers area
+    reg_area.type = MB_PARAM_INPUT;
+    reg_area.start_offset = MB_REG_INPUT_START_AREA0;
+    reg_area.address = (void*)&input_reg_params.input_data0;
+    reg_area.size = sizeof(float) << 2;
+    err = mbc_slave_set_descriptor(reg_area);
+    ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
+                                        SLAVE_TAG,
+                                        "mbc_slave_set_descriptor fail, returns(0x%x).",
+                                        (uint32_t)err);
+    reg_area.type = MB_PARAM_INPUT;
+    reg_area.start_offset = MB_REG_INPUT_START_AREA1;
+    reg_area.address = (void*)&input_reg_params.input_data4;
+    reg_area.size = sizeof(float) << 2;
+    err = mbc_slave_set_descriptor(reg_area);
+    ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
+                                        SLAVE_TAG,
+                                        "mbc_slave_set_descriptor fail, returns(0x%x).",
+                                        (uint32_t)err);
+
+    // Initialization of Coils register area
+    reg_area.type = MB_PARAM_COIL;
+    reg_area.start_offset = MB_REG_COILS_START;
+    reg_area.address = (void*)&coil_reg_params;
+    reg_area.size = sizeof(coil_reg_params);
+    err = mbc_slave_set_descriptor(reg_area);
+    ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
+                                    SLAVE_TAG,
+                                    "mbc_slave_set_descriptor fail, returns(0x%x).",
+                                    (uint32_t)err);
+
+    // Initialization of Discrete Inputs register area
+    reg_area.type = MB_PARAM_DISCRETE;
+    reg_area.start_offset = MB_REG_DISCRETE_INPUT_START;
+    reg_area.address = (void*)&discrete_reg_params;
+    reg_area.size = sizeof(discrete_reg_params);
+    err = mbc_slave_set_descriptor(reg_area);
+    ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
+                                    SLAVE_TAG,
+                                    "mbc_slave_set_descriptor fail, returns(0x%x).",
+                                    (uint32_t)err);
+
+    // Set values into known state
+    setup_reg_data();
+
+    // Starts of modbus controller and stack
+    err = mbc_slave_start();
+    ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
+                                        SLAVE_TAG,
+                                        "mbc_slave_start fail, returns(0x%x).",
+                                        (uint32_t)err);
+    vTaskDelay(5);
+    return err;
+}
+
+static esp_err_t slave_destroy(void)
+{
+    esp_err_t err = mbc_slave_destroy();
+    ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
+                                SLAVE_TAG,
+                                "mbc_slave_destroy fail, returns(0x%x).",
+                                (uint32_t)err);
+    return err;
+}
+
+// An example application of Modbus slave. It is based on freemodbus stack.
+// See deviceparams.h file for more information about assigned Modbus parameters.
+// These parameters can be accessed from main application and also can be changed
+// by external Modbus master host.
+void app_main(void)
+{
+    ESP_ERROR_CHECK(init_services());
+
+    // Set UART log level
+    esp_log_level_set(SLAVE_TAG, ESP_LOG_INFO);
+
+    mb_communication_info_t comm_info = { 0 };
+
+#if !CONFIG_EXAMPLE_CONNECT_IPV6
+    comm_info.ip_addr_type = MB_IPV4;
+#else
+    comm_info.ip_addr_type = MB_IPV6;
 #endif
 #endif
+    comm_info.ip_mode = MB_MODE_TCP;
+
+    comm_info.ip_port = MB_TCP_PORT_NUMBER;
+    ESP_ERROR_CHECK(slave_init(&comm_info));
+
+    // The Modbus slave logic is located in this function (user handling of Modbus)
+    slave_operation_func(NULL);
+
+    ESP_ERROR_CHECK(slave_destroy());
+    ESP_ERROR_CHECK(destroy_services());
 }
 }