295 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			295 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
| /*
 | |
|  * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd
 | |
|  *
 | |
|  * SPDX-License-Identifier: Apache-2.0
 | |
|  *
 | |
|  * Change Logs:
 | |
|  * Date           Author       Notes
 | |
|  * 2019-12-09     Steven Liu   the first version
 | |
|  * 2021-04-14     Meco Man     Check the file path's legitimacy of 'sy' command
 | |
|  */
 | |
| 
 | |
| #include <rtthread.h>
 | |
| #include <ymodem.h>
 | |
| #include <dfs_file.h>
 | |
| #include <unistd.h>
 | |
| #include <sys/stat.h>
 | |
| #include <sys/statfs.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| 
 | |
| #ifndef DFS_USING_POSIX
 | |
| #error "Please enable DFS_USING_POSIX"
 | |
| #endif
 | |
| 
 | |
| struct custom_ctx
 | |
| {
 | |
|     struct rym_ctx parent;
 | |
|     int fd;
 | |
|     int flen;
 | |
|     char fpath[DFS_PATH_MAX];
 | |
| };
 | |
| 
 | |
| static const char *_get_path_lastname(const char *path)
 | |
| {
 | |
|     char *ptr;
 | |
|     if ((ptr = (char *)strrchr(path, '/')) == NULL)
 | |
|         return path;
 | |
| 
 | |
|     /* skip the '/' then return */
 | |
|     return ++ptr;
 | |
| }
 | |
| 
 | |
| static enum rym_code _rym_recv_begin(
 | |
|     struct rym_ctx *ctx,
 | |
|     rt_uint8_t *buf,
 | |
|     rt_size_t len)
 | |
| {
 | |
|     struct custom_ctx *cctx = (struct custom_ctx *)ctx;
 | |
|     struct stat file_buf;
 | |
|     char insert_0 = '\0';
 | |
|     char *ret;
 | |
|     rt_err_t err;
 | |
|     ret = strchr(cctx->fpath,insert_0);
 | |
|     if(ret)
 | |
|     {
 | |
|         *ret = '/';
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         rt_kprintf("No end character\n");
 | |
|         return RYM_ERR_ACK;
 | |
|     }
 | |
|     rt_strncpy(ret + 1, (const char *)buf, len - 1);
 | |
|     cctx->fd = open(cctx->fpath, O_CREAT | O_WRONLY | O_TRUNC, 0);
 | |
|     if (cctx->fd < 0)
 | |
|     {
 | |
|         rt_err_t err = rt_get_errno();
 | |
|         rt_kprintf("error creating file: %d\n", err);
 | |
|         return RYM_CODE_CAN;
 | |
|     }
 | |
|     cctx->flen = atoi(1 + (const char *)buf + rt_strnlen((const char *)buf, len - 1));
 | |
|     if (cctx->flen == 0)
 | |
|         cctx->flen = -1;
 | |
| 
 | |
|     return RYM_CODE_ACK;
 | |
| }
 | |
| 
 | |
| static enum rym_code _rym_recv_data(
 | |
|     struct rym_ctx *ctx,
 | |
|     rt_uint8_t *buf,
 | |
|     rt_size_t len)
 | |
| {
 | |
|     struct custom_ctx *cctx = (struct custom_ctx *)ctx;
 | |
| 
 | |
|     RT_ASSERT(cctx->fd >= 0);
 | |
|     if (cctx->flen == -1)
 | |
|     {
 | |
|         write(cctx->fd, buf, len);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         int wlen = len > cctx->flen ? cctx->flen : len;
 | |
|         write(cctx->fd, buf, wlen);
 | |
|         cctx->flen -= wlen;
 | |
|     }
 | |
| 
 | |
|     return RYM_CODE_ACK;
 | |
| }
 | |
| 
 | |
| static enum rym_code _rym_recv_end(
 | |
|     struct rym_ctx *ctx,
 | |
|     rt_uint8_t *buf,
 | |
|     rt_size_t len)
 | |
