network: 台架 IP 迁到 192.168.31.100,并把重复写死的值收进单一真源
分两段(用户裁定 2026-11-02):先做地址迁移,再把同类字面量收敛成
单一真源,以后再改地址只动一处。
一、IP 迁移 192.168.1.100 → 192.168.31.100(gw 同步 → .31.1)
- 工厂默认:Drivers/BSP/NETCFG/net_cfg.c 的 NET_CFG_DEF_IP/_GW
- 注释/文档示例、主机与板级测试、台架 py 脚本、两份 sim_config.ini
- 字节序教学点同步换算 hex:0x6401A8C0 → 0x641FA8C0(内存
C0 A8 1F 64),旧版示例引文与历史 Trap 记录按冻结纪律不动
- UI 黄金基准:网口设置 4 态 + shot_info 共 5 张 .bin 由
check_content_pages.py --update 重刷(渲染值 IP 变了,属预期变更)
- 保留判定:客户点表引用(IEC104/继电保护规划)、芯片手册摘录、
日期冻结的变更记录行、已退役台架档案 MDK-ARM/retracted_bench_*
二、单一真源收口(A+B+C+D,用户批准全做)
- 新建 test/host/bench_defaults.py:台架 py 默认值唯一定义点
(DEVICE_IP/DEVICE_GW/PC_IP/NET_BCAST),22 个脚本改为引用;
MDK-ARM 两探针与 scripts/board_ui_nav.py 经 sys.path shim 引入
- test/board/net_test_task.h 新增 TEST_PC_PEER_IP,板测三处
PHASE*_REMOTE_IP 改引该宏(保留 -D 覆盖);Phase1 断言改
memcmp 数组比较,数组各只出现一次
- simulator/tests/check_content_pages.py 从 net_cfg.c 正则解析
NET_CFG_DEF_* 推导期望值(解析失败即报错、不静默兜底),
脚本内台架 IP 字面量清零
- 装饰性注释去具体值(net_cfg.h/net_socket.h/net_socket.c/
net_socket_sim.c);字节序教学 hex 对刻意保留为唯一写值点
- 刻意不动:主机单测夹具 IP(逐文件钉住的任意值是正确测试
实践)、文档正文 IP(那是文档内容本身)
顺带:scripts/gen_task_table.py 规范串清掉「,B5」——编号清退提交
72b4b094 改了受管区没重跑生成器,task-table 门禁因此一直红
验证:产品 @build 0/0;CH395F 套件开关构建 0/0 后还原产品态;
6 套主机单测 rc=0;content_pages(含宏推导路径)/菜单 8 态/
推流位比对全 PASS;bom-drift 99 无漂移;doc-links/coding-standard/
cppcheck 绿;py_compile 23 文件 + --help 冒烟(含 shim 绝对路径)
This commit is contained in:
@@ -1276,18 +1276,18 @@ for (i = 1; i < LED_COUNT; i++) /* LE
|
||||
; DTU 通用配置文件
|
||||
[network]
|
||||
; IP 地址
|
||||
ip=192.168.1.100
|
||||
ip=192.168.31.100
|
||||
; 子网掩码
|
||||
mask=255.255.255.0
|
||||
; 默认网关
|
||||
gateway=192.168.1.1
|
||||
gateway=192.168.31.1
|
||||
; MAC 地址 (全零 = 使用芯片内置 MAC)
|
||||
mac=00:00:00:00:00:00
|
||||
```
|
||||
|
||||
**值类型**:`IP4`(`a.b.c.d`)、`MAC`(`aa:bb:cc:dd:ee:ff`)、`UINT`(十进制,兼容 `0x`)、`STR`(≤31 字符)。
|
||||
|
||||
**工厂默认**:IP `192.168.1.100` / 掩码 `255.255.255.0` / 网关 `192.168.1.1` / MAC 全零(= 芯片内置)。
|
||||
**工厂默认**:IP `192.168.31.100` / 掩码 `255.255.255.0` / 网关 `192.168.31.1` / MAC 全零(= 芯片内置)。
|
||||
|
||||
> MAC 全零是"使用芯片内置 MAC"的**哨兵**,不是"MAC 为 0"。恢复出厂:FTP `DELE /config.ini` → 下次上电重新生成模板。
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
| **入口** | 屏幕:`通讯参数 → 网口设置`(修改密码 `123` 可编辑;查看密码 `000` 只读) |
|
||||
| **存储** | NAND Flash 文件 `/config.ini`(INI `[network]` 段,通用配置文件,掉电不丢);旧版 `/cfg/netcfg.bin` **不再读取**(存在则忽略,见 §3.2) |
|
||||
| **生效** | 按「保存」后**立即生效**(网络重建约 1~3s,既有 TCP 连接会断开,无需重启) |
|
||||
| **工厂默认** | `192.168.1.100` / `255.255.255.0` / `192.168.1.1` / 芯片内置 MAC |
|
||||
| **工厂默认** | `192.168.31.100` / `255.255.255.0` / `192.168.31.1` / 芯片内置 MAC |
|
||||
|
||||
**典型操作(改 IP)**:
|
||||
|
||||
@@ -32,9 +32,9 @@
|
||||
|
||||
| 参数 | 字段 | 工厂默认 | 说明 |
|
||||
|---|---|---|---|
|
||||
| IP 地址 | `ip[4]` | **192.168.1.100** | 静态 IP(不启用 DHCP) |
|
||||
| IP 地址 | `ip[4]` | **192.168.31.100** | 静态 IP(不启用 DHCP) |
|
||||
| 子网掩码 | `mask[4]` | **255.255.255.0** | /24 |
|
||||
| 默认网关 | `gw[4]` | **192.168.1.1** | |
|
||||
| 默认网关 | `gw[4]` | **192.168.31.1** | |
|
||||
| MAC 地址 | `mac[6]` | **全零** | 全零 = 不覆盖芯片内置 MAC(见 §2) |
|
||||
|
||||
工厂默认值是**单一来源**:`net_cfg.c` 顶部 `NET_CFG_DEF_*` 宏,同时用于 `s_cfg` 静态初始化与 `s_defaults`(引擎注册的 `p_defaults` 目标),避免两处漂移。
|
||||
@@ -71,9 +71,9 @@
|
||||
; ============================================================
|
||||
|
||||
[network]
|
||||
ip=192.168.1.100
|
||||
ip=192.168.31.100
|
||||
mask=255.255.255.0
|
||||
gw=192.168.1.1
|
||||
gw=192.168.31.1
|
||||
mac=00:00:00:00:00:00
|
||||
```
|
||||
|
||||
@@ -96,7 +96,7 @@ mac=00:00:00:00:00:00
|
||||
| 存在 | — | 正常加载现有文件 |
|
||||
|
||||
- **删除理由**:该一次性路径把整条配置**写**链(`net_cfg_save → cfg_file_save → cfg_store_write_atomic → f_rename → FatFS → dhara FTL`)无条件挂进启动期调用图,使 defaultTask 的 armlink 静态最坏栈链 **+600 B**;而本仓库不存在携带旧档的设备。
|
||||
- **对使用方的影响**:卷上仍残留旧档的设备升级本版本后,网口配置**回落工厂默认**(`192.168.1.100/24`、gw `.1`),需经 UI「网口设置」或 FTP 上传 `/config.ini` 重新配置。
|
||||
- **对使用方的影响**:卷上仍残留旧档的设备升级本版本后,网口配置**回落工厂默认**(`192.168.31.100/24`、gw `.1`),需经 UI「网口设置」或 FTP 上传 `/config.ini` 重新配置。
|
||||
|
||||
### 3.3 存储后端(双端)
|
||||
|
||||
|
||||
@@ -104,11 +104,11 @@
|
||||
|
||||
[network]
|
||||
; IP 地址
|
||||
ip=192.168.1.100
|
||||
ip=192.168.31.100
|
||||
; 子网掩码
|
||||
mask=255.255.255.0
|
||||
; 默认网关
|
||||
gateway=192.168.1.1
|
||||
gateway=192.168.31.1
|
||||
; MAC 地址 (全零 = 使用芯片内置 MAC)
|
||||
mac=00:00:00:00:00:00
|
||||
```
|
||||
@@ -117,7 +117,7 @@ mac=00:00:00:00:00:00
|
||||
|
||||
| 类型 | 语法 | 示例 | 解析失败处理 |
|
||||
|---|---|---|---|
|
||||
| `CFG_VAL_IP4` | `a.b.c.d`(兼容前导零) | `192.168.1.100` | 该键取工厂默认 + `DBG_ERROR` |
|
||||
| `CFG_VAL_IP4` | `a.b.c.d`(兼容前导零) | `192.168.31.100` | 该键取工厂默认 + `DBG_ERROR` |
|
||||
| `CFG_VAL_MAC` | `aa:bb:cc:dd:ee:ff`(十六进制) | `a4:94:b6:12:34:56` | 同上 |
|
||||
| `CFG_VAL_UINT` | 十进制(兼容 `0x` 前缀) | `7003` | 同上 |
|
||||
| `CFG_VAL_STR` | 原始字符串(≤31 字符) | `hello` | 同上 |
|
||||
|
||||
@@ -330,7 +330,7 @@ TPAFE 是双极性、二进制补码,可以注负压;STM32 是单极性,
|
||||
| 板子 | 产品构建(`test/board/test_config.h` 四个 `TEST_SUITE_*` 全注释)+ `/keil-build` 0 错误 0 警告 + 烧录 `-Rst -Run` 与回读校验 | → `stlink-flash` skill 与 AGENTS.md「构建与验证」 |
|
||||
| `[adc_cal]` 状态 | **保持未标定**(`eng=0`),别为"读数好看"先写标定值 | 现在 `meas:` / `phasor` 的量纲是 **ADC 引脚电压 V**(`App/algo/meas.h` 文件头的 A-lite 口径);标定一生效就换成二次值,本节全部期望值作废 |
|
||||
| 串口 | 全程抓 RX 落盘:用 `serial-assistant` skill(`open` → `clear` → 跑 → 读日志文件或 `log --tail`) | 日志文件就是证据本体,§8.10 归档归档的就是它;**长跑别用 `/serial-boot-test`**——它绑定一轮启动语义(静默 8 s、总超时 30 s、`max_boot_count` = 1,且 forbidden 含 `[ERR]`,而削顶轮故意造 `[ERR]`),约 135 min 的 session 必然超时或误判;daemon 全量写 `state/serial.log`(20 MB 上限自动截头保尾 10 MB)→ `docs/测试说明/流程与规范/自动化测试流程.md` 长时间采集一节 |
|
||||
| 网口(可选) | 要读 104 那一路就插网线、PC 与板同网段(出厂 192.168.1.100),跑现成主站 `test/host/iec104_master.py`(`--ip` / `--port` / `--addr`) | 104 是浮点无量化 + 带品质,是 `meas:` 之外的第二条腿 |
|
||||
| 网口(可选) | 要读 104 那一路就插网线、PC 与板同网段(出厂 192.168.31.100),跑现成主站 `test/host/iec104_master.py`(`--ip` / `--port` / `--addr`) | 104 是浮点无量化 + 带品质,是 `meas:` 之外的第二条腿 |
|
||||
| FTP 客户端 | 走现成 21 端口取段文件(出厂 `[ftp]` 账号,连续 5 次失败锁 60 s) | 段文件是相位 / 谐波轮定量档的样本出口;段文件名 `/wave/WAVE<NN>.BIN`(00~99 轮转),**取完立刻改名归档**,否则下一次触发把它盖掉 |
|
||||
| 录波触发路径 | 产品构建里唯一**免改代码**的路径 = UI 菜单第 26 叶「手动录波」确认页(`Drivers/BSP/UI/ui_page_wave_manual.c` → `App/task/ui_task.c:605`) | 保护启动上升沿也算一次触发,但保护判据现处**未标定闭锁**态(AGENTS.md「现状」),别指望它自动来段;bench 定时自抓在双层编译门 `DTU_BENCH` 且 `WAVE_BENCH_AUTOCAP` 非 0 之内(默认 0,`App/task/adc_task.c:153`),开它就走 §8.9 的还原判据 |
|
||||
| 共地 | 发生器 LO/GND 与板 AGND **单点**相连 | 不共地量到的是两地之差;现象见 §8.8 |
|
||||
|
||||
@@ -29,7 +29,7 @@ flowchart LR
|
||||
|
||||
## 2. 到场检查清单(人到板边,打开这份清单逐条打勾)
|
||||
|
||||
- [ ] 板上电、网灯亮:会话里让 agent 跑 `ping 192.168.1.100`——通了就行(这台装置一直在线,串口 COM3、网线、ST-LINK 都常年插在这台电脑上,正常**都不用动**)
|
||||
- [ ] 板上电、网灯亮:会话里让 agent 跑 `ping 192.168.31.100`——通了就行(这台装置一直在线,串口 COM3、网线、ST-LINK 都常年插在这台电脑上,正常**都不用动**)
|
||||
- [ ] 信号发生器:和 2026-10-27 那次已知电压注入用的**是同一台**(波形档正弦、幅值 rms 直读;接线与端子位置照 `docs/测试说明/专项验证/ADC前端注入验证流程.md` §8.3 那四条,本文不重抄)
|
||||
- [ ] 万用表一块(并接监视 UA 端子,接线照上一条引的那四条)
|
||||
- [ ] 打开这个仓库的 agent 会话,对它说一句:**"按故障录波到场轮手册,先做第 X 幕"**——后面每步它自己跑,该你出手时它会说"到你接线了"
|
||||
|
||||
@@ -258,7 +258,7 @@ DTU-RemoteLCD 客户端;输出每帧 `req2first / total / recv 批次到达时
|
||||
& '.venv\Scripts\python.exe' .dsh\skills\keil-build\scripts\keil_build.py # 必须 0 错 0 警
|
||||
# 1) 先 clear 再起 peer(顺序不可反:wait-idle 需要看到会话活跃期)
|
||||
& '.venv\Scripts\python.exe' .dsh\skills\serial-assistant\scripts\serial_tool.py clear
|
||||
& '.venv\Scripts\python.exe' test\latency_peer.py --host 192.168.1.100 --port 8080 `
|
||||
& '.venv\Scripts\python.exe' test\host\latency_peer.py --host 192.168.31.100 --port 8080 `
|
||||
--json "docs\测试说明\测试数据\m2_data\m2_quiet.json" --wait 170 # 后台作业
|
||||
# 2) 烧录(Reset&Run 不可省)
|
||||
& '.venv\Scripts\python.exe' .dsh\skills\stlink-flash\scripts\stlink_flash.py flash
|
||||
@@ -284,16 +284,16 @@ DTU-RemoteLCD 客户端;输出每帧 `req2first / total / recv 批次到达时
|
||||
& '.venv\Scripts\python.exe' .dsh\skills\keil-build\scripts\keil_build.py # 0 错 0 警(Phase 14 构建)
|
||||
& '.venv\Scripts\python.exe' .dsh\skills\serial-assistant\scripts\serial_tool.py clear
|
||||
& '.venv\Scripts\python.exe' .dsh\skills\stlink-flash\scripts\stlink_flash.py flash # 先烧录,再起 peer(顺序不可反!)
|
||||
& '.venv\Scripts\python.exe' test\latency_peer.py --mode remo --host 192.168.1.100 --port 7003 `
|
||||
& '.venv\Scripts\python.exe' test\host\latency_peer.py --mode remo --host 192.168.31.100 --port 7003 `
|
||||
--samples 45 --stress-from 15 --ftp-stress --json "docs\测试说明\测试数据\m3_data\m3_dev_stress.json"
|
||||
# 模拟器基线(Δ 的对照端)
|
||||
& "simulator\build_sim.bat"; .\simulator\build\Debug\lvgl_sim.exe # 等 7003 就绪
|
||||
& '.venv\Scripts\python.exe' test\latency_peer.py --mode remo --host 127.0.0.1 --port 7003 `
|
||||
& '.venv\Scripts\python.exe' test\host\latency_peer.py --mode remo --host 127.0.0.1 --port 7003 `
|
||||
--samples 50 --json "docs\测试说明\测试数据\m3_data\m3_sim_quiet.json"
|
||||
# 尾批定性/解法(都不需要抓包工具)
|
||||
& '.venv\Scripts\python.exe' test\latency_peer.py --mode remo --host 192.168.1.100 --port 7003 `
|
||||
& '.venv\Scripts\python.exe' test\host\latency_peer.py --mode remo --host 192.168.31.100 --port 7003 `
|
||||
--samples 30 --ack-probe --json "docs\测试说明\测试数据\m3_data\m3_tail_ackprobe.json" # 带内补 ACK
|
||||
& '.venv\Scripts\python.exe' test\latency_peer.py --mode remo --host 192.168.1.100 --port 7003 `
|
||||
& '.venv\Scripts\python.exe' test\host\latency_peer.py --mode remo --host 192.168.31.100 --port 7003 `
|
||||
--samples 30 --ack-fast --json "docs\测试说明\测试数据\m3_data\m3_tail_ackfast.json" # 关延迟 ACK
|
||||
```
|
||||
|
||||
|
||||
@@ -249,7 +249,7 @@
|
||||
|---|---|---|---|---|---|
|
||||
| **FTP 一套** | `lftpd.c`(694)、`lftpd_io.c`(207)、`lftpd_inet.c`(171)、`lftpd_string.c`(11) = 1,083 | 0.99/0.90/0.93 | 真实 `ff.h` + 假 diskio;复用 `net_socket.h` | `docs/测试说明/板级测试/FTP_Test_Guide.md`、`docs/子系统设计/网络配置说明.md` §3.4(`pwd_hash`=SHA-256(user‖password)、连续 5 次失败锁 60 s、默认口令启动告警) | **20 次提交里 6 次是 fix**,最近两条都是"静默型":LIST/NLST 满块被截断回 550、对端行为误打 `[ERR]`(2026-10-23)——覆盖率最擅长照的就是这类"日志看不出根因" |
|
||||
| **NET 拆出来的四块** | `net_pending.c`(287)、`net_events.c`(263)、`net_listener.c`(191)、`net_select.c`(162) = 903 | 0.90/0.78/–/0.93 | **新建 `stub/ch395f.h`**(芯片寄存器只到函数边界)+ 假任务通知;`net_socket.h` 已有 | `docs/网络/网络自愈架构设计.md` §4.10(socket 读清点审计 + 新增一处读清的三条准入判据)、`docs/网络/Net层阻塞模型架构设计.md` | 挂起 recv、监听按代次重建、退避这些**语义在真机上极难复现**;这一族的 网络自愈("顺手全量清一遍把别的 socket 门焊死")与 N34 E14 都是 fix 出来的真事 |
|
||||
| **配置与工具(最便宜,建议第一个落地)** | `net_cfg.c`(167)、`task_prof.c`(160)、`ftp_cfg.c`(59)、`prot_set_store.c`(43) = 429 | 1.00/0.97/–/– | 真实头即可(`cfg_file.h` 已被现有单测证明能在 PC 上编),最多补 `dbg_log.h` | `docs/子系统设计/网络配置说明.md`(工厂默认 192.168.1.100/24、MAC 全零=芯片内置、保存立即生效)、`docs/算法/采集与算法层设计说明.md` | 硬件符号 0~2 处,纯解析/编解码/格式化。**一天内能出第一份绿**,用来把"新增 `files_tested`"这条路先跑通 |
|
||||
| **配置与工具(最便宜,建议第一个落地)** | `net_cfg.c`(167)、`task_prof.c`(160)、`ftp_cfg.c`(59)、`prot_set_store.c`(43) = 429 | 1.00/0.97/–/– | 真实头即可(`cfg_file.h` 已被现有单测证明能在 PC 上编),最多补 `dbg_log.h` | `docs/子系统设计/网络配置说明.md`(工厂默认 192.168.31.100/24、MAC 全零=芯片内置、保存立即生效)、`docs/算法/采集与算法层设计说明.md` | 硬件符号 0~2 处,纯解析/编解码/格式化。**一天内能出第一份绿**,用来把"新增 `files_tested`"这条路先跑通 |
|
||||
| **104 服务层** | `iec104_serv.c`(202) | 0.96 | 复用 `time_sync`/stub 的 `cmsis_os2.h` + 已有 `net_socket.h` | 与 `test/host/iec104/`(97 用例)同一套脚手架 | 同族的 `iec104_pts.c` 现在只有 **67.2%**(全仓最低之一);服务层进来才能把 YK/YX 编排的分支照全 |
|
||||
|
||||
**落地进度(2026-10-23,同日推进)**:
|
||||
|
||||
@@ -74,7 +74,7 @@ UDP 路径 `net_socket()` 中对 Socket 4~7 的兜底重设使用同一布局。
|
||||
### 测试环境
|
||||
|
||||
```
|
||||
PC (192.168.1.2) ──── 交换机 ──── CH395F (192.168.1.100)
|
||||
PC (192.168.31.2) ──── 交换机 ──── CH395F (192.168.31.100)
|
||||
MCU: STM32F407ZGTx @ 168MHz, Keil MDK-ARM v5 (ARMCC)
|
||||
```
|
||||
|
||||
@@ -120,8 +120,8 @@ MCU: STM32F407ZGTx @ 168MHz, Keil MDK-ARM v5 (ARMCC)
|
||||
|----|------|----------|----------|
|
||||
| 1 | `ch395f_check_exist()`<br>SPI写: CMD=0x06, DATA=0x57<br>回读: ~0x57 = 0xA8 | 返回 `0x00`(`CH395F_ERR_SUCCESS`)<br>= 回读字节 `0xA8` 匹配 `~0x57` | 返回 `0xFF`(`CH395F_STATUS_NOT_DETECTED`)<br>= 回读字节 ≠ `0xA8`,回显取反不匹配 |
|
||||
| 2 | `ch395f_get_version()` | 版本值 == `0x4A`(CH395F 芯片版本) | 版本值 ≠ `0x4A`(芯片不匹配或未响应) |
|
||||
| 3 | `ch395f_set_ip_addr(192.168.1.100)` → `ch395f_get_ip_inf()` 回读 IP | `ip_info[0..3] == 192.168.1.100` | 任意字节不匹配(写入/回读不一致) |
|
||||
| 4 | `ch395f_set_gwip_addr(192.168.1.1)` → `ch395f_get_ip_inf()` 回读 GW | `ip_info[4..7] == 192.168.1.1` | 任意字节不匹配 |
|
||||
| 3 | `ch395f_set_ip_addr(192.168.31.100)` → `ch395f_get_ip_inf()` 回读 IP | `ip_info[0..3] == 192.168.31.100` | 任意字节不匹配(写入/回读不一致) |
|
||||
| 4 | `ch395f_set_gwip_addr(192.168.31.1)` → `ch395f_get_ip_inf()` 回读 GW | `ip_info[4..7] == 192.168.31.1` | 任意字节不匹配 |
|
||||
| 5 | `ch395f_set_mask_addr(255.255.255.0)` → `ch395f_get_ip_inf()` 回读 MASK | `ip_info[8..11] == 255.255.255.0` | 任意字节不匹配 |
|
||||
| 6 | `ch395f_get_glob_int_status_all()`(16 位)<br>注:测试入口处已预读一次清除 `PHY_CHANGE` 残留(`net_stack_bring_up()` 强制 PHY 重协商 + 等待链路期间锁存,硬件层模式无 netTask 消费) | 返回值 == `0x0000`(无待处理中断) | 返回值 ≠ `0x0000`(有残留中断未清除) |
|
||||
| 7 | `ch395f_open_socket(0)` → `ch395f_close_socket(0)` → `ch395f_get_cmd_status()` | `CMD_STATUS == 0x00`(`CH395F_ERR_SUCCESS`) | `CMD_STATUS` 非 `0x00`(Socket 操作失败) |
|
||||
@@ -161,7 +161,7 @@ MCU: STM32F407ZGTx @ 168MHz, Keil MDK-ARM v5 (ARMCC)
|
||||
|
||||
| 步 | 操作 | 成功标准 | 失败标准 |
|
||||
|----|------|----------|----------|
|
||||
| 1 | `ch395f_set_proto_type(0, CH395F_PROTO_TYPE_TCP)` + 设置目标 IP `192.168.1.2`、端口 `8081`、本地端口 `50000` | 配置写入成功(CMD_STATUS == `0x00`) | 配置失败(SPI 异常或寄存器未更新) |
|
||||
| 1 | `ch395f_set_proto_type(0, CH395F_PROTO_TYPE_TCP)` + 设置目标 IP `192.168.31.2`、端口 `8081`、本地端口 `50000` | 配置写入成功(CMD_STATUS == `0x00`) | 配置失败(SPI 异常或寄存器未更新) |
|
||||
| 2 | `ch395f_open_socket(0)` 打开 Socket 0 | 返回 `CH395F_ERR_SUCCESS`(`0x00`) | 返回值非 `0x00`(Socket 硬件异常或 SPI 通信失败) |
|
||||
| 3 | `ch395f_tcp_connect(0)` 发起 TCP 连接 | 返回 `CH395F_ERR_SUCCESS`(`0x00`) | 返回值非 `0x00`(连接命令下发失败) |
|
||||
| 4 | 轮询 `GET_GLOB_INT_STATUS` 的 `(sock+4)` 位 + `SINT_STAT` 等待 `CH395F_SINT_STAT_CONNECT`,超时 10s | 检测到 CONNECT 中断(连接已建立,进入 ESTABLISHED) | 超时未建立连接(目标不可达 / 链路异常) |
|
||||
@@ -210,13 +210,13 @@ MCU: STM32F407ZGTx @ 168MHz, Keil MDK-ARM v5 (ARMCC)
|
||||
| **优先级** | P1 |
|
||||
| **类型** | 负向测试(硬件层) |
|
||||
| **标题** | 目标端口无服务时连接超时 |
|
||||
| **前置条件** | 1. PC **未**运行 TCP Server(`192.168.1.2:8081` 无监听)<br>2. TC-NET-201 通过 |
|
||||
| **前置条件** | 1. PC **未**运行 TCP Server(`192.168.31.2:8081` 无监听)<br>2. TC-NET-201 通过 |
|
||||
|
||||
**测试步骤与判定标准**:
|
||||
|
||||
| 步 | 操作 | 成功标准 | 失败标准 |
|
||||
|----|------|----------|----------|
|
||||
| 1 | `ch395f_set_proto_type(0, CH395F_PROTO_TYPE_TCP)` + 设置目标 IP `192.168.1.2`、端口 `8081` | 配置写入成功(CMD_STATUS == `0x00`) | 配置失败(SPI 异常或寄存器未更新) |
|
||||
| 1 | `ch395f_set_proto_type(0, CH395F_PROTO_TYPE_TCP)` + 设置目标 IP `192.168.31.2`、端口 `8081` | 配置写入成功(CMD_STATUS == `0x00`) | 配置失败(SPI 异常或寄存器未更新) |
|
||||
| 2 | `ch395f_open_socket(0)` → `ch395f_tcp_connect(0)` | OPEN / CONNECT 均返回 `CH395F_ERR_SUCCESS`(`0x00`),命令异步下发不立即报错 | 命令返回值非 `0x00`(Socket 硬件异常) |
|
||||
| 3 | 轮询 `GET_GLOB_INT_STATUS` 的 `(sock+4)` 位,等待负向结果,超时窗 30s;同时扫全局 `UNREACH` 位作备注 | 收到 `SOCK_TIMEOUT` 或 `DISCONNECT`,且期间未收到 `CH395F_SINT_STAT_CONNECT`。按耗时细分:<br>**<3s** = RST 快速拒绝(端口关闭,实测主路径——芯片毫秒级上报 SOCK_TIMEOUT)<br>**≥3s** = 真无应答(离线/防火墙丢包)。全局 `UNREACH`(ARP 失败)仅备注不影响判定 | 误收到 `CONNECT`(PC 服务未关闭,环境错误——串口给出明确指引)或 30s 内无任何中断(状态机挂死) |
|
||||
| 4 | `ch395f_close_socket(0)` 并轮询 `GET_SOCKET_STATUS` 等待 `CH395F_SOCKET_CLOSED` | Socket 正常关闭、系统无崩溃 / 死锁 | 关闭异常或任务挂死 |
|
||||
@@ -277,7 +277,7 @@ MCU: STM32F407ZGTx @ 168MHz, Keil MDK-ARM v5 (ARMCC)
|
||||
| **优先级** | P0 |
|
||||
| **类型** | 功能测试(硬件层) |
|
||||
| **标题** | 30 轮 64B UDP 数据报回显 |
|
||||
| **前置条件** | PC: `python test/host/ch395f_socket_test.py udp_client --ip 192.168.1.100 --port 60000` |
|
||||
| **前置条件** | PC: `python test/host/ch395f_socket_test.py udp_client --ip 192.168.31.100 --port 60000` |
|
||||
|
||||
> **会话结构**(固件单会话,与 udp_client 脚本约定):累计 **60 个有效数据包**后关闭 Socket——第 1~30 轮对应本用例(PC 发 64B),第 31~60 轮对应 TC-NET-302(变长);脚本 `"HELLO"` 就绪探针只回显、**不计数**,不占用用例预算。
|
||||
|
||||
@@ -341,7 +341,7 @@ CH395F PC (dhcp_server)
|
||||
|
||||
- **xid/chaddr 回填**:OFFER/ACK 必须原样回传 DISCOVER 的 `xid([4:8])` 与 `chaddr([28:34])`(TRAP-NET-03:早期 xid 偏移错误导致芯片丢弃响应)
|
||||
- **option53 位置**:报文类型在 `data[242]`(236B 固定头 + magic `63825363` + option 偏移),`len<=250` 视为无效包
|
||||
- **双广播发送**:OFFER/ACK 同时发 `255.255.255.255` 与 `192.168.1.255`(规避 Windows 定向广播路由限制)
|
||||
- **双广播发送**:OFFER/ACK 同时发 `255.255.255.255` 与 `192.168.31.255`(规避 Windows 定向广播路由限制)
|
||||
- **REQUEST 重试**:PC 最多等 8×5s;期间收到重复 DISCOVER 则重发 OFFER
|
||||
|
||||
**固件会话结构**(phase4_run):
|
||||
@@ -364,7 +364,7 @@ CH395F PC (dhcp_server)
|
||||
| **优先级** | P0 |
|
||||
| **类型** | 功能测试(硬件层) |
|
||||
| **标题** | DISCOVER → OFFER → REQUEST → ACK 全流程获取 IP |
|
||||
| **前置条件** | 管理员 PowerShell: `python test/host/ch395f_socket_test.py dhcp_server --ip 192.168.1.77 --dhcp-iface 192.168.1.2`(`--ip` 建议 ≠ 静态 IP,以证明确为动态获取) |
|
||||
| **前置条件** | 管理员 PowerShell: `python test/host/ch395f_socket_test.py dhcp_server --ip 192.168.31.77 --dhcp-iface 192.168.31.2`(`--ip` 建议 ≠ 静态 IP,以证明确为动态获取) |
|
||||
|
||||
**测试步骤与判定标准**:
|
||||
|
||||
@@ -551,7 +551,7 @@ MCU (TCP Client, ch395f_* 裸命令) PC (tcp_bulk --port 8081)
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
PC["PC(Python)<br/>tcp_client / tcp_server"] -->|"TCP 8080 · 以太网"| CH["CH395F(192.168.1.100)<br/>Socket 0(单连接复用)"]
|
||||
PC["PC(Python)<br/>tcp_client / tcp_server"] -->|"TCP 8080 · 以太网"| CH["CH395F(192.168.31.100)<br/>Socket 0(单连接复用)"]
|
||||
CH -->|"SPI2(分频=8)"| MCU["MCU(STM32F407)<br/>netTask: net_poll() 10ms<br/>testTask: net_layer_test_main()<br/>└─ phase6_run() 原样回显"]
|
||||
```
|
||||
|
||||
@@ -593,7 +593,7 @@ sequenceDiagram
|
||||
| **优先级** | P0 |
|
||||
| **类型** | 功能测试 |
|
||||
| **标题** | Socket 0:OPEN → TCP_LISTEN → ESTABLISHED(单连接) |
|
||||
| **前置条件** | 1. `net_init("192.168.1.100")` 成功、SYS_EVT_NET_READY 已广播(netTask 周期 `net_poll()` 运行)<br>2. `net_layer_test_main()` 已 `net_socket`+`net_bind(8080)`+`net_listen`(进入 LISTEN)<br>3. PC: `python .\test\ch395f_socket_test.py tcp_client --ip 192.168.1.100 --port 8080` |
|
||||
| **前置条件** | 1. `net_init("192.168.31.100")` 成功、SYS_EVT_NET_READY 已广播(netTask 周期 `net_poll()` 运行)<br>2. `net_layer_test_main()` 已 `net_socket`+`net_bind(8080)`+`net_listen`(进入 LISTEN)<br>3. PC: `python .\test\ch395f_socket_test.py tcp_client --ip 192.168.31.100 --port 8080` |
|
||||
|
||||
**测试步骤与判定标准**:
|
||||
|
||||
@@ -751,7 +751,7 @@ net_socket(NET_AF_INET, NET_SOCK_STREAM) // 取空闲 Socket(非监听 So
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
MCU["MCU(STM32F407)<br/>netTask: net_poll() 10ms<br/>testTask: net_layer_client_test_main()<br/>└─ net_connect → 收发 → close"] -->|"SPI2(分频=8)"| CH["CH395F(192.168.1.100)<br/>Socket N(非 0 空闲)"]
|
||||
MCU["MCU(STM32F407)<br/>netTask: net_poll() 10ms<br/>testTask: net_layer_client_test_main()<br/>└─ net_connect → 收发 → close"] -->|"SPI2(分频=8)"| CH["CH395F(192.168.31.100)<br/>Socket N(非 0 空闲)"]
|
||||
CH -->|"TCP 8081 · 以太网"| PC["PC(Python)<br/>tcp_server(回显服务器)"]
|
||||
```
|
||||
|
||||
@@ -796,7 +796,7 @@ sequenceDiagram
|
||||
| 步 | 操作 | 成功标准 | 失败标准 |
|
||||
|----|------|----------|----------|
|
||||
| 1 | `net_socket(NET_AF_INET, NET_SOCK_STREAM)` 创建 TCP socket | 返回 sockfd(`0~7`),非 `-1` | 返回 `-1`(无空闲 Socket 或 net 层未初始化) |
|
||||
| 2 | 构造 `struct net_sockaddr_in`(sin_family=`NET_AF_INET`,sin_port=`net_htons(8081)`,sin_addr=`net_inet_addr("192.168.1.2")`)后 `net_connect(sockfd, &addr, len)` | 返回 `0`(连接命令已异步下发) | 返回 `-1`(地址非法或协议栈异常) |
|
||||
| 2 | 构造 `struct net_sockaddr_in`(sin_family=`NET_AF_INET`,sin_port=`net_htons(8081)`,sin_addr=`net_inet_addr("192.168.31.2")`)后 `net_connect(sockfd, &addr, len)` | 返回 `0`(连接命令已异步下发) | 返回 `-1`(地址非法或协议栈异常) |
|
||||
| 3 | 在 netTask 周期 `net_poll()` 推进下,调用 `net_select(sockfd+1, NULL, &wfds, NULL, &tv)` 等待可写事件,超时 10s | 返回正数且 `NET_FD_ISSET(sockfd)` 指示连接建立(ESTABLISHED) | 超时未连接,`net_errno == NET_ERR_WOULDBLOCK` 持续 |
|
||||
| 4 | `net_send(sockfd, buf, 64, 0)` 发送 64 字节递增模式数据(`0x00..0x3F`) | 返回值 == `64`(全部发出) | 返回值 `< 0`(发送失败)或 `≠ 64`(未完全发出) |
|
||||
| 5 | `net_recv(sockfd, buf, 64, 0)` 阻塞接收回显,超时 10s | 返回值 == `64`、与原数据逐字节一致、且固件字节级比对 + 累加和 `TEST_CHECK` 通过 | 返回值 `< 0`(超时/断开)或 `≠ 64`(数据不完整)或任意字节不符 或 固件 `TEST_CHECK` 失败 |
|
||||
@@ -837,7 +837,7 @@ sequenceDiagram
|
||||
| **优先级** | P1 |
|
||||
| **类型** | 负向测试(NET 层) |
|
||||
| **标题** | 目标端口无服务时 net_connect 超时 |
|
||||
| **前置条件** | 1. PC **未**运行 TCP Server(`192.168.1.2:8081` 无监听)<br>2. TC-NET-701 通过 |
|
||||
| **前置条件** | 1. PC **未**运行 TCP Server(`192.168.31.2:8081` 无监听)<br>2. TC-NET-701 通过 |
|
||||
|
||||
**测试步骤与判定标准**:
|
||||
|
||||
@@ -867,7 +867,7 @@ sequenceDiagram
|
||||
|
||||
| 步 | 操作 | 成功标准 | 失败标准 |
|
||||
|----|------|----------|----------|
|
||||
| 1 | 循环 i=0..4:`net_socket()` 创建 5 个 TCP socket(本地端口 51000+i),`net_connect(192.168.1.2:8081)` | 5 个 `net_connect` 均返回 `0` | 任一返回 `-1` |
|
||||
| 1 | 循环 i=0..4:`net_socket()` 创建 5 个 TCP socket(本地端口 51000+i),`net_connect(192.168.31.2:8081)` | 5 个 `net_connect` 均返回 `0` | 任一返回 `-1` |
|
||||
| 2 | netTask `net_poll()` 推进下,`net_select` 等待全部 5 路可写 | 5 路均在 10s 内 ESTABLISHED | 任一超时未建立 |
|
||||
| 3 | 每路 `net_send(sockfd, 64B)` → `net_recv(sockfd, 64B)` 校验 | 5 路收发各 64B、字节级比对 + 累加和 `TEST_CHECK` 通过 | 任一收发失败 / 数据不符 / `TEST_CHECK` 失败 |
|
||||
|
||||
@@ -889,7 +889,7 @@ sequenceDiagram
|
||||
| **耗时** | 取决于文件大小与速率(100KB 约数秒) |
|
||||
| **入口** | `ENABLE_PHASE8_TESTS` |
|
||||
| **配置** | `PHASE8_FILE_SIZE`(默认 102400 = 100KB);`PHASE8_DIRECTION`(SEND / RECV / ECHO,默认 ECHO) |
|
||||
| **PC 配合** | `python ./test/host/ch395f_socket_test.py tcp_file --ip 192.168.1.100 --port 8080 --op recv --file rx_100k.bin --size 102400`(文件发送)<br>`... --op send --file tx_100k.bin --size 102400`(文件接收) |
|
||||
| **PC 配合** | `python ./test/host/ch395f_socket_test.py tcp_file --ip 192.168.31.100 --port 8080 --op recv --file rx_100k.bin --size 102400`(文件发送)<br>`... --op send --file tx_100k.bin --size 102400`(文件接收) |
|
||||
|
||||
> 架构:MCU 为 TCP Server(`net_test_task` 监听 8080,`net_accept` 后 `phase8_run(acc)`);PC 用 `tcp_file` 子命令作 Client 连接 MCU:8080。一次 `phase8_run` 对应一次 PC 连接。
|
||||
|
||||
@@ -912,7 +912,7 @@ sequenceDiagram
|
||||
| **优先级** | P0 |
|
||||
| **类型** | 功能测试(文件发送) |
|
||||
| **标题** | MCU 流式发送 100KB 至 PC 并落盘校验 |
|
||||
| **前置条件** | 1. PC: `python ./test/host/ch395f_socket_test.py tcp_file --ip 192.168.1.100 --port 8080 --op recv --file rx_100k.bin --size 102400`(先连接等待数据)<br>2. `ENABLE_PHASE8_TESTS`,`PHASE8_FILE_SIZE=102400`,`PHASE8_DIRECTION=SEND`<br>3. `net_init` 完成,MSS=1024 |
|
||||
| **前置条件** | 1. PC: `python ./test/host/ch395f_socket_test.py tcp_file --ip 192.168.31.100 --port 8080 --op recv --file rx_100k.bin --size 102400`(先连接等待数据)<br>2. `ENABLE_PHASE8_TESTS`,`PHASE8_FILE_SIZE=102400`,`PHASE8_DIRECTION=SEND`<br>3. `net_init` 完成,MSS=1024 |
|
||||
| **测试步骤** | 1. MCU `net_accept` 建链(PC 已连接)<br>2. 循环填充一个滑动窗口(≤ s_tx_buf)并调用 `net_send`;`net_send` 内部按硬件发送 FIFO(`NET_SEND_CHUNK_MAX`=1KB,见 TRAP-NET-16)自动拆分写入,直至 100KB 发完<br>3. PC 接收全部字节写入 `rx_100k.bin`,按递增模式或预置 CRC32 校验 |
|
||||
| **通过标准** | PC 收满 102400B 且逐字节/CRC32 校验一致,MCU 无发送错误 |
|
||||
| **覆盖原则** | DMA 边界安全(分块发送、DMA 边界)、缓冲架构(1KB 发送缓冲) |
|
||||
@@ -926,7 +926,7 @@ sequenceDiagram
|
||||
| **优先级** | P0 |
|
||||
| **类型** | 功能测试(文件接收) |
|
||||
| **标题** | PC 流式发送 100KB 文件,MCU 接收并校验 |
|
||||
| **前置条件** | 1. PC: `python ./test/host/ch395f_socket_test.py tcp_file --ip 192.168.1.100 --port 8080 --op send --file tx_100k.bin --size 102400`(先连接并发送;无文件则生成 100KB 递增模式)<br>2. 同 TC-NET-801(`PHASE8_DIRECTION=RECV`) |
|
||||
| **前置条件** | 1. PC: `python ./test/host/ch395f_socket_test.py tcp_file --ip 192.168.31.100 --port 8080 --op send --file tx_100k.bin --size 102400`(先连接并发送;无文件则生成 100KB 递增模式)<br>2. 同 TC-NET-801(`PHASE8_DIRECTION=RECV`) |
|
||||
| **测试步骤** | 1. MCU `net_accept` 建链(PC 已连接)<br>2. 循环 `net_recv`(≤2KB/次,保守一次读空)→ 按 offset 字节校验 + 累计 CRC32,直至收满 100KB<br>3. PC 在文件末尾附 4 字节 CRC32(小端);MCU 收齐后比对 CRC32 |
|
||||
| **通过标准** | MCU 收满 102400B,字节校验全过且 CRC32 匹配,无溢出/截断 |
|
||||
| **覆盖原则** | DMA 边界安全(接收缓冲 2KB 一次读空) |
|
||||
@@ -940,7 +940,7 @@ sequenceDiagram
|
||||
| **优先级** | P1 |
|
||||
| **类型** | 恢复/压力测试 |
|
||||
| **标题** | MCU 发 100KB 经 PC 回显原样返回,MCU 收齐校验 |
|
||||
| **前置条件** | MCU: `PHASE8_DIRECTION=ECHO`(net_accept 监听 8080);PC: `python ./test/host/ch395f_socket_test.py tcp_file --ip 192.168.1.100 --port 8080 --op echo`(PC 作 Client 连 MCU 并原样回显) |
|
||||
| **前置条件** | MCU: `PHASE8_DIRECTION=ECHO`(net_accept 监听 8080);PC: `python ./test/host/ch395f_socket_test.py tcp_file --ip 192.168.31.100 --port 8080 --op echo`(PC 作 Client 连 MCU 并原样回显) |
|
||||
| **测试步骤** | MCU 发 100KB → PC 回显 → MCU 收 100KB 字节校验 |
|
||||
| **通过标准** | 100KB 全过,验证 100KB 经回显链路完整 |
|
||||
| **覆盖原则** | 单连接 socket、DMA 边界安全 |
|
||||
@@ -1140,7 +1140,7 @@ WAIT_CLOSE 阶段已内置二段补发(只补一次),生产 net 层则靠
|
||||
|
||||
| 参数 | 默认值 | 说明 |
|
||||
|------|--------|------|
|
||||
| `--ip` | 192.168.1.100 | 目标 IP |
|
||||
| `--ip` | 192.168.31.100 | 目标 IP |
|
||||
| `--port` | 因模式而异 | 端口 |
|
||||
| `--count` | 10 | 测试次数 |
|
||||
| `--timeout` | 30 | 超时秒数 |
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
### 2.1 硬件与网络
|
||||
|
||||
- CH395F 网口经以太网连接到 PC 或同一台交换机。
|
||||
- PC 网卡与固件 IP **同网段**。固件默认静态 IP **192.168.1.100**(掩码 255.255.255.0);PC 可设 192.168.1.x(如 192.168.1.77)。
|
||||
- PC 网卡与固件 IP **同网段**。固件默认静态 IP **192.168.31.100**(掩码 255.255.255.0);PC 可设 192.168.31.x(如 192.168.31.77)。
|
||||
- **启动时序(2026-09-21 现行实现,取代旧文档的 `osDelay(7000)`)**:`netTask` 完成 `net_init()` + PHY 稳定后置 `SYS_EVT_NET_READY`;`defaultTask` 挂载卷 + 加载配置后置 `SYS_EVT_STORAGE_READY`;`ftpTask` 以 `osEventFlagsWait(两位, osFlagsWaitAll | osFlagsNoClear)` 等**两位同时就绪**再 `lftpd_start`。串口出现 `[FTP] waiting for connection...` 即可连接(实测:上电后约 0.5~1s,取决于存储挂载耗时)。
|
||||
- ⚠ **就绪位等待必须带 `osFlagsNoClear`**(2026-09-21 实证,详见 §8.6):`osEventFlagsWait` 默认**消费**所等待的位,若被其它等待者清掉,`ftpTask` 的 `WaitAll(两位)` 永不成立 → FTP 静默不监听。
|
||||
- **单客户端**:监听 socket 与数据通道复用,同一时刻只服务 1 个会话;上一个会话未 `QUIT` 就断开时,服务端约 30s 后才丢弃旧会话并重新 listen,期间新连接被拒(`WinError 10061`)。脚本已内置连接重试;**不要用裸 TCP 工具探测 21 端口**(探测本身会占掉唯一会话,见 §8.7)。
|
||||
@@ -51,14 +51,14 @@
|
||||
|
||||
## 4. PC 端脚本手测(主要手段)
|
||||
|
||||
所有脚本支持 `--host`(默认 `192.168.1.100`)、`--port`(默认 21)、`--user` / `--password`
|
||||
所有脚本支持 `--host`(默认 `192.168.31.100`)、`--port`(默认 21)、`--user` / `--password`
|
||||
(默认出厂账号 `admin` / `admin`;设备口令改过就要显式传,**没有匿名通道**),在 `test/` 目录运行;`ftp_up_dl_test.py` / `ftp_speed_test.py` 内置**连接重试**(单客户端:旧会话未释放时自动等待重试,默认 6 次 × 3s)。
|
||||
推荐入口:`& '.venv\Scripts\python.exe' test/host/ftp_up_dl_test.py`(功能闭环:登录/TYPE I/PASV/STOR/LIST/RETR/比对/DELE/QUIT)与 `& '.venv\Scripts\python.exe' test/host/ftp_speed_test.py --size 128`(大文件 + 吞吐);后者同时是 **ftpTask 栈水位测量**的负载(见 `docs/内存管理/RAM使用分析与优化方案.md` §4.0.6)。
|
||||
|
||||
### 4.1 冒烟测试:`ftp_test.py`
|
||||
|
||||
- 用途:验证连接、登录、`PWD`、`PASV`、`LIST` 基本链路。
|
||||
- 命令:`python ./test/host/ftp_test.py --host 192.168.1.100`
|
||||
- 命令:`python ./test/host/ftp_test.py --host 192.168.31.100`
|
||||
- 预期:
|
||||
- 连接成功并读到 `220` 欢迎;
|
||||
- `USER admin` 返回 `331`(需要口令)、`PASS admin` 返回 `230`;
|
||||
@@ -70,7 +70,7 @@
|
||||
### 4.2 上传 / 下载 / 比对:`ftp_up_dl_test.py`
|
||||
|
||||
- 用途:验证 `STOR`/`RETR`/`DELE` 与数据一致性(`TYPE I` 二进制 + `PASV`)。
|
||||
- 命令:`python ./test/host/ftp_up_dl_test.py --host 192.168.1.100`
|
||||
- 命令:`python ./test/host/ftp_up_dl_test.py --host 192.168.31.100`
|
||||
- 流程:登录 → `TYPE I` → `STOR up_test.dat` → `LIST` 校验存在 → `RETR up_test.dat` → 逐字节比对 → `DELE` 清理 → `QUIT`。
|
||||
- 预期:`*** MATCH! Upload/Download success. ***`,且 LIST 中出现 `up_test.dat`。
|
||||
- 判据:上传/下载字节数相等且内容逐字节一致。
|
||||
@@ -78,7 +78,7 @@
|
||||
### 4.3 速度与大数据量:`ftp_speed_test.py`
|
||||
|
||||
- 用途:测量上传/下载吞吐,作回归基线,同时验证大文件不丢字节。
|
||||
- 命令:`python ./test/host/ftp_speed_test.py --host 192.168.1.100 --size 512`(默认 512KB,`--size` 可调)。
|
||||
- 命令:`python ./test/host/ftp_speed_test.py --host 192.168.31.100 --size 512`(默认 512KB,`--size` 可调)。
|
||||
- 预期:上传/下载均返回 `226`,回读 `MATCH!`,打印 KB/s。
|
||||
- 注意:脚本使用 8.3 文件名 `SPEEDTST.DAT`(**FTP 仅支持 8.3 短文件名**,见 §8.3);以回读比对(MATCH)为最终判据,中间打印的 Sent 字段仅供参考。
|
||||
- 判据:size 一致 + MATCH + 速度稳定(受 SPI2 分频 8 限制,通常约 300~450 KB/s,参见 `CH395F_Test_Guide.md` 阶段 5 吞吐基线)。
|
||||
@@ -106,7 +106,7 @@
|
||||
|
||||
## 5. GUI 客户端手测(可选)
|
||||
|
||||
- **FileZilla**:主机 `192.168.1.100`,端口 21,用户 `admin`、密码 `admin`(**匿名会被 530 拒**);可拖拽上传/下载、浏览目录。
|
||||
- **FileZilla**:主机 `192.168.31.100`,端口 21,用户 `admin`、密码 `admin`(**匿名会被 530 拒**);可拖拽上传/下载、浏览目录。
|
||||
- 要点:使用二进制模式传输;文件名遵守 8.3;**一次只连一个客户端**。
|
||||
|
||||
---
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
|
||||
```bash
|
||||
# 一键闭环(selftest.log 自动 FTP 抓取;无故障记录 = PASS)
|
||||
& '.venv\Scripts\python.exe' .dsh/skills/serial-boot-test/scripts/run_boot_test.py --require-selftest-pass --device-ip 192.168.1.100
|
||||
& '.venv\Scripts\python.exe' .dsh/skills/serial-boot-test/scripts/run_boot_test.py --require-selftest-pass --device-ip 192.168.31.100
|
||||
|
||||
# 或手动联合判定(本轮串口日志 + selftest.log 本地副本)
|
||||
& '.venv\Scripts\python.exe' .dsh/skills/serial-boot-test/scripts/verify_log.py \
|
||||
|
||||
@@ -208,7 +208,7 @@ D:/Code/DTU Code/
|
||||
|
||||
- 串口 `COM6` @115200
|
||||
- ST-LINK SN `0B250D12A218303030303032`
|
||||
- 设备 IP `192.168.1.100`
|
||||
- 设备 IP `192.168.31.100`
|
||||
|
||||
机制:`_wt/.state/locks/{build,bench}.lock` 记录持有者(任务 ID + pid + 时间戳 + 备注 + 自报 TTL)。
|
||||
|
||||
|
||||
@@ -553,9 +553,9 @@ $env:DTU_KEIL_UV4 = 'D:\NotExist\UV4.exe' # 仅当前会话,不动用户级
|
||||
|
||||
| 参数 | 工厂默认 | 修改方式 |
|
||||
|---|---|---|
|
||||
| IP | **192.168.1.100**(静态,无 DHCP) | 屏幕 `通讯参数 → 网口设置`(修改密码 `123`)保存后**立即生效**(网络重建约 1~3 s);或预置 `/config.ini`(INI;旧版 `/cfg/netcfg.bin` **不再读取**——存在则忽略、不迁移,配置回落工厂默认,2026-10-10 起) |
|
||||
| IP | **192.168.31.100**(静态,无 DHCP) | 屏幕 `通讯参数 → 网口设置`(修改密码 `123`)保存后**立即生效**(网络重建约 1~3 s);或预置 `/config.ini`(INI;旧版 `/cfg/netcfg.bin` **不再读取**——存在则忽略、不迁移,配置回落工厂默认,2026-10-10 起) |
|
||||
| 子网掩码 | 255.255.255.0(/24) | 同上 |
|
||||
| 默认网关 | 192.168.1.1 | 同上 |
|
||||
| 默认网关 | 192.168.31.1 | 同上 |
|
||||
| MAC | 全零 = 芯片内置 MAC | 同上(全零是"使用芯片内置 MAC"的哨兵,不是"MAC 为 0") |
|
||||
| PHY | 强制 100M 全双工 | 固件固定,不可配 |
|
||||
|
||||
@@ -583,7 +583,7 @@ $env:DTU_KEIL_UV4 = 'D:\NotExist\UV4.exe' # 仅当前会话,不动用户级
|
||||
| # | 项目 | 方法 | 通过标准 |
|
||||
|---|---|---|---|
|
||||
| 1 | 上电自启动 | 断电上电 + 串口采集 | `/serial-boot-test` PASS:Required `App init OK;Network Init;net init: OK;PHY: 100M FULL`,无 `FAIL/ERROR/HardFault` |
|
||||
| 2 | 网络连通 | PC ping 192.168.1.100 | 通(PHY 100M FULL) |
|
||||
| 2 | 网络连通 | PC ping 192.168.31.100 | 通(PHY 100M FULL) |
|
||||
| 3 | 远程显示 | DTU-RemoteLCD 连 7003 | 出图(160×160 1bpp)+ 远端菜单导航可用 |
|
||||
| 4 | FTP | FTP 客户端连 :21 | 列目录 / 读写 `/` 下文件 |
|
||||
| 5 | UI 功能 | 屏幕 / 远端操作 | 菜单 7 项导航、内容页、密码(查看 `000` / 修改 `123`)、网口设置保存后立即生效 |
|
||||
|
||||
@@ -222,7 +222,7 @@ int main(void)
|
||||
* 本项目中由 netTask 调用(网口配置已由 defaultTask 在就绪屏障前
|
||||
* 加载进 RAM 副本,netTask 只读副本组网)
|
||||
*/
|
||||
int ret = net_init("192.168.1.100", "255.255.255.0", "192.168.1.1", NULL);
|
||||
int ret = net_init("192.168.31.100", "255.255.255.0", "192.168.31.1", NULL);
|
||||
if (ret != 0) {
|
||||
printf("网络初始化失败!\r\n");
|
||||
return -1;
|
||||
@@ -258,7 +258,7 @@ int main(void)
|
||||
/* 外设初始化... */
|
||||
|
||||
/* BSD Socket API 初始化 */
|
||||
net_init("192.168.1.100", "255.255.255.0", "192.168.1.1", NULL);
|
||||
net_init("192.168.31.100", "255.255.255.0", "192.168.31.1", NULL);
|
||||
|
||||
/* 创建 Socket、绑定、监听... */
|
||||
|
||||
@@ -395,7 +395,7 @@ void tcp_client(void)
|
||||
/* 2. 设置服务器地址 */
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = net_htons(8080);
|
||||
addr.sin_addr.s_addr = net_inet_addr("192.168.1.200");
|
||||
addr.sin_addr.s_addr = net_inet_addr("192.168.31.200");
|
||||
|
||||
/* 3. 连接服务器 */
|
||||
printf("正在连接服务器...\r\n");
|
||||
@@ -473,7 +473,7 @@ void udp_client(void)
|
||||
/* 3. 设置目标地址 */
|
||||
dest_addr.sin_family = AF_INET;
|
||||
dest_addr.sin_port = net_htons(8888);
|
||||
dest_addr.sin_addr.s_addr = net_inet_addr("192.168.1.200");
|
||||
dest_addr.sin_addr.s_addr = net_inet_addr("192.168.31.200");
|
||||
|
||||
/* 4. 发送数据 */
|
||||
const char *msg = "UDP Hello!";
|
||||
@@ -726,7 +726,7 @@ void event_callback_example(void)
|
||||
### 9.0 `s_addr` 的唯一约定(2026-10-24 统一;全仓只此一族,勿再引入第二套)
|
||||
|
||||
**定义**:`sin_addr.s_addr` 一律存**网络字节序整数**,判据是 `&s_addr` 的**第 0 个内存字节 == 点分第一段**。
|
||||
小端主机(STM32F407 与 PC 模拟器都是)上 `"192.168.1.100"` 的数值 = **`0x6401A8C0`**(内存里是 `C0 A8 01 64`)。
|
||||
小端主机(STM32F407 与 PC 模拟器都是)上 `"192.168.31.100"` 的数值 = **`0x641FA8C0`**(内存里是 `C0 A8 1F 64`)。
|
||||
|
||||
| 方向 | 用哪个 API | 要点 |
|
||||
|---|---|---|
|
||||
@@ -759,11 +759,11 @@ uint16_t host_port = net_ntohs(net_port);
|
||||
|
||||
```c
|
||||
/* 字符串转网络序 IP */
|
||||
uint32_t ip = net_inet_addr("192.168.1.100");
|
||||
uint32_t ip = net_inet_addr("192.168.31.100");
|
||||
|
||||
/* 网络序 IP 转字符串 */
|
||||
char ip_str[16];
|
||||
net_inet_ntoa(ip, ip_str); /* ip_str = "192.168.1.100" */
|
||||
net_inet_ntoa(ip, ip_str); /* ip_str = "192.168.31.100" */
|
||||
```
|
||||
|
||||
### 9.3 填充地址结构体
|
||||
@@ -773,7 +773,7 @@ struct net_sockaddr_in addr;
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = net_htons(8080); /* 端口转换 */
|
||||
addr.sin_addr.s_addr = net_inet_addr("192.168.1.100"); /* IP 转换 */
|
||||
addr.sin_addr.s_addr = net_inet_addr("192.168.31.100"); /* IP 转换 */
|
||||
|
||||
/* 如果要绑定任意地址 */
|
||||
addr.sin_addr.s_addr = net_inet_addr("0.0.0.0");
|
||||
@@ -1180,7 +1180,7 @@ NET_FD_ISSET(fd, fdset) /* 检查 fd 是否在集合中 */
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define SERVER_IP "192.168.1.200"
|
||||
#define SERVER_IP "192.168.31.200"
|
||||
#define SERVER_PORT 8080
|
||||
|
||||
void tcp_client_reconnect(void)
|
||||
@@ -1191,7 +1191,7 @@ void tcp_client_reconnect(void)
|
||||
uint32_t reconnect_interval = 5000; /* 5 秒重连间隔 */
|
||||
|
||||
/* 初始化网络 */
|
||||
net_init("192.168.1.100", "255.255.255.0", "192.168.1.1", NULL);
|
||||
net_init("192.168.31.100", "255.255.255.0", "192.168.31.1", NULL);
|
||||
|
||||
while (1)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user