FTP可以连接成功
This commit is contained in:
@@ -219,3 +219,70 @@ CH395F 的 RECV 中断是电平触发的——只要接收缓冲区有数据就
|
||||
|
||||
### UDP 发送缓冲
|
||||
- 每次 `ch395f_write_send_buf()` 后必须等待 `SINT_STAT_SENBUF_FREE` 中断,否则下次写入会被 CH395F 静默丢弃
|
||||
|
||||
---
|
||||
|
||||
## Trap 09:PHY 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(¬ified); // 等待通知
|
||||
return msg.result; // 永远是 -1!
|
||||
|
||||
// 处理方(netTask)
|
||||
osMessageQueueGet(&msg); // 拿到的是队列副本
|
||||
msg.result = actual_result; // 修改的是副本
|
||||
xTaskNotify(...); // 通知回去了,但值丢了
|
||||
```
|
||||
|
||||
### 解决方案
|
||||
不通过消息队列回传结果,改用 **FreeRTOS 通知值**(notification value)携带返回值:
|
||||
|
||||
**Producer(netTask)**:
|
||||
```c
|
||||
xTaskNotify(msg.caller, (uint32_t)msg.result, eSetValueWithOverwrite);
|
||||
```
|
||||
|
||||
**Consumer(调用方)**:
|
||||
```c
|
||||
uint32_t notified;
|
||||
xTaskNotifyWait(0, 0, ¬ified, portMAX_DELAY);
|
||||
msg.result = (int)notified;
|
||||
```
|
||||
|
||||
### 注意事项
|
||||
- 指针成员(`msg.buf`)不受值拷贝影响——netTask 拿到的是同一个指针,可以读写调用方的缓冲区
|
||||
- `net_connect()` 不使用消息队列(在 netTask 内直接调用 `_locked` 版本),不受此 bug 影响
|
||||
- 内核级 API(`net_send_sock` / `net_recv_sock` / `net_listen_locked`)直接操作,同样不受影响
|
||||
|
||||
Reference in New Issue
Block a user