Files

186 lines
5.3 KiB
C

#include "tcp_server.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "lwip/api.h"
#include "lwip/ip_addr.h"
#include "app_runtime.h"
#include "config.h"
#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;
const device_config_t *cfg = config_get();
uint8_t uart_endpoint = config_uart_index_to_endpoint(cfg->links[link_index].uart);
uint8_t src_endpoint = config_link_index_to_endpoint(link_index);
err_t err;
route_msg_t *tx_msg;
route_send_result_t route_result;
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 {
void *data;
uint16_t len;
netbuf_data(buf, &data, &len);
route_result = route_send(xTcpRxQueue,
src_endpoint,
uart_endpoint,
(link_index == CONFIG_LINK_S1) ? ROUTE_CONN_S1 : ROUTE_CONN_S2,
(const uint8_t *)data,
len,
pdMS_TO_TICKS(10));
if (route_result != ROUTE_SEND_OK) {
debug_log_printf("[SRV] idx=%u rx-route-fail rc=%s len=%u\r\n",
(unsigned int)link_index,
route_send_result_to_str(route_result),
(unsigned int)len);
netbuf_delete(buf);
return ERR_CLSD;
}
} while (netbuf_next(buf) >= 0);
netbuf_delete(buf);
} 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) {
return err;
}
}
}
return err;
}
static void tcp_server_task(uint8_t link_index)
{
const device_config_t *cfg;
struct netconn *listener;
struct netconn *newconn;
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) {
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) {
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);
if (tcp_server_delay_with_stop(500u) == pdFALSE) {
break;
}
continue;
}
for (;;) {
if (tcp_server_stop_requested() != pdFALSE || cfg->links[link_index].enabled == 0u) {
break;
}
if (netconn_accept(listener, &newconn) == ERR_OK) {
tcp_server_worker(newconn, link_index);
netconn_close(newconn);
netconn_delete(newconn);
}
}
netconn_close(listener);
netconn_delete(listener);
}
exit_task:
netconn_thread_cleanup();
app_on_network_task_exit(xTaskGetCurrentTaskHandle());
vTaskDelete(NULL);
}
void TcpSrvTask_S1(void *argument)
{
(void)argument;
tcp_server_task(CONFIG_LINK_S1);
}
void TcpSrvTask_S2(void *argument)
{
(void)argument;
tcp_server_task(CONFIG_LINK_S2);
}