--- /dev/null
+cmake_minimum_required(VERSION 3.16)\r
+\r
+# 简单 UART 自测模块\r
+set(COMPONENT_NAME "uarttest")\r
+\r
+set(SOURCES\r
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/uarttest.c\r
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/uarttest_tcp.c\r
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/uarttest_http.c\r
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/uarttest_api_at.c\r
+)\r
+\r
+set(PUBLIC_HEADER\r
+ ${CMAKE_CURRENT_SOURCE_DIR}/include\r
+ ${ROOT_DIR}/open_source/openharmony/third_party/lwip/lwip_v2.1.3/src/include\r
+ ${ROOT_DIR}/open_source/openharmony/third_party/lwip/lwip_adapter/liteos/src/include\r
+ ${ROOT_DIR}/middleware/utils/at/wstp_at/inc\r
+ ${ROOT_DIR}/open_source/openharmony/foundation/ace/ace_engine_lite/modules/netstack/http/include\r
+)\r
+\r
+set(PRIVATE_HEADER\r
+)\r
+\r
+set(PUBLIC_DEFINES\r
+)\r
+\r
+set(PRIVATE_DEFINES\r
+)\r
+\r
+set(COMPONENT_PUBLIC_CCFLAGS\r
+)\r
+\r
+set(COMPONENT_CCFLAGS\r
+ -Wall\r
+ -Wextra\r
+)\r
+\r
+set(WHOLE_LINK\r
+ false\r
+)\r
+\r
+set(MAIN_COMPONENT\r
+ false\r
+)\r
+\r
+build_component()\r
+\r
--- /dev/null
+#ifndef UARTTEST_H\r
+#define UARTTEST_H\r
+\r
+#include "errcode.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+/**\r
+ * @brief 启动 UART 测试线程\r
+ *\r
+ * 线程内部调用 uarttest_loop(),周期性在 SIO UART 上收发数据,\r
+ * 用于验证串口波特率/流控/稳定性。若线程已启动,再次调用无效。\r
+ */\r
+void uarttest_start_thread(void);\r
+\r
+/* TCP 吞吐测试 */\r
+void uarttest_tcp_start(void);\r
+\r
+/* HTTP 测速:通过 AT 指定 URL 下载,不保存文件,仅测速 */\r
+void uarttest_http_start(const char *url);\r
+\r
+/* AT 指令注册:AT^UARTTEST / AT^TCPSPEED / AT^HTTPSPEED */\r
+errcode_t uarttest_at_init(void);\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* UARTTEST_H */\r
+\r
--- /dev/null
+#ifndef UARTTEST_HTTP_H\r
+#define UARTTEST_HTTP_H\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+/**\r
+ * @brief Start HTTP speed test thread.\r
+ * Downloads from url without saving; measures throughput and prints Mbps.\r
+ * If url is NULL or empty, uses default URL (e.g. speedtest.tele2.net/1MB.zip).\r
+ * @param url Full URL (e.g. "http://host/path") or NULL for default.\r
+ */\r
+void uarttest_http_start(const char *url);\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* UARTTEST_HTTP_H */\r
--- /dev/null
+#ifndef UARTTEST_TCP_H\r
+#define UARTTEST_TCP_H\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+/**\r
+ * @brief 启动 TCP 吞吐测试线程(默认作为 client 向模组发送数据)\r
+ *\r
+ * 默认参数:\r
+ * - 目标 IP:172.16.1.2\r
+ * - 目标端口:5001\r
+ * - 发送时长:10s\r
+ * - 单次 send 大小:1460 bytes\r
+ *\r
+ * 线程启动后会周期性打印吞吐(Mbps)。\r
+ */\r
+void uarttest_tcp_start(void);\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* UARTTEST_TCP_H */\r
+\r
--- /dev/null
+#include <stdint.h>\r
+#include <stdbool.h>\r
+#include <string.h>\r
+\r
+#include "uart.h"\r
+#include "uart_porting.h"\r
+#include "cmsis_os2.h"\r
+#include "custom_utils.h" /* 使用 app_task_definition_ext_t / uapi_create_osThread_custom_with_args */\r
+#include "uarttest.h"\r
+\r
+/* 本测试直接使用 UART_BUS_0 + 921600 波特率,避免依赖 lwipopts_default.h 的 SIO 宏 */\r
+#ifndef UARTTEST_BUS\r
+#define UARTTEST_BUS UART_BUS_0\r
+#endif\r
+\r
+#ifndef UARTTEST_BAUD\r
+#define UARTTEST_BAUD 921600U\r
+#endif\r
+\r
+/* 来自 uart_porting.c 的串口打印封装,这里声明后直接使用 */\r
+extern void print_str(const char *str, ...);\r
+\r
+/* 简单延时(粗略 ms 级,依赖于系统 tick) */\r
+static void uarttest_delay_ms(uint32_t ms)\r
+{\r
+ /* 使用 CMSIS-RTOS2 的 osDelay,单位 ms */\r
+ osDelay(ms);\r
+}\r
+\r
+/* 发送一段字符串到测试 UART(默认为 UART_BUS_0) */\r
+static void uarttest_send_string(const char *s)\r
+{\r
+ if (s == NULL) {\r
+ return;\r
+ }\r
+ size_t len = strlen(s);\r
+ if (len == 0) {\r
+ return;\r
+ }\r
+ (void)uapi_uart_write(UARTTEST_BUS, (const uint8_t *)s, (uint16_t)len, 1000);\r
+}\r
+\r
+/* 对当前测试 UART 做一次基础配置(波特率 / 数据位等) */\r
+static void uarttest_config_uart(void)\r
+{\r
+ uart_attr_t attr;\r
+ attr.baud_rate = UARTTEST_BAUD;\r
+ attr.data_bits = UART_DATA_BIT_8;\r
+ attr.parity = UART_PARITY_NONE;\r
+ attr.stop_bits = UART_STOP_BIT_1;\r
+ (void)uapi_uart_set_attr(UARTTEST_BUS, &attr);\r
+}\r
+\r
+/*\r
+ * 简单 UART 自测:\r
+ * 1. 发送一行测试字符串\r
+ * 2. 等待回环/对端回 echo 的数据,并打印收到的内容长度\r
+ *\r
+ * 使用方式:在合适的位置调用 uarttest_run_once() 即可(例如某个命令或测试入口)。\r
+ */\r
+void uarttest_run_once(void)\r
+{\r
+ uint8_t rx_buf[64] = {0};\r
+\r
+ uarttest_config_uart();\r
+\r
+ print_str("\r\n[UARTTEST] start, bus=%d, baud=%u\r\n", (int)UARTTEST_BUS, (unsigned int)UARTTEST_BAUD);\r
+ uarttest_send_string("[UARTTEST] hello from device\r\n");\r
+\r
+ /* 简单等待一会儿,看是否有数据回环回来 */\r
+ uarttest_delay_ms(50);\r
+\r
+ int32_t ret = uapi_uart_read(UARTTEST_BUS, rx_buf, sizeof(rx_buf), 100);\r
+ if (ret > 0) {\r
+ print_str("[UARTTEST] recv %d bytes: ", (int)ret);\r
+ for (int i = 0; i < ret; ++i) {\r
+ print_str("%02X ", rx_buf[i]);\r
+ }\r
+ print_str("\r\n");\r
+ } else {\r
+ print_str("[UARTTEST] no data received (ret=%d)\r\n", (int)ret);\r
+ }\r
+}\r
+\r
+/*\r
+ * 连续收发模式:周期性发送计数值,并尝试读回数据。\r
+ * 可选调用,方便做长时间稳定性测试。\r
+ */\r
+void uarttest_loop(void)\r
+{\r
+ uint32_t counter = 0;\r
+ uint8_t rx_buf[64];\r
+\r
+ uarttest_config_uart();\r
+ print_str("\r\n[UARTTEST] loop mode start, bus=%d, baud=%u\r\n",\r
+ (int)UARTTEST_BUS, (unsigned int)UARTTEST_BAUD);\r
+\r
+ while (1) {\r
+ // char line[64];\r
+ // int len = snprintf(line, sizeof(line), "[UARTTEST] counter=%lu\r\n", (unsigned long)counter++);\r
+ // if (len > 0) {\r
+ // (void)uapi_uart_write(UARTTEST_BUS, (const uint8_t *)line, (uint16_t)len, 100);\r
+ // }\r
+ memset_s(rx_buf,64,1,64);\r
+ int32_t ret = uapi_uart_read(UARTTEST_BUS, rx_buf, sizeof(rx_buf), 10);\r
+ if (ret > 0) {\r
+ printf("[UARTTEST] loop recv %d bytes\r\n", (int)ret);\r
+ printf("%s",rx_buf);\r
+ }\r
+\r
+ uarttest_delay_ms(10);\r
+ }\r
+}\r
+\r
+/* 线程入口:直接跑 uarttest_loop(死循环收发测试) */\r
+static void uarttest_thread(void *argument)\r
+{\r
+ (void)argument;\r
+ uarttest_loop();\r
+}\r
+\r
+static uint32_t g_uarttest_thread_id = 0;\r
+\r
+void uarttest_start_thread(void)\r
+{\r
+ if (g_uarttest_thread_id != 0) {\r
+ print_str("[UARTTEST] thread already started\r\n");\r
+ return;\r
+ }\r
+\r
+ app_task_definition_ext_t task_cfg = {\r
+ .attr = {\r
+ .name = "uarttest",\r
+ .stack_size = 0x2000,\r
+ .priority = osPriorityNormal,\r
+ },\r
+ .func = (osThreadFunc_t)uarttest_thread,\r
+ .task_handle = &g_uarttest_thread_id,\r
+ .create_queue_handle= NULL,\r
+ .use_mem = USE_EXTEND_MEM,\r
+ .inst_args = NULL,\r
+ };\r
+\r
+ if (uapi_create_osThread_custom_with_args(&task_cfg) != ERRCODE_SUCC) {\r
+ print_str("[UARTTEST] failed to create thread\r\n");\r
+ } else {\r
+ print_str("[UARTTEST] thread created\r\n");\r
+ }\r
+}\r
+\r
+\r
--- /dev/null
+#include <stdint.h>\r
+#include <string.h>\r
+#include <stdio.h>\r
+\r
+#include "errcode.h"\r
+#include "at_cmd_api.h"\r
+\r
+#include "uarttest.h"\r
+\r
+#define UARTTEST_UNUSED(a) ((void)(a))\r
+\r
+/* AT^UARTTEST - 启动 uarttest_start_thread() */\r
+static uint32_t uarttest_at_cmd(uint8_t *para, uint32_t para_len, char *str_cmd)\r
+{\r
+ UARTTEST_UNUSED(para);\r
+ UARTTEST_UNUSED(para_len);\r
+ UARTTEST_UNUSED(str_cmd);\r
+\r
+ printf("[UARTTEST][AT] start uart thread\r\n");\r
+ uarttest_start_thread();\r
+ return ERRCODE_SUCC;\r
+}\r
+\r
+/* AT^TCPSPEED - 启动 uarttest_tcp_start() */\r
+static uint32_t uarttest_tcpspeed_at_cmd(uint8_t *para, uint32_t para_len, char *str_cmd)\r
+{\r
+ UARTTEST_UNUSED(para);\r
+ UARTTEST_UNUSED(para_len);\r
+ UARTTEST_UNUSED(str_cmd);\r
+\r
+ printf("[UARTTEST][AT] start tcp speed test\r\n");\r
+ uarttest_tcp_start();\r
+ return ERRCODE_SUCC;\r
+}\r
+\r
+/* AT^HTTPSPEED 或 AT^HTTPSPEED=<url> - 启动 HTTP 测速(不保存文件) */\r
+#define UARTTEST_HTTP_URL_BUF_MAX 256\r
+static uint32_t uarttest_httpspeed_at_cmd(uint8_t *para, uint32_t para_len, char *str_cmd)\r
+{\r
+ UARTTEST_UNUSED(str_cmd);\r
+\r
+ static char url_buf[UARTTEST_HTTP_URL_BUF_MAX];\r
+ url_buf[0] = '\0';\r
+ if (para != NULL && para_len > 0) {\r
+ uint32_t copy_len = para_len;\r
+ if (copy_len >= UARTTEST_HTTP_URL_BUF_MAX) {\r
+ copy_len = UARTTEST_HTTP_URL_BUF_MAX - 1;\r
+ }\r
+ memcpy(url_buf, para, copy_len);\r
+ url_buf[copy_len] = '\0';\r
+ printf("[UARTTEST][AT] start http speed test, url=%.*s\r\n", (int)copy_len, para);\r
+ uarttest_http_start(url_buf);\r
+ } else {\r
+ printf("[UARTTEST][AT] start http speed test (default url)\r\n");\r
+ uarttest_http_start(NULL);\r
+ }\r
+ return ERRCODE_SUCC;\r
+}\r
+\r
+static at_cmd_table_t g_uarttest_at_table[] = {\r
+ { "AT^UARTTEST", uarttest_at_cmd, NULL },\r
+ { "AT^TCPSPEED", uarttest_tcpspeed_at_cmd, NULL },\r
+ { "AT^HTTPSPEED", uarttest_httpspeed_at_cmd, NULL },\r
+};\r
+\r
+errcode_t uarttest_at_init(void)\r
+{\r
+ return at_cmd_add_moudle(g_uarttest_at_table, (uint32_t)(sizeof(g_uarttest_at_table) / sizeof(g_uarttest_at_table[0])));\r
+}\r
+\r
--- /dev/null
+\r
+/**\r
+ * @file uarttest_http.c\r
+ * @brief HTTP speed test: download via AT command, measure throughput, do not save file.\r
+ * Uses openharmony httpclient.h (HttpClientConn, HttpClientSend, HttpClientRecvResponse).\r
+ */\r
+\r
+#include <stdint.h>\r
+#include <stdbool.h>\r
+#include <string.h>\r
+#include <stdio.h>\r
+\r
+#include "cmsis_os2.h"\r
+#include "custom_utils.h"\r
+#include "httpclient.h"\r
+\r
+#include "uarttest_http.h"\r
+\r
+#include "pm.h"\r
+\r
+extern void print_str(const char *str, ...);\r
+\r
+#ifndef UARTTEST_HTTP_DEFAULT_URL\r
+#define UARTTEST_HTTP_DEFAULT_URL "http://ambybox-api.test.leiniao.com/ambybox-device-api/file/minimax_tts_7324f8e915f0_1773299663021.mp3"\r
+#endif\r
+\r
+#ifndef UARTTEST_HTTP_HEADER_SIZE\r
+#define UARTTEST_HTTP_HEADER_SIZE 2048\r
+#endif\r
+\r
+#ifndef UARTTEST_HTTP_RESP_BUF_SIZE\r
+#define UARTTEST_HTTP_RESP_BUF_SIZE 4096\r
+#endif\r
+\r
+#ifndef UARTTEST_HTTP_URL_MAX\r
+#define UARTTEST_HTTP_URL_MAX 256\r
+#endif\r
+\r
+static uint32_t g_uarttest_http_thread_id = 0;\r
+static char g_uarttest_http_url[UARTTEST_HTTP_URL_MAX];\r
+\r
+static void uarttest_http_thread(void *argument)\r
+{\r
+ (void)argument;\r
+\r
+ const char *url = g_uarttest_http_url[0] != '\0' ? g_uarttest_http_url : UARTTEST_HTTP_DEFAULT_URL;\r
+\r
+ HttpClient client = {0};\r
+ HttpClientData clientData = {0};\r
+\r
+ HTTPC_RESULT res = HttpClientPrepare(&clientData, UARTTEST_HTTP_HEADER_SIZE, UARTTEST_HTTP_RESP_BUF_SIZE);\r
+ if (res != HTTP_SUCCESS) {\r
+ print_str("[UARTTEST][HTTP] Prepare failed: %d\r\n", (int)res);\r
+ return;\r
+ }\r
+\r
+ res = HttpClientConn(&client, url);\r
+ if (res != HTTP_SUCCESS) {\r
+ print_str("[UARTTEST][HTTP] Conn failed: %d\r\n", (int)res);\r
+ HttpClientUnprepare(&clientData);\r
+ return;\r
+ }\r
+\r
+ res = HttpClientSend(&client, url, HTTP_GET, &clientData);\r
+ if (res != HTTP_SUCCESS && res != HTTP_EAGAIN) {\r
+ print_str("[UARTTEST][HTTP] Send failed: %d\r\n", (int)res);\r
+ HttpClientClse(&client);\r
+ HttpClientUnprepare(&clientData);\r
+ return;\r
+ }\r
+\r
+ uint32_t total_bytes = 0;\r
+ uint32_t start_tick = osKernelGetTickCount();\r
+ uint32_t last_tick = start_tick;\r
+ uint32_t last_total = 0;\r
+\r
+ while (1) {\r
+ HTTPC_RESULT recv_res = HttpClientRecvResponse(&client, &clientData);\r
+\r
+ if (recv_res == HTTP_SUCCESS || recv_res == HTTP_EAGAIN) {\r
+ int chunk = clientData.contentBlockLen > 0 ? clientData.contentBlockLen : clientData.responseBufLen;\r
+ if (chunk > 0) {\r
+ total_bytes += (uint32_t)chunk;\r
+ }\r
+\r
+ uint32_t now = osKernelGetTickCount();\r
+ if (now - last_tick >= 1000) {\r
+ uint32_t dbytes = total_bytes - last_total;\r
+ float mbps = (float)dbytes * 8.0f / 1000000.0f;\r
+ print_str("[UARTTEST][HTTP] rx=%lu bytes, +%lu bytes/s (%.3f Mbps)\r\n",\r
+ (unsigned long)total_bytes, (unsigned long)dbytes, mbps);\r
+ last_total = total_bytes;\r
+ last_tick = now;\r
+ }\r
+\r
+ if (!clientData.isMore) {\r
+ break;\r
+ }\r
+ } else {\r
+ print_str("[UARTTEST][HTTP] RecvResponse: %d\r\n", (int)recv_res);\r
+ break;\r
+ }\r
+ osDelay(1);\r
+ }\r
+\r
+ uint32_t elapsed_ms = osKernelGetTickCount() - start_tick;\r
+ if (elapsed_ms > 0 && total_bytes > 0) {\r
+ float avg_kbps = (float)total_bytes * 8.0f / (float)elapsed_ms;\r
+ print_str("[UARTTEST][HTTP] done: %lu bytes in %lu ms, avg %.2f Kbps\r\n",\r
+ (unsigned long)total_bytes, (unsigned long)elapsed_ms, avg_kbps);\r
+ } else {\r
+ print_str("[UARTTEST][HTTP] done: %lu bytes\r\n", (unsigned long)total_bytes);\r
+ }\r
+\r
+ HttpClientClse(&client);\r
+ HttpClientUnprepare(&clientData);\r
+ g_uarttest_http_thread_id = 0;\r
+ print_str("[UARTTEST][HTTP] closed\r\n");\r
+}\r
+\r
+void uarttest_http_start(const char *url)\r
+{\r
+ if (g_uarttest_http_thread_id != 0) {\r
+ print_str("[UARTTEST][HTTP] thread already running\r\n");\r
+ return;\r
+ }\r
+\r
+ g_uarttest_http_url[0] = '\0';\r
+ if (url != NULL && url[0] != '\0') {\r
+ size_t len = strlen(url);\r
+ if (len >= UARTTEST_HTTP_URL_MAX) {\r
+ len = UARTTEST_HTTP_URL_MAX - 1;\r
+ }\r
+ memcpy(g_uarttest_http_url, url, len);\r
+ g_uarttest_http_url[len] = '\0';\r
+ }\r
+\r
+ app_task_definition_ext_t task_cfg = {\r
+ .attr = {\r
+ .name = "uarttest_http",\r
+ .stack_size = 0x3000,\r
+ .priority = osPriorityNormal,\r
+ },\r
+ .func = (osThreadFunc_t)uarttest_http_thread,\r
+ .task_handle = &g_uarttest_http_thread_id,\r
+ .create_queue_handle = NULL,\r
+ .use_mem = USE_EXTEND_MEM,\r
+ .inst_args = NULL,\r
+ };\r
+\r
+ if (uapi_create_osThread_custom_with_args(&task_cfg) != ERRCODE_SUCC) {\r
+ print_str("[UARTTEST][HTTP] failed to create thread\r\n");\r
+ g_uarttest_http_thread_id = 0;\r
+ } else {\r
+ print_str("[UARTTEST][HTTP] thread created, url=%s\r\n",\r
+ g_uarttest_http_url[0] != '\0' ? g_uarttest_http_url : UARTTEST_HTTP_DEFAULT_URL);\r
+ }\r
+ int ret = uapi_pm_request_mode(PM_ID_SPI, PM_MODE_PERFORMACE);\r
+ printf("uapi_pm_request_mode ret : %X\n",ret);\r
+}\r
--- /dev/null
+#include <stdint.h>\r
+#include <stdbool.h>\r
+#include <string.h>\r
+\r
+#include "cmsis_os2.h"\r
+#include "custom_utils.h"\r
+\r
+#include "lwip/sockets.h"\r
+#include "lwip/inet.h"\r
+#include "lwip/def.h"\r
+#include "lwip/errno.h"\r
+\r
+#include "uarttest_tcp.h"\r
+\r
+extern void print_str(const char *str, ...);\r
+\r
+#ifndef UARTTEST_TCP_SERVER_IP\r
+#define UARTTEST_TCP_SERVER_IP "172.16.1.2"\r
+#endif\r
+\r
+#ifndef UARTTEST_TCP_SERVER_PORT\r
+#define UARTTEST_TCP_SERVER_PORT 5001\r
+#endif\r
+\r
+#ifndef UARTTEST_TCP_SEND_SECONDS\r
+#define UARTTEST_TCP_SEND_SECONDS 10\r
+#endif\r
+\r
+#ifndef UARTTEST_TCP_PAYLOAD_SIZE\r
+#define UARTTEST_TCP_PAYLOAD_SIZE 1460\r
+#endif\r
+\r
+static uint32_t g_uarttest_tcp_thread_id = 0;\r
+\r
+static void uarttest_tcp_thread(void *argument)\r
+{\r
+ (void)argument;\r
+\r
+ int fd = -1;\r
+ struct sockaddr_in addr;\r
+ memset(&addr, 0, sizeof(addr));\r
+ addr.sin_family = AF_INET;\r
+ addr.sin_port = PP_HTONS(UARTTEST_TCP_SERVER_PORT);\r
+ addr.sin_addr.s_addr = inet_addr(UARTTEST_TCP_SERVER_IP);\r
+\r
+ fd = lwip_socket(AF_INET, SOCK_STREAM, 0);\r
+ if (fd < 0) {\r
+ print_str("[UARTTEST][TCP] socket failed\r\n");\r
+ return;\r
+ }\r
+\r
+ print_str("[UARTTEST][TCP] connect %s:%d ...\r\n", UARTTEST_TCP_SERVER_IP, UARTTEST_TCP_SERVER_PORT);\r
+ if (lwip_connect(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) {\r
+ int err = errno;\r
+ print_str("[UARTTEST][TCP] connect failed, errno=%d\r\n", err);\r
+ lwip_close(fd);\r
+ return;\r
+ }\r
+ print_str("[UARTTEST][TCP] connected\r\n");\r
+\r
+ static uint8_t payload[UARTTEST_TCP_PAYLOAD_SIZE];\r
+ for (uint32_t i = 0; i < sizeof(payload); ++i) {\r
+ payload[i] = (uint8_t)(i & 0xFF);\r
+ }\r
+\r
+ uint32_t total = 0;\r
+ uint32_t last_total = 0;\r
+ uint32_t start_tick = osKernelGetTickCount();\r
+ uint32_t last_tick = start_tick;\r
+\r
+ while (1) {\r
+ int ret = lwip_send(fd, payload, sizeof(payload), 0);\r
+ if (ret <= 0) {\r
+ print_str("[UARTTEST][TCP] send ret=%d, stop\r\n", ret);\r
+ break;\r
+ }\r
+ total += (uint32_t)ret;\r
+\r
+ uint32_t now = osKernelGetTickCount();\r
+ if (now - last_tick >= 1000) {\r
+ uint32_t dbytes = total - last_total;\r
+ float mbps = (float)dbytes * 8.0f / 1000000.0f;\r
+ print_str("[UARTTEST][TCP] tx=%lu bytes, +%lu bytes/s (%.3f Mbps)\r\n",\r
+ (unsigned long)total, (unsigned long)dbytes, mbps);\r
+ last_total = total;\r
+ last_tick = now;\r
+ }\r
+\r
+ if (UARTTEST_TCP_SEND_SECONDS > 0) {\r
+ uint32_t elapsed_ms = now - start_tick;\r
+ if (elapsed_ms >= (uint32_t)UARTTEST_TCP_SEND_SECONDS * 1000U) {\r
+ print_str("[UARTTEST][TCP] done %u seconds\r\n", (unsigned)UARTTEST_TCP_SEND_SECONDS);\r
+ break;\r
+ }\r
+ }\r
+ osDelay(1);\r
+ }\r
+\r
+ lwip_close(fd);\r
+ print_str("[UARTTEST][TCP] closed\r\n");\r
+}\r
+\r
+void uarttest_tcp_start(void)\r
+{\r
+ if (g_uarttest_tcp_thread_id != 0) {\r
+ print_str("[UARTTEST][TCP] thread already started\r\n");\r
+ return;\r
+ }\r
+\r
+ app_task_definition_ext_t task_cfg = {\r
+ .attr = {\r
+ .name = "uarttest_tcp",\r
+ .stack_size = 0x3000,\r
+ .priority = osPriorityNormal,\r
+ },\r
+ .func = (osThreadFunc_t)uarttest_tcp_thread,\r
+ .task_handle = &g_uarttest_tcp_thread_id,\r
+ .create_queue_handle = NULL,\r
+ .use_mem = USE_EXTEND_MEM,\r
+ .inst_args = NULL,\r
+ };\r
+\r
+ if (uapi_create_osThread_custom_with_args(&task_cfg) != ERRCODE_SUCC) {\r
+ print_str("[UARTTEST][TCP] failed to create thread\r\n");\r
+ } else {\r
+ print_str("[UARTTEST][TCP] thread created\r\n");\r
+ }\r
+}\r
+\r