| {
 | |
|     struct custom_ctx *cctx = (struct custom_ctx *)ctx;
 | |
| 
 | |
|     RT_ASSERT(cctx->fd >= 0);
 | |
|     close(cctx->fd);
 | |
|     cctx->fd = -1;
 | |
| 
 | |
|     return RYM_CODE_ACK;
 | |
| }
 | |
| 
 | |
| static enum rym_code _rym_send_begin(
 | |
|     struct rym_ctx *ctx,
 | |
|     rt_uint8_t *buf,
 | |
|     rt_size_t len)
 | |
| {
 | |
|     struct custom_ctx *cctx = (struct custom_ctx *)ctx;
 | |
|     struct stat file_buf;
 | |
|     char insert_0 = '\0';
 | |
|     rt_err_t err;
 | |
| 
 | |
|     cctx->fd = open(cctx->fpath, O_RDONLY);
 | |
|     if (cctx->fd < 0)
 | |
|     {
 | |
|         err = rt_get_errno();
 | |
|         rt_kprintf("error open file: %d\n", err);
 | |
|         return RYM_ERR_FILE;
 | |
|     }
 | |
|     rt_memset(buf, 0, len);
 | |
|     err = stat(cctx->fpath, &file_buf);
 | |
|     if (err != RT_EOK)
 | |
|     {
 | |
|         rt_kprintf("error open file.\n");
 | |
|         return RYM_ERR_FILE;
 | |
|     }
 | |
| 
 | |
|     const char *fdst = _get_path_lastname(cctx->fpath);
 | |
|     if(fdst != cctx->fpath)
 | |
|     {
 | |
|         fdst = dfs_normalize_path(RT_NULL, fdst);
 | |
|         if (fdst == RT_NULL)
 | |
|         {
 | |
|             return RYM_ERR_FILE;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     rt_sprintf((char *)buf, "%s%c%d", fdst, insert_0, file_buf.st_size);
 | |
| 
 | |
|     return RYM_CODE_SOH;
 | |
| }
 | |
| 
 | |
| static enum rym_code _rym_send_data(
 | |
|     struct rym_ctx *ctx,
 | |
|     rt_uint8_t *buf,
 | |
|     rt_size_t len)
 | |
| {
 | |
|     struct custom_ctx *cctx = (struct custom_ctx *)ctx;
 | |
|     rt_size_t read_size;
 | |
|     int retry_read;
 | |
| 
 | |
|     read_size = 0;
 | |
|     for (retry_read = 0; retry_read < 10; retry_read++)
 | |
|     {
 | |
|         read_size += read(cctx->fd, buf + read_size, len - read_size);
 | |
|         if (read_size == len)
 | |
|             break;
 | |
|     }
 | |
| 
 | |
|     if (read_size < len)
 | |
|     {
 | |
|         rt_memset(buf + read_size, 0x1A, len - read_size);
 | |
|         ctx->stage = RYM_STAGE_FINISHING;
 | |
|     }
 | |
| 
 | |
|     if (read_size > 128)
 | |
|     {
 | |
|         return RYM_CODE_STX;
 | |
|     }
 | |
|     return RYM_CODE_SOH;
 | |
| }
 | |
| 
 | |
| static enum rym_code _rym_send_end(
 | |
|     struct rym_ctx *ctx,
 | |
|     rt_uint8_t *buf,
 | |
|     rt_size_t len)
 | |
| {
 | |
|     rt_memset(buf, 0, len);
 | |
| 
 | |
|     return RYM_CODE_SOH;
 | |
| }
 | |
| 
 | |
| static rt_err_t rym_download_file(rt_device_t idev,const char *file_path)
 | |
| {
 | |
|     rt_err_t res;
 | |
|     struct custom_ctx *ctx = rt_calloc(1, sizeof(*ctx));
 | |
| 
 | |
|     if (!ctx)
 | |
|     {
 | |
|         rt_kprintf("rt_malloc failed\n");
 | |
|         return -RT_ENOMEM;
 | |
|     }
 | |
|     ctx->fd = -1;
 | |
|     rt_strncpy(ctx->fpath, file_path, DFS_PATH_MAX);
 | |
|     RT_ASSERT(idev);
 | |
|     res = rym_recv_on_device(&ctx->parent, idev, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
 | |
|                              _rym_recv_begin, _rym_recv_data, _rym_recv_end, 1000);
 | |
|     rt_free(ctx);
 | |
| 
 | |
|     return res;
 | |
| }
 | |
| 
 | |
| static rt_err_t rym_upload_file(rt_device_t idev, const char *file_path)
 | |
| {
 | |
|     rt_err_t res = 0;
 | |
| 
 | |
|     struct custom_ctx *ctx = rt_calloc(1, sizeof(*ctx));
 | |
|     if (!ctx)
 | |
|     {
 | |
|         rt_kprintf("rt_malloc failed\n");
 | |
|         return -RT_ENOMEM;
 | |
|     }
 | |
|     ctx->fd = -1;
 | |
|     rt_strncpy(ctx->fpath, file_path, DFS_PATH_MAX);
 | |
|     RT_ASSERT(idev);
 | |
|     res = rym_send_on_device(&ctx->parent, idev,
 | |
|                              RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
 | |
|                              _rym_send_begin, _rym_send_data, _rym_send_end, 1000);
 | |
|     rt_free(ctx);
 | |
| 
 | |
|     return res;
 | |
| }
 | |
| 
 | |
| #ifdef RT_USING_FINSH
 | |
| #include <finsh.h>
 | |
| 
 | |
| static rt_err_t ry(uint8_t argc, char **argv)
 | |
| {
 | |
|     rt_err_t res;
 | |
|     rt_device_t dev;
 | |
|     /* temporarily support 1 file*/
 | |
|     const char *file_path;
 | |
|     if (argc < 2)
 | |
|     {
 | |
|         rt_kprintf("invalid file path.\n");
 | |
|         return -RT_ERROR;
 | |
|     }
 | |
|     if (argc > 2)
 | |
|         dev = rt_device_find(argv[2]);
 | |
|     else
 | |
|         dev = rt_console_get_device();
 | |
|     if (!dev)
 | |
|     {
 | |
|         rt_kprintf("could not find device.\n");
 | |
|         return -RT_ERROR;
 | |
|     }
 | |
|     file_path = argv[1];
 | |
|     res = rym_download_file(dev,file_path);
 | |
| 
 | |
|     return res;
 | |
| }
 | |
| MSH_CMD_EXPORT(ry, YMODEM Receive e.g: ry file_path [uart0] default by console.);
 | |
| 
 | |
| static rt_err_t sy(uint8_t argc, char **argv)
 | |
| {
 | |
|     rt_err_t res;
 | |
|     /* temporarily support 1 file*/
 | |
|     const char *file_path;
 | |
|     rt_device_t dev;
 | |
| 
 | |
|     if (argc < 2)
 | |
|     {
 | |
|         rt_kprintf("invalid file path.\n");
 | |
|         return -RT_ERROR;
 | |
|     }
 | |
| 
 | |
|     if (argc > 2)
 | |
|         dev = rt_device_find(argv[2]);
 | |
|     else
 | |
|         dev = rt_console_get_device();
 | |
|     if (!dev)
 | |
|     {
 | |
|         rt_kprintf("could not find device.\n");
 | |
|         return -RT_ERROR;
 | |
|     }
 | |
|     file_path = argv[1];
 | |
|     res = rym_upload_file(dev, file_path);
 | |
| 
 | |
|     return res;
 | |
| }
 | |
| MSH_CMD_EXPORT(sy, YMODEM Send e.g: sy file_path [uart0] default by console.);
 | |
| 
 | |
| #endif /* RT_USING_FINSH */
 |