diff --git a/App/app_runtime.h b/App/app_runtime.h index b1198de..91511c3 100644 --- a/App/app_runtime.h +++ b/App/app_runtime.h @@ -28,6 +28,14 @@ extern volatile int32_t g_netif_set_up_err; extern volatile int32_t g_netif_init_ok; void app_start_network_tasks(void); +void app_request_network_task_stop(void); +void app_clear_network_task_stop(void); +BaseType_t app_network_task_stop_requested(void); +BaseType_t app_network_tasks_are_stopped(void); +void app_on_network_task_exit(TaskHandle_t task_handle); +void app_request_network_restart(void); +void app_clear_network_restart_request(void); +BaseType_t app_network_restart_requested(void); #ifdef __cplusplus } diff --git a/App/tcp_client.c b/App/tcp_client.c index 24085de..db1c34b 100644 --- a/App/tcp_client.c +++ b/App/tcp_client.c @@ -14,7 +14,31 @@ #include "ethernetif.h" #include "route_msg.h" -#define TCP_CLIENT_CONNECT_TIMEOUT_MS 5000 +#define TCP_CLIENT_CONNECT_TIMEOUT_MS 500 +#define TCP_CLIENT_STOP_POLL_MS 50u + +static BaseType_t tcp_client_stop_requested(void) +{ + return (app_network_task_stop_requested() != pdFALSE) ? pdTRUE : pdFALSE; +} + +static BaseType_t tcp_client_delay_with_stop(uint32_t delay_ms) +{ + uint32_t remaining_ms = delay_ms; + + while (remaining_ms > 0u) { + uint32_t slice_ms = (remaining_ms > TCP_CLIENT_STOP_POLL_MS) ? TCP_CLIENT_STOP_POLL_MS : remaining_ms; + + if (tcp_client_stop_requested() != pdFALSE) { + return pdFALSE; + } + + vTaskDelay(pdMS_TO_TICKS(slice_ms)); + remaining_ms -= slice_ms; + } + + return (tcp_client_stop_requested() == pdFALSE) ? pdTRUE : pdFALSE; +} static void tcp_client_abort_and_delete(struct netconn *conn, uint8_t link_index) { @@ -53,6 +77,10 @@ static err_t tcp_client_worker(struct netconn *conn, uint8_t link_index) netconn_set_recvtimeout(conn, 10); for (;;) { + if (tcp_client_stop_requested() != pdFALSE) { + return ERR_CLSD; + } + err = netconn_recv(conn, &buf); if (err == ERR_OK) { do { @@ -76,11 +104,19 @@ static err_t tcp_client_worker(struct netconn *conn, uint8_t link_index) } } while (netbuf_next(buf) >= 0); netbuf_delete(buf); - } else if (err != ERR_TIMEOUT) { + } else if (err == ERR_TIMEOUT) { + if (tcp_client_stop_requested() != pdFALSE) { + return ERR_CLSD; + } + } else { return err; } while (xQueueReceive(xLinkTxQueues[link_index], &tx_msg, 0) == pdPASS) { + if (tcp_client_stop_requested() != pdFALSE) { + route_msg_free(tx_msg); + return ERR_CLSD; + } err = netconn_write(conn, tx_msg->data, tx_msg->len, NETCONN_COPY); route_msg_free(tx_msg); if (err != ERR_OK) { @@ -104,13 +140,25 @@ static void tcp_client_task(uint8_t link_index) first_connect_deferred = (link_index == CONFIG_LINK_C1) ? 1u : 0u; for (;;) { + if (tcp_client_stop_requested() != pdFALSE) { + break; + } + while ((g_netif_ready == pdFALSE) || (ethernetif_link_is_up() == 0u)) { + if (tcp_client_stop_requested() != pdFALSE) { + goto exit_task; + } vTaskDelay(pdMS_TO_TICKS(100)); } cfg = config_get(); if (cfg->links[link_index].enabled == 0u) { - vTaskDelay(pdMS_TO_TICKS(500)); + if (tcp_client_stop_requested() != pdFALSE) { + break; + } + if (tcp_client_delay_with_stop(500u) == pdFALSE) { + break; + } continue; } @@ -119,13 +167,17 @@ static void tcp_client_task(uint8_t link_index) if (first_connect_deferred != 0u) { first_connect_deferred = 0u; debug_log_write("[CLI] C1 first-connect defer\r\n"); - vTaskDelay(pdMS_TO_TICKS(delay_ms)); + if (tcp_client_delay_with_stop(delay_ms) == pdFALSE) { + break; + } continue; } conn = netconn_new(NETCONN_TCP); if (conn == NULL) { - vTaskDelay(pdMS_TO_TICKS(delay_ms)); + if (tcp_client_delay_with_stop(delay_ms) == pdFALSE) { + break; + } continue; } @@ -137,7 +189,9 @@ static void tcp_client_task(uint8_t link_index) (int)err, (unsigned int)cfg->links[link_index].local_port); netconn_delete(conn); - vTaskDelay(pdMS_TO_TICKS(delay_ms)); + if (tcp_client_delay_with_stop(delay_ms) == pdFALSE) { + break; + } continue; } } @@ -176,8 +230,18 @@ static void tcp_client_task(uint8_t link_index) } tcp_client_abort_and_delete(conn, link_index); - vTaskDelay(pdMS_TO_TICKS(delay_ms)); + if (tcp_client_stop_requested() != pdFALSE) { + break; + } + if (tcp_client_delay_with_stop(delay_ms) == pdFALSE) { + break; + } } + +exit_task: + netconn_thread_cleanup(); + app_on_network_task_exit(xTaskGetCurrentTaskHandle()); + vTaskDelete(NULL); } void TcpCliTask_C1(void *argument) diff --git a/App/tcp_server.c b/App/tcp_server.c index 9a09340..a66ea8f 100644 --- a/App/tcp_server.c +++ b/App/tcp_server.c @@ -11,6 +11,32 @@ #include "debug_log.h" #include "route_msg.h" +#define TCP_SERVER_ACCEPT_TIMEOUT_MS 100 +#define TCP_SERVER_STOP_POLL_MS 50u + +static BaseType_t tcp_server_stop_requested(void) +{ + return (app_network_task_stop_requested() != pdFALSE) ? pdTRUE : pdFALSE; +} + +static BaseType_t tcp_server_delay_with_stop(uint32_t delay_ms) +{ + uint32_t remaining_ms = delay_ms; + + while (remaining_ms > 0u) { + uint32_t slice_ms = (remaining_ms > TCP_SERVER_STOP_POLL_MS) ? TCP_SERVER_STOP_POLL_MS : remaining_ms; + + if (tcp_server_stop_requested() != pdFALSE) { + return pdFALSE; + } + + vTaskDelay(pdMS_TO_TICKS(slice_ms)); + remaining_ms -= slice_ms; + } + + return (tcp_server_stop_requested() == pdFALSE) ? pdTRUE : pdFALSE; +} + static err_t tcp_server_worker(struct netconn *conn, uint8_t link_index) { struct netbuf *buf; @@ -24,6 +50,10 @@ static err_t tcp_server_worker(struct netconn *conn, uint8_t link_index) netconn_set_recvtimeout(conn, 10); for (;;) { + if (tcp_server_stop_requested() != pdFALSE) { + return ERR_CLSD; + } + err = netconn_recv(conn, &buf); if (err == ERR_OK) { do { @@ -47,11 +77,19 @@ static err_t tcp_server_worker(struct netconn *conn, uint8_t link_index) } } while (netbuf_next(buf) >= 0); netbuf_delete(buf); - } else if (err != ERR_TIMEOUT) { + } else if (err == ERR_TIMEOUT) { + if (tcp_server_stop_requested() != pdFALSE) { + return ERR_CLSD; + } + } else { break; } while (xQueueReceive(xLinkTxQueues[link_index], &tx_msg, 0) == pdPASS) { + if (tcp_server_stop_requested() != pdFALSE) { + route_msg_free(tx_msg); + return ERR_CLSD; + } err = netconn_write(conn, tx_msg->data, tx_msg->len, NETCONN_COPY); route_msg_free(tx_msg); if (err != ERR_OK) { @@ -72,31 +110,49 @@ static void tcp_server_task(uint8_t link_index) netconn_thread_init(); for (;;) { + if (tcp_server_stop_requested() != pdFALSE) { + break; + } + while (g_netif_ready == pdFALSE) { + if (tcp_server_stop_requested() != pdFALSE) { + goto exit_task; + } vTaskDelay(pdMS_TO_TICKS(100)); } cfg = config_get(); if (cfg->links[link_index].enabled == 0u) { - vTaskDelay(pdMS_TO_TICKS(500)); + if (tcp_server_stop_requested() != pdFALSE) { + break; + } + if (tcp_server_delay_with_stop(500u) == pdFALSE) { + break; + } continue; } listener = netconn_new(NETCONN_TCP); if (listener == NULL) { - vTaskDelay(pdMS_TO_TICKS(500)); + if (tcp_server_delay_with_stop(500u) == pdFALSE) { + break; + } continue; } + netconn_set_recvtimeout(listener, TCP_SERVER_ACCEPT_TIMEOUT_MS); + if (netconn_bind(listener, IP_ADDR_ANY, cfg->links[link_index].local_port) != ERR_OK || netconn_listen(listener) != ERR_OK) { netconn_delete(listener); - vTaskDelay(pdMS_TO_TICKS(500)); + if (tcp_server_delay_with_stop(500u) == pdFALSE) { + break; + } continue; } for (;;) { - if (cfg->links[link_index].enabled == 0u) { + if (tcp_server_stop_requested() != pdFALSE || cfg->links[link_index].enabled == 0u) { break; } if (netconn_accept(listener, &newconn) == ERR_OK) { @@ -109,6 +165,11 @@ static void tcp_server_task(uint8_t link_index) netconn_close(listener); netconn_delete(listener); } + +exit_task: + netconn_thread_cleanup(); + app_on_network_task_exit(xTaskGetCurrentTaskHandle()); + vTaskDelete(NULL); } void TcpSrvTask_S1(void *argument) diff --git a/Core/Src/freertos.c b/Core/Src/freertos.c index ecf7d65..6f2b653 100644 --- a/Core/Src/freertos.c +++ b/Core/Src/freertos.c @@ -37,6 +37,8 @@ static TaskHandle_t xTcpCliTaskC1Handle = NULL; static TaskHandle_t xTcpCliTaskC2Handle = NULL; static TaskHandle_t xDefaultTaskHandle = NULL; static BaseType_t xNetworkTasksStarted = pdFALSE; +static volatile BaseType_t xNetworkTaskStopRequested = pdFALSE; +static volatile BaseType_t xNetworkRestartRequested = pdFALSE; void app_start_network_tasks(void) { @@ -49,6 +51,11 @@ void app_start_network_tasks(void) return; } + if (xNetworkTaskStopRequested != pdFALSE) { + debug_log_write("[NET] start-network-tasks stop-pending\r\n"); + return; + } + cfg = config_get(); debug_log_printf("[NET] start-network-tasks enter free=%lu min=%lu\r\n", @@ -107,6 +114,68 @@ void app_start_network_tasks(void) #endif } +void app_request_network_task_stop(void) +{ + xNetworkTaskStopRequested = pdTRUE; +} + +void app_clear_network_task_stop(void) +{ + xNetworkTaskStopRequested = pdFALSE; +} + +BaseType_t app_network_task_stop_requested(void) +{ + return xNetworkTaskStopRequested; +} + +BaseType_t app_network_tasks_are_stopped(void) +{ + return (xTcpSrvTaskS1Handle == NULL && + xTcpSrvTaskS2Handle == NULL && + xTcpCliTaskC1Handle == NULL && + xTcpCliTaskC2Handle == NULL) ? pdTRUE : pdFALSE; +} + +void app_on_network_task_exit(TaskHandle_t task_handle) +{ + taskENTER_CRITICAL(); + + if (task_handle == xTcpSrvTaskS1Handle) { + xTcpSrvTaskS1Handle = NULL; + } else if (task_handle == xTcpSrvTaskS2Handle) { + xTcpSrvTaskS2Handle = NULL; + } else if (task_handle == xTcpCliTaskC1Handle) { + xTcpCliTaskC1Handle = NULL; + } else if (task_handle == xTcpCliTaskC2Handle) { + xTcpCliTaskC2Handle = NULL; + } + + if (xTcpSrvTaskS1Handle == NULL && + xTcpSrvTaskS2Handle == NULL && + xTcpCliTaskC1Handle == NULL && + xTcpCliTaskC2Handle == NULL) { + xNetworkTasksStarted = pdFALSE; + } + + taskEXIT_CRITICAL(); +} + +void app_request_network_restart(void) +{ + xNetworkRestartRequested = pdTRUE; +} + +void app_clear_network_restart_request(void) +{ + xNetworkRestartRequested = pdFALSE; +} + +BaseType_t app_network_restart_requested(void) +{ + return xNetworkRestartRequested; +} + static void StartDefaultTask(void *argument) { BaseType_t iwdg_ready = pdFALSE;