test(net/udp): 阶段 16 台架加固 + 真机首跑证据回填(#73)
第一次上真机把台架的两处软肋照出来了,都不是被测代码的问题: - peer 死在 Windows 的 ICMP 10054:板子还没 bind 时那一下端口不可达会被记在套接句上, 下一次 recvfrom 才抛出来。本机 CPython 3.14.7 既没有 socket.SIO_UDP_CONNRESET 也不接受 它的数值形式,所以主力防线改成把 10054 当「这一轮没收到」继续重试,并在回路自检里加 冷端口探针——探针走脚本真正在用的 _recv_maybe,另拿裸套接句证明这台机器确实会回 ICMP, 否则那条判定就没有牙。 - 单步预算错位:板端每步等 25 s,peer 每步只等 8 s,一步超时后整条梯子全灭。现在 peer 每步都重发、单步预算 --step-budget 默认 35 s(小于 26 s 打警告);板端 udp_bench_expect 按载荷第 0 字节的步号自愈,比本步小的旧包丢掉继续等(上限 UDP_BENCH_STALE_MAX = 8), 比本步大的直接报出来。DBG_WARN 在本工程不存在、字符串字面量必须纯 ASCII,两处已改。 真机已拿到的证据:TC-NET-1601a/b/c(建 socket、bind :6001、net_udp_get_mode 回 SERVER)与 TC-NET-1602(服务端形态收到 20 B、addrlen/sin_family/源端口全对、逐字节回显、形态翻成 CLIENT)全绿——剥 8 字节信息头与源地址回填在真芯片上成立;②③④⑤ 因板子当晚两次失电 (19:19、21:0x,SWD No target connected + ping 不通)未测,指南 §12.6 与覆盖率口径第 4 轮 的状态条据此改写。产品态(宏回默认)重新构建 0 Error 0 Warning,Code 249,124 / RO 29,836 / RW 2,052 / ZI 149,996 与本阶段之前逐字节一致,阶段 16 在产品里被预处理干净。
This commit is contained in:
+54
-18
@@ -1023,6 +1023,7 @@ void net_layer_test_main(void)
|
||||
#define UDP_BENCH_LATE_BUDGET 30000U /* 迟发包那一步的等待预算(比 PC 迟发时刻宽得多) */
|
||||
#define UDP_BENCH_LATE_MIN_MS 7000U /* 迟发包实测等待的下界 */
|
||||
#define UDP_BENCH_LATE_MAX_MS 25000U /* 迟发包实测等待的上界 */
|
||||
#define UDP_BENCH_STALE_MAX 8U /* 单步最多丢掉几个旧步数据报(步序自愈的上限) */
|
||||
|
||||
static uint8_t s_udp_buf[UDP_BENCH_BUF_SIZE];
|
||||
|
||||
@@ -1095,27 +1096,62 @@ static int udp_bench_expect(int fd, uint8_t tag, int exp, int cap, uint32_t to_m
|
||||
{
|
||||
struct net_sockaddr_in from;
|
||||
int alen = (int)sizeof(from);
|
||||
uint32_t t_start;
|
||||
uint32_t left_ms;
|
||||
int stale = 0;
|
||||
int n;
|
||||
int bad;
|
||||
|
||||
(void)memset(&from, 0, sizeof(from));
|
||||
n = net_recvfrom_to(fd, s_udp_buf, cap, to_ms,
|
||||
(src != NULL) ? (struct net_sockaddr *)&from : NULL,
|
||||
(src != NULL) ? &alen : NULL);
|
||||
if (n < 0) {
|
||||
DBG_ERROR("%s: recv tag 0x%02X -> %d (errno=%d)", who, (unsigned)tag, n, net_get_errno());
|
||||
return -1;
|
||||
}
|
||||
if (n != exp) {
|
||||
DBG_ERROR("%s: tag 0x%02X len=%d expect=%d", who, (unsigned)tag, n, exp);
|
||||
return -1;
|
||||
}
|
||||
bad = udp_bench_match(s_udp_buf, n, tag);
|
||||
if (bad != 0) {
|
||||
DBG_ERROR("%s: tag 0x%02X pattern breaks at byte %d (got 0x%02X, want 0x%02X)",
|
||||
who, (unsigned)tag, bad - 1, s_udp_buf[bad - 1],
|
||||
(bad == 1) ? (unsigned)tag : (uint8_t)(((uint32_t)(bad - 1) * 7U + 0x11U) & 0xFFU));
|
||||
return -1;
|
||||
/*
|
||||
* 函数说明(步序自愈):步号写在载荷第 0 字节,所以先认步号再认内容。比本步小的
|
||||
* = 上一步超时后对端重发留下的旧包,丢掉继续等;比本步大的 = 对端抢跑(不该发生,
|
||||
* 报出来好定位)。没有这层判断时,任何一步只要超时一次,后面每一步都会错位 25 秒
|
||||
* ——2026-11-03 第一次上台架就是这样:1602 通了,1603 起整条梯子在 PC 侧 8 秒预算
|
||||
* 里全灭,分不清是板子的问题还是纯粹的错位。只允许有限次丢弃,防止对端脚本写错时
|
||||
* 把包无限吞掉。
|
||||
*/
|
||||
t_start = HAL_GetTick();
|
||||
for (;;) {
|
||||
if ((HAL_GetTick() - t_start) >= to_ms) {
|
||||
/* to_ms==0 在 net_recvfrom_to 里是「非法参数」(0 = 无限等由另一个入口表达),
|
||||
* 预算见底时不能再拿 0 去调它,否则报出来的是 INVAL 而不是超时。 */
|
||||
DBG_ERROR("%s: budget %ums exhausted before tag 0x%02X (stale drops=%d)",
|
||||
who, (unsigned)to_ms, (unsigned)tag, stale);
|
||||
return -1;
|
||||
}
|
||||
left_ms = to_ms - (HAL_GetTick() - t_start);
|
||||
(void)memset(&from, 0, sizeof(from));
|
||||
alen = (int)sizeof(from);
|
||||
n = net_recvfrom_to(fd, s_udp_buf, cap, left_ms,
|
||||
(src != NULL) ? (struct net_sockaddr *)&from : NULL,
|
||||
(src != NULL) ? &alen : NULL);
|
||||
if (n < 0) {
|
||||
DBG_ERROR("%s: recv tag 0x%02X -> %d (errno=%d)", who, (unsigned)tag, n, net_get_errno());
|
||||
return -1;
|
||||
}
|
||||
if (n < 1 || s_udp_buf[0] != tag) {
|
||||
if ((n >= 1) && (s_udp_buf[0] < tag) && ((unsigned)stale < UDP_BENCH_STALE_MAX)) {
|
||||
stale++;
|
||||
DBG_INFO("%s: drop stale tag 0x%02X (drop #%d), still waiting for 0x%02X",
|
||||
who, (unsigned)s_udp_buf[0], stale, (unsigned)tag);
|
||||
continue;
|
||||
}
|
||||
DBG_ERROR("%s: tag 0x%02X got 0x%02X (n=%d, stale drops=%d)",
|
||||
who, (unsigned)tag, (n >= 1) ? (unsigned)s_udp_buf[0] : 0U, n, stale);
|
||||
return -1;
|
||||
}
|
||||
if (n != exp) {
|
||||
DBG_ERROR("%s: tag 0x%02X len=%d expect=%d", who, (unsigned)tag, n, exp);
|
||||
return -1;
|
||||
}
|
||||
bad = udp_bench_match(s_udp_buf, n, tag);
|
||||
if (bad != 0) {
|
||||
DBG_ERROR("%s: tag 0x%02X pattern breaks at byte %d (got 0x%02X, want 0x%02X)",
|
||||
who, (unsigned)tag, bad - 1, s_udp_buf[bad - 1],
|
||||
(bad == 1) ? (unsigned)tag : (uint8_t)(((uint32_t)(bad - 1) * 7U + 0x11U) & 0xFFU));
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (src != NULL) {
|
||||
TEST_CHECK(alen == (int)sizeof(struct net_sockaddr_in),
|
||||
|
||||
Reference in New Issue
Block a user