diff --git a/components/utilities/Kconfig b/components/utilities/Kconfig index 9a5051298997028c23d3575d5001308571154aca..7fa6b476018569dbf15dc9e2b5888fffaaf2d63f 100644 --- a/components/utilities/Kconfig +++ b/components/utilities/Kconfig @@ -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 diff --git a/components/utilities/ymodem/ry_sy.c b/components/utilities/ymodem/ry_sy.c new file mode 100644 index 0000000000000000000000000000000000000000..fa57b8553a9360d8e12c684262c97e2ba240d7a2 --- /dev/null +++ b/components/utilities/ymodem/ry_sy.c @@ -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 +#include +#include +#include +#include +#include + +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 + +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 */ diff --git a/components/utilities/ymodem/ymodem.c b/components/utilities/ymodem/ymodem.c index 716c7023281e4f792af1d6b35f36d56fb4e5301a..02148453036429361d1c079eba757593ef61a655 100644 --- a/components/utilities/ymodem/ymodem.c +++ b/components/utilities/ymodem/ymodem.c @@ -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 #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_do_send_handshake( + struct rym_ctx *ctx, + int tm_sec) +{ + 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) + struct rym_ctx *ctx, + rt_size_t data_sz, + enum rym_code *code) { - const rt_size_t tsz = 2+data_sz+2; + 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); + + _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); - rt_free(ctx->buf); _rym_the_ctx = RT_NULL; return res; } + diff --git a/components/utilities/ymodem/ymodem.h b/components/utilities/ymodem/ymodem.h index 45e8f2272e7730348342d2b586580a99910b0961..8419290e1386f5ee6e269f7b363d8894b20f89dc 100644 --- a/components/utilities/ymodem/ymodem.h +++ b/components/utilities/ymodem/ymodem.h @@ -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 /* 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