* 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.
#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 <string.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+/* 乒乓缓冲区配置 */
+#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
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
*/
}
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);
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.
*
(void)result; /* Ignore result in flush operation */
g_sio_write_buffer_pos = 0; /* Reset buffer position */
}
-}
\ No newline at end of file
+}