fix(ymodem): improve send read loop and unify session cleanup

- Accumulate short reads, mark finishing on EOF
- Track begin/end callback states and cleanup on error paths
- Add ACK handling with retry/error counting in send flow
This commit is contained in:
wdfk-prog
2026-02-27 09:54:28 +08:00
committed by Rbb666
parent 71fd98e56d
commit d8546a9a0f
3 changed files with 152 additions and 44 deletions
+21 -5
View File
@@ -7,6 +7,7 @@
* Date Author Notes
* 2019-12-09 Steven Liu the first version
* 2021-04-14 Meco Man Check the file path's legitimacy of 'sy' command
* 2026-02-01 wdfk-prog update ymodem transfer behaviors
*/
#include <rtthread.h>
@@ -157,20 +158,35 @@ static enum rym_code _rym_send_data(
{
struct custom_ctx *cctx = (struct custom_ctx *)ctx;
rt_size_t read_size;
int retry_read;
int rlen;
read_size = 0;
for (retry_read = 0; retry_read < 10; retry_read++)
/* Loop until we fill one YMODEM data block, hit EOF, or get a read error. */
while (read_size < len)
{
read_size += read(cctx->fd, buf + read_size, len - read_size);
if (read_size == len)
rlen = read(cctx->fd, buf + read_size, len - read_size);
if (rlen > 0)
{
read_size += rlen;
if (read_size == len)
break;
}
else if (rlen == 0)
{
/* EOF: mark finishing so sender switches to EOT after padding. */
ctx->stage = RYM_STAGE_FINISHING;
break;
}
else
{
/* Read error: abort transfer and report file error to the protocol. */
return RYM_ERR_FILE;
}
}
if (read_size < len)
{
rt_memset(buf + read_size, 0x1A, len - read_size);
ctx->stage = RYM_STAGE_FINISHING;
}
if (read_size > 128)
File diff suppressed because it is too large Load Diff
+34 -1
View File
@@ -9,6 +9,7 @@
* 2013-04-14 Grissiom initial implementation
* 2019-12-09 Steven Liu add YMODEM send protocol
* 2022-08-04 Meco Man move error codes to rym_code to silence warnings
* 2026-02-01 wdfk-prog update ymodem callbacks and error handling
*/
#ifndef __YMODEM_H__
@@ -81,13 +82,22 @@ enum rym_stage
};
struct rym_ctx;
/* When receiving files, the buf will be the data received from ymodem protocol
/**
* @brief YMODEM callback signature.
*
* @param ctx The context of the current session.
*
* @note When receiving files, the buf will be the data received from ymodem protocol
* and the len is the data size.
*
* When sending files, the len is the buf size in RYM. The callback need to
* fill the buf with data to send. Returning RYM_CODE_EOT will terminate the
* transfer and the buf will be discarded. Any other return values will cause
* the transfer continue.
*
* @note Keep this typedef unchanged for compatibility with external packages.
* To allow error-aware handling without breaking ABI, add state fields
* (e.g. ctx->last_err) in rym_ctx for callbacks to inspect.
*/
typedef enum rym_code(*rym_callback)(struct rym_ctx *ctx, rt_uint8_t *buf, rt_size_t len);
@@ -98,14 +108,37 @@ typedef enum rym_code(*rym_callback)(struct rym_ctx *ctx, rt_uint8_t *buf, rt_si
*/
struct rym_ctx
{
/**
* @brief Data callback for each received/sent block.
*/
rym_callback on_data;
/**
* @brief Begin callback for the initial header block.
*/
rym_callback on_begin;
/**
* @brief End callback for session finalization.
* Callers should check ctx->last_err to distinguish success vs failure.
*/
rym_callback on_end;
/* When error happened, user need to check this to get when the error has
* happened. */
enum rym_stage stage;
/* user could get the error content through this */
rt_uint8_t *buf;
/**
* @brief Callback lifecycle state: set when on_begin succeeds.
*/
rt_uint8_t begin_called;
/**
* @brief Callback lifecycle state: set when on_end is invoked.
*/
rt_uint8_t end_called;
/**
* @brief Last transfer error seen by the core state machine.
* on_end can inspect this to distinguish success vs failure.
*/
rt_err_t last_err;
struct rt_semaphore sem;