瀏覽代碼

update: netdrv,ch390,优化复位机制,优化拥堵算法

Wendal Chen 3 月之前
父節點
當前提交
5ffd80c7f2

+ 8 - 0
components/network/netdrv/include/luat_netdrv_ch390h.h

@@ -29,6 +29,14 @@ typedef struct ch390h
     luat_ch390h_cstring_t* txqueue[CH390H_MAX_TX_NUM];
     char* txtmp;  // TX临时缓冲区,避免多设备冲突
     int pkg_mem_type;  // 数据包内存类型,每个设备独立配置
+    uint16_t rx_error_count;  // 读包错误计数器
+    uint16_t tx_busy_count;  // TX忙计数器
+    uint16_t vid_pid_error_count;  // VID/PID检查失败计数器
+    uint32_t last_reset_time;  // 最后一次复位时间(毫秒)
+    uint32_t total_reset_count;  // 总复位次数
+    uint32_t total_tx_drop;  // 总丢弃发送包数
+    uint32_t total_rx_drop;  // 总丢弃接收包数
+    uint8_t flow_control;  // 流控状态:0=正常 1=背压中
 }ch390h_t;
 
 

+ 29 - 18
components/network/netdrv/src/ch390h_api.c

@@ -25,7 +25,10 @@ int luat_ch390h_read(ch390h_t* ch, uint8_t addr, uint16_t count, uint8_t* buff)
         luat_gpio_set(ch->cspin, 0);
         ret = luat_spi_send(ch->spiid, tmp, 1);
         if (ret != 1) {
-            LLOGE("luat_spi_send 1 but ret %d", ret);
+            LLOGE("luat_spi_send失败 expect=1 ret=%d", ret);
+            luat_gpio_set(ch->cspin, 1);
+            luat_spi_unlock(ch->spiid);
+            return -1;
         }
         char* ptr = (char*)buff;
         while (count > 0) {
@@ -204,31 +207,39 @@ int luat_ch390h_write_pkg(ch390h_t* ch, uint8_t *buff, uint16_t len) {
     uint8_t NCR = 0;
     uint8_t NSR = 0;
     if (TCR & 0x01) {
-        // busy!!
-        for (size_t i = 0; i < 16; i++)
+        // busy!! 增加重试次数
+        for (size_t i = 0; i < 100; i++)
         {
             luat_timer_us_delay(10);
             luat_ch390h_read(ch, 0x02, 1, tmp);
             TCR = tmp[0];
-            if (TCR & 0x01) {
-                continue;
+            if (!(TCR & 0x01)) {
+                ch->tx_busy_count = 0;  // 成功后清零计数器
+                break;
             }
-            break;
         }
         if (TCR & 0x01) {
-            LLOGW("tx busy, drop pkg len %d and reset ch390!!", len);
-            // 读出NCR 和 NSR
-            luat_ch390h_read(ch, 0x00, 1, tmp);
-            NCR = tmp[0];
-            luat_ch390h_read(ch, 0x01, 1, tmp);
-            NSR = tmp[0];
-            LLOGD("NCR %02X NSR %02X", NCR, NSR);
-            LLOGD("NCR->FDR %02X NSR->SPEED %02X NSR->LINKST %02X", NCR & (1<<3), NSR & (1<<7), NSR & (1<<6));
-            luat_ch390h_software_reset(ch);
-            luat_timer_mdelay(2);
-            return 0;
+            ch->tx_busy_count++;
+            LLOGW("tx busy, drop pkg len %d, busy_count=%d", len, ch->tx_busy_count);
+            // 只有连续多次TX忙且距离上次复位超过5秒才复位
+            extern uint64_t luat_mcu_tick64_ms(void);
+            uint32_t now = (uint32_t)luat_mcu_tick64_ms();
+            if (ch->tx_busy_count >= 10 && (now - ch->last_reset_time > 5000)) {
+                // 读出NCR 和 NSR
+                luat_ch390h_read(ch, 0x00, 1, tmp);
+                NCR = tmp[0];
+                luat_ch390h_read(ch, 0x01, 1, tmp);
+                NSR = tmp[0];
+                LLOGE("连续TX忙超过阈值,执行复位 NCR=%02X NSR=%02X", NCR, NSR);
+                LLOGD("NCR->FDR %02X NSR->SPEED %02X NSR->LINKST %02X", NCR & (1<<3), NSR & (1<<7), NSR & (1<<6));
+                luat_ch390h_software_reset(ch);
+                ch->tx_busy_count = 0;
+                ch->last_reset_time = now;
+                ch->total_reset_count++;
+                luat_timer_mdelay(2);
+            }
+            return -1;
         }
-        // return 1;
     }
     luat_ch390h_write_reg(ch, 0x55, 2);     // 发数据之前重置一下tx的内存指针
     // 写入下一个数据

+ 52 - 16
components/network/netdrv/src/ch390h_task.c

@@ -116,20 +116,29 @@ static void send_msg_cs(ch390h_t* ch, luat_ch390h_cstring_t* cs) {
     uint32_t len = 0;
     luat_rtos_queue_get_cnt(qt, &len);
     uint64_t tm;
+    
+    // 流控背压机制
+    if (len >= 800) {
+        ch->flow_control = 1;  // 进入背压状态
+    } else if (len < 400) {
+        ch->flow_control = 0;  // 解除背压
+    }
+    
     if (len >= 1000) {
         tm = luat_mcu_tick64_ms();
         if (tm - warn_msg_tm > 1000) {
             warn_msg_tm = tm;
-            LLOGW("太多待处理消息了!!! %d", len);
+            LLOGE("队列已满,丢弃数据包 len=%d", len);
         }
+        ch->total_tx_drop++;
         luat_heap_opt_free(ch->pkg_mem_type, cs);
         return;
     }
-    if (len > 512) {
+    if (len > 600) {
         tm = luat_mcu_tick64_ms();
         if (tm - warn_msg_tm > 1000) {
             warn_msg_tm = tm;
-            LLOGD("当前消息数量 %d", len);
+            LLOGW("队列负载较高 len=%d flow_control=%d", len, ch->flow_control);
         }
     }
     
@@ -208,19 +217,35 @@ static int check_vid_pid(ch390h_t* ch) {
     uint8_t buff[6] = {0};
     luat_ch390h_read_vid_pid(ch, buff);
     if (0 == memcmp(buff, "\x00\x1C\x51\x91", 4)) {
-        return 0; // 第一次就读取成功, 那就马上返回
+        ch->vid_pid_error_count = 0;  // 成功后清零计数器
+        return 0;
     }
     // 再读一次
     luat_ch390h_read_vid_pid(ch, buff);
     if (0 != memcmp(buff, "\x00\x1C\x51\x91", 4)) {
+        ch->vid_pid_error_count++;
         uint64_t tnow = luat_mcu_tick64_ms();
         if (tnow - warn_vid_pid_tm > 2000) {
-            LLOGE("读取vid/pid失败!请检查接线!! %d %d %02X%02X%02X%02X", ch->spiid, ch->cspin, buff[0], buff[1], buff[2], buff[3]);
+            // 前几次用WARN,多次失败用ERROR
+            if (ch->vid_pid_error_count < 10) {
+                LLOGW("读取vid/pid失败 spi=%d cs=%d %02X%02X%02X%02X error_count=%d", 
+                      ch->spiid, ch->cspin, buff[0], buff[1], buff[2], buff[3], ch->vid_pid_error_count);
+            } else {
+                LLOGE("读取vid/pid持续失败!请检查接线!! spi=%d cs=%d %02X%02X%02X%02X error_count=%d", 
+                      ch->spiid, ch->cspin, buff[0], buff[1], buff[2], buff[3], ch->vid_pid_error_count);
+            }
             warn_vid_pid_tm = tnow;
         }
+        // 连续多次失败后回退到初始状态
+        if (ch->vid_pid_error_count >= 20 && ch->status >= 2) {
+            LLOGE("VID/PID检查连续失败超过阈值,回退到初始状态");
+            ch->status = 0;
+            ch->init_done = 0;
+            ch->vid_pid_error_count = 0;
+        }
         return -1;
     }
-    // LLOGE("读取vid/pid成功!!! %d %d %02X%02X%02X%02X", ch->spiid, ch->cspin, buff[0], buff[1], buff[2], buff[3]);
+    ch->vid_pid_error_count = 0;
     return 0;
 }
 
@@ -322,19 +347,30 @@ static int task_loop_one(ch390h_t* ch, luat_ch390h_cstring_t* cs) {
     if (NSR & 0x01) {
         ret = luat_ch390h_read_pkg(ch, ch->rxbuff, &len);
         if (ret) {
-            LLOGE("读数据包报错,立即复位模组 ret %d spi %d cs %d", ret, ch->spiid, ch->cspin);
-            luat_ch390h_write_reg(ch, 0x05, 0);
-            luat_ch390h_write_reg(ch, 0x55, 1);
-            luat_ch390h_write_reg(ch, 0x75, 0);
-            luat_rtos_task_sleep(1); // 是否真的需要呢??
-            luat_ch390h_basic_config(ch);
-            luat_ch390h_set_phy(ch, 1);
-            luat_ch390h_set_rx(ch, 1);
-            if (ch->intpin != 255) {
-                luat_ch390h_write_reg(ch, 0x7F, 1); // 开启接收中断
+            ch->rx_error_count++;
+            LLOGW("读数据包报错 ret=%d spi=%d cs=%d, error_count=%d", ret, ch->spiid, ch->cspin, ch->rx_error_count);
+            // 只有连续多次错误且距离上次复位超过3秒才执行复位
+            uint32_t now = (uint32_t)luat_mcu_tick64_ms();
+            if (ch->rx_error_count >= 5 && (now - ch->last_reset_time > 3000)) {
+                LLOGE("连续读包错误超过阈值,执行复位");
+                luat_ch390h_write_reg(ch, 0x05, 0);
+                luat_ch390h_write_reg(ch, 0x55, 1);
+                luat_ch390h_write_reg(ch, 0x75, 0);
+                luat_rtos_task_sleep(1);
+                luat_ch390h_basic_config(ch);
+                luat_ch390h_set_phy(ch, 1);
+                luat_ch390h_set_rx(ch, 1);
+                if (ch->intpin != 255) {
+                    luat_ch390h_write_reg(ch, 0x7F, 1);
+                }
+                ch->rx_error_count = 0;
+                ch->last_reset_time = now;
+                ch->total_reset_count++;
             }
             return 0;
         }
+        // 读取成功,清除错误计数
+        ch->rx_error_count = 0;
         if (len > 0) {
             NETDRV_STAT_IN(ch->netdrv, len);
             // 收到数据, 开始后续处理

+ 39 - 13
components/network/netdrv/src/luat_netdrv_ch390h.c

@@ -28,6 +28,27 @@ extern err_t luat_netdrv_etharp_output(struct netif *netif, struct pbuf *q, cons
 
 extern err_t ch390_netif_output(struct netif *netif, struct pbuf *p);
 
+// 检查设备是否已注册
+static int check_device_duplicate(ch390h_t* ch) {
+    for (size_t i = 0; i < MAX_CH390H_NUM; i++) {
+        if (ch390h_drvs[i] == NULL) continue;
+        
+        if (ch390h_drvs[i]->adapter_id == ch->adapter_id) {
+            LLOGE("已经注册过相同的adapter_id %d", ch->adapter_id);
+            return -1;
+        }
+        if (ch390h_drvs[i]->spiid == ch->spiid && ch390h_drvs[i]->cspin == ch->cspin) {
+            LLOGE("已经注册过相同的spi+cs %d %d", ch->spiid, ch->cspin);
+            return -2;
+        }
+        if (ch390h_drvs[i]->intpin != 255 && ch390h_drvs[i]->intpin == ch->intpin) {
+            LLOGE("已经注册过相同的int脚 %d", ch->intpin);
+            return -3;
+        }
+    }
+    return 0;
+}
+
 static int ch390h_ctrl(luat_netdrv_t* drv, void* userdata, int cmd, void* buff, size_t len) {
     ch390h_t* ch = (ch390h_t*)userdata;
     if (ch == NULL) {
@@ -96,6 +117,14 @@ luat_netdrv_t* luat_netdrv_ch390h_setup(luat_netdrv_conf_t *cfg) {
 
     ch->txtmp = NULL;  // 延迟分配
     ch->pkg_mem_type = LUAT_HEAP_AUTO;  // 默认使用AUTO内存
+    ch->rx_error_count = 0;
+    ch->tx_busy_count = 0;
+    ch->vid_pid_error_count = 0;
+    ch->last_reset_time = 0;
+    ch->total_reset_count = 0;
+    ch->total_tx_drop = 0;
+    ch->total_rx_drop = 0;
+    ch->flow_control = 0;
     ch->adapter_id = cfg->id;
     ch->cspin = cfg->cspin;
     ch->spiid = cfg->spiid;
@@ -107,21 +136,15 @@ luat_netdrv_t* luat_netdrv_ch390h_setup(luat_netdrv_conf_t *cfg) {
 
     drv->ulwip = ulwip;
 
+    // 检查设备是否重复注册
+    if (check_device_duplicate(ch) != 0) {
+        goto clean;
+    }
+
+    // 查找空位并注册设备
     for (size_t i = 0; i < MAX_CH390H_NUM; i++)
     {
         if (ch390h_drvs[i] != NULL) {
-            if (ch390h_drvs[i]->adapter_id == ch->adapter_id) {
-                LLOGE("已经注册过相同的adapter_id %d", ch->adapter_id);
-                goto clean;
-            }
-            if (ch390h_drvs[i]->spiid == ch->spiid  && ch390h_drvs[i]->cspin == ch->cspin) {
-                LLOGE("已经注册过相同的spi+cs %d %d",ch->spiid, ch->cspin);
-                goto clean;
-            }
-            if (ch390h_drvs[i]->intpin != 255 && ch390h_drvs[i]->intpin == ch->intpin) {
-                LLOGE("已经注册过相同的int脚 %d", ch->intpin);
-                goto clean;
-            }
             continue;
         }
         ch390h_drvs[i] = ch;
@@ -144,7 +167,10 @@ luat_netdrv_t* luat_netdrv_ch390h_setup(luat_netdrv_conf_t *cfg) {
     }
     LLOGE("已经没有CH390H空位了!!!");
 clean:
-    if (ch) luat_heap_free(ch);
+    if (ch) {
+        if (ch->txtmp) luat_heap_free(ch->txtmp);
+        luat_heap_free(ch);
+    }
     if (netif) luat_heap_free(netif);
     if (drv) luat_heap_free(drv);
     if (ulwip) luat_heap_free(ulwip);