1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  */
9 
10 #include <rtthread.h>
11 #include <ymodem.h>
12 #include <dfs_file.h>
13 #include <unistd.h>
14 #include <stdio.h>
15 #include <sys/stat.h>
16 #include <sys/statfs.h>
17 #include <stdlib.h>
18 
19 #include <board.h>
20 
21 struct custom_ctx
22 {
23     struct rym_ctx parent;
24     int fd;
25     int flen;
26     char fpath[256];
27 };
28 
_rym_bg(struct rym_ctx * ctx,rt_uint8_t * buf,rt_size_t len)29 static enum rym_code _rym_bg(
30         struct rym_ctx *ctx,
31         rt_uint8_t *buf,
32         rt_size_t len)
33 {
34     struct custom_ctx *cctx = (struct custom_ctx*)ctx;
35     cctx->fpath[0] = '/';
36     /* the buf should be the file name */
37     strcpy(&(cctx->fpath[1]), (const char*)buf);
38     cctx->fd = open(cctx->fpath, O_CREAT | O_WRONLY | O_TRUNC, 0);
39     if (cctx->fd < 0)
40     {
41         rt_err_t err = rt_get_errno();
42         rt_kprintf("error creating file: %d\n", err);
43         rt_kprintf("abort transmission\n");
44         return RYM_CODE_CAN;
45     }
46 
47     cctx->flen = atoi((const char*)buf+strlen((const char*)buf)+1);
48     if (cctx->flen == 0)
49         cctx->flen = -1;
50     return RYM_CODE_ACK;
51 }
52 
_rym_tof(struct rym_ctx * ctx,rt_uint8_t * buf,rt_size_t len)53 static enum rym_code _rym_tof(
54         struct rym_ctx *ctx,
55         rt_uint8_t *buf,
56         rt_size_t len)
57 {
58     struct custom_ctx *cctx = (struct custom_ctx*)ctx;
59     RT_ASSERT(cctx->fd >= 0);
60     if (cctx->flen == -1)
61     {
62         write(cctx->fd, buf, len);
63     }
64     else
65     {
66         int wlen = len > cctx->flen ? cctx->flen : len;
67         write(cctx->fd, buf, wlen);
68         cctx->flen -= wlen;
69     }
70     return RYM_CODE_ACK;
71 }
72 
_rym_end(struct rym_ctx * ctx,rt_uint8_t * buf,rt_size_t len)73 static enum rym_code _rym_end(
74         struct rym_ctx *ctx,
75         rt_uint8_t *buf,
76         rt_size_t len)
77 {
78     struct custom_ctx *cctx = (struct custom_ctx*)ctx;
79 
80     RT_ASSERT(cctx->fd >= 0);
81     close(cctx->fd);
82     cctx->fd = -1;
83 
84     return RYM_CODE_ACK;
85 }
86 
rym_write_to_file(rt_device_t idev)87 rt_err_t rym_write_to_file(rt_device_t idev)
88 {
89     rt_err_t res;
90     struct custom_ctx *ctx = rt_malloc(sizeof(*ctx));
91 
92     RT_ASSERT(idev);
93 
94     rt_kprintf("entering RYM mode\n");
95 
96     res = rym_recv_on_device(&ctx->parent, idev, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
97                              _rym_bg, _rym_tof, _rym_end, 1000);
98 
99     /* there is no Ymodem traffic on the line so print out info. */
100     rt_kprintf("leaving RYM mode with code %d\n", res);
101     rt_kprintf("file %s has been created.\n", ctx->fpath);
102 
103     rt_free(ctx);
104 
105     return res;
106 }
107 
108 #ifdef RT_USING_FINSH
109 #include <finsh.h>
ry(char * dname)110 rt_err_t ry(char *dname)
111 {
112     rt_err_t res;
113 
114     rt_device_t dev = rt_device_find(dname);
115     if (!dev)
116     {
117         rt_kprintf("could not find device:%s\n", dname);
118         return -RT_ERROR;
119     }
120 
121     res = rym_write_to_file(dev);
122 
123     return res;
124 }
125 FINSH_FUNCTION_EXPORT(ry, receive files by ymodem protocol);
126 #endif
127