Merge pull request #3264 from Steven-LiuSF/ymodem
[components]: utilities: ymodem: Add ymodem send protocol and ry_sy application.
This commit is contained in:
commit
b9052a52e7
|
@ -2,8 +2,15 @@ menu "Utilities"
|
||||||
|
|
||||||
config RT_USING_RYM
|
config RT_USING_RYM
|
||||||
bool "Enable Ymodem"
|
bool "Enable Ymodem"
|
||||||
|
depends on RT_USING_DFS = y
|
||||||
default n
|
default n
|
||||||
|
|
||||||
|
if RT_USING_RYM
|
||||||
|
config YMODEM_DISABLE_CRC_TABLE
|
||||||
|
bool "Disable CRC Table"
|
||||||
|
default n
|
||||||
|
endif
|
||||||
|
|
||||||
config RT_USING_ULOG
|
config RT_USING_ULOG
|
||||||
bool "Enable ulog"
|
bool "Enable ulog"
|
||||||
default n
|
default n
|
||||||
|
|
|
@ -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 */
|
|
@ -7,12 +7,15 @@
|
||||||
* Change Logs:
|
* Change Logs:
|
||||||
* Date Author Notes
|
* Date Author Notes
|
||||||
* 2013-04-14 Grissiom initial implementation
|
* 2013-04-14 Grissiom initial implementation
|
||||||
|
* 2019-12-09 Steven Liu add YMODEM send protocol
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <rthw.h>
|
#include <rthw.h>
|
||||||
#include "ymodem.h"
|
#include "ymodem.h"
|
||||||
|
|
||||||
static const rt_uint16_t ccitt_table[256] = {
|
#ifndef YMODEM_DISABLE_CRC_TABLE
|
||||||
|
static const rt_uint16_t ccitt_table[256] =
|
||||||
|
{
|
||||||
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
|
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
|
||||||
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
|
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
|
||||||
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
|
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
|
||||||
|
@ -46,7 +49,7 @@ static const rt_uint16_t ccitt_table[256] = {
|
||||||
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
|
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
|
||||||
0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
|
0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
|
||||||
};
|
};
|
||||||
rt_uint16_t CRC16(unsigned char *q, int len)
|
static rt_uint16_t CRC16(unsigned char *q, int len)
|
||||||
{
|
{
|
||||||
rt_uint16_t crc = 0;
|
rt_uint16_t crc = 0;
|
||||||
|
|
||||||
|
@ -54,6 +57,30 @@ rt_uint16_t CRC16(unsigned char *q, int len)
|
||||||
crc = (crc << 8) ^ ccitt_table[((crc >> 8) ^ *q++) & 0xff];
|
crc = (crc << 8) ^ ccitt_table[((crc >> 8) ^ *q++) & 0xff];
|
||||||
return crc;
|
return crc;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
static rt_uint16_t CRC16(unsigned char *q, int len)
|
||||||
|
{
|
||||||
|
rt_uint16_t crc;
|
||||||
|
char i;
|
||||||
|
|
||||||
|
crc = 0;
|
||||||
|
while (--len >= 0)
|
||||||
|
{
|
||||||
|
crc = crc ^ (int) * q++ << 8;
|
||||||
|
i = 8;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (crc & 0x8000)
|
||||||
|
crc = crc << 1 ^ 0x1021;
|
||||||
|
else
|
||||||
|
crc = crc << 1;
|
||||||
|
}
|
||||||
|
while (--i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (crc);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// we could only use global varible because we could not use
|
// we could only use global varible because we could not use
|
||||||
// rt_device_t->user_data(it is used by the serial driver)...
|
// rt_device_t->user_data(it is used by the serial driver)...
|
||||||
|
@ -69,15 +96,16 @@ static rt_err_t _rym_rx_ind(rt_device_t dev, rt_size_t size)
|
||||||
#define _RYM_STX_PKG_SZ (1+2+1024+2)
|
#define _RYM_STX_PKG_SZ (1+2+1024+2)
|
||||||
|
|
||||||
static enum rym_code _rym_read_code(
|
static enum rym_code _rym_read_code(
|
||||||
struct rym_ctx *ctx,
|
struct rym_ctx *ctx,
|
||||||
rt_tick_t timeout)
|
rt_tick_t timeout)
|
||||||
{
|
{
|
||||||
/* Fast path */
|
/* Fast path */
|
||||||
if (rt_device_read(ctx->dev, 0, ctx->buf, 1) == 1)
|
if (rt_device_read(ctx->dev, 0, ctx->buf, 1) == 1)
|
||||||
return (enum rym_code)(*ctx->buf);
|
return (enum rym_code)(*ctx->buf);
|
||||||
|
|
||||||
/* Slow path */
|
/* Slow path */
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
rt_size_t rsz;
|
rt_size_t rsz;
|
||||||
|
|
||||||
/* No data yet, wait for one */
|
/* No data yet, wait for one */
|
||||||
|
@ -88,13 +116,14 @@ static enum rym_code _rym_read_code(
|
||||||
rsz = rt_device_read(ctx->dev, 0, ctx->buf, 1);
|
rsz = rt_device_read(ctx->dev, 0, ctx->buf, 1);
|
||||||
if (rsz == 1)
|
if (rsz == 1)
|
||||||
return (enum rym_code)(*ctx->buf);
|
return (enum rym_code)(*ctx->buf);
|
||||||
} while (1);
|
}
|
||||||
|
while (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* the caller should at least alloc _RYM_STX_PKG_SZ buffer */
|
/* the caller should at least alloc _RYM_STX_PKG_SZ buffer */
|
||||||
static rt_size_t _rym_read_data(
|
static rt_size_t _rym_read_data(
|
||||||
struct rym_ctx *ctx,
|
struct rym_ctx *ctx,
|
||||||
rt_size_t len)
|
rt_size_t len)
|
||||||
{
|
{
|
||||||
/* we should already have had the code */
|
/* we should already have had the code */
|
||||||
rt_uint8_t *buf = ctx->buf + 1;
|
rt_uint8_t *buf = ctx->buf + 1;
|
||||||
|
@ -103,23 +132,61 @@ static rt_size_t _rym_read_data(
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
readlen += rt_device_read(ctx->dev,
|
readlen += rt_device_read(ctx->dev,
|
||||||
0, buf+readlen, len-readlen);
|
0, buf + readlen, len - readlen);
|
||||||
if (readlen >= len)
|
if (readlen >= len)
|
||||||
return readlen;
|
return readlen;
|
||||||
} while (rt_sem_take(&ctx->sem, RYM_WAIT_CHR_TICK) == RT_EOK);
|
}
|
||||||
|
while (rt_sem_take(&ctx->sem, RYM_WAIT_CHR_TICK) == RT_EOK);
|
||||||
|
|
||||||
return readlen;
|
return readlen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static rt_err_t _rym_send_packet(
|
||||||
|
struct rym_ctx *ctx,
|
||||||
|
enum rym_code code,
|
||||||
|
rt_uint8_t index)
|
||||||
|
{
|
||||||
|
rt_uint16_t send_crc;
|
||||||
|
rt_uint8_t index_inv = ~index;
|
||||||
|
rt_size_t writelen = 0;
|
||||||
|
|
||||||
|
send_crc = CRC16(ctx->buf + 3, _RYM_SOH_PKG_SZ - 5);
|
||||||
|
ctx->buf[0] = code;
|
||||||
|
ctx->buf[1] = index;
|
||||||
|
ctx->buf[2] = index_inv;
|
||||||
|
ctx->buf[131] = (rt_uint8_t)(send_crc >> 8);
|
||||||
|
ctx->buf[132] = (rt_uint8_t)send_crc & 0xff;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
writelen += rt_device_write(ctx->dev, 0, ctx->buf + writelen,
|
||||||
|
_RYM_SOH_PKG_SZ - writelen);
|
||||||
|
}
|
||||||
|
while (writelen < _RYM_SOH_PKG_SZ);
|
||||||
|
|
||||||
|
return RT_EOK;
|
||||||
|
}
|
||||||
|
|
||||||
static rt_size_t _rym_putchar(struct rym_ctx *ctx, rt_uint8_t code)
|
static rt_size_t _rym_putchar(struct rym_ctx *ctx, rt_uint8_t code)
|
||||||
{
|
{
|
||||||
rt_device_write(ctx->dev, 0, &code, sizeof(code));
|
rt_device_write(ctx->dev, 0, &code, sizeof(code));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static rt_size_t _rym_getchar(struct rym_ctx *ctx)
|
||||||
|
{
|
||||||
|
rt_uint8_t getc_ack;
|
||||||
|
|
||||||
|
while (rt_device_read(ctx->dev, 0, &getc_ack, 1) != 1)
|
||||||
|
{
|
||||||
|
rt_sem_take(&ctx->sem, RT_WAITING_FOREVER);
|
||||||
|
}
|
||||||
|
return getc_ack;
|
||||||
|
}
|
||||||
|
|
||||||
static rt_err_t _rym_do_handshake(
|
static rt_err_t _rym_do_handshake(
|
||||||
struct rym_ctx *ctx,
|
struct rym_ctx *ctx,
|
||||||
int tm_sec)
|
int tm_sec)
|
||||||
{
|
{
|
||||||
enum rym_code code;
|
enum rym_code code;
|
||||||
rt_size_t i;
|
rt_size_t i;
|
||||||
|
@ -133,13 +200,13 @@ static rt_err_t _rym_do_handshake(
|
||||||
{
|
{
|
||||||
_rym_putchar(ctx, RYM_CODE_C);
|
_rym_putchar(ctx, RYM_CODE_C);
|
||||||
code = _rym_read_code(ctx,
|
code = _rym_read_code(ctx,
|
||||||
RYM_CHD_INTV_TICK);
|
RYM_CHD_INTV_TICK);
|
||||||
if (code == RYM_CODE_SOH)
|
if (code == RYM_CODE_SOH)
|
||||||
{
|
{
|
||||||
data_sz = _RYM_SOH_PKG_SZ;
|
data_sz = _RYM_SOH_PKG_SZ;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if(code == RYM_CODE_STX)
|
else if (code == RYM_CODE_STX)
|
||||||
{
|
{
|
||||||
data_sz = _RYM_STX_PKG_SZ;
|
data_sz = _RYM_STX_PKG_SZ;
|
||||||
break;
|
break;
|
||||||
|
@ -154,7 +221,7 @@ static rt_err_t _rym_do_handshake(
|
||||||
i = 0;
|
i = 0;
|
||||||
/* automatic exit after receiving specified length data, timeout: 100ms */
|
/* automatic exit after receiving specified length data, timeout: 100ms */
|
||||||
tick = rt_tick_get();
|
tick = rt_tick_get();
|
||||||
while (rt_tick_get() <= (tick + rt_tick_from_millisecond(100)) && i < (data_sz-1))
|
while (rt_tick_get() <= (tick + rt_tick_from_millisecond(100)) && i < (data_sz - 1))
|
||||||
{
|
{
|
||||||
i += _rym_read_data(ctx, data_sz - 1);
|
i += _rym_read_data(ctx, data_sz - 1);
|
||||||
rt_thread_mdelay(5);
|
rt_thread_mdelay(5);
|
||||||
|
@ -167,24 +234,79 @@ static rt_err_t _rym_do_handshake(
|
||||||
if (ctx->buf[1] != 0 || ctx->buf[2] != 0xFF)
|
if (ctx->buf[1] != 0 || ctx->buf[2] != 0xFF)
|
||||||
return -RYM_ERR_SEQ;
|
return -RYM_ERR_SEQ;
|
||||||
|
|
||||||
recv_crc = (rt_uint16_t)(*(ctx->buf+data_sz-2) << 8) | *(ctx->buf+data_sz-1);
|
recv_crc = (rt_uint16_t)(*(ctx->buf + data_sz - 2) << 8) | *(ctx->buf + data_sz - 1);
|
||||||
cal_crc = CRC16(ctx->buf+3, data_sz-5);
|
cal_crc = CRC16(ctx->buf + 3, data_sz - 5);
|
||||||
if (recv_crc != cal_crc)
|
if (recv_crc != cal_crc)
|
||||||
return -RYM_ERR_CRC;
|
return -RYM_ERR_CRC;
|
||||||
|
|
||||||
/* congratulations, check passed. */
|
/* congratulations, check passed. */
|
||||||
if (ctx->on_begin && ctx->on_begin(ctx, ctx->buf+3, data_sz-5) != RYM_CODE_ACK)
|
if (ctx->on_begin && ctx->on_begin(ctx, ctx->buf + 3, data_sz - 5) != RYM_CODE_ACK)
|
||||||
return -RYM_ERR_CAN;
|
return -RYM_ERR_CAN;
|
||||||
|
|
||||||
return RT_EOK;
|
return RT_EOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static rt_err_t _rym_trans_data(
|
static rt_err_t _rym_do_send_handshake(
|
||||||
struct rym_ctx *ctx,
|
struct rym_ctx *ctx,
|
||||||
rt_size_t data_sz,
|
int tm_sec)
|
||||||
enum rym_code *code)
|
|
||||||
{
|
{
|
||||||
const rt_size_t tsz = 2+data_sz+2;
|
enum rym_code code;
|
||||||
|
rt_size_t i;
|
||||||
|
rt_size_t data_sz;
|
||||||
|
rt_uint8_t index = 0;
|
||||||
|
rt_uint8_t getc_ack;
|
||||||
|
|
||||||
|
ctx->stage = RYM_STAGE_ESTABLISHING;
|
||||||
|
data_sz = _RYM_SOH_PKG_SZ;
|
||||||
|
|
||||||
|
/* receive C every second */
|
||||||
|
for (i = 0; i < tm_sec; i++)
|
||||||
|
{
|
||||||
|
code = _rym_read_code(ctx,
|
||||||
|
RYM_CHD_INTV_TICK);
|
||||||
|
if (code == RYM_CODE_C)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i == tm_sec)
|
||||||
|
{
|
||||||
|
return -RYM_ERR_TMO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* congratulations, check passed. */
|
||||||
|
if (ctx->on_begin && ctx->on_begin(ctx, ctx->buf + 3, data_sz - 5) != RYM_CODE_SOH)
|
||||||
|
return -RYM_ERR_CODE;
|
||||||
|
|
||||||
|
code = RYM_CODE_SOH;
|
||||||
|
_rym_send_packet(ctx, code, index);
|
||||||
|
|
||||||
|
rt_device_set_rx_indicate(ctx->dev, _rym_rx_ind);
|
||||||
|
getc_ack = _rym_getchar(ctx);
|
||||||
|
|
||||||
|
if (getc_ack != RYM_CODE_ACK)
|
||||||
|
{
|
||||||
|
return -RYM_ERR_ACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
getc_ack = _rym_getchar(ctx);
|
||||||
|
|
||||||
|
if (getc_ack != RYM_CODE_C)
|
||||||
|
{
|
||||||
|
return -RYM_ERR_ACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->stage = RYM_STAGE_ESTABLISHED;
|
||||||
|
|
||||||
|
return RT_EOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static rt_err_t _rym_trans_data(
|
||||||
|
struct rym_ctx *ctx,
|
||||||
|
rt_size_t data_sz,
|
||||||
|
enum rym_code *code)
|
||||||
|
{
|
||||||
|
const rt_size_t tsz = 2 + data_sz + 2;
|
||||||
rt_uint16_t recv_crc;
|
rt_uint16_t recv_crc;
|
||||||
|
|
||||||
/* seq + data + crc */
|
/* seq + data + crc */
|
||||||
|
@ -210,13 +332,13 @@ static rt_err_t _rym_trans_data(
|
||||||
ctx->stage = RYM_STAGE_TRANSMITTING;
|
ctx->stage = RYM_STAGE_TRANSMITTING;
|
||||||
|
|
||||||
/* sanity check */
|
/* sanity check */
|
||||||
recv_crc = (rt_uint16_t)(*(ctx->buf+tsz-1) << 8) | *(ctx->buf+tsz);
|
recv_crc = (rt_uint16_t)(*(ctx->buf + tsz - 1) << 8) | *(ctx->buf + tsz);
|
||||||
if (recv_crc != CRC16(ctx->buf+3, data_sz))
|
if (recv_crc != CRC16(ctx->buf + 3, data_sz))
|
||||||
return -RYM_ERR_CRC;
|
return -RYM_ERR_CRC;
|
||||||
|
|
||||||
/* congratulations, check passed. */
|
/* congratulations, check passed. */
|
||||||
if (ctx->on_data)
|
if (ctx->on_data)
|
||||||
*code = ctx->on_data(ctx, ctx->buf+3, data_sz);
|
*code = ctx->on_data(ctx, ctx->buf + 3, data_sz);
|
||||||
else
|
else
|
||||||
*code = RYM_CODE_ACK;
|
*code = RYM_CODE_ACK;
|
||||||
return RT_EOK;
|
return RT_EOK;
|
||||||
|
@ -235,7 +357,7 @@ static rt_err_t _rym_do_trans(struct rym_ctx *ctx)
|
||||||
rt_size_t data_sz, i;
|
rt_size_t data_sz, i;
|
||||||
|
|
||||||
code = _rym_read_code(ctx,
|
code = _rym_read_code(ctx,
|
||||||
RYM_WAIT_PKG_TICK);
|
RYM_WAIT_PKG_TICK);
|
||||||
switch (code)
|
switch (code)
|
||||||
{
|
{
|
||||||
case RYM_CODE_SOH:
|
case RYM_CODE_SOH:
|
||||||
|
@ -257,7 +379,8 @@ static rt_err_t _rym_do_trans(struct rym_ctx *ctx)
|
||||||
{
|
{
|
||||||
case RYM_CODE_CAN:
|
case RYM_CODE_CAN:
|
||||||
/* the spec require multiple CAN */
|
/* the spec require multiple CAN */
|
||||||
for (i = 0; i < RYM_END_SESSION_SEND_CAN_NUM; i++) {
|
for (i = 0; i < RYM_END_SESSION_SEND_CAN_NUM; i++)
|
||||||
|
{
|
||||||
_rym_putchar(ctx, RYM_CODE_CAN);
|
_rym_putchar(ctx, RYM_CODE_CAN);
|
||||||
}
|
}
|
||||||
return -RYM_ERR_CAN;
|
return -RYM_ERR_CAN;
|
||||||
|
@ -271,6 +394,41 @@ static rt_err_t _rym_do_trans(struct rym_ctx *ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static rt_err_t _rym_do_send_trans(struct rym_ctx *ctx)
|
||||||
|
{
|
||||||
|
ctx->stage = RYM_STAGE_TRANSMITTING;
|
||||||
|
enum rym_code code;
|
||||||
|
rt_size_t data_sz;
|
||||||
|
rt_uint32_t index = 1;
|
||||||
|
rt_uint8_t getc_ack;
|
||||||
|
|
||||||
|
data_sz = _RYM_SOH_PKG_SZ;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
if (ctx->on_data && ctx->on_data(ctx, ctx->buf + 3, data_sz - 5) != RYM_CODE_SOH)
|
||||||
|
return -RYM_ERR_CODE;
|
||||||
|
|
||||||
|
code = RYM_CODE_SOH;
|
||||||
|
|
||||||
|
_rym_send_packet(ctx, code, index);
|
||||||
|
index++;
|
||||||
|
rt_device_set_rx_indicate(ctx->dev, _rym_rx_ind);
|
||||||
|
|
||||||
|
getc_ack = _rym_getchar(ctx);
|
||||||
|
|
||||||
|
if (getc_ack != RYM_CODE_ACK)
|
||||||
|
{
|
||||||
|
return -RYM_ERR_ACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx->stage == RYM_STAGE_FINISHING)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RT_EOK;
|
||||||
|
}
|
||||||
|
|
||||||
static rt_err_t _rym_do_fin(struct rym_ctx *ctx)
|
static rt_err_t _rym_do_fin(struct rym_ctx *ctx)
|
||||||
{
|
{
|
||||||
enum rym_code code;
|
enum rym_code code;
|
||||||
|
@ -282,7 +440,7 @@ static rt_err_t _rym_do_fin(struct rym_ctx *ctx)
|
||||||
/* we already got one EOT in the caller. invoke the callback if there is
|
/* we already got one EOT in the caller. invoke the callback if there is
|
||||||
* one. */
|
* one. */
|
||||||
if (ctx->on_end)
|
if (ctx->on_end)
|
||||||
ctx->on_end(ctx, ctx->buf+3, 128);
|
ctx->on_end(ctx, ctx->buf + 3, 128);
|
||||||
|
|
||||||
_rym_putchar(ctx, RYM_CODE_NAK);
|
_rym_putchar(ctx, RYM_CODE_NAK);
|
||||||
code = _rym_read_code(ctx, RYM_WAIT_PKG_TICK);
|
code = _rym_read_code(ctx, RYM_WAIT_PKG_TICK);
|
||||||
|
@ -297,15 +455,15 @@ static rt_err_t _rym_do_fin(struct rym_ctx *ctx)
|
||||||
{
|
{
|
||||||
data_sz = _RYM_SOH_PKG_SZ;
|
data_sz = _RYM_SOH_PKG_SZ;
|
||||||
}
|
}
|
||||||
else if(code == RYM_CODE_STX)
|
else if (code == RYM_CODE_STX)
|
||||||
{
|
{
|
||||||
data_sz = _RYM_STX_PKG_SZ;
|
data_sz = _RYM_STX_PKG_SZ;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return -RYM_ERR_CODE;
|
return -RYM_ERR_CODE;
|
||||||
|
|
||||||
i = _rym_read_data(ctx, _RYM_SOH_PKG_SZ-1);
|
i = _rym_read_data(ctx, _RYM_SOH_PKG_SZ - 1);
|
||||||
if (i != (_RYM_SOH_PKG_SZ-1))
|
if (i != (_RYM_SOH_PKG_SZ - 1))
|
||||||
return -RYM_ERR_DSZ;
|
return -RYM_ERR_DSZ;
|
||||||
|
|
||||||
/* sanity check
|
/* sanity check
|
||||||
|
@ -313,14 +471,14 @@ static rt_err_t _rym_do_fin(struct rym_ctx *ctx)
|
||||||
if (ctx->buf[1] != 0 || ctx->buf[2] != 0xFF)
|
if (ctx->buf[1] != 0 || ctx->buf[2] != 0xFF)
|
||||||
return -RYM_ERR_SEQ;
|
return -RYM_ERR_SEQ;
|
||||||
|
|
||||||
recv_crc = (rt_uint16_t)(*(ctx->buf+_RYM_SOH_PKG_SZ-2) << 8) | *(ctx->buf+_RYM_SOH_PKG_SZ-1);
|
recv_crc = (rt_uint16_t)(*(ctx->buf + _RYM_SOH_PKG_SZ - 2) << 8) | *(ctx->buf + _RYM_SOH_PKG_SZ - 1);
|
||||||
if (recv_crc != CRC16(ctx->buf+3, _RYM_SOH_PKG_SZ-5))
|
if (recv_crc != CRC16(ctx->buf + 3, _RYM_SOH_PKG_SZ - 5))
|
||||||
return -RYM_ERR_CRC;
|
return -RYM_ERR_CRC;
|
||||||
|
|
||||||
/*next file transmission*/
|
/*next file transmission*/
|
||||||
if (ctx->buf[3] != 0)
|
if (ctx->buf[3] != 0)
|
||||||
{
|
{
|
||||||
if (ctx->on_begin && ctx->on_begin(ctx, ctx->buf+3, data_sz-5) != RYM_CODE_ACK)
|
if (ctx->on_begin && ctx->on_begin(ctx, ctx->buf + 3, data_sz - 5) != RYM_CODE_ACK)
|
||||||
return -RYM_ERR_CAN;
|
return -RYM_ERR_CAN;
|
||||||
return RT_EOK;
|
return RT_EOK;
|
||||||
}
|
}
|
||||||
|
@ -334,9 +492,54 @@ static rt_err_t _rym_do_fin(struct rym_ctx *ctx)
|
||||||
return RT_EOK;
|
return RT_EOK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static rt_err_t _rym_do_send_fin(struct rym_ctx *ctx)
|
||||||
|
{
|
||||||
|
enum rym_code code;
|
||||||
|
rt_size_t data_sz;
|
||||||
|
rt_uint8_t index = 0;
|
||||||
|
rt_uint8_t getc_ack;
|
||||||
|
|
||||||
|
data_sz = _RYM_SOH_PKG_SZ;
|
||||||
|
rt_device_set_rx_indicate(ctx->dev, _rym_rx_ind);
|
||||||
|
|
||||||
|
_rym_putchar(ctx, RYM_CODE_EOT);
|
||||||
|
getc_ack = _rym_getchar(ctx);
|
||||||
|
|
||||||
|
if (getc_ack != RYM_CODE_NAK)
|
||||||
|
{
|
||||||
|
return -RYM_ERR_ACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
_rym_putchar(ctx, RYM_CODE_EOT);
|
||||||
|
getc_ack = _rym_getchar(ctx);
|
||||||
|
|
||||||
|
if (getc_ack != RYM_CODE_ACK)
|
||||||
|
{
|
||||||
|
return -RYM_ERR_ACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
getc_ack = _rym_getchar(ctx);
|
||||||
|
|
||||||
|
if (getc_ack != RYM_CODE_C)
|
||||||
|
{
|
||||||
|
return -RYM_ERR_ACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx->on_end && ctx->on_end(ctx, ctx->buf + 3, data_sz - 5) != RYM_CODE_SOH)
|
||||||
|
return -RYM_ERR_CODE;
|
||||||
|
|
||||||
|
code = RYM_CODE_SOH;
|
||||||
|
|
||||||
|
_rym_send_packet(ctx, code, index);
|
||||||
|
|
||||||
|
ctx->stage = RYM_STAGE_FINISHED;
|
||||||
|
|
||||||
|
return RT_EOK;
|
||||||
|
}
|
||||||
|
|
||||||
static rt_err_t _rym_do_recv(
|
static rt_err_t _rym_do_recv(
|
||||||
struct rym_ctx *ctx,
|
struct rym_ctx *ctx,
|
||||||
int handshake_timeout)
|
int handshake_timeout)
|
||||||
{
|
{
|
||||||
rt_err_t err;
|
rt_err_t err;
|
||||||
|
|
||||||
|
@ -348,30 +551,78 @@ static rt_err_t _rym_do_recv(
|
||||||
|
|
||||||
err = _rym_do_handshake(ctx, handshake_timeout);
|
err = _rym_do_handshake(ctx, handshake_timeout);
|
||||||
if (err != RT_EOK)
|
if (err != RT_EOK)
|
||||||
|
{
|
||||||
|
rt_free(ctx->buf);
|
||||||
return err;
|
return err;
|
||||||
|
}
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
err = _rym_do_trans(ctx);
|
err = _rym_do_trans(ctx);
|
||||||
if (err != RT_EOK)
|
if (err != RT_EOK)
|
||||||
|
{
|
||||||
|
rt_free(ctx->buf);
|
||||||
return err;
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
err = _rym_do_fin(ctx);
|
err = _rym_do_fin(ctx);
|
||||||
if (err != RT_EOK)
|
if (err != RT_EOK)
|
||||||
|
{
|
||||||
|
rt_free(ctx->buf);
|
||||||
return err;
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
if (ctx->stage == RYM_STAGE_FINISHED)
|
if (ctx->stage == RYM_STAGE_FINISHED)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
rt_free(ctx->buf);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static rt_err_t _rym_do_send(
|
||||||
|
struct rym_ctx *ctx,
|
||||||
|
int handshake_timeout)
|
||||||
|
{
|
||||||
|
rt_err_t err;
|
||||||
|
|
||||||
|
ctx->stage = RYM_STAGE_NONE;
|
||||||
|
|
||||||
|
ctx->buf = rt_malloc(_RYM_STX_PKG_SZ);
|
||||||
|
if (ctx->buf == RT_NULL)
|
||||||
|
return -RT_ENOMEM;
|
||||||
|
|
||||||
|
err = _rym_do_send_handshake(ctx, handshake_timeout);
|
||||||
|
if (err != RT_EOK)
|
||||||
|
{
|
||||||
|
rt_free(ctx->buf);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = _rym_do_send_trans(ctx);
|
||||||
|
if (err != RT_EOK)
|
||||||
|
{
|
||||||
|
rt_free(ctx->buf);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = _rym_do_send_fin(ctx);
|
||||||
|
if (err != RT_EOK)
|
||||||
|
{
|
||||||
|
rt_free(ctx->buf);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
rt_free(ctx->buf);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
rt_err_t rym_recv_on_device(
|
rt_err_t rym_recv_on_device(
|
||||||
struct rym_ctx *ctx,
|
struct rym_ctx *ctx,
|
||||||
rt_device_t dev,
|
rt_device_t dev,
|
||||||
rt_uint16_t oflag,
|
rt_uint16_t oflag,
|
||||||
rym_callback on_begin,
|
rym_callback on_begin,
|
||||||
rym_callback on_data,
|
rym_callback on_data,
|
||||||
rym_callback on_end,
|
rym_callback on_end,
|
||||||
int handshake_timeout)
|
int handshake_timeout)
|
||||||
{
|
{
|
||||||
rt_err_t res;
|
rt_err_t res;
|
||||||
rt_err_t (*odev_rx_ind)(rt_device_t dev, rt_size_t size);
|
rt_err_t (*odev_rx_ind)(rt_device_t dev, rt_size_t size);
|
||||||
|
@ -393,9 +644,9 @@ rt_err_t rym_recv_on_device(
|
||||||
int_lvl = rt_hw_interrupt_disable();
|
int_lvl = rt_hw_interrupt_disable();
|
||||||
rt_device_set_rx_indicate(dev, _rym_rx_ind);
|
rt_device_set_rx_indicate(dev, _rym_rx_ind);
|
||||||
|
|
||||||
odev_flag = dev->flag;
|
odev_flag = dev->open_flag;
|
||||||
/* make sure the device don't change the content. */
|
/* make sure the device don't change the content. */
|
||||||
dev->flag &= ~RT_DEVICE_FLAG_STREAM;
|
dev->open_flag &= ~RT_DEVICE_FLAG_STREAM;
|
||||||
rt_hw_interrupt_enable(int_lvl);
|
rt_hw_interrupt_enable(int_lvl);
|
||||||
|
|
||||||
res = rt_device_open(dev, oflag);
|
res = rt_device_open(dev, oflag);
|
||||||
|
@ -412,12 +663,68 @@ __exit:
|
||||||
int_lvl = rt_hw_interrupt_disable();
|
int_lvl = rt_hw_interrupt_disable();
|
||||||
rt_sem_detach(&ctx->sem);
|
rt_sem_detach(&ctx->sem);
|
||||||
|
|
||||||
dev->flag = odev_flag;
|
dev->open_flag = odev_flag;
|
||||||
rt_device_set_rx_indicate(dev, odev_rx_ind);
|
rt_device_set_rx_indicate(dev, odev_rx_ind);
|
||||||
rt_hw_interrupt_enable(int_lvl);
|
rt_hw_interrupt_enable(int_lvl);
|
||||||
|
|
||||||
rt_free(ctx->buf);
|
|
||||||
_rym_the_ctx = RT_NULL;
|
_rym_the_ctx = RT_NULL;
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
rt_err_t res = 0;
|
||||||
|
rt_err_t (*odev_rx_ind)(rt_device_t dev, rt_size_t size);
|
||||||
|
rt_uint16_t odev_flag;
|
||||||
|
int int_lvl;
|
||||||
|
|
||||||
|
RT_ASSERT(_rym_the_ctx == 0);
|
||||||
|
_rym_the_ctx = ctx;
|
||||||
|
|
||||||
|
ctx->on_begin = on_begin;
|
||||||
|
ctx->on_data = on_data;
|
||||||
|
ctx->on_end = on_end;
|
||||||
|
ctx->dev = dev;
|
||||||
|
rt_sem_init(&ctx->sem, "rymsem", 0, RT_IPC_FLAG_FIFO);
|
||||||
|
|
||||||
|
odev_rx_ind = dev->rx_indicate;
|
||||||
|
/* no data should be received before the device has been fully setted up.
|
||||||
|
*/
|
||||||
|
int_lvl = rt_hw_interrupt_disable();
|
||||||
|
rt_device_set_rx_indicate(dev, _rym_rx_ind);
|
||||||
|
|
||||||
|
odev_flag = dev->open_flag;
|
||||||
|
/* make sure the device don't change the content. */
|
||||||
|
dev->open_flag &= ~RT_DEVICE_FLAG_STREAM;
|
||||||
|
rt_hw_interrupt_enable(int_lvl);
|
||||||
|
|
||||||
|
res = rt_device_open(dev, oflag);
|
||||||
|
if (res != RT_EOK)
|
||||||
|
goto __exit;
|
||||||
|
|
||||||
|
res = _rym_do_send(ctx, handshake_timeout);
|
||||||
|
|
||||||
|
rt_device_close(dev);
|
||||||
|
|
||||||
|
__exit:
|
||||||
|
|
||||||
|
int_lvl = rt_hw_interrupt_disable();
|
||||||
|
rt_sem_detach(&ctx->sem);
|
||||||
|
|
||||||
|
dev->open_flag = odev_flag;
|
||||||
|
rt_device_set_rx_indicate(dev, odev_rx_ind);
|
||||||
|
rt_hw_interrupt_enable(int_lvl);
|
||||||
|
|
||||||
|
_rym_the_ctx = RT_NULL;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,16 +7,19 @@
|
||||||
* Change Logs:
|
* Change Logs:
|
||||||
* Date Author Notes
|
* Date Author Notes
|
||||||
* 2013-04-14 Grissiom initial implementation
|
* 2013-04-14 Grissiom initial implementation
|
||||||
|
* 2019-12-09 Steven Liu add YMODEM send protocol
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __YMODEM_H__
|
#ifndef __YMODEM_H__
|
||||||
#define __YMODEM_H__
|
#define __YMODEM_H__
|
||||||
|
|
||||||
#include "rtthread.h"
|
#include "rtthread.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
/* The word "RYM" is stand for "Real-YModem". */
|
/* The word "RYM" is stand for "Real-YModem". */
|
||||||
|
|
||||||
enum rym_code {
|
enum rym_code
|
||||||
|
{
|
||||||
RYM_CODE_NONE = 0x00,
|
RYM_CODE_NONE = 0x00,
|
||||||
RYM_CODE_SOH = 0x01,
|
RYM_CODE_SOH = 0x01,
|
||||||
RYM_CODE_STX = 0x02,
|
RYM_CODE_STX = 0x02,
|
||||||
|
@ -44,6 +47,10 @@ enum rym_code {
|
||||||
#define RYM_ERR_DSZ 0x74
|
#define RYM_ERR_DSZ 0x74
|
||||||
/* the transmission is aborted by user */
|
/* the transmission is aborted by user */
|
||||||
#define RYM_ERR_CAN 0x75
|
#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. */
|
/* how many ticks wait for chars between packet. */
|
||||||
#ifndef RYM_WAIT_CHR_TICK
|
#ifndef RYM_WAIT_CHR_TICK
|
||||||
|
@ -63,7 +70,8 @@ enum rym_code {
|
||||||
#define RYM_END_SESSION_SEND_CAN_NUM 0x07
|
#define RYM_END_SESSION_SEND_CAN_NUM 0x07
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
enum rym_stage {
|
enum rym_stage
|
||||||
|
{
|
||||||
RYM_STAGE_NONE,
|
RYM_STAGE_NONE,
|
||||||
/* set when C is send */
|
/* set when C is send */
|
||||||
RYM_STAGE_ESTABLISHING,
|
RYM_STAGE_ESTABLISHING,
|
||||||
|
@ -80,16 +88,15 @@ enum rym_stage {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct rym_ctx;
|
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.
|
* and the len is the data size.
|
||||||
*
|
*
|
||||||
* TODO:
|
|
||||||
* When sending files, the len is the buf size in RYM. The callback need to
|
* 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
|
* 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
|
* transfer and the buf will be discarded. Any other return values will cause
|
||||||
* the transfer continue.
|
* 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.
|
/* Currently RYM only support one transfer session(ctx) for simplicity.
|
||||||
*
|
*
|
||||||
|
@ -112,7 +119,7 @@ struct rym_ctx
|
||||||
rt_device_t dev;
|
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.
|
* If an error happens, you can get where it is failed from ctx->stage.
|
||||||
*
|
*
|
||||||
|
@ -138,7 +145,30 @@ struct rym_ctx
|
||||||
* second.
|
* second.
|
||||||
*/
|
*/
|
||||||
rt_err_t rym_recv_on_device(struct rym_ctx *ctx, rt_device_t dev, rt_uint16_t oflag,
|
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,
|
rym_callback on_begin, rym_callback on_data, rym_callback on_end,
|
||||||
int handshake_timeout);
|
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
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue