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 */