From 527fc2faaa29ed0d2386d7230c41ade27892e71a Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E5=AD=99=E6=98=A5=E9=98=B3?= Date: Tue, 14 Oct 2025 09:29:33 +0800 Subject: [PATCH] =?utf8?q?slip=E6=B7=BB=E5=8A=A0=E7=BC=93=E5=AD=98?= =?utf8?q?=E3=80=82=E6=9C=9F=E6=9C=9B=E5=87=8F=E5=B0=91=E4=B8=A2=E5=B8=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- .../brandy/brandy_standard/thread_init.c | 2 +- .../lwip/lwip_adapter/liteos/src/arch/sio.c | 740 +++++++++++++++++- .../lwip/lwip_v2.1.3/src/netif/slipif.c | 50 +- 3 files changed, 778 insertions(+), 14 deletions(-) diff --git a/code/sdk/application/brandy/brandy_standard/thread_init.c b/code/sdk/application/brandy/brandy_standard/thread_init.c index 7b35e12eb..d51d6120e 100644 --- a/code/sdk/application/brandy/brandy_standard/thread_init.c +++ b/code/sdk/application/brandy/brandy_standard/thread_init.c @@ -113,7 +113,7 @@ #define APP_MAIN_STACK_SIZE 0xC00 #define SAVE_FILE_STACK_SIZE 0xC00 #define AUTO_OTA_STACK_SIZE 0xC00 -#define LWIP_MAIN_STACK_SIZE 0xC00 +#define LWIP_MAIN_STACK_SIZE 0xF00 #define TIME_MAX 64 #define USEC_TO_MILLI 1000 diff --git a/code/sdk/open_source/openharmony/third_party/lwip/lwip_adapter/liteos/src/arch/sio.c b/code/sdk/open_source/openharmony/third_party/lwip/lwip_adapter/liteos/src/arch/sio.c index dc23fc6d6..ace61d0af 100644 --- a/code/sdk/open_source/openharmony/third_party/lwip/lwip_adapter/liteos/src/arch/sio.c +++ b/code/sdk/open_source/openharmony/third_party/lwip/lwip_adapter/liteos/src/arch/sio.c @@ -19,9 +19,9 @@ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. @@ -38,6 +38,64 @@ #include "securec.h" #include "errcode.h" #include "hal_uart.h" +#include "osal_task.h" +#include "osal_msgqueue.h" +#include "time/osal_timer.h" +#include "soc_osal.h" +#include "custom_utils.h" +#include "thread_init.h" // 添加:用于app_task_definition_t定义 +#include +#include +#include + +/* 乒乓缓冲区配置 */ +#ifndef SIO_PING_PONG_BUFFER_SIZE +#define SIO_PING_PONG_BUFFER_SIZE 2048 // 每个buffer大小(2KB) +#endif + +#define SIO_PING_PONG_BUFFER_COUNT 3 // 三缓冲模式 +#define SIO_PING_PONG_TIMEOUT_MS 30 // buffer超时时间(30ms) + +/* SIO中断消息队列配置 */ +#define SIO_IRQ_MSG_QUEUE_SIZE 16 // 队列深度 +#define SIO_IRQ_PROCESS_TASK_PRIO 24 // 处理线程优先级 +#define SIO_IRQ_PROCESS_STACK_SIZE 4096 // 处理线程栈大小 + +/* 乒乓缓冲区状态 */ +typedef enum { + SIO_BUFFER_STATE_EMPTY = 0, // 空闲,可以写入 + SIO_BUFFER_STATE_FILLING, // 正在填充中 + SIO_BUFFER_STATE_FULL, // 已满或超时,等待处理 + SIO_BUFFER_STATE_PROCESSING // 正在处理中 +} sio_buffer_state_t; + +/* 乒乓缓冲区结构 */ +typedef struct { + uint8_t *data; // 数据缓冲区(动态分配) + volatile uint32_t write_pos; // 当前写入位置 + volatile sio_buffer_state_t state; // 缓冲区状态 + volatile uint32_t last_write_time; // 最后写入时间戳(ms) + volatile uint32_t first_write_time; // 首次写入时间戳 +} sio_ping_pong_buffer_t; + +/* SIO中断消息结构 */ +typedef struct { + uint8_t buffer_index; // 缓冲区索引 + uint16_t length; // 数据长度 +} sio_irq_msg_t; + +/* SIO统计信息 */ +typedef struct { + uint32_t total_interrupts; // 总中断次数 + uint32_t total_bytes_received; // 接收总字节数 + uint32_t total_bytes_processed; // 处理总字节数 + uint32_t error_count; // 错误次数 + uint32_t buffer_full_count; // buffer满次数 + uint32_t buffer_timeout_count; // buffer超时次数 + uint32_t buffer_switch_count; // buffer切换次数 + uint32_t dropped_both_full; // 两个buffer都满导致丢弃的字节数 + uint32_t cross_buffer_count; // 跨buffer写入次数 +} sio_stats_t; /* SIO UART buffer configuration */ #define SIO_UART_RX_BUFFER_SIZE 256 @@ -76,8 +134,350 @@ static bool g_sio_uart_initialized = false; static uint8_t g_sio_write_buffer[SIO_WRITE_BUFFER_SIZE]; static uint32_t g_sio_write_buffer_pos = 0; +/* 中断使能标志 */ +static volatile bool g_sio_interrupt_enabled = false; + +/* 处理线程相关 */ +static uint32_t g_sio_irq_process_task = 0; +static unsigned long g_sio_irq_msg_queue = 0; +static volatile bool g_sio_irq_task_running = false; + +/* 乒乓缓冲区(动态分配) */ +static sio_ping_pong_buffer_t *g_sio_ping_pong_buffers = NULL; +static volatile uint8_t g_sio_current_buffer_index = 0; + +/* 全局时间戳(由定时器更新) */ +static volatile uint32_t g_sio_timer_timestamp_ms = 0; + +/* 定时器相关 */ +static osal_timer g_sio_timeout_timer; +static volatile bool g_sio_timer_running = false; + +/* 统计信息 */ +static sio_stats_t g_sio_stats = {0}; + +/* 数据处理回调函数指针 - 用于将数据传递给SLIP */ +static void (*g_sio_data_callback)(const uint8_t *data, uint32_t len) = NULL; + +/* 内部函数声明 */ +static uint32_t sio_get_current_time_ms(void); +static errcode_t sio_flush_buffer(uint8_t buffer_index); +static void sio_timeout_timer_callback(unsigned long arg); +static void sio_irq_process_thread(void *arg); +static void sio_uart_rx_interrupt_handler(const void *buffer, uint16_t length, bool error); +static void sio_print_stats(void); + +/* 保留原有的uart_read_data_int_handler声明 */ extern void uart_read_data_int_handler(const void *buffer, uint16_t length, bool error); +/** + * @brief 获取当前时间戳(毫秒) + */ +static uint32_t sio_get_current_time_ms(void) +{ + unsigned long long jiffies = osal_get_jiffies(); + return (uint32_t)osal_jiffies_to_msecs((unsigned int)jiffies); +} + +/** + * @brief SIO中断数据处理线程(乒乓缓冲区模式) + */ +static void sio_irq_process_thread(void *arg) +{ + (void)arg; + sio_irq_msg_t msg; + unsigned int msg_size = sizeof(sio_irq_msg_t); + + printf("[SIO] IRQ process thread started (ping-pong mode)\n"); + + while (g_sio_irq_task_running) { + int ret = osal_msg_queue_read_copy( + g_sio_irq_msg_queue, + &msg, + &msg_size, + OSAL_MSGQ_WAIT_FOREVER + ); + + if (ret != OSAL_SUCCESS || !g_sio_irq_task_running) { + continue; + } + + if (msg.buffer_index >= SIO_PING_PONG_BUFFER_COUNT) { + printf("[SIO] Invalid buffer index: %u\n", msg.buffer_index); + continue; + } + + if (g_sio_ping_pong_buffers == NULL) { + printf("[SIO] Buffer memory not allocated\n"); + continue; + } + + sio_ping_pong_buffer_t *buffer = &g_sio_ping_pong_buffers[msg.buffer_index]; + + if (msg.length == 0 || msg.length > SIO_PING_PONG_BUFFER_SIZE) { + printf("[SIO] Invalid data length: %u\n", msg.length); + buffer->state = SIO_BUFFER_STATE_EMPTY; + buffer->write_pos = 0; + continue; + } + + buffer->state = SIO_BUFFER_STATE_PROCESSING; + + // 如果设置了数据回调,调用它(给SLIP使用) + if (g_sio_data_callback != NULL) { + g_sio_data_callback(buffer->data, msg.length); + } + + g_sio_stats.total_bytes_processed += msg.length; + + // 释放buffer + buffer->state = SIO_BUFFER_STATE_EMPTY; + buffer->write_pos = 0; + buffer->first_write_time = 0; + } + + printf("[SIO] IRQ process thread exited\n"); +} + +/** + * @brief 刷新指定buffer到消息队列 + */ +static errcode_t sio_flush_buffer(uint8_t buffer_index) +{ + if (buffer_index >= SIO_PING_PONG_BUFFER_COUNT || g_sio_ping_pong_buffers == NULL) { + return ERRCODE_FAIL; + } + + sio_ping_pong_buffer_t *buffer = &g_sio_ping_pong_buffers[buffer_index]; + + if (buffer->state != SIO_BUFFER_STATE_FILLING || buffer->write_pos == 0) { + return ERRCODE_SUCC; + } + + buffer->state = SIO_BUFFER_STATE_FULL; + + sio_irq_msg_t msg = { + .buffer_index = buffer_index, + .length = (uint16_t)buffer->write_pos + }; + + int ret = osal_msg_queue_write_copy( + g_sio_irq_msg_queue, + &msg, + sizeof(sio_irq_msg_t), + OSAL_MSGQ_NO_WAIT + ); + + if (ret != OSAL_SUCCESS) { + return ERRCODE_FAIL; + } + + return ERRCODE_SUCC; +} + +/** + * @brief 定时器回调:检查buffer超时并flush,定期打印统计信息 + * @note 定时器上下文,应快速返回 + * @param arg 定时器参数(未使用) + * @warning osal_timer默认是one-shot,必须在回调中手动重启实现周期性执行 + */ +static void sio_timeout_timer_callback(unsigned long arg) +{ + (void)arg; + + // 增加定时器调用计数(用于定期打印统计) + static volatile uint32_t timer_call_count = 0; + timer_call_count++; + + // 每100次(约3秒)打印一次诊断信息 + if ((timer_call_count % 100) == 1) { + printf("[SIO] Timer callback executed %u times, enabled=%d, running=%d\n", + timer_call_count, g_sio_interrupt_enabled, g_sio_timer_running); + } + + // 每333次(约10秒)打印一次完整统计信息 + // 30ms * 333 ≈ 10秒 + if ((timer_call_count % 333) == 0) { + sio_print_stats(); + } + + if (!g_sio_interrupt_enabled || !g_sio_timer_running) { + return; + } + + uint32_t current_time = sio_get_current_time_ms(); + + // ⚠️ 更新全局时间戳(供ISR使用,ISR中不能调用时间函数) + g_sio_timer_timestamp_ms = current_time; + + if (g_sio_ping_pong_buffers == NULL) { + goto restart_timer; + } + + uint8_t current_idx = g_sio_current_buffer_index; + + // ⚠️ 检查所有buffer的超时状态 + // 需求:超时时如果当前buffer未满也要flush,避免数据滞留 + for (uint8_t i = 0; i < SIO_PING_PONG_BUFFER_COUNT; i++) { + uint8_t current_check = g_sio_current_buffer_index; + bool is_current = (i == current_check); + + sio_ping_pong_buffer_t *buffer = &g_sio_ping_pong_buffers[i]; + + if (buffer->state == SIO_BUFFER_STATE_FILLING && buffer->write_pos > 0) { + if (buffer->last_write_time == 0) { + buffer->last_write_time = current_time; + } else { + uint32_t elapsed = current_time - buffer->last_write_time; + + if (elapsed >= SIO_PING_PONG_TIMEOUT_MS) { + if (sio_flush_buffer(i) == ERRCODE_SUCC) { + g_sio_stats.buffer_timeout_count++; + + if (is_current) { + uint8_t next_idx = (i + 1) % SIO_PING_PONG_BUFFER_COUNT; + if (g_sio_ping_pong_buffers[next_idx].state == SIO_BUFFER_STATE_EMPTY) { + g_sio_current_buffer_index = next_idx; + g_sio_stats.buffer_switch_count++; + } + } + } + } + } + } + } + +restart_timer: + // ⚠️ 关键修复:osal_timer是one-shot类型,必须手动重启以实现周期性执行 + if (g_sio_timer_running) { + osal_timer_start(&g_sio_timeout_timer); + } +} + +/** + * @brief UART接收中断回调函数(乒乓缓冲区模式) + */ +static void sio_uart_rx_interrupt_handler(const void *buffer, uint16_t length, bool error) +{ + if (!buffer || length == 0 || length > 200 || g_sio_ping_pong_buffers == NULL) { + g_sio_stats.error_count++; + return; + } + + if (error) { + g_sio_stats.error_count++; + } + + g_sio_stats.total_interrupts++; + g_sio_stats.total_bytes_received += length; + + uint8_t current_idx = g_sio_current_buffer_index; + sio_ping_pong_buffer_t *current_buffer = &g_sio_ping_pong_buffers[current_idx]; + + // 检查当前buffer超时 + if (current_buffer->state == SIO_BUFFER_STATE_FILLING && + current_buffer->write_pos > 0 && + current_buffer->last_write_time != 0) { + uint32_t current_time = g_sio_timer_timestamp_ms; + uint32_t elapsed = current_time - current_buffer->last_write_time; + + if (elapsed >= SIO_PING_PONG_TIMEOUT_MS) { + sio_flush_buffer(current_idx); + g_sio_stats.buffer_timeout_count++; + + uint8_t next_idx = (current_idx + 1) % SIO_PING_PONG_BUFFER_COUNT; + if (g_sio_ping_pong_buffers[next_idx].state == SIO_BUFFER_STATE_EMPTY) { + g_sio_current_buffer_index = next_idx; + g_sio_stats.buffer_switch_count++; + current_idx = next_idx; + current_buffer = &g_sio_ping_pong_buffers[current_idx]; + } + } + } + + // 如果当前buffer不可写,切换 + if (current_buffer->state != SIO_BUFFER_STATE_EMPTY && + current_buffer->state != SIO_BUFFER_STATE_FILLING) { + uint8_t next_idx = (current_idx + 1) % SIO_PING_PONG_BUFFER_COUNT; + if (g_sio_ping_pong_buffers[next_idx].state == SIO_BUFFER_STATE_EMPTY) { + g_sio_current_buffer_index = next_idx; + g_sio_stats.buffer_switch_count++; + current_idx = next_idx; + current_buffer = &g_sio_ping_pong_buffers[current_idx]; + } + } + + // 初始化空buffer + if (current_buffer->state == SIO_BUFFER_STATE_EMPTY) { + current_buffer->state = SIO_BUFFER_STATE_FILLING; + current_buffer->write_pos = 0; + current_buffer->first_write_time = g_sio_timer_timestamp_ms; + } + + uint32_t available = SIO_PING_PONG_BUFFER_SIZE - current_buffer->write_pos; + uint16_t remaining_data = length; + const uint8_t *data_ptr = (const uint8_t *)buffer; + + // 跨buffer写入处理 + if (current_buffer->state == SIO_BUFFER_STATE_FILLING) { + if (remaining_data <= available) { + // 数据完全放得下 + memcpy(current_buffer->data + current_buffer->write_pos, data_ptr, remaining_data); + current_buffer->write_pos += remaining_data; + current_buffer->last_write_time = 0; + + // 检查是否填满 + if (current_buffer->write_pos >= SIO_PING_PONG_BUFFER_SIZE) { + sio_flush_buffer(current_idx); + g_sio_stats.buffer_full_count++; + + uint8_t next_idx = (current_idx + 1) % SIO_PING_PONG_BUFFER_COUNT; + if (g_sio_ping_pong_buffers[next_idx].state == SIO_BUFFER_STATE_EMPTY) { + g_sio_current_buffer_index = next_idx; + g_sio_stats.buffer_switch_count++; + } + } + } else { + // 需要跨buffer写入 + g_sio_stats.cross_buffer_count++; + + // 填满当前buffer + if (available > 0) { + memcpy(current_buffer->data + current_buffer->write_pos, data_ptr, available); + current_buffer->write_pos += available; + data_ptr += available; + remaining_data -= available; + } + + // flush当前buffer + sio_flush_buffer(current_idx); + g_sio_stats.buffer_full_count++; + + // 切换到下一个buffer + uint8_t next_idx = (current_idx + 1) % SIO_PING_PONG_BUFFER_COUNT; + sio_ping_pong_buffer_t *next_buffer = &g_sio_ping_pong_buffers[next_idx]; + + if (next_buffer->state == SIO_BUFFER_STATE_EMPTY && + remaining_data <= SIO_PING_PONG_BUFFER_SIZE) { + g_sio_current_buffer_index = next_idx; + g_sio_stats.buffer_switch_count++; + + next_buffer->state = SIO_BUFFER_STATE_FILLING; + next_buffer->write_pos = 0; + next_buffer->first_write_time = g_sio_timer_timestamp_ms; + + memcpy(next_buffer->data, data_ptr, remaining_data); + next_buffer->write_pos = remaining_data; + next_buffer->last_write_time = 0; + } else { + g_sio_stats.dropped_both_full += remaining_data; + } + } + } else { + g_sio_stats.dropped_both_full += length; + } +} + /** * Initialize SIO UART */ @@ -90,16 +490,16 @@ static errcode_t sio_uart_init(void) } printf(" %s %d\n", __FUNCTION__, __LINE__); - /* Initialize UART */ - // ret = uapi_uart_init(SIO_UART_BUS, (const void*)&g_sio_uart_pin_config, - // (const void*)&g_sio_uart_attr, NULL, (void*)&g_sio_uart_buffer_config); ret = uapi_uart_set_attr(SIO_UART_BUS, (const void*)&g_sio_uart_attr); if (ret != ERRCODE_SUCC) { return ret; } - ret = uapi_uart_register_rx_callback(SIO_UART_BUS, UART_RX_CONDITION_FULL_OR_SUFFICIENT_DATA_OR_IDLE, - SIO_UART_RX_BUFFER_SIZE, uart_read_data_int_handler); + // 使用新的中断处理函数 + ret = uapi_uart_register_rx_callback(SIO_UART_BUS, + UART_RX_CONDITION_FULL_OR_SUFFICIENT_DATA_OR_IDLE, + 8, // 8字节阈值 + sio_uart_rx_interrupt_handler); printf("uapi_uart_register_rx_callback ret=%x\r\n", ret); @@ -108,6 +508,328 @@ static errcode_t sio_uart_init(void) return ERRCODE_SUCC; } +/** + * @brief 启用SIO中断模式(乒乓缓冲区) + */ +errcode_t sio_interrupt_enable(void (*data_callback)(const uint8_t *data, uint32_t len)) +{ + if (g_sio_interrupt_enabled) { + printf("[SIO] Interrupt already enabled\n"); + return ERRCODE_SUCC; + } + + printf("[SIO] Enabling interrupt mode (ping-pong buffer)\n"); + + // 保存数据回调函数 + g_sio_data_callback = data_callback; + + // 1. 动态分配乒乓缓冲区内存 + if (g_sio_ping_pong_buffers != NULL) { + printf("[SIO] WARNING: Memory leak detected!\n"); + free(g_sio_ping_pong_buffers); + g_sio_ping_pong_buffers = NULL; + } + + size_t buffer_struct_size = sizeof(sio_ping_pong_buffer_t) * SIO_PING_PONG_BUFFER_COUNT; + g_sio_ping_pong_buffers = (sio_ping_pong_buffer_t *)malloc(buffer_struct_size); + + if (g_sio_ping_pong_buffers == NULL) { + printf("[SIO] Failed to allocate buffer structures\n"); + return ERRCODE_MALLOC; + } + + // 为每个buffer分配数据区域 + for (uint8_t i = 0; i < SIO_PING_PONG_BUFFER_COUNT; i++) { + g_sio_ping_pong_buffers[i].data = (uint8_t *)malloc(SIO_PING_PONG_BUFFER_SIZE); + if (g_sio_ping_pong_buffers[i].data == NULL) { + printf("[SIO] Failed to allocate buffer[%u] data\n", i); + // 清理已分配的内存 + for (uint8_t j = 0; j < i; j++) { + free(g_sio_ping_pong_buffers[j].data); + } + free(g_sio_ping_pong_buffers); + g_sio_ping_pong_buffers = NULL; + return ERRCODE_MALLOC; + } + g_sio_ping_pong_buffers[i].write_pos = 0; + g_sio_ping_pong_buffers[i].state = SIO_BUFFER_STATE_EMPTY; + g_sio_ping_pong_buffers[i].last_write_time = 0; + g_sio_ping_pong_buffers[i].first_write_time = 0; + memset(g_sio_ping_pong_buffers[i].data, 0, SIO_PING_PONG_BUFFER_SIZE); + } + g_sio_current_buffer_index = 0; + + printf("[SIO] Allocated %d x %d bytes = %.2f KB total\n", + SIO_PING_PONG_BUFFER_COUNT, SIO_PING_PONG_BUFFER_SIZE, + (SIO_PING_PONG_BUFFER_COUNT * SIO_PING_PONG_BUFFER_SIZE) / 1024.0); + + // 2. 创建消息队列 + int ret = osal_msg_queue_create( + "sio_irq_queue", + SIO_IRQ_MSG_QUEUE_SIZE, + &g_sio_irq_msg_queue, + 0, + sizeof(sio_irq_msg_t) + ); + + if (ret != OSAL_SUCCESS) { + printf("[SIO] Failed to create message queue: 0x%x\n", ret); + for (uint8_t i = 0; i < SIO_PING_PONG_BUFFER_COUNT; i++) { + free(g_sio_ping_pong_buffers[i].data); + } + free(g_sio_ping_pong_buffers); + g_sio_ping_pong_buffers = NULL; + return ERRCODE_FAIL; + } + + printf("[SIO] Message queue created (depth=%d)\n", SIO_IRQ_MSG_QUEUE_SIZE); + + // 3. 启动处理线程 + g_sio_irq_task_running = true; + + app_task_definition_t irq_task_cfg = {0}; + irq_task_cfg.attr.name = "sio_irq_proc"; + irq_task_cfg.attr.priority = osPriorityNormal; + irq_task_cfg.attr.stack_size = SIO_IRQ_PROCESS_STACK_SIZE; + irq_task_cfg.func = (osThreadFunc_t)sio_irq_process_thread; + irq_task_cfg.task_handle = &g_sio_irq_process_task; + irq_task_cfg.use_mem = USE_EXTEND_MEM; + irq_task_cfg.create_queue_handle = NULL; + + ret = uapi_create_osThread_custom(&irq_task_cfg); + if (ret != ERRCODE_SUCC) { + printf("[SIO] Failed to create IRQ process thread: 0x%x\n", ret); + osal_msg_queue_delete(g_sio_irq_msg_queue); + g_sio_irq_msg_queue = 0; + g_sio_irq_task_running = false; + for (uint8_t i = 0; i < SIO_PING_PONG_BUFFER_COUNT; i++) { + free(g_sio_ping_pong_buffers[i].data); + } + free(g_sio_ping_pong_buffers); + g_sio_ping_pong_buffers = NULL; + return ERRCODE_FAIL; + } + + printf("[SIO] IRQ process thread created (PSRAM stack)\n"); + + // 4. 启动定时器 + g_sio_timeout_timer.handler = sio_timeout_timer_callback; + g_sio_timeout_timer.data = 0; + g_sio_timeout_timer.interval = SIO_PING_PONG_TIMEOUT_MS; + + ret = osal_timer_init(&g_sio_timeout_timer); + if (ret != OSAL_SUCCESS) { + printf("[SIO] Failed to init timeout timer: 0x%x\n", ret); + g_sio_irq_task_running = false; + osal_msleep(100); + osal_msg_queue_delete(g_sio_irq_msg_queue); + g_sio_irq_msg_queue = 0; + for (uint8_t i = 0; i < SIO_PING_PONG_BUFFER_COUNT; i++) { + free(g_sio_ping_pong_buffers[i].data); + } + free(g_sio_ping_pong_buffers); + g_sio_ping_pong_buffers = NULL; + return ERRCODE_FAIL; + } + + g_sio_timer_running = true; + ret = osal_timer_start(&g_sio_timeout_timer); + if (ret != OSAL_SUCCESS) { + printf("[SIO] Failed to start timeout timer: 0x%x\n", ret); + g_sio_timer_running = false; + g_sio_irq_task_running = false; + osal_timer_destroy(&g_sio_timeout_timer); + osal_msleep(100); + osal_msg_queue_delete(g_sio_irq_msg_queue); + g_sio_irq_msg_queue = 0; + for (uint8_t i = 0; i < SIO_PING_PONG_BUFFER_COUNT; i++) { + free(g_sio_ping_pong_buffers[i].data); + } + free(g_sio_ping_pong_buffers); + g_sio_ping_pong_buffers = NULL; + return ERRCODE_FAIL; + } + + printf("[SIO] Timeout timer started (period=%d ms)\n", SIO_PING_PONG_TIMEOUT_MS); + + g_sio_interrupt_enabled = true; + + printf("[SIO] Interrupt mode enabled successfully!\n"); + printf(" - Buffers: %d x %d KB\n", SIO_PING_PONG_BUFFER_COUNT, SIO_PING_PONG_BUFFER_SIZE / 1024); + printf(" - Timeout: %d ms\n", SIO_PING_PONG_TIMEOUT_MS); + printf(" - Queue: %d slots\n", SIO_IRQ_MSG_QUEUE_SIZE); + + return ERRCODE_SUCC; +} + +/** + * @brief 禁用SIO中断模式 + */ +errcode_t sio_interrupt_disable(void) +{ + if (!g_sio_interrupt_enabled) { + return ERRCODE_SUCC; + } + + printf("[SIO] Disabling interrupt mode\n"); + + // 1. 停止定时器 + if (g_sio_timer_running) { + g_sio_timer_running = false; + osal_timer_stop(&g_sio_timeout_timer); + osal_timer_destroy(&g_sio_timeout_timer); + g_sio_timeout_timer.timer = NULL; + printf("[SIO] Timer stopped\n"); + } + + // 2. 停止处理线程 + g_sio_irq_task_running = false; + + sio_irq_msg_t empty_msg = {0}; + osal_msg_queue_write_copy(g_sio_irq_msg_queue, &empty_msg, + sizeof(sio_irq_msg_t), OSAL_MSGQ_NO_WAIT); + + osal_msleep(200); + + // 3. 删除消息队列 + osal_msg_queue_delete(g_sio_irq_msg_queue); + g_sio_irq_msg_queue = 0; + + // 4. 释放内存 + if (g_sio_ping_pong_buffers != NULL) { + for (uint8_t i = 0; i < SIO_PING_PONG_BUFFER_COUNT; i++) { + if (g_sio_ping_pong_buffers[i].data != NULL) { + free(g_sio_ping_pong_buffers[i].data); + } + } + free(g_sio_ping_pong_buffers); + g_sio_ping_pong_buffers = NULL; + printf("[SIO] Memory freed\n"); + } + + // 5. 清零统计 + memset(&g_sio_stats, 0, sizeof(sio_stats_t)); + + g_sio_interrupt_enabled = false; + g_sio_irq_process_task = 0; + g_sio_data_callback = NULL; + + printf("[SIO] Interrupt mode disabled\n"); + + return ERRCODE_SUCC; +} + +/** + * @brief 打印SIO统计信息(乒乓缓冲区模式) + */ +void sio_print_stats(void) +{ + printf("=== SIO Interrupt Statistics (Ping-Pong Mode) ===\n"); + printf("Interrupt Status: %s\n", g_sio_interrupt_enabled ? "ENABLED" : "DISABLED"); + printf("Ping-Pong Buffers: %d x %d bytes = %d KB total\n", + SIO_PING_PONG_BUFFER_COUNT, SIO_PING_PONG_BUFFER_SIZE, + (SIO_PING_PONG_BUFFER_COUNT * SIO_PING_PONG_BUFFER_SIZE) / 1024); + printf("Timeout: %d ms\n", SIO_PING_PONG_TIMEOUT_MS); + printf("Message Queue: %d slots (%d bytes per message)\n", + SIO_IRQ_MSG_QUEUE_SIZE, sizeof(sio_irq_msg_t)); + printf("\n"); + + // 乒乓缓冲区状态 + printf("Buffer Status:\n"); + if (g_sio_ping_pong_buffers != NULL) { + for (uint8_t i = 0; i < SIO_PING_PONG_BUFFER_COUNT; i++) { + const char *state_str = "UNKNOWN"; + switch (g_sio_ping_pong_buffers[i].state) { + case SIO_BUFFER_STATE_EMPTY: state_str = "EMPTY"; break; + case SIO_BUFFER_STATE_FILLING: state_str = "FILLING"; break; + case SIO_BUFFER_STATE_FULL: state_str = "FULL"; break; + case SIO_BUFFER_STATE_PROCESSING: state_str = "PROCESSING"; break; + } + printf(" Buffer[%u]: %s, %u/%u bytes%s\n", + i, state_str, g_sio_ping_pong_buffers[i].write_pos, SIO_PING_PONG_BUFFER_SIZE, + (i == g_sio_current_buffer_index) ? " (current)" : ""); + } + } else { + printf(" Buffers not allocated\n"); + } + printf("\n"); + + // 乒乓缓冲区统计 + printf("Ping-Pong Buffer Statistics:\n"); + printf(" Buffer Full Count: %u\n", g_sio_stats.buffer_full_count); + printf(" Buffer Timeout Count: %u\n", g_sio_stats.buffer_timeout_count); + printf(" Buffer Switch Count: %u (success)\n", g_sio_stats.buffer_switch_count); + printf(" Cross-Buffer Writes: %u (跨buffer写入)\n", g_sio_stats.cross_buffer_count); + printf(" Dropped (Both Full): %u bytes\n", g_sio_stats.dropped_both_full); + printf("\n"); + + // 中断层统计 + printf("=== Interrupt Layer Statistics ===\n"); + printf("Total UART Interrupts: %u\n", g_sio_stats.total_interrupts); + printf(" - With RX Error: %u\n", g_sio_stats.error_count); + + if (g_sio_stats.total_interrupts > 0) { + uint32_t avg_bytes_per_irq = g_sio_stats.total_bytes_received / + g_sio_stats.total_interrupts; + printf(" Average bytes per interrupt: %u\n", avg_bytes_per_irq); + + // 错误率 + if (g_sio_stats.error_count > 0) { + uint32_t error_rate = (g_sio_stats.error_count * 10000) / + g_sio_stats.total_interrupts; + printf(" Error Rate: %u.%02u%%\n", error_rate / 100, error_rate % 100); + + // 如果错误率 > 1%,发出警告 + if (error_rate > 100) { + printf(" ⚠️ High error rate! Check UART config and cable.\n"); + } + } + } + printf("\n"); + + // 字节统计 + printf("Byte Statistics:\n"); + printf(" Total Bytes Received: %u\n", g_sio_stats.total_bytes_received); + printf(" Total Bytes Processed: %u\n", g_sio_stats.total_bytes_processed); + printf(" Total Bytes Discarded: %u\n", g_sio_stats.dropped_both_full); + printf("\n"); + + // 计算丢包率 + if (g_sio_stats.total_bytes_received > 0) { + uint32_t drop_rate = (g_sio_stats.dropped_both_full * 10000) / + g_sio_stats.total_bytes_received; + printf("Total Drop Rate: %u.%02u%%\n", drop_rate / 100, drop_rate % 100); + + // 两个buffer都满导致的丢失率 + if (g_sio_stats.dropped_both_full > 0) { + uint32_t both_full_rate = (g_sio_stats.dropped_both_full * 10000) / + g_sio_stats.total_bytes_received; + printf("Both Buffers Full Rate: %u.%02u%% ⚠️\n", + both_full_rate / 100, both_full_rate % 100); + printf(" (processing too slow or buffers too small)\n"); + } + + // 处理效率 + if (g_sio_stats.total_bytes_processed > 0) { + uint32_t process_rate = (g_sio_stats.total_bytes_processed * 10000) / + g_sio_stats.total_bytes_received; + printf("Process Success Rate: %u.%02u%%\n", + process_rate / 100, process_rate % 100); + } + } + + printf("=================================================\n"); +} + +/** + * @brief 重置SIO统计信息 + */ +void sio_reset_stats(void) +{ + memset(&g_sio_stats, 0, sizeof(sio_stats_t)); + printf("[SIO] Statistics reset\n"); +} + /** * Opens a serial device for communication. * @@ -281,4 +1003,4 @@ void sio_send_flush(void) (void)result; /* Ignore result in flush operation */ g_sio_write_buffer_pos = 0; /* Reset buffer position */ } -} \ No newline at end of file +} diff --git a/code/sdk/open_source/openharmony/third_party/lwip/lwip_v2.1.3/src/netif/slipif.c b/code/sdk/open_source/openharmony/third_party/lwip/lwip_v2.1.3/src/netif/slipif.c index c96d07790..ebf0ff7be 100644 --- a/code/sdk/open_source/openharmony/third_party/lwip/lwip_v2.1.3/src/netif/slipif.c +++ b/code/sdk/open_source/openharmony/third_party/lwip/lwip_v2.1.3/src/netif/slipif.c @@ -126,17 +126,46 @@ static volatile bool slipif_thread_running = true; /* Global variable to store current netif */ static struct netif *g_current_slipif_netif = NULL; +/* SIO乒乓buffer扩展函数声明 */ +extern errcode_t sio_interrupt_enable(void (*data_callback)(const uint8_t *data, uint32_t len)); +extern errcode_t sio_interrupt_disable(void); /** * @ingroup slipif * Get the current netif from slipif_loop_thread * * @return pointer to the current netif, or NULL if not available */ - static struct netif *slipif_get_current_netif(void) - { - return g_current_slipif_netif; +static struct netif *slipif_get_current_netif(void) +{ + return g_current_slipif_netif; +} + +/** + * @brief SIO数据回调函数 - 从乒乓buffer接收数据并传递给SLIP + */ +static void slipif_sio_data_callback(const uint8_t *data, uint32_t len) +{ + struct netif *netif = slipif_get_current_netif(); + + if (netif == NULL || netif->state == NULL) { + printf("[SLIP] ERROR: netif or netif->state is NULL in SIO callback\n"); + return; } - + +#if SLIP_RX_FROM_ISR + // ISR模式:逐字节加入队列 + for (uint32_t i = 0; i < len; i++) { + slipif_received_byte(netif, data[i]); + } +#else + // 轮询模式:直接处理 + for (uint32_t i = 0; i < len; i++) { + slipif_rxbyte_input(netif, data[i]); + } +#endif +} + + /** * @ingroup slipif * Set the current netif for slipif_loop_thread @@ -567,6 +596,19 @@ slipif_init(struct netif *netif) return ERR_IF; } LWIP_DEBUGF(SLIP_DEBUG, ("slipif_init: sio_open success, sd=%p\n", priv->sd)); + + /* 设置全局netif供SIO回调使用 */ + slipif_set_current_netif(netif); + + /* 启用SIO乒乓buffer中断模式 */ + printf("[SLIP] Enabling SIO ping-pong buffer interrupt mode...\n"); + errcode_t ret_sio = sio_interrupt_enable(slipif_sio_data_callback); + if (ret_sio != ERRCODE_SUCC) { + printf("[SLIP] WARNING: sio_interrupt_enable failed: 0x%x, falling back to polling mode\n", ret_sio); + } else { + printf("[SLIP] SIO ping-pong buffer enabled successfully!\n"); + printf("[SLIP] Data flow: UART ISR -> ping-pong buffer -> SIO callback -> SLIP parser\n"); + } #if SLIP_USE_RX_THREAD /* Create a thread to poll the serial device. */ LWIP_DEBUGF(SLIP_DEBUG, ("slipif_init: creating RX thread with stack=%d, prio=%d\n", -- 2.17.1