|
|
|
@ -100,6 +100,34 @@ static enum rym_code _rym_read_code(struct rym_ctx *ctx, uint32_t timeout_ms) |
|
|
|
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) |
|
|
|
{ |
|
|
|
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); |
|
|
|
|
|
|
|
_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) |
|
|
|
{ |
|
|
|
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_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) |
|
|
|
data_sz = _RYM_SOH_PKG_SZ; |
|
|
|
else if (code == RYM_CODE_STX) |
|
|
|
data_sz = _RYM_STX_PKG_SZ; |
|
|
|
else |
|
|
|
{ |
|
|
|
log_e("ymodem RX FIN phase: expected header, got 0x%02X (0x00=timeout)", (unsigned)code); |
|
|
|
return -RYM_ERR_CODE; |
|
|
|
} |
|
|
|
|
|
|
|
i = _rym_read_data(ctx, 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; |
|
|
|
|
|
|
|
/* 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++) |
|
|
|
{ |
|
|
|
_rym_putchar(ctx, RYM_CODE_EOT); |
|
|
|
@ -605,7 +650,7 @@ static int _rym_do_send_fin(struct rym_ctx *ctx) |
|
|
|
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", |
|
|
|
(unsigned)(retry + 1), (unsigned)RYM_TX_RETRY_MAX); |
|
|
|
} |
|
|
|
|