[components]: utilities: ymodem: Add ry_sy function.

Use "ry" to receive files and use "sy file_path" to
send files. Default console uart and you can choose
any other uart if you want.

Signed-off-by: Steven Liu <steven.liu@rock-chips.com>
This commit is contained in:
Steven Liu
2019-12-13 11:49:53 +08:00
parent bb9a55817c
commit 3c5f46468c
4 changed files with 637 additions and 56 deletions
+7
View File
@@ -2,8 +2,15 @@ menu "Utilities"
config RT_USING_RYM
bool "Enable Ymodem"
depends on RT_USING_DFS = y
default n
if RT_USING_RYM
config YMODEM_DISABLE_CRC_TABLE
bool "Disable CRC Table"
default n
endif
config RT_USING_ULOG
bool "Enable ulog"
default n
+237
View File
@@ -0,0 +1,237 @@
/*
* 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
*/
#include <rtthread.h>
#include <ymodem.h>
#include <dfs_posix.h>
#include <stdlib.h>
#include <board.h>
#include <string.h>
struct custom_ctx
{
struct rym_ctx parent;
int fd;
int flen;
char fpath[DFS_PATH_MAX];
};
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;
cctx->fpath[0] = '/';
rt_strncpy(&(cctx->fpath[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((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;
}
sprintf((char *)buf, "%s%c%ld", (char *) & (cctx->fpath[1]), 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);
/* stage = RYM_STAGE_FINISHING */
ctx->stage = 4;
}
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)
{
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_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;
if (argc > 1)
dev = rt_device_find(argv[1]);
else
dev = rt_console_get_device();
if (!dev)
{
rt_kprintf("could not find device.\n");
return -RT_ERROR;
}
res = rym_download_file(dev);
return res;
}
MSH_CMD_EXPORT(ry, YMODEM Receive e.g: ry [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)
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 */
File diff suppressed because it is too large Load Diff
+38 -8
View File
@@ -7,16 +7,19 @@
* Change Logs:
* Date Author Notes
* 2013-04-14 Grissiom initial implementation
* 2019-12-09 Steven Liu add YMODEM send protocol
*/
#ifndef __YMODEM_H__
#define __YMODEM_H__
#include "rtthread.h"
#include <string.h>
/* The word "RYM" is stand for "Real-YModem". */
enum rym_code {
enum rym_code
{
RYM_CODE_NONE = 0x00,
RYM_CODE_SOH = 0x01,
RYM_CODE_STX = 0x02,
@@ -44,6 +47,10 @@ enum rym_code {
#define RYM_ERR_DSZ 0x74
/* the transmission is aborted by user */
#define RYM_ERR_CAN 0x75
/* wrong answer, wrong ACK or C */
#define RYM_ERR_ACK 0x76
/* transmit file invalid */
#define RYM_ERR_FILE 0x77
/* how many ticks wait for chars between packet. */
#ifndef RYM_WAIT_CHR_TICK
@@ -63,7 +70,8 @@ enum rym_code {
#define RYM_END_SESSION_SEND_CAN_NUM 0x07
#endif
enum rym_stage {
enum rym_stage
{
RYM_STAGE_NONE,
/* set when C is send */
RYM_STAGE_ESTABLISHING,
@@ -80,16 +88,15 @@ enum rym_stage {
};
struct rym_ctx;
/* when receiving files, the buf will be the data received from ymodem protocol
/* When receiving files, the buf will be the data received from ymodem protocol
* and the len is the data size.
*
* TODO:
* When sending files, the len is the buf size in RYM. The callback need to
* fill the buf with data to send. Returning RYM_CODE_EOT will terminate the
* transfer and the buf will be discarded. Any other return values will cause
* the transfer continue.
*/
typedef enum rym_code (*rym_callback)(struct rym_ctx *ctx, rt_uint8_t *buf, rt_size_t len);
typedef enum rym_code(*rym_callback)(struct rym_ctx *ctx, rt_uint8_t *buf, rt_size_t len);
/* Currently RYM only support one transfer session(ctx) for simplicity.
*
@@ -112,7 +119,7 @@ struct rym_ctx
rt_device_t dev;
};
/** recv a file on device dev with ymodem session ctx.
/* recv a file on device dev with ymodem session ctx.
*
* If an error happens, you can get where it is failed from ctx->stage.
*
@@ -138,7 +145,30 @@ struct rym_ctx
* second.
*/
rt_err_t rym_recv_on_device(struct rym_ctx *ctx, rt_device_t dev, rt_uint16_t oflag,
rym_callback on_begin, rym_callback on_data, rym_callback on_end,
int handshake_timeout);
rym_callback on_begin, rym_callback on_data, rym_callback on_end,
int handshake_timeout);
/* send a file on device dev with ymodem session ctx.
*
* If an error happens, you can get where it is failed from ctx->stage.
*
* @param on_begin The callback will be invoked when the first packet is sent.
* This packet often contain file names and the size of the file. It is the
* on_begin's responsibility to parse the basic information of the file. The
* on_begin can not be NULL.
*
* @param on_data The callback will be invoked when the data packets is sent.
* The callback should read file system and prepare the data packets. The
* on_data can not be NULL.
*
* @param on_end The callback will be invoked when one transmission is
* finished. The data should be 128 bytes of NULL. The on_end can not be NULL.
*
* @param handshake_timeout the timeout when hand shaking. The unit is in
* second.
*/
rt_err_t rym_send_on_device(struct rym_ctx *ctx, rt_device_t dev, rt_uint16_t oflag,
rym_callback on_begin, rym_callback on_data, rym_callback on_end,
int handshake_timeout);
#endif