/* USER CODE BEGIN Header */ /** ****************************************************************************** * File Name : freertos.c * Description : Code for freertos applications ****************************************************************************** * @attention * * Copyright (c) 2026 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "FreeRTOS.h" #include "task.h" #include "main.h" #include "cmsis_os.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "semphr.h" #include "stream_buffer.h" /* Application modules */ #include "tcp_server.h" #include "tcp_client.h" #include "uart_trans.h" #include "config.h" #include "ethernetif.h" /* LwIP includes */ #include "lwip/tcpip.h" #include "lwip/ip4_addr.h" #include "lwip/dhcp.h" #include "lwip/timeouts.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ /* Task stack sizes (words, not bytes) */ #define LWIP_TASK_STACK_SIZE 512 #define TCP_SERVER_TASK_STACK_SIZE 384 #define TCP_CLIENT_TASK_STACK_SIZE 384 #define UART_TRANS_TASK_STACK_SIZE 256 #define CONFIG_TASK_STACK_SIZE 384 #define DEFAULT_TASK_STACK_SIZE 128 /* Task priorities */ #define LWIP_TASK_PRIORITY (osPriorityAboveNormal) #define TCP_SERVER_TASK_PRIORITY (osPriorityNormal) #define TCP_CLIENT_TASK_PRIORITY (osPriorityNormal) #define UART_TRANS_TASK_PRIORITY (osPriorityNormal) #define CONFIG_TASK_PRIORITY (osPriorityBelowNormal) #define DEFAULT_TASK_PRIORITY (osPriorityLow) /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN Variables */ /* Task handles */ TaskHandle_t lwipTaskHandle = NULL; TaskHandle_t tcpServerTaskHandle = NULL; TaskHandle_t tcpClientTaskHandle = NULL; TaskHandle_t uartServerTransTaskHandle = NULL; TaskHandle_t uartClientTransTaskHandle = NULL; TaskHandle_t configTaskHandle = NULL; /* SPI mutex for CH390 access */ SemaphoreHandle_t ch390SpiMutex = NULL; /* CH390 interrupt notification semaphore */ SemaphoreHandle_t ch390IntSemaphore = NULL; /* USER CODE END Variables */ /* Definitions for defaultTask */ osThreadId_t defaultTaskHandle; const osThreadAttr_t defaultTask_attributes = { .name = "defaultTask", .stack_size = DEFAULT_TASK_STACK_SIZE * 4, .priority = (osPriority_t) DEFAULT_TASK_PRIORITY, }; /* Private function prototypes -----------------------------------------------*/ /* USER CODE BEGIN FunctionPrototypes */ void LwIPTask(void *argument); /* USER CODE END FunctionPrototypes */ void StartDefaultTask(void *argument); void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */ /** * @brief FreeRTOS initialization * @param None * @retval None */ void MX_FREERTOS_Init(void) { /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* USER CODE BEGIN RTOS_MUTEX */ /* Create SPI mutex for CH390 access */ ch390SpiMutex = xSemaphoreCreateMutex(); configASSERT(ch390SpiMutex != NULL); /* USER CODE END RTOS_MUTEX */ /* USER CODE BEGIN RTOS_SEMAPHORES */ /* Create CH390 interrupt notification semaphore */ ch390IntSemaphore = xSemaphoreCreateBinary(); configASSERT(ch390IntSemaphore != NULL); /* USER CODE END RTOS_SEMAPHORES */ /* USER CODE BEGIN RTOS_TIMERS */ /* start timers, add new ones, ... */ /* USER CODE END RTOS_TIMERS */ /* USER CODE BEGIN RTOS_QUEUES */ /* add queues, ... */ /* USER CODE END RTOS_QUEUES */ /* Create the thread(s) */ /* creation of defaultTask */ defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes); /* USER CODE BEGIN RTOS_THREADS */ BaseType_t task_created; /* Create LwIP task (handles network stack + TCP server/client) */ task_created = xTaskCreate(LwIPTask, "LwIP", LWIP_TASK_STACK_SIZE, NULL, tskIDLE_PRIORITY + 3, &lwipTaskHandle); configASSERT(task_created == pdPASS); /* Create TCP Server task */ task_created = xTaskCreate(tcp_server_task, "TCPServer", TCP_SERVER_TASK_STACK_SIZE, NULL, tskIDLE_PRIORITY + 2, &tcpServerTaskHandle); configASSERT(task_created == pdPASS); /* Create TCP Client task */ task_created = xTaskCreate(tcp_client_task, "TCPClient", TCP_CLIENT_TASK_STACK_SIZE, NULL, tskIDLE_PRIORITY + 2, &tcpClientTaskHandle); configASSERT(task_created == pdPASS); /* Create UART Server transparent transmission task */ task_created = xTaskCreate(uart_server_trans_task, "UartSrvTx", UART_TRANS_TASK_STACK_SIZE, NULL, tskIDLE_PRIORITY + 2, &uartServerTransTaskHandle); configASSERT(task_created == pdPASS); /* Create UART Client transparent transmission task */ task_created = xTaskCreate(uart_client_trans_task, "UartCliTx", UART_TRANS_TASK_STACK_SIZE, NULL, tskIDLE_PRIORITY + 2, &uartClientTransTaskHandle); configASSERT(task_created == pdPASS); /* Create Configuration task (AT commands via UART1) */ task_created = xTaskCreate(config_task, "Config", CONFIG_TASK_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, &configTaskHandle); configASSERT(task_created == pdPASS); /* USER CODE END RTOS_THREADS */ /* USER CODE BEGIN RTOS_EVENTS */ /* add events, ... */ /* USER CODE END RTOS_EVENTS */ } /* USER CODE BEGIN Header_StartDefaultTask */ /** * @brief Function implementing the defaultTask thread. * LED blinking for system status indication. * @param argument: Not used * @retval None */ /* USER CODE END Header_StartDefaultTask */ void StartDefaultTask(void *argument) { /* USER CODE BEGIN StartDefaultTask */ (void)argument; /* Infinite loop - LED heartbeat */ for(;;) { /* Toggle LED (PC13, active low) */ HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); /* 500ms toggle = 1Hz blink rate */ osDelay(500); } /* USER CODE END StartDefaultTask */ } /* Private application code --------------------------------------------------*/ /* USER CODE BEGIN Application */ /** * @brief LwIP task - handles network stack initialization and processing */ void LwIPTask(void *argument) { (void)argument; ip4_addr_t ipaddr, netmask, gw; uart_config_t uart_server_cfg; uart_config_t uart_client_cfg; uint8_t use_dhcp = 0; const device_config_t *cfg; /* Wait for configuration to be loaded */ vTaskDelay(pdMS_TO_TICKS(100)); /* Get device configuration */ cfg = config_get(); /* Initialize UART transparent transmission module */ uart_trans_init(); /* Apply UART settings from configuration */ uart_server_cfg.baudrate = UART_DEFAULT_BAUDRATE; uart_server_cfg.data_bits = UART_DEFAULT_DATA_BITS; uart_server_cfg.stop_bits = UART_DEFAULT_STOP_BITS; uart_server_cfg.parity = UART_DEFAULT_PARITY; uart_client_cfg.baudrate = UART_DEFAULT_BAUDRATE; uart_client_cfg.data_bits = UART_DEFAULT_DATA_BITS; uart_client_cfg.stop_bits = UART_DEFAULT_STOP_BITS; uart_client_cfg.parity = UART_DEFAULT_PARITY; if (cfg != NULL) { uart_server_cfg.baudrate = cfg->uart2_baudrate; uart_server_cfg.data_bits = cfg->uart2_databits; uart_server_cfg.stop_bits = cfg->uart2_stopbits; uart_server_cfg.parity = cfg->uart2_parity; uart_client_cfg.baudrate = cfg->uart3_baudrate; uart_client_cfg.data_bits = cfg->uart3_databits; uart_client_cfg.stop_bits = cfg->uart3_stopbits; uart_client_cfg.parity = cfg->uart3_parity; } (void)uart_trans_config(UART_CHANNEL_SERVER, &uart_server_cfg); (void)uart_trans_config(UART_CHANNEL_CLIENT, &uart_client_cfg); /* Wait for TCP tasks to initialize their StreamBuffers */ /* TCP Server and TCP Client tasks call tcp_server_init() / tcp_client_init() */ /* which create the StreamBuffers. We need to wait until they're ready. */ while (tcp_server_get_rx_stream() == NULL || tcp_server_get_tx_stream() == NULL || tcp_client_get_rx_stream() == NULL || tcp_client_get_tx_stream() == NULL) { vTaskDelay(pdMS_TO_TICKS(50)); } /* Connect StreamBuffers between TCP and UART modules */ /* Server: TCP Server RX -> UART2 TX, UART2 RX -> TCP Server TX */ uart_trans_set_streams(UART_CHANNEL_SERVER, tcp_server_get_rx_stream(), /* TCP RX -> UART TX */ tcp_server_get_tx_stream()); /* UART RX -> TCP TX */ /* Client: TCP Client RX -> UART3 TX, UART3 RX -> TCP Client TX */ uart_trans_set_streams(UART_CHANNEL_CLIENT, tcp_client_get_rx_stream(), /* TCP RX -> UART TX */ tcp_client_get_tx_stream()); /* UART RX -> TCP TX */ /* Initialize LwIP stack (calls tcpip_init internally) */ tcpip_init(NULL, NULL); /* Wait for tcpip thread to initialize */ vTaskDelay(pdMS_TO_TICKS(100)); /* Set IP addresses */ if (cfg != NULL && cfg->dhcp_enable != 0) { use_dhcp = 1; IP4_ADDR(&ipaddr, 0, 0, 0, 0); IP4_ADDR(&netmask, 0, 0, 0, 0); IP4_ADDR(&gw, 0, 0, 0, 0); } else if (cfg != NULL) { IP4_ADDR(&ipaddr, cfg->ip[0], cfg->ip[1], cfg->ip[2], cfg->ip[3]); IP4_ADDR(&netmask, cfg->mask[0], cfg->mask[1], cfg->mask[2], cfg->mask[3]); IP4_ADDR(&gw, cfg->gw[0], cfg->gw[1], cfg->gw[2], cfg->gw[3]); } else { /* Default IP if no config */ IP4_ADDR(&ipaddr, 192, 168, 1, 200); IP4_ADDR(&netmask, 255, 255, 255, 0); IP4_ADDR(&gw, 192, 168, 1, 1); } /* Initialize network interface */ lwip_netif_init(&ipaddr, &netmask, &gw); if (use_dhcp) { dhcp_start(&ch390_netif); } /* Main loop - handle network events */ for (;;) { /* Wait for CH390 interrupt or timeout */ if (xSemaphoreTake(ch390IntSemaphore, pdMS_TO_TICKS(10)) == pdTRUE) { /* Process network input - poll all pending packets */ ethernetif_poll(); } /* Check link status periodically */ ethernetif_check_link(); } } /** * @brief Get SPI mutex handle for CH390 driver */ SemaphoreHandle_t get_ch390_spi_mutex(void) { return ch390SpiMutex; } /** * @brief Notify LwIP task of CH390 interrupt (call from ISR) */ void notify_ch390_interrupt_from_isr(void) { BaseType_t xHigherPriorityTaskWoken = pdFALSE; if (ch390IntSemaphore != NULL) { xSemaphoreGiveFromISR(ch390IntSemaphore, &xHigherPriorityTaskWoken); portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } } /** * @brief Get UART Server transparent task handle */ TaskHandle_t get_uart_server_task_handle(void) { return uartServerTransTaskHandle; } /** * @brief Get UART Client transparent task handle */ TaskHandle_t get_uart_client_task_handle(void) { return uartClientTransTaskHandle; } /* USER CODE END Application */