/* * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2025-10-20 Administrator the first version * 2025-11-12 Modified Switch to IDLE interrupt mode (no DMA, no ringbuffer) * 2025-11-21 Fixed Enable RX_IDLE mode correctly for RT-Thread 5.1 */ #include #include #include // ← 显式包含,确保 RT_SERIAL_EVENT_RX_IDLE 可见 #include "data_comm.h" #define DBG_TAG "SCCM_link" #define DBG_LVL DBG_LOG #include #define SAMPLE_UART_NAME "uart1" #define RX_LINE_BUF_SIZE 1024 static rt_device_t serial; static struct rt_semaphore rx_sem; // 接收回调 static rt_err_t uart_rx_ind(rt_device_t dev, rt_size_t size) { // 注意:在 RT-Thread 5.x,当使用 INT_RX 时,size 是接收到的字节数 // 但若启用了 RX_IDLE 模式,底层驱动会在 IDLE 时回调,并传入事件 // 安全做法:检查是否为事件(高位标志) // if (size & RT_SERIAL_EVENT_RX_IDLE) { LOG_D("RX IDLE event received"); rt_sem_release(&rx_sem); return RT_EOK; } // 如果是普通数据(size > 0),也可处理,但本例依赖 IDLE 触发 return RT_EOK; } static int read_line_from_uart(char *buf, int maxlen) { char ch; int len = 0; while (len < maxlen - 1) { // 注意:在 INT_RX 模式下,rt_device_read 会从驱动内部 buffer 读取 rt_size_t result = rt_device_read(serial, 0, &ch, 1); if (result <= 0) { break; // 无更多数据 } buf[len++] = ch; if (ch == '\n') { buf[len] = '\0'; return len; } } buf[len] = '\0'; return len; } void uart_thread_entry(void *parameter) { char input[RX_LINE_BUF_SIZE]; int len; rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO); serial = rt_device_find(SAMPLE_UART_NAME); if (!serial) { LOG_E("Cannot find %s", SAMPLE_UART_NAME); return; } // Step 1: 设置串口基本参数(波特率等) struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; config.baud_rate = BAUD_RATE_115200; // 根据需要调整 config.data_bits = DATA_BITS_8; config.stop_bits = STOP_BITS_1; config.parity = PARITY_NONE; config.bufsz = RX_LINE_BUF_SIZE; // 驱动内部接收 buffer 大小 rt_device_control(serial, RT_DEVICE_CTRL_CONFIG, &config); // Step 2: 【关键】启用 RX IDLE 模式 // rt_device_control(serial, RT_DEVICE_CTRL_CONFIG, (void*)RT_SERIAL_RX_IDLE); // Step 3: 打开串口(使用中断接收) rt_err_t result = rt_device_open(serial, RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX); if (result != RT_EOK) { LOG_E("Failed to open %s, error=%d", SAMPLE_UART_NAME, result); return; } // Step 4: 设置回调 rt_device_set_rx_indicate(serial, uart_rx_ind); LOG_I("SCCM thread (IDLE mode) running on %s", SAMPLE_UART_NAME); while (1) { // 等待数据就绪 if (rt_sem_take(&rx_sem, RT_WAITING_FOREVER) == RT_EOK) { // 处理接收到的数据(提取完整行) while ((len = get_line(input, sizeof(input))) > 0) { // 动态分配请求结构体(见之前完整代码) struct proc_request *req = rt_malloc(sizeof(struct proc_request)); if (!req) continue; rt_strncpy(req->input, input, sizeof(req->input)); req->input_len = len; //req->input[len]='\0'; req->sem = rt_malloc(sizeof(struct rt_semaphore)); if (!req->sem) { rt_free(req); continue; } rt_sem_init(req->sem, "uart_resp", 0, RT_IPC_FLAG_FIFO); // 发送到处理线程 if (rt_mq_send(proc_mq, &req, sizeof(req)) == RT_EOK) { // 等待处理完成 if (rt_sem_take(req->sem, RT_WAITING_FOREVER) == RT_EOK) { rt_device_write(serial, 0, req->output, req->output_len); } } // 清理 rt_sem_detach(req->sem); // 或 rt_sem_delete rt_free(req->sem); rt_free(req); } } } } int start_uart_thread(void) { rt_thread_t tid = rt_thread_create("data_uart", uart_thread_entry, RT_NULL, 2048, 25, 10); if (tid != RT_NULL) { rt_thread_startup(tid); LOG_I("Create SCCM_uart thread"); return 0; } else { LOG_E("Failed to create SCCM_uart thread!"); return -1; } }