'LCD_JD9885',
'SUPPORT_LEINIAO',
'SKIP_LN_PROTOCOL_TEST',
+ # 'SUPPORT_PPP_SERVICE_POLLING',
+ 'SUPPORT_PPP_SERVICE_INTERRUPT',
],
#添加自定义应用
'ram_component': [
/** UART_BUS_0, which is used to at cmd and debug print in wstp version,
* and which is used to testustie and debug print in testsuite version
*/
- #if defined(SUPPORT_CAT1_SERVICE)
+ #if defined(SUPPORT_CAT1_SERVICE) || defined(SUPPORT_PPP_SERVICE_POLLING)
{
{
.tx_pin = PIN_NONE,
.rx_pin = PIN_NONE,
.cts_pin = PIN_NONE,
.rts_pin = PIN_NONE
- },
+ },//pin
{
.tx_pin_mode = (pin_mode_t)HAL_PIO_FUNC_MAX,
.rx_pin_mode = (pin_mode_t)HAL_PIO_FUNC_MAX,
.cts_pin_mode = (pin_mode_t)HAL_PIO_FUNC_MAX,
.rts_pin_mode = (pin_mode_t)HAL_PIO_FUNC_MAX
- },
- UART_0_IRQN,
- (osal_irq_handler)irq_uart0_handler,
- NULL,
+ },//pin_mode
+ UART_0_IRQN,//irq_num
+ (osal_irq_handler)irq_uart0_handler,//irq_func
+ NULL,//rx_callback
{
.baud_rate = 115200,
.data_bits = UART_DATA_BIT_8,
.parity = UART_PARITY_NONE,
.stop_bits = UART_STOP_BIT_1,
- },
+ },//line_config
{
.rx_buffer_size = UART_RX_BUFFER_SIZE,
.rx_buffer = g_uart0_rx_buffer,
},
- NULL,
- #if defined(SUPPORT_TEST_COMMON)
- false,
- #else
- true,
- #endif
+ NULL, //uart_mutex
+ false, //support_mutex
},
- #elif defined(SUPPORT_PPP_SERVICE)
+ #elif defined(SUPPORT_PPP_SERVICE_INTERRUPT)
{
{
.tx_pin = S_MGPIO19,
(void)para;
(void)paraLen;
- ppp_print_info("PPP RUNTIME SHOW: Current runtime status:\n");
+ ppp_print_warning("PPP RUNTIME SHOW: Current runtime status:\n");
// 显示当前runtime状态
- ppp_print_info("\n=== Current Runtime Status ===");
- ppp_print_info("Power Status: %s", cat1_api_runtime_get_cat1_powerstat() ? "ON" : "OFF");
- ppp_print_info("Network Status: %s", cat1_api_runtime_get_cat1_networkstat() ? "CONNECTED" : "DISCONNECTED");
+ ppp_print_warning("\n=== Current Runtime Status ===");
+ ppp_print_warning("Power Status: %s", cat1_api_runtime_get_cat1_powerstat() ? "ON" : "OFF");
+ ppp_print_warning("Network Status: %s", cat1_api_runtime_get_cat1_networkstat() ? "CONNECTED" : "DISCONNECTED");
int signal = cat1_api_runtime_get_cat1_signal();
if (signal == 99) {
- ppp_print_info("Signal Strength: No Signal (99)");
+ ppp_print_warning("Signal Strength: No Signal (99)");
} else {
- ppp_print_info("Signal Strength: %d/31 (%s)", signal,
+ ppp_print_warning("Signal Strength: %d/31 (%s)", signal,
signal >= 20 ? "Excellent" :
signal >= 15 ? "Good" :
signal >= 10 ? "Fair" :
signal >= 5 ? "Poor" : "Very Poor");
}
- ppp_print_info("SIM Status: %s", cat1_api_runtime_get_cat1_simstat() ? "NORMAL" : "ERROR");
+ ppp_print_warning("SIM Status: %s", cat1_api_runtime_get_cat1_simstat() ? "NORMAL" : "ERROR");
uint8_t net_type = cat1_api_runtime_get_cat1_networktype();
const char* net_type_str = "Unknown";
case 5: net_type_str = "Registered (Roaming)"; break;
default: net_type_str = "Invalid"; break;
}
- ppp_print_info("Network Type: %d (%s)", net_type, net_type_str);
+ ppp_print_warning("Network Type: %d (%s)", net_type, net_type_str);
char* operator = cat1_api_runtime_get_cat1_operator();
- ppp_print_info("Operator: %s", (operator && strlen(operator) > 0) ? operator : "Unknown");
+ ppp_print_warning("Operator: %s", (operator && strlen(operator) > 0) ? operator : "Unknown");
char* imei = cat1_api_runtime_get_cat1_imei();
- ppp_print_info("IMEI: %s", (imei && strlen(imei) > 0) ? imei : "Unknown");
+ ppp_print_warning("IMEI: %s", (imei && strlen(imei) > 0) ? imei : "Unknown");
char* iccid = cat1_api_runtime_get_cat1_iccid();
- ppp_print_info("ICCID: %s", (iccid && strlen(iccid) > 0) ? iccid : "Unknown");
+ ppp_print_warning("ICCID: %s", (iccid && strlen(iccid) > 0) ? iccid : "Unknown");
char* version = cat1_api_runtime_get_cat1_modemver();
- ppp_print_info("Modem Version: %s", (version && strlen(version) > 0) ? version : "Unknown");
+ ppp_print_warning("Modem Version: %s", (version && strlen(version) > 0) ? version : "Unknown");
- ppp_print_info("===============================");
+ ppp_print_warning("===============================");
// 显示PPP输出统计信息
ppp_lwip_output_stats_t ppp_stats;
if (ppp_lwip_get_output_stats(&ppp_stats) == PPP_ERR_OK) {
- ppp_print_info("\n=== PPP Output Statistics ===");
- ppp_print_info("Total Output Packets: %llu", ppp_stats.total_packets);
- ppp_print_info("Total Output Bytes: %llu", ppp_stats.total_bytes);
- ppp_print_info("LCP Packets: %u", ppp_stats.lcp_packets);
- ppp_print_info("IPCP Packets: %u", ppp_stats.ipcp_packets);
- ppp_print_info("IP Packets: %u", ppp_stats.ip_packets);
- ppp_print_info("Other Protocol Packets: %u", ppp_stats.other_packets);
- ppp_print_info("Failed Sends: %u", ppp_stats.failed_sends);
+ ppp_print_warning("\n=== PPP Output Statistics ===");
+ ppp_print_warning("Total Output Packets: %llu", ppp_stats.total_packets);
+ ppp_print_warning("Total Output Bytes: %llu", ppp_stats.total_bytes);
+ ppp_print_warning("LCP Packets: %u", ppp_stats.lcp_packets);
+ ppp_print_warning("IPCP Packets: %u", ppp_stats.ipcp_packets);
+ ppp_print_warning("IP Packets: %u", ppp_stats.ip_packets);
+ ppp_print_warning("Other Protocol Packets: %u", ppp_stats.other_packets);
+ ppp_print_warning("Failed Sends: %u", ppp_stats.failed_sends);
// 计算PPP输出统计的运行时间和速率
uint32_t current_time = ppp_stats.last_packet_time;
uint32_t ppp_elapsed_sec = ppp_elapsed_ms / 1000;
if (ppp_elapsed_sec > 0) {
- ppp_print_info("PPP Stats Duration: %u seconds", ppp_elapsed_sec);
+ ppp_print_warning("PPP Stats Duration: %u seconds", ppp_elapsed_sec);
}
if (ppp_elapsed_ms > 0 && ppp_stats.total_bytes > 0) {
uint64_t ppp_throughput_bps = (ppp_stats.total_bytes * 1000) / ppp_elapsed_ms;
- ppp_print_info("PPP Output Throughput: %llu bytes/s", ppp_throughput_bps);
+ ppp_print_warning("PPP Output Throughput: %llu bytes/s", ppp_throughput_bps);
float ppp_packet_rate = (float)ppp_stats.total_packets * 1000 / ppp_elapsed_ms;
- ppp_print_info("PPP Output Packet Rate: %.1f packets/s", ppp_packet_rate);
+ ppp_print_warning("PPP Output Packet Rate: %.1f packets/s", ppp_packet_rate);
}
// 计算成功率
uint64_t total_attempts = ppp_stats.total_packets + ppp_stats.failed_sends;
if (total_attempts > 0) {
float success_rate = (float)ppp_stats.total_packets / total_attempts * 100;
- ppp_print_info("PPP Output Success Rate: %.1f%%", success_rate);
+ ppp_print_warning("PPP Output Success Rate: %.1f%%", success_rate);
}
- ppp_print_info("=============================");
+ ppp_print_warning("=============================");
} else {
- ppp_print_info("\n=== PPP Output Statistics ===");
- ppp_print_info("Failed to get PPP output statistics");
- ppp_print_info("=============================");
+ ppp_print_warning("\n=== PPP Output Statistics ===");
+ ppp_print_warning("Failed to get PPP output statistics");
+ ppp_print_warning("=============================");
}
ppp_lwip_print_discard_stats();
+ // 打印中断统计信息
+ ppp_interrupt_print_stats();
+
return ERRCODE_SUCC;
}
#define SIO_UART_IRQ_NUM UART_0_IRQN // UART IRQ引脚
#endif
-#define PPP_UART_BAUDRATE 115200
+#define PPP_UART_BAUDRATE 921600
/* 支持的波特率列表(自适应模式) */
#define PPP_BAUDRATE_AUTO_LIST {9600, 57600, 115200}
/* PPP数据接收线程配置 */
#define PPP_RX_THREAD_STACK_SIZE 4096 // 接收线程栈大小
-#define PPP_RX_THREAD_PRIORITY osPriorityNormal // 接收线程优先级
+#define PPP_RX_THREAD_PRIORITY osPriorityHigh // 接收线程优先级(提高以确保及时读取数据)
+#define PPP_PROCESS_THREAD_PRIORITY osPriorityAboveNormal // 处理线程优先级
/* 调试配置 */
#define PPP_DEBUG_ENABLE 1 // 启用调试输出
-#define PPP_DEBUG_LEVEL PPP_DEBUG_LEVEL_INFO // 默认只显示警告和错误 (1=ERROR, 2=WARN, 3=INFO, 4=DEBUG)
+#define PPP_DEBUG_LEVEL PPP_DEBUG_LEVEL_WARN // 默认只显示警告和错误 (1=ERROR, 2=WARN, 3=INFO, 4=DEBUG)
/*
* 调试级别说明:
// 保存用户配置
memcpy_s(&g_ppp_config, sizeof(ppp_config_t), config, sizeof(ppp_config_t));
- // PPP_DO_SERIAL_TEST 不进行电源初始化, 用于调试串口读取能力测试。
-#if defined(PPP_DO_SERIAL_TEST) && (PPP_DO_SERIAL_TEST == 1)
- PPP_DEBUG_PRINT("PPP_DO_SERIAL_TEST is defined, skip power init\n");
-#else
ppp_api_power_init();
-#endif
+
+ PPP_DEBUG_WARN("Step 3: Initializing UART for AT mode baudrate: %d\n", g_ppp_config.baudrate);
#define PPP_SERIAL_INIT 1 //外接串口调试模组时,串口要设置input防止干扰。
#if PPP_SERIAL_INIT
// 3. UART初始化
- PPP_DEBUG_PRINT("Step 3: Initializing UART for AT mode baudrate: %d\n", g_ppp_config.baudrate);
ppp_serial_config_t serial_config = {
.uart_bus = SIO_UART_BUS,
.irq_num = SIO_UART_IRQ_NUM,
ppp_interrupt_disable();
PPP_DEBUG_INFO("PPP interrupt mode disabled");
- // 打印中断统计信息
- ppp_interrupt_print_stats();
+
#else
// 轮询模式:停止接收线程
PPP_DEBUG_INFO("Stopping PPP receive thread...");
PPP_DEBUG_DEBUG("WAIT_RESPONSE: Attempting UART read #%u...", read_attempts);
uint32_t uart_read_start = (uint32_t)osal_get_jiffies();
- int32_t ret = uapi_uart_read(g_at_ctx.uart_bus,
- g_at_response_buffer + bytes_received,
- g_at_buffer_size - bytes_received - 1,
- UART_READ_TIMEOUT_MS);
+ #if defined(CONFIG_UART_SUPPORT_DMA)
+ uart_write_dma_config_t dma_cfg = {
+ .src_width = 0,//UART_DMA_WIDTH,
+ .dest_width = 0,//UART_DMA_WIDTH,
+ .burst_length = 2,//UART_DMA_BURST_LENGTH,
+ .priority = 0//UART_DMA_PRIORITY
+ };
+ int32_t ret = uapi_uart_read_by_dma(g_at_ctx.uart_bus, g_at_response_buffer + bytes_received,
+ g_at_buffer_size - bytes_received - 1
+ , &dma_cfg);
+
+ #else
+ int32_t ret =uapi_uart_read(g_at_ctx.uart_bus, g_at_response_buffer + bytes_received,
+ g_at_buffer_size - bytes_received - 1,
+ UART_READ_TIMEOUT_MS);
+ #endif
uint32_t uart_read_end = (uint32_t)osal_get_jiffies();
uint32_t uart_read_time = osal_jiffies_to_msecs(uart_read_end - uart_read_start);
} ppp_irq_msg_t;
/* 中断使能标志 */
-static bool g_ppp_interrupt_enabled = false;
+static volatile bool g_ppp_interrupt_enabled = false;
/* 处理线程相关 */
static osal_task *g_ppp_irq_process_task = NULL;
/* 乒乓缓冲区 */
static ppp_ping_pong_buffer_t g_ping_pong_buffers[PPP_PING_PONG_BUFFER_COUNT];
-static volatile uint8_t g_current_buffer_index = 0; // 当前正在填充的buffer索引
+static volatile uint8_t g_current_buffer_index = 0;
+
+/* 全局时间戳(由定时器更新,ISR只读) */
+static volatile uint32_t g_timer_timestamp_ms = 0;
/* 定时器相关 */
static osal_timer g_ppp_timeout_timer;
static ppp_pingpong_stats_t g_pingpong_stats = {0};
+/* UART错误统计信息 */
+typedef struct {
+ uint32_t parity_error_count; // 奇偶校验错误次数
+ uint32_t frame_error_count; // 帧错误次数
+ uint32_t last_parity_error_info[4]; // 最近一次奇偶校验错误信息
+ uint32_t last_frame_error_info[4]; // 最近一次帧错误信息
+} ppp_uart_error_stats_t;
+
+static ppp_uart_error_stats_t g_uart_error_stats = {0};
+
/* 外部函数声明(在ppp_lwip.c中实现) */
extern ppp_pcb* ppp_lwip_get_pcb(void);
extern bool ppp_lwip_is_initialized(void);
static uint32_t ppp_get_current_time_ms(void);
static ppp_error_t ppp_flush_buffer(uint8_t buffer_index);
static void ppp_timeout_timer_callback(unsigned long arg);
+static void ppp_uart_parity_error_callback(uint32_t *err_info, uint32_t len);
+static void ppp_uart_frame_error_callback(uint32_t *err_info, uint32_t len);
/**
* @brief 获取当前时间戳(毫秒)
ppp_irq_msg_t msg;
unsigned int msg_size = sizeof(ppp_irq_msg_t);
- PPP_DEBUG_INFO("PPP IRQ process thread started (ping-pong mode)");
+ // ⚠️ 使用 WARN 级别确保能看到此日志,用于诊断线程是否正常启动
+ PPP_DEBUG_WARN(">>> PPP IRQ process thread STARTED (ping-pong mode) <<<");
+ PPP_DEBUG_INFO("Thread running, waiting for messages from ISR...");
#if defined(PPP_DO_SERIAL_TEST) && (PPP_DO_SERIAL_TEST == 1)
const uint8_t print_data[] = "PPP IRQ process thread started (ping-pong mode)\n";
uapi_uart_write(SIO_UART_BUS, print_data, sizeof(print_data), 100);
* @note 定时器上下文,应快速返回
* @param arg 定时器参数(未使用)
* @warning osal_timer默认是one-shot,必须在回调中手动重启实现周期性执行
+ *
+ * 数据安全设计(避免竞态):
+ * - 定时器职责:只检查和flush **非当前** buffer(避免与ISR竞争)
+ * - ISR 职责:
+ * 1. 在写入前检查当前buffer是否超时(last_write_time == 0),超时则flush+切换
+ * 2. 检查当前buffer状态,如果不可写则切换
+ * 3. 独占 g_current_buffer_index 的修改权
+ * - 分工明确:定时器不操作当前buffer,ISR负责当前buffer的超时处理
+ * - 数据保证:disable时强制flush所有buffer,确保数据不丢失
*/
static void ppp_timeout_timer_callback(unsigned long arg)
{
uint32_t current_time = ppp_get_current_time_ms();
- // 检查所有buffer的超时状态
+ // ⚠️ 更新全局时间戳(供ISR使用,ISR中不能调用时间函数)
+ g_timer_timestamp_ms = current_time;
+
+ uint8_t current_idx = g_current_buffer_index; // 读取一次,避免重复读取
+
+ // 检查非当前buffer的超时状态
+ // ⚠️ 数据安全设计:定时器只处理非当前buffer,避免与ISR竞争
+ // 当前buffer的超时由ISR在写入时主动检查并处理
for (uint8_t i = 0; i < PPP_PING_PONG_BUFFER_COUNT; i++) {
+ // 跳过当前正在写入的buffer(避免与ISR竞争,保证数据安全)
+ if (i == current_idx) {
+ continue;
+ }
+
ppp_ping_pong_buffer_t *buffer = &g_ping_pong_buffers[i];
// 只处理FILLING状态的buffer
if (buffer->state == PPP_BUFFER_STATE_FILLING && buffer->write_pos > 0) {
- uint32_t elapsed = current_time - buffer->last_write_time;
-
- // 超时检查
- if (elapsed >= PPP_PING_PONG_TIMEOUT_MS) {
- // 超时,flush buffer
- PPP_DEBUG_DEBUG("[TIMER] Flushing buffer[%u] due to timeout (%u ms)", i, elapsed);
- if (ppp_flush_buffer(i) == PPP_ERR_OK) {
- g_pingpong_stats.buffer_timeout_count++;
+ // ⚠️ 修复:避免误判超时
+ // last_write_time == 0 表示ISR刚写入数据,需要更新时间戳(不是超时)
+ if (buffer->last_write_time == 0) {
+ // 第一次看到,更新时间戳,不flush
+ buffer->last_write_time = current_time;
+ PPP_DEBUG_DEBUG("[TIMER] Update timestamp for buffer[%u]", i);
+ } else {
+ // 已经有时间戳了,检查是否真的超时
+ uint32_t elapsed = current_time - buffer->last_write_time;
+
+ if (elapsed >= PPP_PING_PONG_TIMEOUT_MS) {
+ // 真正超时,flush buffer
+ PPP_DEBUG_DEBUG("[TIMER] Flushing buffer[%u] due to timeout (%u ms)", i, elapsed);
- // ⚠️ 关键修复:Timer flush后切换buffer(类似ISR中buffer满的逻辑)
- // 只有当前flush的是正在使用的buffer时才切换
- if (i == g_current_buffer_index) {
- uint8_t next_idx = (i + 1) % PPP_PING_PONG_BUFFER_COUNT;
- ppp_ping_pong_buffer_t *next_buffer = &g_ping_pong_buffers[next_idx];
-
- if (next_buffer->state == PPP_BUFFER_STATE_EMPTY) {
- g_current_buffer_index = next_idx;
- g_pingpong_stats.buffer_switch_count++;
- }
- // 如果next_buffer不是EMPTY,保持当前索引,等待其处理完成
+ if (ppp_flush_buffer(i) == PPP_ERR_OK) {
+ g_pingpong_stats.buffer_timeout_count++;
}
}
}
}
}
+/**
+ * @brief UART奇偶校验错误回调函数
+ * @param err_info 错误信息数组
+ * @param len 错误信息数组长度
+ * @note 在中断上下文中执行,必须快速返回
+ */
+static void ppp_uart_parity_error_callback(uint32_t *err_info, uint32_t len)
+{
+ g_uart_error_stats.parity_error_count++;
+
+ // 保存错误信息用于诊断(只保存前4个)
+ if (err_info && len > 0) {
+ uint32_t copy_len = (len > 4) ? 4 : len;
+ for (uint32_t i = 0; i < copy_len; i++) {
+ g_uart_error_stats.last_parity_error_info[i] = err_info[i];
+ }
+ }
+
+ // ⚠️ 中断中禁止打印日志,只统计
+}
+
+/**
+ * @brief UART帧错误回调函数
+ * @param err_info 错误信息数组
+ * @param len 错误信息数组长度
+ * @note 在中断上下文中执行,必须快速返回
+ */
+static void ppp_uart_frame_error_callback(uint32_t *err_info, uint32_t len)
+{
+ g_uart_error_stats.frame_error_count++;
+
+ // 保存错误信息用于诊断(只保存前4个)
+ if (err_info && len > 0) {
+ uint32_t copy_len = (len > 4) ? 4 : len;
+ for (uint32_t i = 0; i < copy_len; i++) {
+ g_uart_error_stats.last_frame_error_info[i] = err_info[i];
+ }
+ }
+
+ // ⚠️ 中断中禁止打印日志,只统计
+}
+
/**
* @brief UART接收中断回调函数(乒乓缓冲区模式)
* @note 中断上下文,必须极快返回
void _ppp_uart_rx_interrupt_handler(const void *buffer, uint16_t length, bool error)
{
// 快速路径:参数校验
- if (error || !buffer || length == 0 || length > 200) { // 单次中断最多200字节
- if (error) {
- g_ppp_interrupt_stats.error_count++;
- }
+ if ( !buffer || length == 0 || length > 200) { // 单次中断最多200字节
+ PPP_DEBUG_ERROR("ppp_uart_rx_interrupt_handler !buffer || length == 0 || length > 200 ");
return;
}
+ if (error) {
+ g_ppp_interrupt_stats.error_count++;
+ }
// 更新统计(用于诊断 - 可以在统计打印中看到)
g_ppp_interrupt_stats.total_interrupts++;
uint8_t current_idx = g_current_buffer_index;
ppp_ping_pong_buffer_t *current_buffer = &g_ping_pong_buffers[current_idx];
+ // ⚠️ 数据安全设计:ISR负责检查当前buffer的超时
+ // 定时器只处理非当前buffer,避免竞态
+ //
+ // 检查逻辑(方案2 + 全局时间戳):
+ // - last_write_time == 0:ISR刚写入,定时器还没更新时间戳(不算超时)
+ // - last_write_time != 0:定时器已更新过时间戳,可以检查是否真的超时
+ // 使用 g_timer_timestamp_ms(定时器每30ms更新一次)
+ if (current_buffer->state == PPP_BUFFER_STATE_FILLING &&
+ current_buffer->write_pos > 0 &&
+ current_buffer->last_write_time != 0) { // ← 只检查已有时间戳的
+ // 使用全局时间戳(ISR中安全,不调用函数)
+ uint32_t current_time = g_timer_timestamp_ms;
+ uint32_t elapsed = current_time - current_buffer->last_write_time;
+
+ if (elapsed >= PPP_PING_PONG_TIMEOUT_MS) {
+ // 当前buffer真的超时了,flush并切换
+ ppp_flush_buffer(current_idx);
+ g_pingpong_stats.buffer_timeout_count++;
+
+ // 切换到下一个buffer
+ uint8_t next_idx = (current_idx + 1) % PPP_PING_PONG_BUFFER_COUNT;
+ ppp_ping_pong_buffer_t *next_buffer = &g_ping_pong_buffers[next_idx];
+
+ if (next_buffer->state == PPP_BUFFER_STATE_EMPTY) {
+ g_current_buffer_index = next_idx;
+ g_pingpong_stats.buffer_switch_count++;
+ current_idx = next_idx;
+ current_buffer = next_buffer;
+ }
+ }
+ }
+
+ // 如果当前buffer不可写(状态不对),尝试切换
+ if (current_buffer->state != PPP_BUFFER_STATE_EMPTY &&
+ current_buffer->state != PPP_BUFFER_STATE_FILLING) {
+ uint8_t next_idx = (current_idx + 1) % PPP_PING_PONG_BUFFER_COUNT;
+ ppp_ping_pong_buffer_t *next_buffer = &g_ping_pong_buffers[next_idx];
+
+ if (next_buffer->state == PPP_BUFFER_STATE_EMPTY) {
+ g_current_buffer_index = next_idx;
+ g_pingpong_stats.buffer_switch_count++;
+ current_idx = next_idx;
+ current_buffer = next_buffer;
+ }
+ }
+
// 尝试写入当前buffer
uint32_t available = PPP_PING_PONG_BUFFER_SIZE - current_buffer->write_pos;
// buffer是空的,初始化为FILLING状态
current_buffer->state = PPP_BUFFER_STATE_FILLING;
current_buffer->write_pos = 0;
+ available = PPP_PING_PONG_BUFFER_SIZE; // 重新计算可用空间
}
if (current_buffer->state == PPP_BUFFER_STATE_FILLING && length <= available) {
// 空间足够,直接写入
memcpy(current_buffer->data + current_buffer->write_pos, buffer, length);
current_buffer->write_pos += length;
- current_buffer->last_write_time = ppp_get_current_time_ms();
+ // ⚠️ 关键修复:移除中断中的时间函数调用(可能导致死机)
+ // current_buffer->last_write_time = ppp_get_current_time_ms();
+ current_buffer->last_write_time = 0; // 由定时器回调更新
// 检查是否满了
if (current_buffer->write_pos >= PPP_PING_PONG_BUFFER_SIZE) {
next_buffer->write_pos = 0;
memcpy(next_buffer->data, buffer, length);
next_buffer->write_pos = length;
- next_buffer->last_write_time = ppp_get_current_time_ms();
+ // ⚠️ 关键修复:移除中断中的时间函数调用(可能导致死机)
+ // next_buffer->last_write_time = ppp_get_current_time_ms();
+ next_buffer->last_write_time = 0; // 由定时器回调更新
} else {
// 两个buffer都不可用,丢弃数据
g_pingpong_stats.dropped_both_full += length;
PPP_DEBUG_INFO("Message queue created (depth=%d, item_size=%d bytes)",
PPP_IRQ_MSG_QUEUE_SIZE, sizeof(ppp_irq_msg_t));
- // 3. 启动处理线程
+ // 3. 启动处理线程(使用 osal_kthread_create_ext 创建时指定优先级)
+ // ⚠️ 关键修复:必须在创建时就指定优先级,否则线程以默认低优先级创建可能永远得不到调度
g_ppp_irq_task_running = true;
+ osal_kthread_init init_cfg = {
+ .handler = (osal_kthread_handler)ppp_irq_process_thread,
+ .data = NULL,
+ .taskname = "ppp_irq_proc",
+ .stacksize = PPP_IRQ_PROCESS_STACK_SIZE,
+ .taskprio = OSAL_TASK_PRIORITY_MIDDLE // 使用中等优先级(6),避免阻塞看门狗
+ };
+
osal_kthread_lock();
- g_ppp_irq_process_task = osal_kthread_create(
- (osal_kthread_handler)ppp_irq_process_thread,
- NULL,
- "ppp_irq_proc",
- PPP_IRQ_PROCESS_STACK_SIZE
- );
+ g_ppp_irq_process_task = osal_kthread_create_ext(&init_cfg);
osal_kthread_unlock();
if (!g_ppp_irq_process_task) {
return PPP_ERR_MEMORY;
}
- PPP_DEBUG_INFO("Process thread created (stack=%d)", PPP_IRQ_PROCESS_STACK_SIZE);
+ PPP_DEBUG_WARN("IRQ process thread created @ %p with MIDDLE priority (6)",
+ g_ppp_irq_process_task);
+ PPP_DEBUG_INFO("Process thread: stack=%d bytes, priority=MIDDLE(6)",
+ PPP_IRQ_PROCESS_STACK_SIZE);
// 4. 启动定时器(30ms周期检查buffer超时)
// 先设置timer的handler、data和interval
PPP_DEBUG_INFO("Registering UART RX callback:");
PPP_DEBUG_INFO(" UART Bus: %d", uart_bus);
PPP_DEBUG_INFO(" Condition: 0x07 (FULL_OR_SUFFICIENT_DATA_OR_IDLE)");
- PPP_DEBUG_INFO(" Threshold: 56 bytes");
+ PPP_DEBUG_INFO(" Threshold: 8 bytes");
PPP_DEBUG_INFO(" Callback: ppp_uart_rx_interrupt_handler @ %p", ppp_uart_rx_interrupt_handler);
- // ⚠️ 关键修复:降低阈值从200到56字节,确保小数据包也能触发中断
- // PPP LCP/IPCP响应通常只有30-50字节,200字节阈值太高会导致无法触发
+ // ⚠️ 阈值说明:
+ // - 参数是直接的字节数(不是编码)
+ // - 8字节阈值确保小数据包能触发(PPP协商包通常30-50字节)
+ // - 配合IDLE条件,即使不满8字节也会在数据停止时触发
ret = uapi_uart_register_rx_callback(
uart_bus,
0x07, // UART_RX_CONDITION_FULL_OR_SUFFICIENT_DATA_OR_IDLE
- 8, // 56字节阈值
+ 8, // 阈值:8字节
ppp_uart_rx_interrupt_handler
);
- PPP_DEBUG_INFO("uapi_uart_register_rx_callback returned: 0x%x (ERRCODE_SUCC=0x%x)",
+ PPP_DEBUG_WARN("uapi_uart_register_rx_callback returned: 0x%x (ERRCODE_SUCC=0x%x)",
ret, ERRCODE_SUCC);
if (ret != ERRCODE_SUCC) {
PPP_DEBUG_INFO("UART RX callback registered successfully!");
+ // 6. 注册UART错误回调(用于详细错误诊断)
+ // 6.1 注册奇偶校验错误回调
+ ret = uapi_uart_register_parity_error_callback(uart_bus, ppp_uart_parity_error_callback);
+ if (ret != ERRCODE_SUCC) {
+ PPP_DEBUG_WARN("Failed to register parity error callback: 0x%x (non-critical)", ret);
+ // 不是关键错误,继续运行
+ } else {
+ PPP_DEBUG_INFO("Parity error callback registered");
+ }
+
+ // 6.2 注册帧错误回调
+ ret = uapi_uart_register_frame_error_callback(uart_bus, ppp_uart_frame_error_callback);
+ if (ret != ERRCODE_SUCC) {
+ PPP_DEBUG_WARN("Failed to register frame error callback: 0x%x (non-critical)", ret);
+ // 不是关键错误,继续运行
+ } else {
+ PPP_DEBUG_INFO("Frame error callback registered");
+ }
+
g_ppp_interrupt_enabled = true;
- PPP_DEBUG_INFO("PPP UART interrupt enabled successfully (ping-pong mode)");
- PPP_DEBUG_INFO(" Ping-pong buffers: %d x %d KB",
+ PPP_DEBUG_WARN("PPP UART interrupt enabled successfully (ping-pong mode)");
+ PPP_DEBUG_WARN(" Ping-pong buffers: %d x %d KB",
PPP_PING_PONG_BUFFER_COUNT, PPP_PING_PONG_BUFFER_SIZE / 1024);
- PPP_DEBUG_INFO(" Timeout: %d ms", PPP_PING_PONG_TIMEOUT_MS);
- PPP_DEBUG_INFO(" Message queue: %d slots (only %d bytes per message)",
+ PPP_DEBUG_WARN(" Timeout: %d ms", PPP_PING_PONG_TIMEOUT_MS);
+ PPP_DEBUG_WARN(" Message queue: %d slots (only %d bytes per message)",
PPP_IRQ_MSG_QUEUE_SIZE, sizeof(ppp_irq_msg_t));
PPP_DEBUG_INFO(" ISR latency: <5μs (memcpy + queue_write, no malloc!)");
PPP_DEBUG_INFO(" Data flow: UART IRQ -> ping-pong buffer -> timer/full flush -> msg_queue -> process_thread -> pppos_input_tcpip");
// osal_msg_queue_delete 不会清零队列句柄,但下次 create 需要它为 0
g_ppp_irq_msg_queue = 0;
- // 5. 清空乒乓缓冲区
+ // 5. ⚠️ 数据安全:在清空前,先flush所有有数据的buffer,确保数据不丢失
+ PPP_DEBUG_INFO("Flushing all buffers before disable...");
+ for (uint8_t i = 0; i < PPP_PING_PONG_BUFFER_COUNT; i++) {
+ if (g_ping_pong_buffers[i].state == PPP_BUFFER_STATE_FILLING &&
+ g_ping_pong_buffers[i].write_pos > 0) {
+ PPP_DEBUG_INFO(" Flushing buffer[%u]: %u bytes",
+ i, g_ping_pong_buffers[i].write_pos);
+ ppp_flush_buffer(i);
+ // 给处理线程一点时间处理最后的数据
+ osal_msleep(50);
+ }
+ }
+
+ // 6. 清空乒乓缓冲区
for (uint8_t i = 0; i < PPP_PING_PONG_BUFFER_COUNT; i++) {
g_ping_pong_buffers[i].write_pos = 0;
g_ping_pong_buffers[i].state = PPP_BUFFER_STATE_EMPTY;
}
g_current_buffer_index = 0;
+ // 7. 清零统计信息(为下次启用准备)
+ memset(&g_ppp_interrupt_stats, 0, sizeof(ppp_interrupt_stats_t));
+ memset(&g_pingpong_stats, 0, sizeof(ppp_pingpong_stats_t));
+ memset(&g_uart_error_stats, 0, sizeof(ppp_uart_error_stats_t));
+
g_ppp_interrupt_enabled = false;
g_ppp_irq_process_task = NULL;
{
memset(&g_ppp_interrupt_stats, 0, sizeof(ppp_interrupt_stats_t));
memset(&g_pingpong_stats, 0, sizeof(ppp_pingpong_stats_t));
- PPP_DEBUG_INFO("PPP interrupt statistics reset (including ping-pong stats)");
+ memset(&g_uart_error_stats, 0, sizeof(ppp_uart_error_stats_t));
+ PPP_DEBUG_INFO("PPP interrupt statistics reset (including ping-pong and UART error stats)");
}
/**
*/
void ppp_interrupt_print_stats(void)
{
- PPP_DEBUG_INFO("=== PPP Interrupt Statistics (Ping-Pong Mode) ===");
- PPP_DEBUG_INFO("Interrupt Status: %s", g_ppp_interrupt_enabled ? "ENABLED" : "DISABLED");
- PPP_DEBUG_INFO("Ping-Pong Buffers: %d x %d bytes = %d KB total",
+ PPP_DEBUG_WARN("=== PPP Interrupt Statistics (Ping-Pong Mode) ===");
+ PPP_DEBUG_WARN("Interrupt Status: %s", g_ppp_interrupt_enabled ? "ENABLED" : "DISABLED");
+ PPP_DEBUG_WARN("Ping-Pong Buffers: %d x %d bytes = %d KB total",
PPP_PING_PONG_BUFFER_COUNT, PPP_PING_PONG_BUFFER_SIZE,
(PPP_PING_PONG_BUFFER_COUNT * PPP_PING_PONG_BUFFER_SIZE) / 1024);
- PPP_DEBUG_INFO("Timeout: %d ms", PPP_PING_PONG_TIMEOUT_MS);
- PPP_DEBUG_INFO("Message Queue: %d slots (%d bytes per message)",
+ PPP_DEBUG_WARN("Timeout: %d ms", PPP_PING_PONG_TIMEOUT_MS);
+ PPP_DEBUG_WARN("Message Queue: %d slots (%d bytes per message)",
PPP_IRQ_MSG_QUEUE_SIZE, sizeof(ppp_irq_msg_t));
- PPP_DEBUG_INFO("");
+ PPP_DEBUG_WARN("");
// 乒乓缓冲区状态
- PPP_DEBUG_INFO("Buffer Status:");
+ PPP_DEBUG_WARN("Buffer Status:");
for (uint8_t i = 0; i < PPP_PING_PONG_BUFFER_COUNT; i++) {
const char *state_str = "UNKNOWN";
switch (g_ping_pong_buffers[i].state) {
case PPP_BUFFER_STATE_FULL: state_str = "FULL"; break;
case PPP_BUFFER_STATE_PROCESSING: state_str = "PROCESSING"; break;
}
- PPP_DEBUG_INFO(" Buffer[%u]: %s, %u/%u bytes%s",
+ PPP_DEBUG_WARN(" Buffer[%u]: %s, %u/%u bytes%s",
i, state_str, g_ping_pong_buffers[i].write_pos, PPP_PING_PONG_BUFFER_SIZE,
(i == g_current_buffer_index) ? " (current)" : "");
}
- PPP_DEBUG_INFO("");
+ PPP_DEBUG_WARN("");
// 乒乓缓冲区统计
- PPP_DEBUG_INFO("Ping-Pong Buffer Statistics:");
- PPP_DEBUG_INFO(" Buffer Full Count: %u", g_pingpong_stats.buffer_full_count);
- PPP_DEBUG_INFO(" Buffer Timeout Count: %u", g_pingpong_stats.buffer_timeout_count);
- PPP_DEBUG_INFO(" Buffer Switch Count: %u", g_pingpong_stats.buffer_switch_count);
- PPP_DEBUG_INFO(" Dropped (Both Full): %u bytes ⚠️", g_pingpong_stats.dropped_both_full);
- PPP_DEBUG_INFO("");
-
- // 中断统计
- PPP_DEBUG_INFO("Total Interrupts: %u", g_ppp_interrupt_stats.total_interrupts);
- PPP_DEBUG_INFO(" - Success: %u", g_ppp_interrupt_stats.success_count);
- PPP_DEBUG_INFO(" - Error: %u", g_ppp_interrupt_stats.error_count);
- PPP_DEBUG_INFO(" - lwIP Error: %u", g_ppp_interrupt_stats.lwip_error_count);
- PPP_DEBUG_INFO("");
-
- // 字节统计
- PPP_DEBUG_INFO("Total Bytes Received: %u", g_ppp_interrupt_stats.total_bytes_received);
- PPP_DEBUG_INFO("Total Bytes Sent to lwIP: %u", g_ppp_interrupt_stats.total_bytes_sent_to_lwip);
- PPP_DEBUG_INFO("");
-
- // 丢弃统计
- PPP_DEBUG_INFO("Dropped Bytes:");
- PPP_DEBUG_INFO(" - Not Initialized: %u", g_ppp_interrupt_stats.dropped_not_initialized);
- PPP_DEBUG_INFO(" - lwIP Error: %u", g_ppp_interrupt_stats.dropped_lwip_error);
- PPP_DEBUG_INFO(" - Queue Full: %u", g_ppp_interrupt_stats.dropped_queue_full);
- PPP_DEBUG_INFO(" - Both Buffers Full: %u ⚠️", g_pingpong_stats.dropped_both_full);
- PPP_DEBUG_INFO("");
+ PPP_DEBUG_WARN("Ping-Pong Buffer Statistics:");
+ PPP_DEBUG_WARN(" Buffer Full Count: %u", g_pingpong_stats.buffer_full_count);
+ PPP_DEBUG_WARN(" Buffer Timeout Count: %u", g_pingpong_stats.buffer_timeout_count);
+ PPP_DEBUG_WARN(" Buffer Switch Count: %u", g_pingpong_stats.buffer_switch_count);
+ PPP_DEBUG_WARN(" Dropped (Both Full): %u bytes ⚠️", g_pingpong_stats.dropped_both_full);
+ PPP_DEBUG_WARN("");
+
+ // 中断层统计
+ PPP_DEBUG_WARN("=== Interrupt Layer Statistics ===");
+ PPP_DEBUG_WARN("Total UART Interrupts: %u", g_ppp_interrupt_stats.total_interrupts);
+ PPP_DEBUG_WARN(" - With RX Error: %u", g_ppp_interrupt_stats.error_count);
+ PPP_DEBUG_WARN(" · Parity Error: %u", g_uart_error_stats.parity_error_count);
+ PPP_DEBUG_WARN(" · Frame Error: %u", g_uart_error_stats.frame_error_count);
+
+ // 如果有错误,显示错误率和详情
+ if (g_ppp_interrupt_stats.total_interrupts > 0) {
+ uint32_t avg_bytes_per_irq = g_ppp_interrupt_stats.total_bytes_received /
+ g_ppp_interrupt_stats.total_interrupts;
+ PPP_DEBUG_WARN(" Average bytes per interrupt: %u", avg_bytes_per_irq);
+
+ // 错误率
+ if (g_ppp_interrupt_stats.error_count > 0) {
+ uint32_t error_rate = (g_ppp_interrupt_stats.error_count * 10000) /
+ g_ppp_interrupt_stats.total_interrupts;
+ PPP_DEBUG_WARN(" Error Rate: %u.%02u%%", error_rate / 100, error_rate % 100);
+
+ // 如果错误率 > 1%,发出警告
+ if (error_rate > 100) {
+ PPP_DEBUG_ERROR(" ⚠️ High error rate! Check UART config and cable.");
+ }
+ }
+ }
+
+ // 如果有奇偶校验错误,打印最近一次的错误信息
+ if (g_uart_error_stats.parity_error_count > 0) {
+ PPP_DEBUG_INFO(" Last Parity Error Info:");
+ for (uint32_t i = 0; i < 4; i++) {
+ if (g_uart_error_stats.last_parity_error_info[i] != 0) {
+ PPP_DEBUG_INFO(" [%u]: 0x%08X", i,
+ g_uart_error_stats.last_parity_error_info[i]);
+ }
+ }
+ }
+
+ // 如果有帧错误,打印最近一次的错误信息
+ if (g_uart_error_stats.frame_error_count > 0) {
+ PPP_DEBUG_INFO(" Last Frame Error Info:");
+ for (uint32_t i = 0; i < 4; i++) {
+ if (g_uart_error_stats.last_frame_error_info[i] != 0) {
+ PPP_DEBUG_INFO(" [%u]: 0x%08X", i,
+ g_uart_error_stats.last_frame_error_info[i]);
+ }
+ }
+ }
+ PPP_DEBUG_WARN("");
+
+ // 消息层统计
+ PPP_DEBUG_WARN("=== Message Layer Statistics ===");
+ PPP_DEBUG_WARN("Total Messages Sent to lwIP: %u", g_ppp_interrupt_stats.success_count);
+ PPP_DEBUG_WARN(" - lwIP Accept Error: %u", g_ppp_interrupt_stats.lwip_error_count);
+ if (g_ppp_interrupt_stats.success_count > 0) {
+ uint32_t avg_bytes = g_ppp_interrupt_stats.total_bytes_sent_to_lwip /
+ g_ppp_interrupt_stats.success_count;
+ PPP_DEBUG_WARN(" Average bytes per message: %u", avg_bytes);
+
+ // 计算中断聚合比例
+ if (g_ppp_interrupt_stats.total_interrupts > 0) {
+ uint32_t irq_per_msg = g_ppp_interrupt_stats.total_interrupts /
+ g_ppp_interrupt_stats.success_count;
+ PPP_DEBUG_WARN(" Interrupts per message: ~%u (aggregation ratio)", irq_per_msg);
+ }
+ }
+ PPP_DEBUG_WARN("");
+
+ // 字节统计(与轮询模式格式一致)
+ uint32_t total_discarded = g_ppp_interrupt_stats.dropped_not_initialized +
+ g_ppp_interrupt_stats.dropped_lwip_error +
+ g_ppp_interrupt_stats.dropped_queue_full +
+ g_pingpong_stats.dropped_both_full;
+
+ PPP_DEBUG_WARN("");
+ PPP_DEBUG_WARN("Byte Statistics:");
+ PPP_DEBUG_WARN(" Total Bytes Received: %u", g_ppp_interrupt_stats.total_bytes_received);
+ PPP_DEBUG_WARN(" Total Bytes Processed: %u", g_ppp_interrupt_stats.total_bytes_sent_to_lwip);
+ PPP_DEBUG_WARN(" Total Bytes Discarded: %u", total_discarded);
+ PPP_DEBUG_WARN(" - Both Buffers Full: %u", g_pingpong_stats.dropped_both_full);
+ PPP_DEBUG_WARN(" - Queue Full: %u", g_ppp_interrupt_stats.dropped_queue_full);
+ PPP_DEBUG_WARN(" lwIP Errors: %u", g_ppp_interrupt_stats.lwip_error_count);
+ PPP_DEBUG_WARN("");
+
+ // 详细丢弃统计(INFO级别)
+ if (total_discarded > 0) {
+ PPP_DEBUG_WARN("Detailed Dropped Bytes:");
+ PPP_DEBUG_WARN(" - Not Initialized: %u", g_ppp_interrupt_stats.dropped_not_initialized);
+ PPP_DEBUG_WARN(" - lwIP Error: %u", g_ppp_interrupt_stats.dropped_lwip_error);
+ PPP_DEBUG_WARN(" - Queue Full: %u", g_ppp_interrupt_stats.dropped_queue_full);
+ PPP_DEBUG_WARN(" - Both Buffers Full: %u", g_pingpong_stats.dropped_both_full);
+ PPP_DEBUG_WARN("");
+ }
// 计算丢包率
if (g_ppp_interrupt_stats.total_bytes_received > 0) {
g_ppp_interrupt_stats.dropped_queue_full +
g_pingpong_stats.dropped_both_full;
uint32_t drop_rate = (total_dropped * 10000) / g_ppp_interrupt_stats.total_bytes_received;
- PPP_DEBUG_INFO("Total Drop Rate: %u.%02u%%", drop_rate / 100, drop_rate % 100);
+ PPP_DEBUG_WARN("Total Drop Rate: %u.%02u%%", drop_rate / 100, drop_rate % 100);
// 队列满导致的丢失率
if (g_ppp_interrupt_stats.dropped_queue_full > 0) {
uint32_t queue_full_rate = (g_ppp_interrupt_stats.dropped_queue_full * 10000) /
g_ppp_interrupt_stats.total_bytes_received;
- PPP_DEBUG_INFO("Queue Full Rate: %u.%02u%%", queue_full_rate / 100, queue_full_rate % 100);
+ PPP_DEBUG_WARN("Queue Full Rate: %u.%02u%%", queue_full_rate / 100, queue_full_rate % 100);
}
// 两个buffer都满导致的丢失率
}
}
- // 性能指标
- if (g_ppp_interrupt_stats.success_count > 0) {
- uint32_t avg_bytes = g_ppp_interrupt_stats.total_bytes_sent_to_lwip /
- g_ppp_interrupt_stats.success_count;
- PPP_DEBUG_INFO("Average bytes per message: %u", avg_bytes);
- }
-
- if (g_ppp_interrupt_stats.total_interrupts > 0) {
- uint32_t avg_bytes_per_irq = g_ppp_interrupt_stats.total_bytes_received /
- g_ppp_interrupt_stats.total_interrupts;
- PPP_DEBUG_INFO("Average bytes per interrupt: %u", avg_bytes_per_irq);
- }
+ // 性能总结(已经在上面各部分显示过了,这里不再重复)
- PPP_DEBUG_INFO("=================================================");
+ PPP_DEBUG_WARN("=================================================");
}
\ No newline at end of file
/**
* @brief 定时器回调:检查buffer超时并flush
+ *
+ * 数据安全设计(避免竞态):
+ * - 定时器职责:只检查和flush **非当前** buffer(避免与接收线程竞争)
+ * - 接收线程职责:
+ * 1. 在循环开始时主动检查当前buffer是否超时,超时则flush+切换
+ * 2. 检查当前buffer状态,如果不可写则切换
+ * 3. 独占 g_current_buffer_index 的修改权
+ * - 分工明确:定时器不操作当前buffer,接收线程负责当前buffer的超时处理
+ * - 数据保证:stop时强制flush所有buffer,确保数据不丢失
*/
static void ppp_timeout_timer_callback(unsigned long arg)
{
}
uint32_t current_time = ppp_get_current_time_ms();
+ uint8_t current_idx = g_current_buffer_index; // 读取一次,避免重复读取
- // 检查所有buffer的超时状态
+ // 检查非当前buffer的超时状态
+ // ⚠️ 数据安全设计:定时器只处理非当前buffer,避免与接收线程竞争
+ // 当前buffer的超时由接收线程主动检查并处理
for (uint8_t i = 0; i < PPP_PING_PONG_BUFFER_COUNT; i++) {
+ // 跳过当前正在写入的buffer(避免与接收线程竞争,保证数据安全)
+ if (i == current_idx) {
+ continue;
+ }
+
ppp_ping_pong_buffer_t *buffer = &g_ping_pong_buffers[i];
// 只处理FILLING状态的buffer
if (buffer->state == PPP_BUFFER_STATE_FILLING && buffer->write_pos > 0) {
- uint32_t elapsed = current_time - buffer->last_write_time;
-
- if (elapsed >= PPP_PING_PONG_TIMEOUT_MS) {
- PPP_DEBUG_DEBUG("[TIMER] Flushing buffer[%u] due to timeout (%u ms)", i, elapsed);
+ // ⚠️ 修复:避免误判超时
+ // last_write_time == 0 表示接收线程刚写入数据,需要更新时间戳(不是超时)
+ if (buffer->last_write_time == 0) {
+ // 第一次看到,更新时间戳,不flush
+ buffer->last_write_time = current_time;
+ PPP_DEBUG_DEBUG("[TIMER] Update timestamp for buffer[%u]", i);
+ } else {
+ // 已经有时间戳了,检查是否真的超时
+ uint32_t elapsed = current_time - buffer->last_write_time;
- if (ppp_flush_buffer(i) == PPP_ERR_OK) {
- g_ppp_stats.buffer_timeout_count++;
+ if (elapsed >= PPP_PING_PONG_TIMEOUT_MS) {
+ // 真正超时,flush buffer
+ PPP_DEBUG_DEBUG("[TIMER] Flushing buffer[%u] due to timeout (%u ms)", i, elapsed);
- // Timer flush后切换buffer
- if (i == g_current_buffer_index) {
- uint8_t next_idx = (i + 1) % PPP_PING_PONG_BUFFER_COUNT;
- ppp_ping_pong_buffer_t *next_buffer = &g_ping_pong_buffers[next_idx];
-
- if (next_buffer->state == PPP_BUFFER_STATE_EMPTY) {
- g_current_buffer_index = next_idx;
- g_ppp_stats.buffer_switch_count++;
- }
+ if (ppp_flush_buffer(i) == PPP_ERR_OK) {
+ g_ppp_stats.buffer_timeout_count++;
}
}
}
/**
* @brief PPP数据接收线程 - 轮询UART并填充到乒乓buffer
+ *
+ * 优化设计:
+ * - 每次读取尝试填满当前 buffer 的剩余空间(高效利用)
+ * - 独占 g_current_buffer_index 的修改权(避免竞态)
+ * - 及时检查 buffer 状态并切换(避免数据丢失)
+ * - 检查超时并主动 flush 当前 buffer(配合定时器)
*/
static void ppp_lwip_receive_thread(void *arg)
{
PPP_DEBUG_INFO("PPP receive thread started (ping-pong polling mode)");
- // å\88\86é\85\8d临æ\97¶è¯»å\8f\96ç¼\93å\86²å\8cºï¼\88æ¯\8f次æ\9c\80å¤\9a读å\8f\96512å\97è\8a\82)
- const uint32_t read_chunk_size = 1;
- uint8_t *rx_buffer = (uint8_t *)malloc(read_chunk_size);
+ // å\88\86é\85\8d临æ\97¶è¯»å\8f\96ç¼\93å\86²å\8cºï¼\88æ\9c\80大读å\8f\96大å°\8f)
+ const uint32_t max_read_size = PPP_PING_PONG_BUFFER_SIZE;
+ uint8_t *rx_buffer = (uint8_t *)malloc(max_read_size);
if (!rx_buffer) {
PPP_DEBUG_ERROR("PPP RX buffer alloc failed");
g_ppp_rx_thread_completed = true;
}
uint32_t total_bytes = 0;
- uint32_t consecutive_empty = 0;
+ uint32_t last_timeout_check = 0;
- PPP_DEBUG_INFO("PPP receive thread: allocated %d bytes temp buffer", read_chunk_size);
+ PPP_DEBUG_INFO("PPP receive thread: allocated %d bytes temp buffer", max_read_size);
// 主循环:连续轮询UART读取
while (g_ppp_rx_thread_running) {
+ // 1. ⚠️ 数据安全:主动检查当前 buffer 是否超时
+ // 定时器只处理非当前buffer,所以当前buffer的超时要在这里处理
+ uint8_t current_idx = g_current_buffer_index;
+ ppp_ping_pong_buffer_t *current_buffer = &g_ping_pong_buffers[current_idx];
+
+ if (current_buffer->state == PPP_BUFFER_STATE_FILLING &&
+ current_buffer->write_pos > 0 &&
+ current_buffer->last_write_time != 0) { // ← 修复:只有已有时间戳的才检查超时
+ uint32_t current_time = ppp_get_current_time_ms();
+ uint32_t elapsed = current_time - current_buffer->last_write_time;
+
+ if (elapsed >= PPP_PING_PONG_TIMEOUT_MS) {
+ // 当前buffer超时,flush并切换
+ PPP_DEBUG_DEBUG("[RX] Flushing current buffer[%u] due to timeout (%u ms)",
+ current_idx, elapsed);
+ ppp_flush_buffer(current_idx);
+ g_ppp_stats.buffer_timeout_count++;
+
+ // 切换到下一个EMPTY的buffer
+ uint8_t next_idx = (current_idx + 1) % PPP_PING_PONG_BUFFER_COUNT;
+ ppp_ping_pong_buffer_t *next_buffer = &g_ping_pong_buffers[next_idx];
+
+ if (next_buffer->state == PPP_BUFFER_STATE_EMPTY) {
+ g_current_buffer_index = next_idx;
+ g_ppp_stats.buffer_switch_count++;
+ current_idx = next_idx;
+ current_buffer = next_buffer;
+ }
+ }
+ }
+
+ // 2. 检查当前 buffer 状态,确保可用
+ // 重新读取(可能在步骤1中已经切换了)
+ current_idx = g_current_buffer_index;
+ current_buffer = &g_ping_pong_buffers[current_idx];
+
+ // 如果当前 buffer 不是 FILLING 状态(可能被定时器 flush 了或正在处理)
+ // 尝试切换到下一个 EMPTY 的 buffer
+ if (current_buffer->state != PPP_BUFFER_STATE_FILLING &&
+ current_buffer->state != PPP_BUFFER_STATE_EMPTY) {
+
+ bool switched = false;
+ for (uint8_t attempts = 0; attempts < PPP_PING_PONG_BUFFER_COUNT; attempts++) {
+ uint8_t next_idx = (current_idx + attempts + 1) % PPP_PING_PONG_BUFFER_COUNT;
+ ppp_ping_pong_buffer_t *next_buffer = &g_ping_pong_buffers[next_idx];
+
+ if (next_buffer->state == PPP_BUFFER_STATE_EMPTY) {
+ g_current_buffer_index = next_idx;
+ g_ppp_stats.buffer_switch_count++;
+ current_idx = next_idx;
+ current_buffer = next_buffer;
+ switched = true;
+ PPP_DEBUG_DEBUG("Switched to buffer[%u] (previous not available)", next_idx);
+ break;
+ }
+ }
+
+ if (!switched) {
+ // 所有 buffer 都不可用,等待一下
+ g_ppp_stats.dropped_both_full++;
+
+ // ⚠️ 打印 buffer 状态,帮助诊断
+ static uint32_t drop_log_counter = 0;
+ if ((drop_log_counter++ % 10) == 0) { // 每 10 次打印一次,避免日志过多
+ PPP_DEBUG_WARN("Both buffers unavailable! Drop event %u", drop_log_counter);
+ for (uint8_t i = 0; i < PPP_PING_PONG_BUFFER_COUNT; i++) {
+ const char *state = "UNKNOWN";
+ switch (g_ping_pong_buffers[i].state) {
+ case PPP_BUFFER_STATE_EMPTY: state = "EMPTY"; break;
+ case PPP_BUFFER_STATE_FILLING: state = "FILLING"; break;
+ case PPP_BUFFER_STATE_FULL: state = "FULL"; break;
+ case PPP_BUFFER_STATE_PROCESSING: state = "PROCESSING"; break;
+ }
+ PPP_DEBUG_WARN(" Buffer[%u]: %s, %u bytes",
+ i, state, g_ping_pong_buffers[i].write_pos);
+ }
+ }
+
+ osal_msleep(1);
+ continue;
+ }
+ }
+
+ // 2. 初始化 buffer(如果需要)
+ if (current_buffer->state == PPP_BUFFER_STATE_EMPTY) {
+ current_buffer->state = PPP_BUFFER_STATE_FILLING;
+ current_buffer->write_pos = 0;
+ current_buffer->last_write_time = ppp_get_current_time_ms();
+ }
+
+ // 3. 计算可读取的大小(尝试填满 buffer)
+ uint32_t available = PPP_PING_PONG_BUFFER_SIZE - current_buffer->write_pos;
+ uint32_t read_size = (available < max_read_size) ? available : max_read_size;
+
+ // 限制单次读取不超过 1024 字节(平衡性能和响应速度)
+ if (read_size > 1024) {
+ read_size = 1024;
+ }
+
+ // 4. 读取数据
uint32_t bytes_read = 0;
- ppp_error_t ret = ppp_serial_tryread(rx_buffer, read_chunk_size, &bytes_read);
+ ppp_error_t ret = ppp_serial_tryread(rx_buffer, read_size, &bytes_read);
if (ret == PPP_ERR_OK && bytes_read > 0) {
// 成功读取数据
total_bytes += bytes_read;
- consecutive_empty = 0;
g_ppp_stats.read_count++;
g_ppp_stats.total_bytes_received += bytes_read;
- PPP_DEBUG_DEBUG("PPP RX: Got %u bytes", bytes_read);
+ PPP_DEBUG_DEBUG("PPP RX: Got %u bytes (buffer[%u]: %u/%u)",
+ bytes_read, current_idx, current_buffer->write_pos,
+ PPP_PING_PONG_BUFFER_SIZE);
- // 填充到乒乓buffer
- uint32_t processed = 0;
- while (processed < bytes_read && g_ppp_rx_thread_running) {
- uint8_t current_idx = g_current_buffer_index;
- ppp_ping_pong_buffer_t *current_buffer = &g_ping_pong_buffers[current_idx];
-
- // 如果buffer是空的,初始化为FILLING状态
- if (current_buffer->state == PPP_BUFFER_STATE_EMPTY) {
- current_buffer->state = PPP_BUFFER_STATE_FILLING;
- current_buffer->write_pos = 0;
- }
-
- // 尝试写入当前buffer
- uint32_t available = PPP_PING_PONG_BUFFER_SIZE - current_buffer->write_pos;
- uint32_t to_write = bytes_read - processed;
+ // 5. 写入当前 buffer
+ memcpy(current_buffer->data + current_buffer->write_pos, rx_buffer, bytes_read);
+ current_buffer->write_pos += bytes_read;
+ current_buffer->last_write_time = ppp_get_current_time_ms();
+
+ // 6. 检查是否满了或接近满了
+ if (current_buffer->write_pos >= PPP_PING_PONG_BUFFER_SIZE) {
+ // buffer 满了,立即 flush 并切换
+ PPP_DEBUG_DEBUG("Buffer[%u] full, flushing...", current_idx);
+ ppp_flush_buffer(current_idx);
+ g_ppp_stats.buffer_full_count++;
- if (current_buffer->state == PPP_BUFFER_STATE_FILLING && to_write <= available) {
- // 空间足够,直接写入
- memcpy(current_buffer->data + current_buffer->write_pos,
- rx_buffer + processed, to_write);
- current_buffer->write_pos += to_write;
- current_buffer->last_write_time = ppp_get_current_time_ms();
- processed += to_write;
-
- // 检查是否满了
- if (current_buffer->write_pos >= PPP_PING_PONG_BUFFER_SIZE) {
- // buffer满,flush
- ppp_flush_buffer(current_idx);
- g_ppp_stats.buffer_full_count++;
-
- // 切换到另一个buffer
- uint8_t next_idx = (current_idx + 1) % PPP_PING_PONG_BUFFER_COUNT;
- ppp_ping_pong_buffer_t *next_buffer = &g_ping_pong_buffers[next_idx];
-
- if (next_buffer->state == PPP_BUFFER_STATE_EMPTY) {
- g_current_buffer_index = next_idx;
- g_ppp_stats.buffer_switch_count++;
- }
- }
- } else {
- // 当前buffer空间不足或不可用,尝试切换
- uint8_t next_idx = (current_idx + 1) % PPP_PING_PONG_BUFFER_COUNT;
+ // 切换到下一个 EMPTY 的 buffer
+ bool switched = false;
+ for (uint8_t attempts = 0; attempts < PPP_PING_PONG_BUFFER_COUNT; attempts++) {
+ uint8_t next_idx = (current_idx + attempts + 1) % PPP_PING_PONG_BUFFER_COUNT;
ppp_ping_pong_buffer_t *next_buffer = &g_ping_pong_buffers[next_idx];
if (next_buffer->state == PPP_BUFFER_STATE_EMPTY) {
- // 先flush当前buffer(如果有数据)
- if (current_buffer->state == PPP_BUFFER_STATE_FILLING &&
- current_buffer->write_pos > 0) {
- ppp_flush_buffer(current_idx);
- }
-
- // 切换到新buffer
g_current_buffer_index = next_idx;
g_ppp_stats.buffer_switch_count++;
-
- // 继续处理剩余数据(下次循环会写入新buffer)
- } else {
- // 两个buffer都不可用,丢弃数据
- uint32_t discarded = bytes_read - processed;
- g_ppp_stats.dropped_both_full += discarded;
- g_ppp_stats.total_bytes_discarded += discarded;
- PPP_DEBUG_WARN("Both buffers full, discarding %u bytes", discarded);
+ switched = true;
+ PPP_DEBUG_DEBUG("Switched to buffer[%u]", next_idx);
break;
}
}
+
+ if (!switched) {
+ // 没有空闲 buffer,等待处理线程
+ PPP_DEBUG_WARN("No empty buffer available, waiting...");
+ osal_msleep(1);
+ }
}
// 有数据,不休眠,继续读取
+
} else if (ret != PPP_ERR_OK) {
// 读取错误
if (!g_ppp_rx_thread_running) {
break;
}
PPP_DEBUG_ERROR("PPP serial tryread error: %d", ret);
- osal_msleep(10); // 错误时稍微休眠
+ osal_msleep(10);
+
} else {
// 无数据
- consecutive_empty++;
g_ppp_stats.read_empty_count++;
- // 无数据时休眠1ms
+ // 7. 检查当前 buffer 是否超时(配合定时器)
+ uint32_t current_time = ppp_get_current_time_ms();
+ if (current_time - last_timeout_check >= PPP_PING_PONG_TIMEOUT_MS) {
+ last_timeout_check = current_time;
+
+ // 检查当前 buffer 是否有数据且超时
+ if (current_buffer->state == PPP_BUFFER_STATE_FILLING &&
+ current_buffer->write_pos > 0) {
+
+ uint32_t elapsed = current_time - current_buffer->last_write_time;
+ if (elapsed >= PPP_PING_PONG_TIMEOUT_MS) {
+ // 超时,flush 当前 buffer
+ PPP_DEBUG_DEBUG("Buffer[%u] timeout (%u ms), flushing %u bytes",
+ current_idx, elapsed, current_buffer->write_pos);
+ ppp_flush_buffer(current_idx);
+ g_ppp_stats.buffer_timeout_count++;
+
+ // 切换到下一个 buffer
+ uint8_t next_idx = (current_idx + 1) % PPP_PING_PONG_BUFFER_COUNT;
+ ppp_ping_pong_buffer_t *next_buffer = &g_ping_pong_buffers[next_idx];
+
+ if (next_buffer->state == PPP_BUFFER_STATE_EMPTY) {
+ g_current_buffer_index = next_idx;
+ g_ppp_stats.buffer_switch_count++;
+ }
+ }
+ }
+ }
+
+ // 无数据时休眠 1ms
osal_msleep(1);
}
}
}
+ // 退出前,flush 当前 buffer(如果有数据)
+ uint8_t final_idx = g_current_buffer_index;
+ ppp_ping_pong_buffer_t *final_buffer = &g_ping_pong_buffers[final_idx];
+ if (final_buffer->state == PPP_BUFFER_STATE_FILLING && final_buffer->write_pos > 0) {
+ PPP_DEBUG_INFO("Flushing final buffer[%u] with %u bytes",
+ final_idx, final_buffer->write_pos);
+ ppp_flush_buffer(final_idx);
+ }
+
// 释放缓冲区
free(rx_buffer);
app_task_definition_t process_task_cfg = {0};
process_task_cfg.create_queue_handle = NULL;
process_task_cfg.attr.name = "ppp_process";
- process_task_cfg.attr.priority = osPriorityNormal1;
+ process_task_cfg.attr.priority = PPP_PROCESS_THREAD_PRIORITY; // 使用配置的优先级
process_task_cfg.attr.stack_size = PPP_PROCESS_STACK_SIZE;
process_task_cfg.func = ppp_lwip_process_thread;
process_task_cfg.task_handle = &g_ppp_process_thread_handle;
return PPP_ERR_MEMORY;
}
- // 5. 启动接收线程
+ // 5. 启动接收线程(高优先级以确保及时读取数据)
g_ppp_rx_thread_running = true;
app_task_definition_t rx_task_cfg = {0};
rx_task_cfg.create_queue_handle = NULL;
rx_task_cfg.attr.name = "ppp_receive";
- rx_task_cfg.attr.priority = osPriorityNormal1;
+ rx_task_cfg.attr.priority = PPP_RX_THREAD_PRIORITY; // 使用配置的高优先级
rx_task_cfg.attr.stack_size = PPP_RX_STACK_SIZE;
rx_task_cfg.func = ppp_lwip_receive_thread;
rx_task_cfg.task_handle = &g_ppp_rx_thread_handle;
g_ppp_timer_running = false;
osal_timer_stop(&g_ppp_timeout_timer);
osal_timer_destroy(&g_ppp_timeout_timer);
- PPP_DEBUG_INFO("Timeout timer stopped");
+
+ // ⚠️ 关键:清零定时器句柄,确保可以重新初始化
+ g_ppp_timeout_timer.timer = NULL;
+
+ PPP_DEBUG_INFO("Timeout timer stopped and cleared");
}
// 2. 停止接收线程
// 4. 清理队列
if (g_ppp_msg_queue != 0) {
osal_msg_queue_delete(g_ppp_msg_queue);
+
+ // ⚠️ 关键:清零队列句柄,确保可以重新创建
g_ppp_msg_queue = 0;
}
- // 5. 清空乒乓缓冲区
+ // 5. ⚠️ 数据安全:在清空前,先flush所有有数据的buffer,确保数据不丢失
+ PPP_DEBUG_INFO("Flushing all buffers before stop...");
+ for (uint8_t i = 0; i < PPP_PING_PONG_BUFFER_COUNT; i++) {
+ if (g_ping_pong_buffers[i].state == PPP_BUFFER_STATE_FILLING &&
+ g_ping_pong_buffers[i].write_pos > 0) {
+ PPP_DEBUG_INFO(" Flushing buffer[%u]: %u bytes",
+ i, g_ping_pong_buffers[i].write_pos);
+ ppp_flush_buffer(i);
+ // 给处理线程一点时间处理最后的数据
+ osal_msleep(50);
+ }
+ }
+
+ // 6. 清空乒乓缓冲区
for (uint8_t i = 0; i < PPP_PING_PONG_BUFFER_COUNT; i++) {
g_ping_pong_buffers[i].write_pos = 0;
g_ping_pong_buffers[i].state = PPP_BUFFER_STATE_EMPTY;
*/
void ppp_lwip_print_discard_stats(void)
{
- PPP_DEBUG_INFO("=== PPP Polling Statistics (Ping-Pong Mode) ===");
- PPP_DEBUG_INFO("Mode: Polling (轮询替代中断)");
- PPP_DEBUG_INFO("Buffers: %d x %d bytes = %d KB total",
+ PPP_DEBUG_WARN("=== PPP Polling Statistics (Ping-Pong Mode) ===");
+ PPP_DEBUG_WARN("Mode: Polling (轮询替代中断)");
+ PPP_DEBUG_WARN("Buffers: %d x %d bytes = %d KB total",
PPP_PING_PONG_BUFFER_COUNT, PPP_PING_PONG_BUFFER_SIZE,
(PPP_PING_PONG_BUFFER_COUNT * PPP_PING_PONG_BUFFER_SIZE) / 1024);
- PPP_DEBUG_INFO("Timeout: %d ms", PPP_PING_PONG_TIMEOUT_MS);
- PPP_DEBUG_INFO("");
+ PPP_DEBUG_WARN("Timeout: %d ms", PPP_PING_PONG_TIMEOUT_MS);
+ PPP_DEBUG_WARN("");
// Buffer状态
- PPP_DEBUG_INFO("Buffer Status:");
+ PPP_DEBUG_WARN("Buffer Status:");
for (uint8_t i = 0; i < PPP_PING_PONG_BUFFER_COUNT; i++) {
const char *state_str = "UNKNOWN";
switch (g_ping_pong_buffers[i].state) {
case PPP_BUFFER_STATE_FULL: state_str = "FULL"; break;
case PPP_BUFFER_STATE_PROCESSING: state_str = "PROCESSING"; break;
}
- PPP_DEBUG_INFO(" Buffer[%u]: %s, %u/%u bytes%s",
+ PPP_DEBUG_WARN(" Buffer[%u]: %s, %u/%u bytes%s",
i, state_str, g_ping_pong_buffers[i].write_pos,
PPP_PING_PONG_BUFFER_SIZE,
(i == g_current_buffer_index) ? " (current)" : "");
}
- PPP_DEBUG_INFO("");
+ PPP_DEBUG_WARN("");
// 乒乓buffer统计
- PPP_DEBUG_INFO("Ping-Pong Buffer Statistics:");
- PPP_DEBUG_INFO(" Buffer Full Count: %u", g_ppp_stats.buffer_full_count);
- PPP_DEBUG_INFO(" Buffer Timeout Count: %u", g_ppp_stats.buffer_timeout_count);
- PPP_DEBUG_INFO(" Buffer Switch Count: %u", g_ppp_stats.buffer_switch_count);
- PPP_DEBUG_INFO("");
+ PPP_DEBUG_WARN("Ping-Pong Buffer Statistics:");
+ PPP_DEBUG_WARN(" Buffer Full Count: %u", g_ppp_stats.buffer_full_count);
+ PPP_DEBUG_WARN(" Buffer Timeout Count: %u", g_ppp_stats.buffer_timeout_count);
+ PPP_DEBUG_WARN(" Buffer Switch Count: %u", g_ppp_stats.buffer_switch_count);
+ PPP_DEBUG_WARN("");
// UART轮询统计
- PPP_DEBUG_INFO("UART Polling Statistics:");
- PPP_DEBUG_INFO(" Total Read Attempts: %u", g_ppp_stats.read_count + g_ppp_stats.read_empty_count);
- PPP_DEBUG_INFO(" Successful Reads: %u", g_ppp_stats.read_count);
- PPP_DEBUG_INFO(" Empty Reads: %u", g_ppp_stats.read_empty_count);
+ PPP_DEBUG_WARN("UART Polling Statistics:");
+ PPP_DEBUG_WARN(" Total Read Attempts: %u", g_ppp_stats.read_count + g_ppp_stats.read_empty_count);
+ PPP_DEBUG_WARN(" Successful Reads: %u", g_ppp_stats.read_count);
+ PPP_DEBUG_WARN(" Empty Reads: %u", g_ppp_stats.read_empty_count);
if (g_ppp_stats.read_count + g_ppp_stats.read_empty_count > 0) {
uint32_t hit_rate = (g_ppp_stats.read_count * 100) /
(g_ppp_stats.read_count + g_ppp_stats.read_empty_count);
- PPP_DEBUG_INFO(" Hit Rate: %u%%", hit_rate);
+ PPP_DEBUG_WARN(" Hit Rate: %u%%", hit_rate);
}
- PPP_DEBUG_INFO("");
+ PPP_DEBUG_WARN("");
// 字节统计
- PPP_DEBUG_INFO("Byte Statistics:");
- PPP_DEBUG_INFO(" Total Bytes Received: %u", g_ppp_stats.total_bytes_received);
- PPP_DEBUG_INFO(" Total Bytes Processed: %u", g_ppp_stats.total_bytes_processed);
- PPP_DEBUG_INFO(" Total Bytes Discarded: %u", g_ppp_stats.total_bytes_discarded);
- PPP_DEBUG_INFO(" - Both Buffers Full: %u", g_ppp_stats.dropped_both_full);
- PPP_DEBUG_INFO(" - Queue Full: %u", g_ppp_stats.dropped_queue_full);
- PPP_DEBUG_INFO(" lwIP Errors: %u", g_ppp_stats.lwip_error_count);
- PPP_DEBUG_INFO("");
+ PPP_DEBUG_WARN("Byte Statistics:");
+ PPP_DEBUG_WARN(" Total Bytes Received: %u", g_ppp_stats.total_bytes_received);
+ PPP_DEBUG_WARN(" Total Bytes Processed: %u", g_ppp_stats.total_bytes_processed);
+ PPP_DEBUG_WARN(" Total Bytes Discarded: %u", g_ppp_stats.total_bytes_discarded);
+ PPP_DEBUG_WARN(" - Both Buffers Full: %u", g_ppp_stats.dropped_both_full);
+ PPP_DEBUG_WARN(" - Queue Full: %u", g_ppp_stats.dropped_queue_full);
+ PPP_DEBUG_WARN(" lwIP Errors: %u", g_ppp_stats.lwip_error_count);
+ PPP_DEBUG_WARN("");
// 丢包率
if (g_ppp_stats.total_bytes_received > 0) {
uint32_t drop_rate = (g_ppp_stats.total_bytes_discarded * 10000) /
g_ppp_stats.total_bytes_received;
- PPP_DEBUG_INFO("Drop Rate: %u.%02u%%", drop_rate / 100, drop_rate % 100);
+ PPP_DEBUG_WARN("Drop Rate: %u.%02u%%", drop_rate / 100, drop_rate % 100);
}
// 平均字节数
if (g_ppp_stats.read_count > 0) {
uint32_t avg_bytes = g_ppp_stats.total_bytes_received / g_ppp_stats.read_count;
- PPP_DEBUG_INFO("Average bytes per read: %u", avg_bytes);
+ PPP_DEBUG_WARN("Average bytes per read: %u", avg_bytes);
}
- PPP_DEBUG_INFO("=================================================");
+ PPP_DEBUG_WARN("=================================================");
}
\ No newline at end of file
/* PPP性能优化配置 */
#define PPP_OPTIMIZED_UART_WRITE_TIMEOUT 200 /* UART写超时优化: 1000ms -> 200ms */
#define PPP_OPTIMIZED_UART_READ_TIMEOUT 100 /* UART读超时优化: 200ms -> 100ms */
-
+#if defined(CONFIG_UART_SUPPORT_DMA)
+#define UART_DMA_WIDTH 0
+#define UART_DMA_BURST_LENGTH 2
+#define UART_DMA_PRIORITY 0
+#define UART_DMA_TX_ENABLE 1
+#define UART_DMA_RX_ENABLE 1
+#endif
/* 串口上下文结构 - 优化缓存机制 */
typedef struct {
bool initialized;
uart_pin_config_t pin_config;
uart_attr_t uart_attr;
uart_buffer_config_t buffer_config;
+ uart_extra_attr_t extra_attr;
/* 统一的接收缓冲区(AT和PPP模式共用) */
uint8_t *rx_buffer;
/* 初始化UART */
PPP_DEBUG_DEBUG("Calling uapi_uart_init...");
+ #if defined(PPP_USE_INTERRUPT_MODE) && (PPP_USE_INTERRUPT_MODE == 0)
// 注意:uart_porting.c中已经做了UART初始化,这里只需要设置属性
- // errcode_t ret = uapi_uart_init(g_serial_ctx.uart_bus,
- // &g_serial_ctx.pin_config,
- // &g_serial_ctx.uart_attr,
- // NULL,
- // &g_serial_ctx.buffer_config);
+
+
+
+
+ #if defined(CONFIG_UART_SUPPORT_DMA)
+ g_serial_ctx.extra_attr.tx_dma_enable = UART_DMA_TX_ENABLE;
+ g_serial_ctx.extra_attr.tx_int_threshold = 0;
+ g_serial_ctx.extra_attr.rx_dma_enable = UART_DMA_RX_ENABLE;
+ g_serial_ctx.extra_attr.rx_int_threshold = 0;
+ uapi_dma_init();
+ uapi_dma_open();
+ errcode_t ret = uapi_uart_init(g_serial_ctx.uart_bus,
+ &g_serial_ctx.pin_config,
+ &g_serial_ctx.uart_attr,
+ &g_serial_ctx.extra_attr,
+ &g_serial_ctx.buffer_config);
+ #else
+ errcode_t ret = uapi_uart_init(g_serial_ctx.uart_bus,
+ &g_serial_ctx.pin_config,
+ &g_serial_ctx.uart_attr,
+ NULL,
+ &g_serial_ctx.buffer_config);
+ #endif
+
+ #else
+
+ // 注意:uart_porting.c中已经做了UART初始化,这里只需要设置属性
+ // 需要配置 SUPPORT_PPP_SERVICE_INTERRUPT 才在uart_porting里初始化uart
errcode_t ret = uapi_uart_set_attr(g_serial_ctx.uart_bus, &g_serial_ctx.uart_attr);
+
+ #endif
if (ret != ERRCODE_SUCC) {
PPP_DEBUG_ERROR("Failed to initialize UART: error code = %d (0x%x)", ret, ret);
PPP_DEBUG_ERROR("UART init failed with bus=%u, tx_pin=%u, rx_pin=%u, baudrate=%u",
osal_mutex_destroy(&g_serial_ctx.tx_mutex);
return PPP_ERR_UART;
}
-
PPP_DEBUG_INFO("UART initialized successfully (error code = %d)", ret);
/* 创建同步对象 */
case PPP_SERIAL_MODE_AT:
/* AT命令模式:直接从UART读取 */
{
+
+ #if defined(CONFIG_UART_SUPPORT_DMA)
+ uart_write_dma_config_t dma_cfg = {
+ .src_width = UART_DMA_WIDTH,
+ .dest_width = UART_DMA_WIDTH,
+ .burst_length = UART_DMA_BURST_LENGTH,
+ .priority = UART_DMA_PRIORITY
+ };
+ int32_t read_result = uapi_uart_read_by_dma(g_serial_ctx.uart_bus, buffer, buffer_size,&dma_cfg);
+
+ #else
int32_t read_result = uapi_uart_read(g_serial_ctx.uart_bus, buffer, buffer_size, 100);
+ #endif
if (read_result > 0) {
*bytes_read = (uint32_t)read_result;
g_serial_ctx.rx_bytes += *bytes_read;
uint8_t *current_buffer = buffer + total_read;
// 使用短超时进行读取,类似sio_tryread的1ms超时
- int32_t read_result = uapi_uart_read(g_serial_ctx.uart_bus, current_buffer,
- remaining, batch_count == 0 ? 10 : 1);
+ #if defined(CONFIG_UART_SUPPORT_DMA)
+ uart_write_dma_config_t dma_cfg = {
+ .src_width = UART_DMA_WIDTH,
+ .dest_width = UART_DMA_WIDTH,
+ .burst_length = UART_DMA_BURST_LENGTH,
+ .priority = UART_DMA_PRIORITY
+ };
+ int32_t read_result = uapi_uart_read_by_dma(g_serial_ctx.uart_bus, current_buffer,
+ remaining,&dma_cfg);
+
+ #else
+ int32_t read_result = uapi_uart_read(g_serial_ctx.uart_bus, current_buffer,
+ remaining, batch_count == 0 ? 10 : 1);
+ #endif
if (read_result > 0) {
total_read += (uint32_t)read_result;
g_serial_ctx.rx_bytes += (uint32_t)read_result;
if (g_serial_ctx.current_mode == PPP_SERIAL_MODE_PPP_DATA) {
/* PPP数据模式:使用1ms超时快速读取,类似SLIP的sio_tryread */
+
+ #if defined(CONFIG_UART_SUPPORT_DMA)
+ uart_write_dma_config_t dma_cfg = {
+ .src_width = UART_DMA_WIDTH,
+ .dest_width = UART_DMA_WIDTH,
+ .burst_length = UART_DMA_BURST_LENGTH,
+ .priority = UART_DMA_PRIORITY
+ };
+ int32_t read_result = uapi_uart_read_by_dma(g_serial_ctx.uart_bus, buffer, buffer_size,&dma_cfg);
+
+ #else
int32_t read_result = uapi_uart_read(g_serial_ctx.uart_bus, buffer, buffer_size, 0);
+ #endif
if (read_result > 0) {
*bytes_read = (uint32_t)read_result;
g_serial_ctx.rx_bytes += *bytes_read;