From 32e597a13617c4833347ebf010c1cec4d2cc1de6 Mon Sep 17 00:00:00 2001 From: anjiahao Date: Thu, 20 Apr 2023 11:53:44 +0800 Subject: [PATCH] support ymodem send/recve can asynchronous Signed-off-by: anjiahao --- system/ymodem/Kconfig | 12 +- system/ymodem/README.md | 2 +- system/ymodem/rb_main.c | 406 +++++++++++++++----- system/ymodem/sb_main.c | 331 ++++++++++++---- system/ymodem/ymodem.c | 812 ++++++++++++++++++---------------------- system/ymodem/ymodem.h | 49 ++- 6 files changed, 978 insertions(+), 634 deletions(-) diff --git a/system/ymodem/Kconfig b/system/ymodem/Kconfig index ac4706059..a1a908705 100644 --- a/system/ymodem/Kconfig +++ b/system/ymodem/Kconfig @@ -12,25 +12,23 @@ if SYSTEM_YMODEM config SYSTEM_YMODEM_STACKSIZE int "ymodem stack size" - default 4096 + default DEFAULT_TASK_STACKSIZE ---help--- The size of stack allocated for the ymodem task. config SYSTEM_YMODEM_PRIORITY int "ymodem priority" - default 255 + default 100 ---help--- The priority of the ymodem task. config SYSTEM_YMODEM_DEBUG bool "ymodem debug" - default false + default n -if SYSTEM_YMODEM_DEBUG -config SYSTEM_YMODEM_DEBUGFILE_PATH +config SYSTEM_YMODEM_DEBUG_FILEPATH string "save ymodem debug log path" + depends on SYSTEM_YMODEM_DEBUG default "/tmp/ymodem" endif - -endif diff --git a/system/ymodem/README.md b/system/ymodem/README.md index dbde3536f..6c814e04a 100644 --- a/system/ymodem/README.md +++ b/system/ymodem/README.md @@ -15,7 +15,7 @@ then use ` , r` chose `ymodem` to receive board file. ## Sendfile to board -use rb cmd like this `nsh> sb`, this command support receive multiple files together +use rb cmd like this `nsh> rb`, this command support receive multiple files together then use ` , s` chose `ymodem`, then chose what file need to send. ## help diff --git a/system/ymodem/rb_main.c b/system/ymodem/rb_main.c index 62a4c891c..0c8cee041 100644 --- a/system/ymodem/rb_main.c +++ b/system/ymodem/rb_main.c @@ -25,117 +25,313 @@ #include #include #include -#include +#include + +#include + #include "ymodem.h" /**************************************************************************** * Private Types ****************************************************************************/ -struct ymodem_fd +struct ymodem_priv_s { - int file_fd; - char pathname[PATH_MAX]; + int fd; + FAR char *foldname; size_t file_saved_size; - char *removeperfix; - char *removesuffix; + FAR char *skip_perfix; + FAR char *skip_suffix; + + /* Async */ + + struct circbuf_s circ; + pthread_mutex_t mutex; + pthread_cond_t cond; + size_t buffersize; + size_t threshold; + pthread_t pid; + bool exited; }; /**************************************************************************** * Private Functions ****************************************************************************/ -static int handler(FAR struct ymodem_ctx *ctx) +static int flush_data(FAR struct ymodem_priv_s *priv) { - char pathname[PATH_MAX + YMODEM_FILE_NAME_LENGTH]; - FAR struct ymodem_fd *ym_fd = ctx->priv; - FAR char *filename; - size_t size; - size_t ret; - - if (ctx->packet_type == YMODEM_FILE_RECV_NAME_PACKET) + while (priv->fd > 0 && circbuf_used(&priv->circ)) { - if (ym_fd->file_fd != 0) + FAR uint8_t *buffer; + size_t i = 0; + size_t size; + + buffer = circbuf_get_readptr(&priv->circ, &size); + while (i < size) { - close(ym_fd->file_fd); + ssize_t ret = write(priv->fd, buffer + i, size - i); + if (ret < 0) + { + return -errno; + } + + i += ret; + } + + circbuf_readcommit(&priv->circ, size); + } + + return 0; +} + +static FAR void *async_write(FAR void *arg) +{ + FAR struct ymodem_priv_s *priv = arg; + + pthread_mutex_lock(&priv->mutex); + while (priv->exited == false) + { + if (circbuf_used(&priv->circ) <= priv->threshold) + { + pthread_cond_wait(&priv->cond, &priv->mutex); + continue; + } + + if (flush_data(priv) < 0) + { + pthread_mutex_unlock(&priv->mutex); + return NULL; + } + } + + flush_data(priv); + pthread_mutex_unlock(&priv->mutex); + return NULL; +} + +static int write_data(FAR struct ymodem_priv_s *priv, + FAR const uint8_t *data, size_t size) +{ + size_t i = 0; + + if (priv->buffersize) + { + pthread_mutex_lock(&priv->mutex); + while (i < size) + { + ssize_t ret = circbuf_write(&priv->circ, data + i, size - i); + if (ret < 0) + { + pthread_mutex_unlock(&priv->mutex); + return ret; + } + else if (ret == 0) + { + ret = flush_data(priv); + if (ret < 0) + { + pthread_mutex_unlock(&priv->mutex); + return ret; + } + } + else + { + i += ret; + } + } + + if (circbuf_used(&priv->circ) > priv->threshold) + { + pthread_cond_signal(&priv->cond); + } + + pthread_mutex_unlock(&priv->mutex); + } + else + { + while (i < size) + { + ssize_t ret = write(priv->fd, data + i, size - i); + if (ret < 0) + { + return -errno; + } + + i += ret; + } + } + + return 0; +} + +static int handler(FAR struct ymodem_ctx_s *ctx) +{ + FAR struct ymodem_priv_s *priv = ctx->priv; + int ret; + + if (ctx->packet_type == YMODEM_FILENAME_PACKET) + { + char temp[PATH_MAX]; + FAR char *filename; + + if (priv->fd > 0) + { + if (priv->buffersize) + { + pthread_mutex_lock(&priv->mutex); + ret = flush_data(priv); + pthread_mutex_unlock(&priv->mutex); + if (ret < 0) + { + return ret; + } + } + + close(priv->fd); } filename = ctx->file_name; - if (ym_fd->removeperfix) + if (priv->skip_perfix != NULL) { - if (strncmp(ctx->file_name, ym_fd->removeperfix, - strlen(ym_fd->removeperfix)) == 0) + size_t len = strlen(priv->skip_perfix); + + if (strncmp(ctx->file_name, priv->skip_perfix, + len) == 0) { - filename = filename + strlen(ym_fd->removeperfix); + filename += len; } } - if (ym_fd->removesuffix) + if (priv->skip_suffix != NULL) { - int len = strlen(filename); - if (len > strlen(ym_fd->removesuffix) && - strcmp(filename + len - strlen(ym_fd->removesuffix), - ym_fd->removesuffix) == 0) + size_t len = strlen(filename); + size_t len2 = strlen(priv->skip_suffix); + + if (len > len2 && strcmp(filename + len - len2, + priv->skip_suffix) == 0) { - filename[len - strlen(ym_fd->removesuffix)] = 0; + filename[len - len2] = '\0'; } } - if (strlen(ym_fd->pathname) != 0) + if (priv->foldname != NULL) { - sprintf(pathname, "%s/%s", ym_fd->pathname, filename); - filename = pathname; + snprintf(temp, PATH_MAX, "%s/%s", priv->foldname, + filename); + filename = temp; } - ym_fd->file_fd = open(filename, O_CREAT | O_RDWR); - if (ym_fd->file_fd < 0) + priv->fd = open(filename, O_CREAT | O_WRONLY, 0777); + if (priv->fd < 0) { return -errno; } - ym_fd->file_saved_size = 0; + priv->file_saved_size = 0; } - else if (ctx->packet_type == YMODEM_RECV_DATA_PACKET) + else if (ctx->packet_type == YMODEM_DATA_PACKET) { - if (ym_fd->file_saved_size + ctx->packet_size > ctx->file_length) + size_t size; + + if (priv->file_saved_size + ctx->packet_size > ctx->file_length) { - size = ctx->file_length - ym_fd->file_saved_size; + size = ctx->file_length - priv->file_saved_size; } else { size = ctx->packet_size; } - ret = write(ym_fd->file_fd, ctx->data, size); + ret = write_data(priv, ctx->data, size); if (ret < 0) { - return -errno; - } - else if (ret < size) - { - return ERROR; + return ret; } - ym_fd->file_saved_size += ret; + priv->file_saved_size += size; } return 0; } -static void show_usage(FAR const char *progname, int errcode) +static int async_init(FAR struct ymodem_priv_s *priv) +{ + int ret; + + ret = circbuf_init(&priv->circ, NULL, priv->buffersize); + if (ret < 0) + { + fprintf(stderr, "ERROR: circbuf_init error\n"); + return ret; + } + + ret = pthread_mutex_init(&priv->mutex, NULL); + if (ret > 0) + { + fprintf(stderr, "ERROR: pthread_mutex_init error\n"); + ret = -ret; + goto circ_err; + } + + ret = pthread_cond_init(&priv->cond, NULL); + if (ret > 0) + { + fprintf(stderr, "ERROR: pthread_cond_init error\n"); + ret = -ret; + goto mutex_err; + } + + ret = pthread_create(&priv->pid, NULL, async_write, priv); + if (ret > 0) + { + ret = -ret; + goto cond_err; + } + + return ret; +cond_err: + pthread_cond_destroy(&priv->cond); +mutex_err: + pthread_mutex_destroy(&priv->mutex); +circ_err: + circbuf_uninit(&priv->circ); + return ret; +} + +static void async_uninit(FAR struct ymodem_priv_s *priv) +{ + pthread_mutex_lock(&priv->mutex); + priv->exited = true; + pthread_cond_signal(&priv->cond); + pthread_mutex_unlock(&priv->mutex); + pthread_join(priv->pid, NULL); + pthread_cond_destroy(&priv->cond); + pthread_mutex_destroy(&priv->mutex); + circbuf_uninit(&priv->circ); +} + +static void show_usage(FAR const char *progname) { fprintf(stderr, "USAGE: %s [OPTIONS]\n", progname); fprintf(stderr, "\nWhere:\n"); fprintf(stderr, "\nand OPTIONS include the following:\n"); fprintf(stderr, - "\t-d : Communication device to use. Default: stdin & stdout\n"); + "\t-d : Communication device to use." + "Default: stdin & stdout\n"); fprintf(stderr, - "\t-p : Save remote file path. Default: Current path\n"); + "\t-f : Save remote file fold. Default: Current fold\n"); fprintf(stderr, - "\t--removeprefix : Remove save file name prefix\n"); + "\t-p|--skip_prefix : Remove file name prefix\n"); fprintf(stderr, - "\t--removesuffix : Remove save file name suffix\n"); - exit(errcode); + "\t-s|--skip_suffix : Remove file name suffix\n"); + fprintf(stderr, + "\t-b|--buffersize : Asynchronously receive buffer size." + "If greater than 0, accept data asynchronously, Default: 0kB\n"); + fprintf(stderr, + "\t-t|--threshold : Threshold for writing asynchronously." + "Threshold must be less than or equal buffersize, Default: 0kB\n"); + + exit(EXIT_FAILURE); } /**************************************************************************** @@ -144,72 +340,108 @@ static void show_usage(FAR const char *progname, int errcode) int main(int argc, FAR char *argv[]) { - struct ymodem_fd ym_fd; - struct ymodem_ctx ctx; - int index; + struct ymodem_priv_s priv; + struct ymodem_ctx_s ctx; + FAR char *devname = NULL; int ret; + struct option options[] = { - {"removeprefix", 1, NULL, 1}, - {"removesuffix", 1, NULL, 2}, + {"buffersize", 1, NULL, 'b'}, + {"skip_prefix", 1, NULL, 'p'}, + {"skip_suffix", 1, NULL, 's'}, + {"threshold", 1, NULL, 't'} }; - memset(&ym_fd, 0, sizeof(struct ymodem_fd)); - memset(&ctx, 0, sizeof(struct ymodem_ctx)); - ctx.packet_handler = handler; - ctx.timeout = 200; - ctx.priv = &ym_fd; - ctx.recvfd = 0; - ctx.sendfd = 1; - while ((ret = getopt_long(argc, argv, "p:d:h", options, &index)) + memset(&priv, 0, sizeof(priv)); + memset(&ctx, 0, sizeof(ctx)); + while ((ret = getopt_long(argc, argv, "b:d:f:hp:s:t:", options, NULL)) != ERROR) { switch (ret) { - case 1: - ym_fd.removeperfix = optarg; - break; - case 2: - ym_fd.removesuffix = optarg; - break; - case 'p': - strlcpy(ym_fd.pathname, optarg, PATH_MAX); - if (ym_fd.pathname[strlen(ym_fd.pathname)] == '/') - { - ym_fd.pathname[strlen(ym_fd.pathname)] = 0; - } - + case 'b': + priv.buffersize = atoi(optarg) * 1024; break; case 'd': - ctx.recvfd = open(optarg, O_RDWR | O_NONBLOCK); - if (ctx.recvfd < 0) + devname = optarg; + break; + case 'f': + priv.foldname = optarg; + if (priv.foldname[strlen(priv.foldname)] == '/') { - fprintf(stderr, "ERROR: can't open %s\n", optarg); + priv.foldname[strlen(priv.foldname)] = '\0'; } - ctx.sendfd = ctx.recvfd; break; case 'h': - show_usage(argv[0], EXIT_FAILURE); + show_usage(argv[0]); break; + case 'p': + priv.skip_perfix = optarg; + break; + case 's': + priv.skip_suffix = optarg; + break; + case 't': + priv.threshold = atoi(optarg) * 1024; + break; + default: - case '?': - fprintf(stderr, "ERROR: Unrecognized option\n"); - show_usage(argv[0], EXIT_FAILURE); + show_usage(argv[0]); break; } } - ymodem_recv(&ctx); - if (ctx.recvfd) + if (priv.threshold > priv.buffersize) + { + show_usage(argv[0]); + } + + if (priv.buffersize) + { + ret = async_init(&priv); + if (ret < 0) + { + return ret; + } + } + + ctx.packet_handler = handler; + ctx.priv = &priv; + if (devname) + { + ctx.recvfd = open(devname, O_RDWR); + if (ctx.recvfd < 0) + { + fprintf(stderr, "ERROR: can't open %s\n", devname); + goto out; + } + + ctx.sendfd = ctx.recvfd; + } + else + { + ctx.recvfd = STDIN_FILENO; + ctx.sendfd = STDOUT_FILENO; + } + + ret = ymodem_recv(&ctx); + if (ctx.recvfd > 0) { close(ctx.recvfd); } - if (ym_fd.file_fd) +out: + if (priv.buffersize) { - close(ym_fd.file_fd); + async_uninit(&priv); } - return 0; + if (priv.fd > 0) + { + close(priv.fd); + } + + return ret; } diff --git a/system/ymodem/sb_main.c b/system/ymodem/sb_main.c index 8c888dc81..7fc34e9ea 100644 --- a/system/ymodem/sb_main.c +++ b/system/ymodem/sb_main.c @@ -23,72 +23,247 @@ ****************************************************************************/ #include -#include #include -#include +#include +#include +#include #include +#include + #include "ymodem.h" /**************************************************************************** - * Private Functions + * Private Type Definitions ****************************************************************************/ -struct ymodem_fd +struct ymodem_priv_s { - int file_fd; + int fd; FAR char **filelist; size_t filenum; + + /* Async */ + + struct circbuf_s circ; + pthread_mutex_t mutex; + pthread_cond_t cond; + size_t buffersize; + pthread_t pid; + bool exited; }; /**************************************************************************** * Private Functions ****************************************************************************/ -static ssize_t handler(FAR struct ymodem_ctx *ctx) +static FAR void *async_read(FAR void *arg) { - FAR struct ymodem_fd *ym_fd = ctx->priv; - ssize_t ret = -EINVAL; - FAR char *filename; - struct stat info; + FAR struct ymodem_priv_s *priv = arg; - if (ctx->packet_type == YMODEM_FILE_SEND_NAME_PACKET) + pthread_mutex_lock(&priv->mutex); + while (priv->exited == false) { - if (ym_fd->file_fd != 0) + FAR uint8_t *buffer; + ssize_t ret = 0; + size_t size; + + if (priv->fd > 0) { - close(ym_fd->file_fd); + buffer = circbuf_get_writeptr(&priv->circ, &size); + ret = read(priv->fd, buffer, size); + if (ret < 0) + { + break; + } + + circbuf_writecommit(&priv->circ, ret); } - filename = ym_fd->filelist[ym_fd->filenum++]; - ret = lstat(filename, &info); + if (circbuf_is_full(&priv->circ) || priv->fd <= 0 || ret == 0) + { + pthread_cond_wait(&priv->cond, &priv->mutex); + } + } + + pthread_mutex_unlock(&priv->mutex); + return NULL; +} + +static int read_data(FAR struct ymodem_priv_s *priv, + FAR uint8_t *data, size_t size) +{ + ssize_t i = 0; + + if (priv->buffersize) + { + pthread_mutex_lock(&priv->mutex); + while (i < size) + { + ssize_t ret = circbuf_read(&priv->circ, data + i, size - i); + + if (ret < 0) + { + pthread_mutex_unlock(&priv->mutex); + return ret; + } + + if (ret == 0) + { + ret = read(priv->fd, data + i, size - i); + if (ret < 0) + { + pthread_mutex_unlock(&priv->mutex); + return -errno; + } + } + + i += ret; + } + + pthread_cond_signal(&priv->cond); + pthread_mutex_unlock(&priv->mutex); + } + else + { + while (i < size) + { + ssize_t ret = read(priv->fd, data + i, size - i); + + if (ret < 0) + { + return -errno; + } + + i += ret; + } + } + + return 0; +} + +static int handler(FAR struct ymodem_ctx_s *ctx) +{ + FAR struct ymodem_priv_s *priv = ctx->priv; + int ret; + + if (ctx->packet_type == YMODEM_FILENAME_PACKET) + { + FAR char *filename; + struct stat st; + + if (priv->fd > 0) + { + close(priv->fd); + priv->fd = 0; + } + + filename = priv->filelist[priv->filenum++]; + if (filename == NULL) + { + return -ENOENT; + } + + ret = stat(filename, &st); if (ret < 0) { - return ret; + return -errno; } - ym_fd->file_fd = open(filename, O_RDWR); - if (ym_fd->file_fd < 0) + priv->fd = open(filename, O_RDONLY); + if (priv->fd < 0) { - return ym_fd->file_fd; + return -errno; } filename = basename(filename); - strncpy(ctx->file_name, filename, YMODEM_FILE_NAME_LENGTH); - ctx->file_length = info.st_size; + strlcpy(ctx->file_name, filename, PATH_MAX); + ctx->file_length = st.st_size; } - else if (ctx->packet_type == YMODEM_SEND_DATA_PACKET) + else if (ctx->packet_type == YMODEM_DATA_PACKET) { - ret = read(ym_fd->file_fd, ctx->data, ctx->packet_size); + size_t size; + + if (ctx->file_length > ctx->packet_size) + { + size = ctx->packet_size; + } + else + { + size = ctx->file_length; + memset(ctx->data + size, 0x1a, + ctx->packet_size - ctx->file_length); + } + + ret = read_data(priv, ctx->data, size); if (ret < 0) { return ret; } + + ctx->file_length -= size; + } + + return 0; +} + +static int async_init(FAR struct ymodem_priv_s *priv) +{ + int ret; + + ret = circbuf_init(&priv->circ, NULL, priv->buffersize); + if (ret < 0) + { + fprintf(stderr, "ERROR: circbuf_init error\n"); + return ret; + } + + ret = pthread_mutex_init(&priv->mutex, NULL); + if (ret > 0) + { + fprintf(stderr, "ERROR: pthread_mutex_init error\n"); + ret = -ret; + goto circ_err; + } + + ret = pthread_cond_init(&priv->cond, NULL); + if (ret > 0) + { + fprintf(stderr, "ERROR: pthread_cond_init error\n"); + ret = -ret; + goto mutex_err; + } + + ret = pthread_create(&priv->pid, NULL, async_read, priv); + if (ret < 0) + { + ret = -ret; + goto cond_err; } return ret; +cond_err: + pthread_cond_destroy(&priv->cond); +mutex_err: + pthread_mutex_destroy(&priv->mutex); +circ_err: + circbuf_uninit(&priv->circ); + return ret; } -static void show_usage(FAR const char *progname, int errcode) +static void async_uninit(FAR struct ymodem_priv_s *priv) +{ + pthread_mutex_lock(&priv->mutex); + priv->exited = true; + pthread_cond_signal(&priv->cond); + pthread_mutex_unlock(&priv->mutex); + pthread_join(priv->pid, NULL); + pthread_cond_destroy(&priv->cond); + pthread_mutex_destroy(&priv->mutex); + circbuf_uninit(&priv->circ); +} + +static void show_usage(FAR const char *progname) { fprintf(stderr, "USAGE: %s [OPTIONS] [ [ ...]]\n", progname); @@ -97,8 +272,10 @@ static void show_usage(FAR const char *progname, int errcode) fprintf(stderr, "\nand OPTIONS include the following:\n"); fprintf(stderr, "\t-d : Communication device to use. Default: stdin & stdout\n"); - - exit(errcode); + fprintf(stderr, + "\t-b|--buffersize : Asynchronously send buffer size." + "If greater than 0, accept data asynchronously, Default: 0kB\n"); + exit(EXIT_FAILURE); } /**************************************************************************** @@ -107,56 +284,82 @@ static void show_usage(FAR const char *progname, int errcode) int main(int argc, FAR char *argv[]) { - struct ymodem_fd ym_fd; - struct ymodem_ctx ctx; - int option; - - memset(&ctx, 0, sizeof(struct ymodem_ctx)); - ctx.packet_handler = handler; - ctx.timeout = 3000; - ctx.recvfd = 0; - ctx.sendfd = 1; - ctx.priv = &ym_fd; - while ((option = getopt(argc, argv, "d:h")) != ERROR) + struct ymodem_priv_s priv; + struct ymodem_ctx_s ctx; + FAR char *devname = NULL; + int ret = 0; + struct option options[] = { - switch (option) + {"buffersize", 1, NULL, 'b'}, + }; + + memset(&priv, 0, sizeof(priv)); + memset(&ctx, 0, sizeof(ctx)); + while ((ret = getopt_long(argc, argv, "b:d:h", options, NULL)) + != ERROR) + { + switch (ret) { - case 'd': - ctx.recvfd = open(optarg, O_RDWR); - if (ctx.recvfd < 0) - { - fprintf(stderr, "ERROR: can't open %s\n", optarg); - } - - ctx.sendfd = ctx.recvfd; + case 'b': + priv.buffersize = atoi(optarg) * 1024; + break; + case 'd': + devname = optarg; break; - case 'h': - show_usage(argv[0], EXIT_FAILURE); - - default: case '?': - fprintf(stderr, "ERROR: Unrecognized option\n"); - show_usage(argv[0], EXIT_FAILURE); + default: + show_usage(argv[0]); break; } } - ctx.need_sendfile_num = argc - optind; - ym_fd.file_fd = 0; - ym_fd.filelist = &argv[optind]; - ym_fd.filenum = 0; + ctx.packet_handler = handler; + if (devname) + { + ctx.recvfd = open(devname, O_RDWR); + if (ctx.recvfd < 0) + { + fprintf(stderr, "ERROR: can't open %s\n", devname); + return -errno; + } - ymodem_send(&ctx); - if (ctx.recvfd) + ctx.sendfd = ctx.recvfd; + } + else + { + ctx.recvfd = STDIN_FILENO; + ctx.sendfd = STDOUT_FILENO; + } + + ctx.priv = &priv; + priv.filelist = &argv[optind]; + if (priv.buffersize) + { + ret = async_init(&priv); + if (ret < 0) + { + goto out; + } + } + + ret = ymodem_send(&ctx); + + if (priv.buffersize) + { + async_uninit(&priv); + } + +out: + if (priv.fd > 0) + { + close(priv.fd); + } + + if (ctx.recvfd > 0) { close(ctx.recvfd); } - if (ym_fd.file_fd) - { - close(ym_fd.file_fd); - } - - return 0; + return ret; } diff --git a/system/ymodem/ymodem.c b/system/ymodem/ymodem.c index 9c77f62aa..8a528950e 100644 --- a/system/ymodem/ymodem.c +++ b/system/ymodem/ymodem.c @@ -22,416 +22,328 @@ * Included Files ****************************************************************************/ -#include -#include -#include -#include #include -#include +#include +#include +#include +#include #include -#include -#include -#include +#include + #include + #include "ymodem.h" /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ -#define SOH 0x01 /* start of 128-byte data packet */ -#define STX 0x02 /* start of 1024-byte data packet */ -#define EOT 0x04 /* end of transmission */ -#define ACK 0x06 /* acknowledge */ -#define NAK 0x15 /* negative acknowledge */ -#define CA 0x18 /* two of these in succession aborts transfer */ -#define CRC16 0x43 /* 'C' == 0x43, request 16-bit CRC */ +#ifdef CONFIG_SYSTEM_YMODEM_DEBUG_FILEPATH +# define ymodem_debug(...) \ + do \ + { \ + dprintf(ctx->debug_fd, ##__VA_ARGS__); \ + fsync(ctx->debug_fd); \ + } \ + while(0) -#define MAX_ERRORS 100 +#else +# define ymodem_debug(...) +#endif -#define EEOT 200 /* End of transfer */ +#define SOH 0x01 /* Start of 128-byte data packet */ +#define STX 0x02 /* Start of 1024-byte data packet */ +#define EOT 0x04 /* End of transmission */ +#define ACK 0x06 /* Acknowledge */ +#define NAK 0x15 /* Negative acknowledge */ +#define CAN 0x18 /* Two of these in succession aborts transfer */ +#define CRC 0x43 /* 'C' == 0x43, request 16-bit CRC */ + +#define MAX_RETRIES 100 /**************************************************************************** * Private Functions ****************************************************************************/ -static long get_current_time(void) +static int ymodem_recv_buffer(FAR struct ymodem_ctx_s *ctx, FAR uint8_t *buf, + size_t size) { - struct timeval tv; - gettimeofday(&tv, NULL); - return tv.tv_sec * 1000 + tv.tv_usec / 1000; -} + size_t i = 0; -static ssize_t ymodem_uart_recv(FAR struct ymodem_ctx *ctx, - FAR uint8_t *buf, size_t size, - uint32_t timeout) -{ - ssize_t i = 0; - ssize_t ret; - long base; - struct pollfd pfd = + ymodem_debug("recv buffer data, read size is %zu\n", size); + while (i < size) { - ctx->recvfd, POLLIN, 0 - }; - - base = get_current_time(); - while (i < size && poll(&pfd, 1, timeout) > 0) - { - if (get_current_time() - base >= timeout) - { - ymodem_debug("ymodem_uart_recv timeout\n"); - return -1; - } - - ret = read(ctx->recvfd, buf + i, size - i); + ssize_t ret = read(ctx->recvfd, buf + i, size - i); if (ret >= 0) { + ymodem_debug("recv buffer data, size %zd\n", ret); i += ret; } else { - ymodem_debug("ymodem_uart_recv read data error\n"); - return ret; + ymodem_debug("recv buffer error, ret %d\n", -errno); + return -errno; } } - if (i == 0) - { - return -1; - } - - return i; -} - -static ssize_t ymodem_uart_send(FAR struct ymodem_ctx *ctx, - FAR uint8_t *buf, size_t size, - uint32_t timeout) -{ - ssize_t ret = write(ctx->sendfd, buf, size); - if (ret != size) - { - ymodem_debug("ymodem_uart_send error\n"); - return ret; - } - - return ret; -} - -static int ymodem_rcev_packet(FAR struct ymodem_ctx *ctx) -{ - uint32_t timeout = ctx->timeout; - uint16_t packet_size; - uint16_t rcev_crc; - uint16_t cal_crc; - uint8_t crchl[2]; - uint8_t chunk[1]; - int ret; - - ret = ymodem_uart_recv(ctx, chunk, 1, timeout); - if (ret != 1) - { - return ret; - } - - switch (chunk[0]) - { - case SOH: - packet_size = YMODEM_PACKET_SIZE; - break; - case STX: - packet_size = YMODEM_PACKET_1K_SIZE; - break; - case EOT: - return -EEOT; - case CA: - ret = ymodem_uart_recv(ctx, chunk, 1, timeout); - if (ret != 1 && chunk[0] == CA) - { - return -ECANCELED; - } - else - { - return -EBADMSG; - } - - default: - ymodem_debug("rcev_packet: EBADMSG: chunk[0]=%d\n", chunk[0]); - return -EBADMSG; - } - - ret = ymodem_uart_recv(ctx, ctx->seq, 2, timeout); - if (ret != 2) - { - ymodem_debug("rcev_packet: err=%d\n", ret); - return ret; - } - - ret = ymodem_uart_recv(ctx, ctx->data, packet_size, timeout); - if (ret != packet_size) - { - ymodem_debug("rcev_packet: err=%d\n", ret); - return ret; - } - - ret = ymodem_uart_recv(ctx, crchl, 2, timeout); - if (ret != 2) - { - ymodem_debug("rcev_packet: err=%d\n", ret); - return ret; - } - - if ((ctx->seq[0] + ctx->seq[1]) != 0xff) - { - ymodem_debug("rcev_packet: EILSEQ seq[]=%d %d\n", ctx->seq[0], - ctx->seq[1]); - return -EILSEQ; - } - - rcev_crc = (uint16_t)((crchl[0] << 8) + crchl[1]); - cal_crc = crc16(ctx->data, packet_size); - if (rcev_crc != cal_crc) - { - ymodem_debug("rcev_packet: EBADMSG rcev:cal=%x %x\n", - rcev_crc, cal_crc); - return -EBADMSG; - } - - ctx->packet_size = packet_size; - ymodem_debug("rcev_packet:OK: size=%d, seq=%d\n", - packet_size, ctx->seq[0]); return 0; } -static int ymodem_rcev_file(FAR struct ymodem_ctx *ctx) +static int ymodem_send_buffer(FAR struct ymodem_ctx_s *ctx, + FAR const uint8_t *buf, size_t size) { - uint32_t timeout = ctx->timeout; - bool file_start = false; - bool file_done = false; - uint32_t total_seq = 0; - bool canceled = false; - uint8_t chunk[1]; - FAR char *str; - int ret = 0; - int err = 0; + size_t i = 0; - chunk[0] = CRC16; - ymodem_uart_send(ctx, chunk, 1, timeout); - while (!file_done) + ymodem_debug("send buffer data, write size is %zu\n", size); + while (i < size) { - ret = ymodem_rcev_packet(ctx); - if (!ret) + ssize_t ret = write(ctx->sendfd, buf, size); + if (ret >= 0) { - if ((total_seq & 0xff) != ctx->seq[0]) - { - ymodem_debug("rcev_file: total seq erro:%lu %u\n", - total_seq, ctx->seq[0]); - chunk[0] = CRC16; - ymodem_uart_send(ctx, chunk, 1, timeout); - } - else - { - /* update with the total sequence number */ - - ctx->seq[0] = total_seq; - - /* file name packet */ - - if (total_seq == 0) - { - /* Filename packet is empty, end session */ - - if (ctx->data[0] == '\0') - { - ymodem_debug("rcev_file: session finished\n"); - chunk[0] = ACK; - ymodem_uart_send(ctx, chunk, 1, timeout); - - /* last file done, so the session also finished */ - - file_done = true; - } - else - { - str = (FAR char *)ctx->data; - ctx->packet_type = YMODEM_FILE_RECV_NAME_PACKET; - strncpy(ctx->file_name, str, YMODEM_FILE_NAME_LENGTH); - ctx->file_name[YMODEM_FILE_NAME_LENGTH - 1] = '\0'; - str += strlen(str) + 1; - ctx->file_length = atoi(str); - ymodem_debug("rcev_file: new file %s(%lu) start\n", - ctx->file_name, ctx->file_length); - ret = ctx->packet_handler(ctx); - if (ret) - { - ymodem_debug("rcev_file: handler err for file \ - name packet: ret=%d\n", ret); - canceled = true; - ret = -ENOEXEC; - break; - } - - file_start = true; - chunk[0] = ACK; - ymodem_uart_send(ctx, chunk, 1, timeout); - chunk[0] = CRC16; - ymodem_uart_send(ctx, chunk, 1, timeout); - } - } - else - { - /* data packet */ - - ctx->packet_type = YMODEM_RECV_DATA_PACKET; - ret = ctx->packet_handler(ctx); - if (ret) - { - ymodem_debug("rcev_file: handler err for data \ - packet: ret=%d\n", ret); - canceled = true; - ret = -ENOEXEC; - break; - } - - chunk[0] = ACK; - ymodem_uart_send(ctx, chunk, 1, timeout); - } - - ymodem_debug("rcev_file: packet %lu %s\n", - total_seq, ret ? "failed" : "success"); - - total_seq++; - } - } - else if (ret == -ECANCELED) - { - ymodem_debug("rcev_file: canceled by sender\n"); - canceled = true; - break; - } - else if (ret == -EEOT) - { - chunk[0] = ACK; - ymodem_uart_send(ctx, chunk, 1, timeout); - file_done = true; - ymodem_debug("rcev_file: finished one file transfer\n"); + ymodem_debug("send buffer data, size %zd\n", ret); + i += ret; } else { - /* other errors, like ETIME, EILSEQ, EBADMSG... */ - - if (file_start) - { - err++; - } - - if (err > MAX_ERRORS) - { - ymodem_debug("rcev_file: too many errors, cancel!!\n"); - canceled = true; - break; - } - - chunk[0] = CRC16; - ymodem_uart_send(ctx, chunk, 1, timeout); + ymodem_debug("send buffer error, ret %d\n", -errno); + return -errno; } } - if (canceled) - { - chunk[0] = CA; - ymodem_uart_send(ctx, chunk, 1, timeout); - ymodem_uart_send(ctx, chunk, 1, timeout); - ymodem_debug("rcev_file: cancel command sent to sender\n"); - } - - return ret; -} - -static int ymodem_send_packet(FAR struct ymodem_ctx *ctx) -{ - size_t size; - uint16_t crc; - uint8_t send_crc[2]; - - crc = crc16(ctx->data, ctx->packet_size); - size = ymodem_uart_send(ctx, &ctx->header, ctx->packet_size + 3, - ctx->timeout); - - if (size != ctx->packet_size + 3) - { - ymodem_debug("send packet error\n"); - return -1; - } - - send_crc[0] = crc >> 8; - send_crc[1] = crc & 0x00ff; - size = ymodem_uart_send(ctx, send_crc, 2, ctx->timeout); - if (size != 2) - { - ymodem_debug("send crc16 error\n"); - return -1; - } - return 0; } -static int ymodem_rcev_cmd(FAR struct ymodem_ctx *ctx, uint8_t cmd) +static int ymodem_recv_packet(FAR struct ymodem_ctx_s *ctx) { - size_t size; - uint8_t chunk[1]; + uint16_t recv_crc; + uint16_t cal_crc; + int ret; - size = ymodem_uart_recv(ctx, chunk, 1, ctx->timeout); - if (size != 1) + ret = ymodem_recv_buffer(ctx, ctx->header, 1); + if (ret < 0) { - ymodem_debug("recv cmd error\n"); - return -1; + return ret; } - if (chunk[0] == NAK) + switch (ctx->header[0]) + { + case SOH: + ctx->packet_size = YMODEM_PACKET_SIZE; + break; + case STX: + ctx->packet_size = YMODEM_PACKET_1K_SIZE; + break; + case EOT: + return -EAGAIN; + case CAN: + ret = ymodem_recv_buffer(ctx, ctx->header, 1); + if (ret < 0) + { + return ret; + } + else if (ctx->header[0] == CAN) + { + return -ECANCELED; + } + + default: + ymodem_debug("recv_packet: EBADMSG: header[0]=0x%x\n", + ctx->header[0]); + return -EBADMSG; + } + + ret = ymodem_recv_buffer(ctx, &ctx->header[1], + 2 + ctx->packet_size + 2); + if (ret < 0) + { + ymodem_debug("recv_packet: err=%d\n", ret); + return ret; + } + + if ((ctx->header[1] + ctx->header[2]) != 0xff) + { + ymodem_debug("recv_packet: EILSEQ seq[]=%d %d\n", + ctx->header[1], ctx->header[2]); + return -EILSEQ; + } + + recv_crc = (ctx->data[ctx->packet_size] << 8) + + ctx->data[ctx->packet_size + 1]; + cal_crc = crc16(ctx->data, ctx->packet_size); + if (cal_crc != recv_crc) + { + ymodem_debug("recv_packet: EBADMSG rcev:cal=0x%x 0x%x\n", + recv_crc, cal_crc); + return -EBADMSG; + } + + ymodem_debug("recv_packet:OK: size=%d, seq=%d\n", + ctx->packet_size, ctx->header[1]); + return 0; +} + +static int ymodem_recv_file(FAR struct ymodem_ctx_s *ctx) +{ + FAR char *str = NULL; + uint32_t total_seq = 0; + int retries = 0; + int ret; + + ctx->header[0] = CRC; +recv_packet: + ymodem_send_buffer(ctx, ctx->header, 1); + ret = ymodem_recv_packet(ctx); + if (ret == -ECANCELED) + { + ymodem_debug("recv_file: canceled by sender\n"); + goto cancel; + } + else if (ret == -EAGAIN) + { + ctx->header[0] = ACK; + ymodem_send_buffer(ctx, ctx->header, 1); + ymodem_debug("recv_file: finished one file transfer\n"); + ctx->header[0] = CRC; + total_seq = 0; + goto recv_packet; + } + else if (ret < 0) + { + /* other errors, like ETIMEDOUT, EILSEQ, EBADMSG... */ + + if (++retries > MAX_RETRIES) + { + ymodem_debug("recv_file: too many errors, cancel!!\n"); + goto cancel; + } + + /* Use str to mask transfer start */ + + ctx->header[0] = str ? NAK : CRC; + goto recv_packet; + } + + if ((total_seq & 0xff) - 1 == ctx->header[1]) + { + ymodem_debug("recv_file: Received the previous packet that has" + "been received, continue %lu %u\n", total_seq, + ctx->header[1]); + + ctx->header[0] = ACK; + goto recv_packet; + } + else if ((total_seq & 0xff) != ctx->header[1]) + { + ymodem_debug("recv_file: total seq error:%lu %u\n", total_seq, + ctx->header[1]); + ctx->header[0] = CRC; + goto recv_packet; + } + + /* File name packet */ + + if (total_seq == 0) + { + /* Filename packet is empty, end session */ + + if (ctx->data[0] == '\0') + { + /* Last file done, so the session also finished */ + + ymodem_debug("recv_file: session finished\n"); + ctx->header[0] = ACK; + ymodem_send_buffer(ctx, ctx->header, 1); + return 0; + } + + str = (FAR char *)ctx->data; + ctx->packet_type = YMODEM_FILENAME_PACKET; + strlcpy(ctx->file_name, str, PATH_MAX); + str += strlen(str) + 1; + ctx->file_length = atoi(str); + ymodem_debug("recv_file: new file %s(%zu) start\n", ctx->file_name, + ctx->file_length); + ret = ctx->packet_handler(ctx); + if (ret < 0) + { + ymodem_debug("recv_file: handler err for file name packet:" + " ret=%d\n", ret); + goto cancel; + } + + ctx->header[0] = ACK; + ymodem_send_buffer(ctx, ctx->header, 1); + ctx->header[0] = CRC; + total_seq++; + goto recv_packet; + } + + /* data packet */ + + ctx->packet_type = YMODEM_DATA_PACKET; + ret = ctx->packet_handler(ctx); + if (ret < 0) + { + ymodem_debug("recv_file: handler err for data packet: ret=%d\n", ret); + goto cancel; + } + + ctx->header[0] = ACK; + total_seq++; + ymodem_debug("recv_file: recv data success\n"); + goto recv_packet; + +cancel: + ctx->header[0] = CAN; + ymodem_send_buffer(ctx, ctx->header, 1); + ymodem_send_buffer(ctx, ctx->header, 1); + ymodem_debug("recv_file: cancel command sent to sender\n"); + return ret; +} + +static int ymodem_recv_cmd(FAR struct ymodem_ctx_s *ctx, uint8_t cmd) +{ + int ret; + + ret = ymodem_recv_buffer(ctx, ctx->header, 1); + if (ret < 0) + { + ymodem_debug("recv cmd error\n"); + return ret; + } + + if (ctx->header[0] == NAK) { return -EAGAIN; } - if (chunk[0] != cmd) + if (ctx->header[0] != cmd) { - ymodem_debug("recv cmd error, must 0x%x, but receive %d\n", - cmd, chunk[0]); + ymodem_debug("recv cmd error, must 0x%x, but receive 0x%x\n", + cmd, ctx->header[0]); return -EINVAL; } return 0; } -static int ymodem_send_file(FAR struct ymodem_ctx *ctx) +static int ymodem_send_file(FAR struct ymodem_ctx_s *ctx) { - uint8_t chunk[1]; - ssize_t readsize; - ssize_t size; - int err = 0; + uint16_t crc; + int retries; int ret; - if (!ctx || !ctx->packet_handler) - { - ymodem_debug("%s: invalid context config\n", __func__); - return -EINVAL; - } - - if (ctx->need_sendfile_num <= 0) - { - ymodem_debug("need_sendfile_num is %d, no file to send!\n", - ctx->need_sendfile_num); - return -EINVAL; - } - - chunk[0] = 0; ymodem_debug("waiting handshake\n"); - do + for (retries = 0; retries < MAX_RETRIES; retries++) { - size = ymodem_uart_recv(ctx, chunk, 1, ctx->timeout); + ret = ymodem_recv_cmd(ctx, CRC); + if (ret >= 0) + { + break; + } } - while (err++ < MAX_ERRORS && chunk[0] != CRC16); - if (err >= MAX_ERRORS) + if (retries >= MAX_RETRIES) { ymodem_debug("waiting handshake error\n"); return -ETIMEDOUT; @@ -439,34 +351,34 @@ static int ymodem_send_file(FAR struct ymodem_ctx *ctx) ymodem_debug("ymodem send file start\n"); send_start: - ctx->packet_type = YMODEM_FILE_SEND_NAME_PACKET; - ctx->packet_handler(ctx); - if ((ctx->file_name[0] == 0 || ctx->file_length == 0)) + ctx->packet_type = YMODEM_FILENAME_PACKET; + ret = ctx->packet_handler(ctx); + if (ret < 0) { - ymodem_debug("get fileinfo error\n"); - return -EINVAL; + goto send_last; } - ymodem_debug("sendfile filename:%s filelength:%lu\n", + ymodem_debug("sendfile filename:%s filelength:%zu\n", ctx->file_name, ctx->file_length); - memset(ctx->data, 0, YMODEM_PACKET_SIZE); - strncpy((FAR char *)ctx->data, ctx->file_name, YMODEM_FILE_NAME_LENGTH); - sprintf((FAR char *)ctx->data + strlen(ctx->file_name) + 1, "%ld", - ctx->file_length); - ctx->header = SOH; + sprintf((FAR char *)ctx->data, "%s%c%zu", ctx->file_name, + '\0', ctx->file_length); + ctx->header[0] = SOH; + ctx->header[1] = 0x00; + ctx->header[2] = 0xff; ctx->packet_size = YMODEM_PACKET_SIZE; - ctx->seq[0] = 0x00; - ctx->seq[1] = 0xff; + crc = crc16(ctx->data, ctx->packet_size); + ctx->data[ctx->packet_size] = crc >> 8; + ctx->data[ctx->packet_size + 1] = crc; send_name: - ret = ymodem_send_packet(ctx); + ret = ymodem_send_buffer(ctx, ctx->header, 3 + ctx->packet_size + 2); if (ret < 0) { ymodem_debug("send name packet error\n"); - return -EINVAL; + return ret; } - ret = ymodem_rcev_cmd(ctx, ACK); + ret = ymodem_recv_cmd(ctx, ACK); if (ret == -EAGAIN) { ymodem_debug("send name packet recv NAK, need send again\n"); @@ -479,7 +391,7 @@ send_name: return ret; } - ret = ymodem_rcev_cmd(ctx, CRC16); + ret = ymodem_recv_cmd(ctx, CRC); if (ret == -EAGAIN) { ymodem_debug("send name packet recv NAK, need send again\n"); @@ -492,49 +404,40 @@ send_name: return ret; } - ctx->packet_type = YMODEM_SEND_DATA_PACKET; + ctx->packet_type = YMODEM_DATA_PACKET; send_packet: - if (ctx->file_length <= YMODEM_PACKET_1K_SIZE) + if (ctx->file_length <= YMODEM_PACKET_SIZE) { - ctx->header = SOH; + ctx->header[0] = SOH; ctx->packet_size = YMODEM_PACKET_SIZE; } else { - ctx->header = STX; + ctx->header[0] = STX; ctx->packet_size = YMODEM_PACKET_1K_SIZE; } - ymodem_debug("packet_size is %d\n", ctx->packet_size); - ctx->seq[0]++; - ctx->seq[1]--; - readsize = ctx->packet_handler(ctx); - ymodem_debug("%s:%d: readsize is %d\n", __FILE__, __LINE__, readsize); - - if (readsize < 0) + ymodem_debug("packet_size is %zu\n", ctx->packet_size); + ctx->header[1]++; + ctx->header[2]--; + ret = ctx->packet_handler(ctx); + if (ret < 0) { - return readsize; - } - - if (readsize == 0) - { - goto send_eot; - } - - if (readsize < ctx->packet_size) - { - memset(ctx->data + readsize, 0x1a, ctx->packet_size - readsize); + return ret; } + crc = crc16(ctx->data, ctx->packet_size); + ctx->data[ctx->packet_size] = crc >> 8; + ctx->data[ctx->packet_size + 1] = crc; send_packet_again: - ret = ymodem_send_packet(ctx); + ret = ymodem_send_buffer(ctx, ctx->header, 3 + ctx->packet_size + 2); if (ret < 0) { ymodem_debug("send data packet error\n"); return ret; } - ret = ymodem_rcev_cmd(ctx, ACK); + ret = ymodem_recv_cmd(ctx, ACK); if (ret == -EAGAIN) { ymodem_debug("send data packet recv NAK, need send again\n"); @@ -547,23 +450,22 @@ send_packet_again: return ret; } - ctx->file_length -= readsize; if (ctx->file_length != 0) { - ymodem_debug("The remain bytes sent are %lu\n", ctx->file_length); + ymodem_debug("The remain bytes sent are %zu\n", ctx->file_length); goto send_packet; } send_eot: - chunk[0] = EOT; - size = ymodem_uart_send(ctx, chunk, 1, ctx->timeout); - if (size < 0) + ctx->header[0] = EOT; + ret = ymodem_send_buffer(ctx, ctx->header, 1); + if (ret < 0) { - ymodem_debug("%s:%d: send EOT error\n", __FILE__, __LINE__); - return -1; + ymodem_debug("send EOT error\n"); + return ret; } - ret = ymodem_rcev_cmd(ctx, ACK); + ret = ymodem_recv_cmd(ctx, ACK); if (ret == -EAGAIN) { ymodem_debug("send EOT recv NAK, need send again\n"); @@ -576,7 +478,7 @@ send_eot: return ret; } - ret = ymodem_rcev_cmd(ctx, CRC16); + ret = ymodem_recv_cmd(ctx, CRC); if (ret == -EAGAIN) { ymodem_debug("send EOT recv NAK, need send again\n"); @@ -585,36 +487,35 @@ send_eot: if (ret < 0) { - ymodem_debug("send EOT, recv CRC16 error\n"); + ymodem_debug("send EOT, recv CRC error\n"); return ret; } - if (--ctx->need_sendfile_num != 0) - { - ymodem_debug("need sendfile num is %d, so send file again\n", - ctx->need_sendfile_num); - goto send_start; - } + goto send_start; send_last: - ctx->header = SOH; - ctx->packet_type = YMODEM_SEND_DATA_PACKET; + ctx->header[0] = SOH; + ctx->header[1] = 0x00; + ctx->header[2] = 0xff; + ctx->packet_type = YMODEM_DATA_PACKET; ctx->packet_size = YMODEM_PACKET_SIZE; - ctx->seq[0] = 0x00; - ctx->seq[1] = 0xff; memset(ctx->data, 0, YMODEM_PACKET_SIZE); - ret = ymodem_send_packet(ctx); + crc = crc16(ctx->data, ctx->packet_size); + ctx->data[ctx->packet_size] = crc >> 8; + ctx->data[ctx->packet_size + 1] = crc; +send_last_again: + ret = ymodem_send_buffer(ctx, ctx->header, 3 + ctx->packet_size + 2); if (ret < 0) { ymodem_debug("send last packet error\n"); - return -1; + return ret; } - ret = ymodem_rcev_cmd(ctx, ACK); + ret = ymodem_recv_cmd(ctx, ACK); if (ret == -EAGAIN) { ymodem_debug("send last packet, need send again\n"); - goto send_last; + goto send_last_again; } if (ret < 0) @@ -630,81 +531,96 @@ send_last: * Public Functions ****************************************************************************/ -int ymodem_recv(FAR struct ymodem_ctx *ctx) +int ymodem_recv(FAR struct ymodem_ctx_s *ctx) { struct termios saveterm; struct termios term; int ret; - tcgetattr(ctx->recvfd, &saveterm); - tcgetattr(ctx->recvfd, &term); - cfmakeraw(&term); - tcsetattr(ctx->recvfd, TCSANOW, &term); - -#ifdef CONFIG_SYSTEM_YMODEM_DEBUGFILE_PATH - ctx->debug_fd = open(CONFIG_SYSTEM_YMODEM_DEBUGFILE_PATH, - O_CREAT | O_RDWR); - if (ctx->debug_fd < 0) + if (ctx == NULL || ctx->packet_handler == NULL) { return -EINVAL; } + + ctx->header = calloc(1, 3 + YMODEM_PACKET_1K_SIZE + 2); + if (ctx->header == NULL) + { + return -ENOMEM; + } + + ctx->data = ctx->header + 3; +#ifdef CONFIG_SYSTEM_YMODEM_DEBUG_FILEPATH + ctx->debug_fd = open(CONFIG_SYSTEM_YMODEM_DEBUG_FILEPATH, + O_CREAT | O_TRUNC | O_WRONLY, 0666); + if (ctx->debug_fd < 0) + { + free(ctx->header); + return -errno; + } #endif - if (!ctx || !ctx->packet_handler) - { - ymodem_debug("ymodem: invalid context config\n"); - return -EINVAL; - } + tcgetattr(ctx->recvfd, &term); + memcpy(&saveterm, &term, sizeof(struct termios)); + cfmakeraw(&term); + term.c_cc[VTIME] = 30; + term.c_cc[VMIN] = 255; + tcsetattr(ctx->recvfd, TCSANOW, &term); - while (1) - { - ret = ymodem_rcev_file(ctx); - if (ret == -EEOT) - { - continue; - } + ret = ymodem_recv_file(ctx); - break; - } - -#ifdef CONFIG_SYSTEM_YMODEM_DEBUGFILE_PATH + tcsetattr(ctx->recvfd, TCSANOW, &saveterm); +#ifdef CONFIG_SYSTEM_YMODEM_DEBUG_FILEPATH close(ctx->debug_fd); #endif - tcsetattr(ctx->recvfd, TCSANOW, &saveterm); + free(ctx->header); return ret; } -int ymodem_send(FAR struct ymodem_ctx *ctx) +int ymodem_send(FAR struct ymodem_ctx_s *ctx) { struct termios saveterm; struct termios term; int ret; - tcgetattr(ctx->recvfd, &saveterm); - tcgetattr(ctx->recvfd, &term); - cfmakeraw(&term); - tcsetattr(ctx->recvfd, TCSANOW, &term); - -#ifdef CONFIG_SYSTEM_YMODEM_DEBUGFILE_PATH - ctx->debug_fd = open(CONFIG_SYSTEM_YMODEM_DEBUGFILE_PATH, - O_CREAT | O_RDWR); - if (ctx->debug_fd < 0) + if (ctx == NULL || ctx->packet_handler == NULL) { return -EINVAL; } + + ctx->header = calloc(1, 3 + YMODEM_PACKET_1K_SIZE + 2); + if (ctx->header == NULL) + { + return -ENOMEM; + } + + ctx->data = ctx->header + 3; +#ifdef CONFIG_SYSTEM_YMODEM_DEBUG_FILEPATH + ctx->debug_fd = open(CONFIG_SYSTEM_YMODEM_DEBUG_FILEPATH, + O_CREAT | O_TRUNC | O_WRONLY, 0666); + if (ctx->debug_fd < 0) + { + free(ctx->header); + return -errno; + } #endif + tcgetattr(ctx->recvfd, &term); + memcpy(&saveterm, &term, sizeof(struct termios)); + cfmakeraw(&term); + tcsetattr(ctx->recvfd, TCSANOW, &term); + ret = ymodem_send_file(ctx); if (ret < 0) { ymodem_debug("ymodem send file error, ret:%d\n", ret); } -#ifdef CONFIG_SYSTEM_YMODEM_DEBUGFILE_PATH + tcsetattr(ctx->recvfd, TCSANOW, &saveterm); +#ifdef CONFIG_SYSTEM_YMODEM_DEBUG_FILEPATH close(ctx->debug_fd); #endif - tcsetattr(ctx->recvfd, TCSANOW, &saveterm); - return 0; + free(ctx->header); + return ret; } diff --git a/system/ymodem/ymodem.h b/system/ymodem/ymodem.h index 5e9459ce6..a94f64f92 100644 --- a/system/ymodem/ymodem.h +++ b/system/ymodem/ymodem.h @@ -25,48 +25,43 @@ * Included Files ****************************************************************************/ -#include -#include +#include /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ -#ifdef CONFIG_SYSTEM_YMODEM_DEBUGFILE_PATH -# define ymodem_debug(...) dprintf(ctx->debug_fd, ##__VA_ARGS__) -#else -# define ymodem_debug(...) -#endif - #define YMODEM_PACKET_SIZE 128 #define YMODEM_PACKET_1K_SIZE 1024 -#define YMODEM_FILE_NAME_LENGTH 64 -#define YMODEM_FILE_RECV_NAME_PACKET 0 -#define YMODEM_RECV_DATA_PACKET 1 -#define YMODEM_FILE_SEND_NAME_PACKET 2 -#define YMODEM_SEND_DATA_PACKET 3 +#define YMODEM_FILENAME_PACKET 0 +#define YMODEM_DATA_PACKET 1 /**************************************************************************** * Public Types ****************************************************************************/ -struct ymodem_ctx +struct ymodem_ctx_s { - uint8_t header; - uint8_t seq[2]; - uint8_t data[YMODEM_PACKET_1K_SIZE]; - char file_name[YMODEM_FILE_NAME_LENGTH]; - uint16_t packet_size; - uint32_t file_length; - uint32_t timeout; - uint32_t packet_type; + /* User need initialization */ + int recvfd; int sendfd; - CODE ssize_t (*packet_handler)(FAR struct ymodem_ctx *ctx); + CODE int (*packet_handler)(FAR struct ymodem_ctx_s *ctx); FAR void *priv; - uint16_t need_sendfile_num; -#ifdef CONFIG_SYSTEM_YMODEM_DEBUGFILE_PATH + + /* Public data */ + + FAR uint8_t *data; + size_t packet_size; + int packet_type; + char file_name[PATH_MAX]; + size_t file_length; + + /* Private data */ + + FAR uint8_t *header; +#ifdef CONFIG_SYSTEM_YMODEM_DEBUG_FILEPATH int debug_fd; #endif }; @@ -75,7 +70,7 @@ struct ymodem_ctx * Public Function Prototypes ****************************************************************************/ -int ymodem_recv(FAR struct ymodem_ctx *ctx); -int ymodem_send(FAR struct ymodem_ctx *ctx); +int ymodem_recv(FAR struct ymodem_ctx_s *ctx); +int ymodem_send(FAR struct ymodem_ctx_s *ctx); #endif /* __APPS_SYSTEM_YMODEM_YMODEM_H */