[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

View File

@@ -7,12 +7,15 @@
* Change Logs:
* Date Author Notes
* 2013-04-14 Grissiom initial implementation
* 2019-12-09 Steven Liu add YMODEM send protocol
*/
#include <rthw.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,
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
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,
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;
@@ -54,6 +57,30 @@ rt_uint16_t CRC16(unsigned char *q, int len)
crc = (crc << 8) ^ ccitt_table[((crc >> 8) ^ *q++) & 0xff];
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
// 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)
static enum rym_code _rym_read_code(
struct rym_ctx *ctx,
rt_tick_t timeout)
struct rym_ctx *ctx,
rt_tick_t timeout)
{
/* Fast path */
if (rt_device_read(ctx->dev, 0, ctx->buf, 1) == 1)
return (enum rym_code)(*ctx->buf);
/* Slow path */
do {
do
{
rt_size_t rsz;
/* 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);
if (rsz == 1)
return (enum rym_code)(*ctx->buf);
} while (1);
}
while (1);
}
/* the caller should at least alloc _RYM_STX_PKG_SZ buffer */
static rt_size_t _rym_read_data(
struct rym_ctx *ctx,
rt_size_t len)
struct rym_ctx *ctx,
rt_size_t len)
{
/* we should already have had the code */
rt_uint8_t *buf = ctx->buf + 1;
@@ -103,23 +132,61 @@ static rt_size_t _rym_read_data(
do
{
readlen += rt_device_read(ctx->dev,
0, buf+readlen, len-readlen);
0, buf + readlen, len - readlen);
if (readlen >= len)
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;
}
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)
{
rt_device_write(ctx->dev, 0, &code, sizeof(code));
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(
struct rym_ctx *ctx,
int tm_sec)
struct rym_ctx *ctx,
int tm_sec)
{
enum rym_code code;
rt_size_t i;
@@ -133,13 +200,13 @@ static rt_err_t _rym_do_handshake(
{
_rym_putchar(ctx, RYM_CODE_C);
code = _rym_read_code(ctx,
RYM_CHD_INTV_TICK);
RYM_CHD_INTV_TICK);
if (code == RYM_CODE_SOH)
{
data_sz = _RYM_SOH_PKG_SZ;
break;
}
else if(code == RYM_CODE_STX)
else if (code == RYM_CODE_STX)
{
data_sz = _RYM_STX_PKG_SZ;
break;
@@ -154,7 +221,7 @@ static rt_err_t _rym_do_handshake(
i = 0;
/* automatic exit after receiving specified length data, timeout: 100ms */
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);
rt_thread_mdelay(5);
@@ -167,24 +234,79 @@ static rt_err_t _rym_do_handshake(
if (ctx->buf[1] != 0 || ctx->buf[2] != 0xFF)
return -RYM_ERR_SEQ;
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);
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);
if (recv_crc != cal_crc)
return -RYM_ERR_CRC;
/* 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 RT_EOK;
}
static rt_err_t _rym_trans_data(
struct rym_ctx *ctx,
rt_size_t data_sz,
enum rym_code *code)
static rt_err_t _rym_do_send_handshake(
struct rym_ctx *ctx,
int tm_sec)
{
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;
/* seq + data + crc */
@@ -210,13 +332,13 @@ static rt_err_t _rym_trans_data(
ctx->stage = RYM_STAGE_TRANSMITTING;
/* sanity check */
recv_crc = (rt_uint16_t)(*(ctx->buf+tsz-1) << 8) | *(ctx->buf+tsz);
if (recv_crc != CRC16(ctx->buf+3, data_sz))
recv_crc = (rt_uint16_t)(*(ctx->buf + tsz - 1) << 8) | *(ctx->buf + tsz);
if (recv_crc != CRC16(ctx->buf + 3, data_sz))
return -RYM_ERR_CRC;
/* congratulations, check passed. */
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
*code = RYM_CODE_ACK;
return RT_EOK;
@@ -235,7 +357,7 @@ static rt_err_t _rym_do_trans(struct rym_ctx *ctx)
rt_size_t data_sz, i;
code = _rym_read_code(ctx,
RYM_WAIT_PKG_TICK);
RYM_WAIT_PKG_TICK);
switch (code)
{
case RYM_CODE_SOH:
@@ -257,7 +379,8 @@ static rt_err_t _rym_do_trans(struct rym_ctx *ctx)
{
case RYM_CODE_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);
}
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)
{
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
* one. */
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);
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;
}
else if(code == RYM_CODE_STX)
else if (code == RYM_CODE_STX)
{
data_sz = _RYM_STX_PKG_SZ;
}
else
return -RYM_ERR_CODE;
i = _rym_read_data(ctx, _RYM_SOH_PKG_SZ-1);
if (i != (_RYM_SOH_PKG_SZ-1))
i = _rym_read_data(ctx, _RYM_SOH_PKG_SZ - 1);
if (i != (_RYM_SOH_PKG_SZ - 1))
return -RYM_ERR_DSZ;
/* 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)
return -RYM_ERR_SEQ;
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))
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))
return -RYM_ERR_CRC;
/*next file transmission*/
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 RT_EOK;
}
@@ -334,9 +492,54 @@ static rt_err_t _rym_do_fin(struct rym_ctx *ctx)
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(
struct rym_ctx *ctx,
int handshake_timeout)
struct rym_ctx *ctx,
int handshake_timeout)
{
rt_err_t err;
@@ -348,30 +551,78 @@ static rt_err_t _rym_do_recv(
err = _rym_do_handshake(ctx, handshake_timeout);
if (err != RT_EOK)
{
rt_free(ctx->buf);
return err;
}
while (1)
{
err = _rym_do_trans(ctx);
if (err != RT_EOK)
{
rt_free(ctx->buf);
return err;
}
err = _rym_do_fin(ctx);
if (err != RT_EOK)
{
rt_free(ctx->buf);
return err;
}
if (ctx->stage == RYM_STAGE_FINISHED)
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;
}
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)
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;
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();
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. */
dev->flag &= ~RT_DEVICE_FLAG_STREAM;
dev->open_flag &= ~RT_DEVICE_FLAG_STREAM;
rt_hw_interrupt_enable(int_lvl);
res = rt_device_open(dev, oflag);
@@ -412,12 +663,68 @@ __exit:
int_lvl = rt_hw_interrupt_disable();
rt_sem_detach(&ctx->sem);
dev->flag = odev_flag;
dev->open_flag = odev_flag;
rt_device_set_rx_indicate(dev, odev_rx_ind);
rt_hw_interrupt_enable(int_lvl);
rt_free(ctx->buf);
_rym_the_ctx = RT_NULL;
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;
}