Browse Source

ymoden 增加过滤策略,防止因日志输出导致协议误判,另外发送侧日志降级为debug

master
Lizongdi 3 days ago
parent
commit
95d9f5e66f
  1. 53
      peripheral/ymodem.c

53
peripheral/ymodem.c

@ -100,6 +100,34 @@ static enum rym_code _rym_read_code(struct rym_ctx *ctx, uint32_t timeout_ms)
return RYM_CODE_NONE; return RYM_CODE_NONE;
} }
/* 带杂字节容忍的协议码等待: 超时窗口内逐字节扫描, 只认 accept 集合,
* 其余字节忽略并记 debug 日志.
* 场景: MCU 固件里 elog 与 ymodem 共用控制台串口, FIN 间隙的对端日志
* (ANSI 色码 0x1B 开头 / 文本行) 会插在协议码之前, "首字节即协议码"
* 的 _rym_read_code 会把它误判成协议错误 (实测 got 0x1B → -113) */
static enum rym_code _rym_read_code_scan(struct rym_ctx *ctx, uint32_t timeout_ms,
const uint8_t *_pcAccept, size_t _nAccept)
{
uint32_t start = Rd_GetTime();
while (Rd_GetTime() - start < timeout_ms)
{
size_t rsz = ctx->dev.read(ctx->dev.opaque, ctx->buf, 1);
if (rsz == 1)
{
uint8_t ucByte = *ctx->buf;
for (size_t k = 0; k < _nAccept; k++)
{
if (ucByte == _pcAccept[k])
return (enum rym_code)ucByte;
}
log_d("ymodem: skip junk byte 0x%02X while waiting code", (unsigned)ucByte);
continue;
}
Rd_Delay(1);
}
return RYM_CODE_NONE;
}
static ssize_t _rym_read_data(struct rym_ctx *ctx, size_t len) static ssize_t _rym_read_data(struct rym_ctx *ctx, size_t len)
{ {
uint8_t *buf = ctx->buf + 1; uint8_t *buf = ctx->buf + 1;
@ -530,7 +558,13 @@ static int _rym_do_fin(struct rym_ctx *ctx)
ctx->on_end(ctx, ctx->buf + 3, 128); ctx->on_end(ctx, ctx->buf + 3, 128);
_rym_putchar(ctx, RYM_CODE_NAK); _rym_putchar(ctx, RYM_CODE_NAK);
code = _rym_read_code(ctx, RYM_WAIT_PKG_MS); /* 容忍杂字节扫描: 等发送端按双 EOT 约定补发的第二个 EOT.
* 发送端在收到 NAK 后可能正往同一条串口打日志 (共享控制台传输时),
* 首字节未必是 EOT, 不能用 _rym_read_code 直读 */
{
const uint8_t ucAccept[1] = { RYM_CODE_EOT };
code = _rym_read_code_scan(ctx, RYM_WAIT_PKG_MS, ucAccept, 1);
}
if (code != RYM_CODE_EOT) if (code != RYM_CODE_EOT)
{ {
log_e("ymodem RX FIN phase: expected EOT, got 0x%02X (0x00=timeout)", (unsigned)code); log_e("ymodem RX FIN phase: expected EOT, got 0x%02X (0x00=timeout)", (unsigned)code);
@ -540,13 +574,20 @@ static int _rym_do_fin(struct rym_ctx *ctx)
_rym_putchar(ctx, RYM_CODE_ACK); _rym_putchar(ctx, RYM_CODE_ACK);
_rym_putchar(ctx, RYM_CODE_C); _rym_putchar(ctx, RYM_CODE_C);
code = _rym_read_code(ctx, RYM_WAIT_PKG_MS); /* 等结束帧/下一文件包头, 同样容忍日志杂字节 */
{
const uint8_t ucAccept[2] = { RYM_CODE_SOH, RYM_CODE_STX };
code = _rym_read_code_scan(ctx, RYM_WAIT_PKG_MS, ucAccept, 2);
}
if (code == RYM_CODE_SOH) if (code == RYM_CODE_SOH)
data_sz = _RYM_SOH_PKG_SZ; data_sz = _RYM_SOH_PKG_SZ;
else if (code == RYM_CODE_STX) else if (code == RYM_CODE_STX)
data_sz = _RYM_STX_PKG_SZ; data_sz = _RYM_STX_PKG_SZ;
else else
{
log_e("ymodem RX FIN phase: expected header, got 0x%02X (0x00=timeout)", (unsigned)code);
return -RYM_ERR_CODE; return -RYM_ERR_CODE;
}
i = _rym_read_data(ctx, data_sz - 1); i = _rym_read_data(ctx, data_sz - 1);
if (i != (data_sz - 1)) if (i != (data_sz - 1))
@ -583,7 +624,11 @@ static int _rym_do_send_fin(struct rym_ctx *ctx)
data_sz = _RYM_SOH_PKG_SZ; data_sz = _RYM_SOH_PKG_SZ;
/* EOT 阶段: 对端回 NAK 表示"请再发一次 EOT", 直接回 ACK 表示收到, /* EOT 阶段: 对端回 NAK 表示"请再发一次 EOT", 直接回 ACK 表示收到,
* 不回(超时)也重发; 三种情况都不能当失败退出 (有些接收端要两三次才确认) */ * 不回(超时)也重发; 三种情况都不能当失败退出 (有些接收端要两三次才确认)
* 【注意】NAK 是本工程接收端 (_rym_do_fin) 的标准首次应答, 属正常路径;
* 日志只能打 debug —— MCU 固件里 elog 与 ymodem 共用控制台串口,
* 在两次 EOT 之间往线上打 WARN 会污染协议流 (接收端会把 ANSI 色码
* 0x1B 当协议码, 误报 -113), 见 _rym_read_code_scan 注释 */
for (retry = 0; ; retry++) for (retry = 0; ; retry++)
{ {
_rym_putchar(ctx, RYM_CODE_EOT); _rym_putchar(ctx, RYM_CODE_EOT);
@ -605,7 +650,7 @@ static int _rym_do_send_fin(struct rym_ctx *ctx)
return -RYM_ERR_ACK; return -RYM_ERR_ACK;
} }
log_w("ymodem TX fin: EOT %s -> resend (%u/%u)", log_d("ymodem TX fin: EOT %s -> resend (%u/%u)",
(getc_ack == RYM_CODE_NAK) ? "NAKed" : "no reply", (getc_ack == RYM_CODE_NAK) ? "NAKed" : "no reply",
(unsigned)(retry + 1), (unsigned)RYM_TX_RETRY_MAX); (unsigned)(retry + 1), (unsigned)RYM_TX_RETRY_MAX);
} }

Loading…
Cancel
Save