FTP可以连接成功

This commit is contained in:
2026-07-21 22:42:39 +08:00
parent 75cf4c9fbf
commit 46a74f24f3
6 changed files with 298 additions and 41 deletions

View File

@@ -219,3 +219,70 @@ CH395F 的 RECV 中断是电平触发的——只要接收缓冲区有数据就
### UDP 发送缓冲
- 每次 `ch395f_write_send_buf()` 后必须等待 `SINT_STAT_SENBUF_FREE` 中断,否则下次写入会被 CH395F 静默丢弃
---
## Trap 09PHY link up 后立即 open_socket 失败
### 现象
`net_listen()` 在 PHY_CHANGE 中断同一时刻调用 `ch395f_open_socket()` 返回错误码(非 BUSY 超时),导致首次 listen 失败。3 秒后重试成功。
```
[NET] PHY_CHANGE: 0x08 ← PHY 刚 link up (100M FULL)
[ERR] error listening on socket ← 同一秒 open_socket 失败
[FTP] waiting for connection... ← 3秒后重试成功
```
### 根因
CH395F 的 PHY link up 后,内部 TCP/IP 协议栈需要额外时间完成初始化ARP 缓存、路由表等)。在 PHY_CHANGE 中断触发的同一 `net_poll()` 迭代内立即调用 `OPEN_SOCKET`,芯片可能返回 `ERR_BUSY` 或其他错误码。
### 解决方案
1. **应用层重试兜底**FTP Server (`lftpd_start`) 的 `while(1)` 循环中listen 失败后 `vTaskDelay(3000)` 重试3 秒足够 PHY 稳定
2. **启动延时消峰**FTP 任务启动时 `osDelay(7000)`,等 netTask 完成 `net_init() → PHY 协商 → 首轮 net_poll()` 后再发起 listen此时 PHY 已稳定 2 秒以上,首次就成功
### 注意事项
- 此问题在单连接模式 (`FUN_PARA=0x00`) 和多连接模式 (`0x02`) 下均存在,与 FUN_PARA 无关
- 如果多个应用任务同时启动 listen可能全部首次失败、全部重试成功——建议各任务错峰启动
---
## Trap 10消息队列值拷贝导致结果无法回传
### 现象
`net_send()` / `net_recv()` / `net_listen()` / `net_accept()` / `net_close()` 等线程安全 API通过消息队列委托 netTask 执行)永远返回 `-1`,即使 netTask 内部操作成功。
### 根因
CMSIS-RTOS v2 `osMessageQueue` 传递 `net_msg_t` 结构体是**值拷贝**。调用方 puts 后 `msg.result = -1`栈变量netTask 侧 `osMessageQueueGet` 拿到的是**队列中的副本**,修改副本的 `msg.result = 0``xTaskNotifyGive` 通知调用方。调用方的栈变量 `msg.result` 仍然是 `-1`,从未被更新。
```c
// 调用方ftpTask
msg.result = -1;
osMessageQueuePut(&msg); // 值拷贝到队列
xTaskNotifyWait(&notified); // 等待通知
return msg.result; // 永远是 -1
// 处理方netTask
osMessageQueueGet(&msg); // 拿到的是队列副本
msg.result = actual_result; // 修改的是副本
xTaskNotify(...); // 通知回去了,但值丢了
```
### 解决方案
不通过消息队列回传结果,改用 **FreeRTOS 通知值**notification value携带返回值
**ProducernetTask**
```c
xTaskNotify(msg.caller, (uint32_t)msg.result, eSetValueWithOverwrite);
```
**Consumer调用方**
```c
uint32_t notified;
xTaskNotifyWait(0, 0, &notified, portMAX_DELAY);
msg.result = (int)notified;
```
### 注意事项
- 指针成员(`msg.buf`不受值拷贝影响——netTask 拿到的是同一个指针,可以读写调用方的缓冲区
- `net_connect()` 不使用消息队列(在 netTask 内直接调用 `_locked` 版本),不受此 bug 影响
- 内核级 API`net_send_sock` / `net_recv_sock` / `net_listen_locked`)直接操作,同样不受影响