You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2023/04/29 13:24:02 UTC
[nuttx-apps] 01/02: support ymodem send/recve can asynchronous
This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git
commit 32e597a13617c4833347ebf010c1cec4d2cc1de6
Author: anjiahao <an...@xiaomi.com>
AuthorDate: Thu Apr 20 11:53:44 2023 +0800
support ymodem send/recve can asynchronous
Signed-off-by: anjiahao <an...@xiaomi.com>
---
system/ymodem/Kconfig | 12 +-
system/ymodem/README.md | 2 +-
system/ymodem/rb_main.c | 404 ++++++++++++++++++++++------
system/ymodem/sb_main.c | 323 +++++++++++++++++-----
system/ymodem/ymodem.c | 700 +++++++++++++++++++++---------------------------
system/ymodem/ymodem.h | 49 ++--
6 files changed, 917 insertions(+), 573 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 `<Ctrl + a> , 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 `<Ctrl + a> , 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 <fcntl.h>
#include <stdio.h>
#include <getopt.h>
-#include <nuttx/fs/ioctl.h>
+#include <pthread.h>
+
+#include <nuttx/mm/circbuf.h>
+
#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)
+{
+ while (priv->fd > 0 && circbuf_used(&priv->circ))
+ {
+ FAR uint8_t *buffer;
+ size_t i = 0;
+ size_t size;
+
+ buffer = circbuf_get_readptr(&priv->circ, &size);
+ while (i < size)
+ {
+ 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)
{
- 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;
+ FAR struct ymodem_priv_s *priv = ctx->priv;
+ int ret;
- if (ctx->packet_type == YMODEM_FILE_RECV_NAME_PACKET)
+ if (ctx->packet_type == YMODEM_FILENAME_PACKET)
{
- if (ym_fd->file_fd != 0)
+ char temp[PATH_MAX];
+ FAR char *filename;
+
+ if (priv->fd > 0)
{
- close(ym_fd->file_fd);
+ 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 <device>: Communication device to use. Default: stdin & stdout\n");
+ "\t-d <device>: Communication device to use."
+ "Default: stdin & stdout\n");
fprintf(stderr,
- "\t-p <path>: Save remote file path. Default: Current path\n");
+ "\t-f <foldname>: Save remote file fold. Default: Current fold\n");
fprintf(stderr,
- "\t--removeprefix <prefix>: Remove save file name prefix\n");
+ "\t-p|--skip_prefix <prefix>: Remove file name prefix\n");
fprintf(stderr,
- "\t--removesuffix <suffix>: Remove save file name suffix\n");
- exit(errcode);
+ "\t-s|--skip_suffix <suffix>: Remove file name suffix\n");
+ fprintf(stderr,
+ "\t-b|--buffersize <size>: Asynchronously receive buffer size."
+ "If greater than 0, accept data asynchronously, Default: 0kB\n");
+ fprintf(stderr,
+ "\t-t|--threshold <size>: 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 <fcntl.h>
-#include <libgen.h>
#include <stdio.h>
-#include <termios.h>
+#include <getopt.h>
+#include <libgen.h>
+#include <pthread.h>
#include <sys/stat.h>
+#include <nuttx/mm/circbuf.h>
+
#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);
+ }
+
+ 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);
- filename = ym_fd->filelist[ym_fd->filenum++];
- ret = lstat(filename, &info);
+ 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] <lname> [<lname> [<lname> ...]]\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 <device>: Communication device to use. Default: stdin & stdout\n");
-
- exit(errcode);
+ fprintf(stderr,
+ "\t-b|--buffersize <size>: 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;
+ struct ymodem_priv_s priv;
+ struct ymodem_ctx_s ctx;
+ FAR char *devname = NULL;
+ int ret = 0;
+ struct option options[] =
+ {
+ {"buffersize", 1, NULL, 'b'},
+ };
- 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)
+ memset(&priv, 0, sizeof(priv));
+ memset(&ctx, 0, sizeof(ctx));
+ while ((ret = getopt_long(argc, argv, "b:d:h", options, NULL))
+ != ERROR)
{
- switch (option)
+ switch (ret)
{
+ case 'b':
+ priv.buffersize = atoi(optarg) * 1024;
+ break;
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;
+ 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
{
- close(ctx.recvfd);
+ 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;
+ }
}
- if (ym_fd.file_fd)
+ ret = ymodem_send(&ctx);
+
+ if (priv.buffersize)
{
- close(ym_fd.file_fd);
+ async_uninit(&priv);
}
- return 0;
+out:
+ if (priv.fd > 0)
+ {
+ close(priv.fd);
+ }
+
+ if (ctx.recvfd > 0)
+ {
+ close(ctx.recvfd);
+ }
+
+ 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 <errno.h>
#include <stdio.h>
-#include <stdbool.h>
#include <fcntl.h>
+#include <unistd.h>
#include <stdlib.h>
-#include <errno.h>
-#include <termios.h>
#include <string.h>
-#include <sys/time.h>
-#include <sys/ioctl.h>
-#include <poll.h>
+#include <termios.h>
+
#include <nuttx/crc16.h>
+
#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)
+
+#else
+# define ymodem_debug(...)
+#endif
-#define MAX_ERRORS 100
+#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 EEOT 200 /* End of transfer */
+#define MAX_RETRIES 100
/****************************************************************************
* Private Functions
****************************************************************************/
-static long get_current_time(void)
-{
- struct timeval tv;
- gettimeofday(&tv, NULL);
- return tv.tv_sec * 1000 + tv.tv_usec / 1000;
-}
-
-static ssize_t ymodem_uart_recv(FAR struct ymodem_ctx *ctx,
- FAR uint8_t *buf, size_t size,
- uint32_t timeout)
+static int ymodem_recv_buffer(FAR struct ymodem_ctx_s *ctx, FAR uint8_t *buf,
+ size_t size)
{
- ssize_t i = 0;
- ssize_t ret;
- long base;
- struct pollfd pfd =
- {
- ctx->recvfd, POLLIN, 0
- };
+ size_t i = 0;
- base = get_current_time();
- while (i < size && poll(&pfd, 1, timeout) > 0)
+ ymodem_debug("recv buffer data, read size is %zu\n", size);
+ while (i < size)
{
- 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;
+ return 0;
}
-static ssize_t ymodem_uart_send(FAR struct ymodem_ctx *ctx,
- FAR uint8_t *buf, size_t size,
- uint32_t timeout)
+static int ymodem_send_buffer(FAR struct ymodem_ctx_s *ctx,
+ FAR const uint8_t *buf, size_t size)
{
- ssize_t ret = write(ctx->sendfd, buf, size);
- if (ret != size)
+ size_t i = 0;
+
+ ymodem_debug("send buffer data, write size is %zu\n", size);
+ while (i < size)
{
- ymodem_debug("ymodem_uart_send error\n");
- return ret;
+ ssize_t ret = write(ctx->sendfd, buf, size);
+ if (ret >= 0)
+ {
+ ymodem_debug("send buffer data, size %zd\n", ret);
+ i += ret;
+ }
+ else
+ {
+ ymodem_debug("send buffer error, ret %d\n", -errno);
+ return -errno;
+ }
}
- return ret;
+ return 0;
}
-static int ymodem_rcev_packet(FAR struct ymodem_ctx *ctx)
+static int ymodem_recv_packet(FAR struct ymodem_ctx_s *ctx)
{
- uint32_t timeout = ctx->timeout;
- uint16_t packet_size;
- uint16_t rcev_crc;
+ uint16_t recv_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)
+ ret = ymodem_recv_buffer(ctx, ctx->header, 1);
+ if (ret < 0)
{
return ret;
}
- switch (chunk[0])
+ switch (ctx->header[0])
{
case SOH:
- packet_size = YMODEM_PACKET_SIZE;
+ ctx->packet_size = YMODEM_PACKET_SIZE;
break;
case STX:
- packet_size = YMODEM_PACKET_1K_SIZE;
+ ctx->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 -EAGAIN;
+ case CAN:
+ ret = ymodem_recv_buffer(ctx, ctx->header, 1);
+ if (ret < 0)
{
- return -ECANCELED;
+ return ret;
}
- else
+ else if (ctx->header[0] == CAN)
{
- return -EBADMSG;
+ return -ECANCELED;
}
default:
- ymodem_debug("rcev_packet: EBADMSG: chunk[0]=%d\n", chunk[0]);
+ ymodem_debug("recv_packet: EBADMSG: header[0]=0x%x\n",
+ ctx->header[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)
+ ret = ymodem_recv_buffer(ctx, &ctx->header[1],
+ 2 + ctx->packet_size + 2);
+ if (ret < 0)
{
- ymodem_debug("rcev_packet: err=%d\n", ret);
+ ymodem_debug("recv_packet: err=%d\n", ret);
return ret;
}
- if ((ctx->seq[0] + ctx->seq[1]) != 0xff)
+ if ((ctx->header[1] + ctx->header[2]) != 0xff)
{
- ymodem_debug("rcev_packet: EILSEQ seq[]=%d %d\n", ctx->seq[0],
- ctx->seq[1]);
+ ymodem_debug("recv_packet: EILSEQ seq[]=%d %d\n",
+ ctx->header[1], ctx->header[2]);
return -EILSEQ;
}
- rcev_crc = (uint16_t)((crchl[0] << 8) + crchl[1]);
- cal_crc = crc16(ctx->data, packet_size);
- if (rcev_crc != cal_crc)
+ 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("rcev_packet: EBADMSG rcev:cal=%x %x\n",
- rcev_crc, cal_crc);
+ ymodem_debug("recv_packet: EBADMSG rcev:cal=0x%x 0x%x\n",
+ recv_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]);
+ ymodem_debug("recv_packet:OK: size=%d, seq=%d\n",
+ ctx->packet_size, ctx->header[1]);
return 0;
}
-static int ymodem_rcev_file(FAR struct ymodem_ctx *ctx)
+static int ymodem_recv_file(FAR struct ymodem_ctx_s *ctx)
{
- uint32_t timeout = ctx->timeout;
- bool file_start = false;
- bool file_done = false;
+ FAR char *str = NULL;
uint32_t total_seq = 0;
- bool canceled = false;
- uint8_t chunk[1];
- FAR char *str;
- int ret = 0;
- int err = 0;
-
- chunk[0] = CRC16;
- ymodem_uart_send(ctx, chunk, 1, timeout);
- while (!file_done)
- {
- ret = ymodem_rcev_packet(ctx);
- if (!ret)
- {
- 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");
- }
- else
+ 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)
{
- /* 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("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 (canceled)
+ if ((total_seq & 0xff) - 1 == ctx->header[1])
{
- 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");
+ 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;
}
- return ret;
-}
+ /* File name packet */
-static int ymodem_send_packet(FAR struct ymodem_ctx *ctx)
-{
- size_t size;
- uint16_t crc;
- uint8_t send_crc[2];
+ if (total_seq == 0)
+ {
+ /* Filename packet is empty, end session */
- crc = crc16(ctx->data, ctx->packet_size);
- size = ymodem_uart_send(ctx, &ctx->header, ctx->packet_size + 3,
- ctx->timeout);
+ if (ctx->data[0] == '\0')
+ {
+ /* Last file done, so the session also finished */
- if (size != ctx->packet_size + 3)
- {
- ymodem_debug("send packet error\n");
- return -1;
+ 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;
}
- send_crc[0] = crc >> 8;
- send_crc[1] = crc & 0x00ff;
- size = ymodem_uart_send(ctx, send_crc, 2, ctx->timeout);
- if (size != 2)
+ /* data packet */
+
+ ctx->packet_type = YMODEM_DATA_PACKET;
+ ret = ctx->packet_handler(ctx);
+ if (ret < 0)
{
- ymodem_debug("send crc16 error\n");
- return -1;
+ ymodem_debug("recv_file: handler err for data packet: ret=%d\n", ret);
+ goto cancel;
}
- return 0;
+ 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_rcev_cmd(FAR struct ymodem_ctx *ctx, uint8_t cmd)
+static int ymodem_recv_cmd(FAR struct ymodem_ctx_s *ctx, uint8_t cmd)
{
- size_t size;
- uint8_t chunk[1];
+ 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)
+ 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)
- {
- return readsize;
- }
-
- if (readsize == 0)
- {
- goto send_eot;
- }
-
- if (readsize < ctx->packet_size)
+ ymodem_debug("packet_size is %zu\n", ctx->packet_size);
+ ctx->header[1]++;
+ ctx->header[2]--;
+ ret = ctx->packet_handler(ctx);
+ if (ret < 0)
{
- 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;
}
-#endif
- if (!ctx || !ctx->packet_handler)
+ ctx->header = calloc(1, 3 + YMODEM_PACKET_1K_SIZE + 2);
+ if (ctx->header == NULL)
{
- ymodem_debug("ymodem: invalid context config\n");
- return -EINVAL;
+ return -ENOMEM;
}
- while (1)
+ 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)
{
- ret = ymodem_rcev_file(ctx);
- if (ret == -EEOT)
- {
- continue;
- }
-
- break;
+ free(ctx->header);
+ return -errno;
}
+#endif
+
+ 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);
-#ifdef CONFIG_SYSTEM_YMODEM_DEBUGFILE_PATH
+ ret = ymodem_recv_file(ctx);
+
+ 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);
+ 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;
+ }
-#ifdef CONFIG_SYSTEM_YMODEM_DEBUGFILE_PATH
- ctx->debug_fd = open(CONFIG_SYSTEM_YMODEM_DEBUGFILE_PATH,
- O_CREAT | O_RDWR);
+ 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)
{
- return -EINVAL;
+ 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 <stdint.h>
-#include <stdlib.h>
+#include <stddef.h>
/****************************************************************************
* 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 */