1 /*
2 * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2019-12-09 Steven Liu the first version
9 * 2021-04-14 Meco Man Check the file path's legitimacy of 'sy' command
10 */
11
12 #include <rtthread.h>
13 #include <ymodem.h>
14 #include <dfs_file.h>
15 #include <unistd.h>
16 #include <sys/stat.h>
17 #include <sys/statfs.h>
18 #include <stdlib.h>
19 #include <string.h>
20
21 #ifndef DFS_USING_POSIX
22 #error "Please enable DFS_USING_POSIX"
23 #endif
24
25 struct custom_ctx
26 {
27 struct rym_ctx parent;
28 int fd;
29 int flen;
30 char fpath[DFS_PATH_MAX];
31 };
32
_get_path_lastname(const char * path)33 static const char *_get_path_lastname(const char *path)
34 {
35 char *ptr;
36 if ((ptr = (char *)strrchr(path, '/')) == NULL)
37 return path;
38
39 /* skip the '/' then return */
40 return ++ptr;
41 }
42
_rym_recv_begin(struct rym_ctx * ctx,rt_uint8_t * buf,rt_size_t len)43 static enum rym_code _rym_recv_begin(
44 struct rym_ctx *ctx,
45 rt_uint8_t *buf,
46 rt_size_t len)
47 {
48 struct custom_ctx *cctx = (struct custom_ctx *)ctx;
49 char insert_0 = '\0';
50 char *ret;
51 rt_err_t err;
52 ret = strchr(cctx->fpath,insert_0);
53 if(ret)
54 {
55 *ret = '/';
56 }
57 else
58 {
59 rt_kprintf("No end character\n");
60 return RYM_ERR_ACK;
61 }
62 rt_strncpy(ret + 1, (const char *)buf, len - 1);
63 cctx->fd = open(cctx->fpath, O_CREAT | O_WRONLY | O_TRUNC, 0);
64 if (cctx->fd < 0)
65 {
66 err = rt_get_errno();
67 rt_kprintf("error creating file: %d\n", err);
68 return RYM_CODE_CAN;
69 }
70 cctx->flen = atoi(1 + (const char *)buf + rt_strnlen((const char *)buf, len - 1));
71 if (cctx->flen == 0)
72 cctx->flen = -1;
73
74 return RYM_CODE_ACK;
75 }
76
_rym_recv_data(struct rym_ctx * ctx,rt_uint8_t * buf,rt_size_t len)77 static enum rym_code _rym_recv_data(
78 struct rym_ctx *ctx,
79 rt_uint8_t *buf,
80 rt_size_t len)
81 {
82 struct custom_ctx *cctx = (struct custom_ctx *)ctx;
83
84 RT_ASSERT(cctx->fd >= 0);
85 if (cctx->flen == -1)
86 {
87 write(cctx->fd, buf, len);
88 }
89 else
90 {
91 int wlen = len > cctx->flen ? cctx->flen : len;
92 write(cctx->fd, buf, wlen);
93 cctx->flen -= wlen;
94 }
95
96 return RYM_CODE_ACK;
97 }
98
_rym_recv_end(struct rym_ctx * ctx,rt_uint8_t * buf,rt_size_t len)99 static enum rym_code _rym_recv_end(
100 struct rym_ctx *ctx,
101 rt_uint8_t *buf,
102 rt_size_t len)
103 {
104 struct custom_ctx *cctx = (struct custom_ctx *)ctx;
105
106 RT_ASSERT(cctx->fd >= 0);
107 close(cctx->fd);
108 cctx->fd = -1;
109
110 return RYM_CODE_ACK;
111 }
112
_rym_send_begin(struct rym_ctx * ctx,rt_uint8_t * buf,rt_size_t len)113 static enum rym_code _rym_send_begin(
114 struct rym_ctx *ctx,
115 rt_uint8_t *buf,
116 rt_size_t len)
117 {
118 struct custom_ctx *cctx = (struct custom_ctx *)ctx;
119 struct stat file_buf;
120 char insert_0 = '\0';
121 rt_err_t err;
122
123 cctx->fd = open(cctx->fpath, O_RDONLY);
124 if (cctx->fd < 0)
125 {
126 err = rt_get_errno();
127 rt_kprintf("error open file: %d\n", err);
128 return RYM_ERR_FILE;
129 }
130 rt_memset(buf, 0, len);
131 err = stat(cctx->fpath, &file_buf);
132 if (err != RT_EOK)
133 {
134 rt_kprintf("error open file.\n");
135 return RYM_ERR_FILE;
136 }
137
138 const char *fdst = _get_path_lastname(cctx->fpath);
139 if(fdst != cctx->fpath)
140 {
141 fdst = dfs_normalize_path(RT_NULL, fdst);
142 if (fdst == RT_NULL)
143 {
144 return RYM_ERR_FILE;
145 }
146 }
147
148 rt_sprintf((char *)buf, "%s%c%d", fdst, insert_0, file_buf.st_size);
149
150 return RYM_CODE_SOH;
151 }
152
_rym_send_data(struct rym_ctx * ctx,rt_uint8_t * buf,rt_size_t len)153 static enum rym_code _rym_send_data(
154 struct rym_ctx *ctx,
155 rt_uint8_t *buf,
156 rt_size_t len)
157 {
158 struct custom_ctx *cctx = (struct custom_ctx *)ctx;
159 rt_size_t read_size;
160 int retry_read;
161
162 read_size = 0;
163 for (retry_read = 0; retry_read < 10; retry_read++)
164 {
165 read_size += read(cctx->fd, buf + read_size, len - read_size);
166 if (read_size == len)
167 break;
168 }
169
170 if (read_size < len)
171 {
172 rt_memset(buf + read_size, 0x1A, len - read_size);
173 ctx->stage = RYM_STAGE_FINISHING;
174 }
175
176 if (read_size > 128)
177 {
178 return RYM_CODE_STX;
179 }
180 return RYM_CODE_SOH;
181 }
182
_rym_send_end(struct rym_ctx * ctx,rt_uint8_t * buf,rt_size_t len)183 static enum rym_code _rym_send_end(
184 struct rym_ctx *ctx,
185 rt_uint8_t *buf,
186 rt_size_t len)
187 {
188 struct custom_ctx *cctx = (struct custom_ctx *)ctx;
189 rt_memset(buf, 0, len);
190 close(cctx->fd);
191 cctx->fd = -1;
192
193 return RYM_CODE_SOH;
194 }
195
rym_download_file(rt_device_t idev,const char * file_path)196 static rt_err_t rym_download_file(rt_device_t idev,const char *file_path)
197 {
198 rt_err_t res;
199 struct custom_ctx *ctx = rt_calloc(1, sizeof(*ctx));
200
201 if (!ctx)
202 {
203 rt_kprintf("rt_malloc failed\n");
204 return -RT_ENOMEM;
205 }
206 ctx->fd = -1;
207 rt_strncpy(ctx->fpath, file_path, DFS_PATH_MAX);
208 RT_ASSERT(idev);
209 res = rym_recv_on_device(&ctx->parent, idev, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
210 _rym_recv_begin, _rym_recv_data, _rym_recv_end, 1000);
211 rt_free(ctx);
212
213 return res;
214 }
215
rym_upload_file(rt_device_t idev,const char * file_path)216 static rt_err_t rym_upload_file(rt_device_t idev, const char *file_path)
217 {
218 rt_err_t res = 0;
219
220 struct custom_ctx *ctx = rt_calloc(1, sizeof(*ctx));
221 if (!ctx)
222 {
223 rt_kprintf("rt_malloc failed\n");
224 return -RT_ENOMEM;
225 }
226 ctx->fd = -1;
227 rt_strncpy(ctx->fpath, file_path, DFS_PATH_MAX);
228 RT_ASSERT(idev);
229 res = rym_send_on_device(&ctx->parent, idev,
230 RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
231 _rym_send_begin, _rym_send_data, _rym_send_end, 1000);
232 rt_free(ctx);
233
234 return res;
235 }
236
237 #ifdef RT_USING_FINSH
238 #include <finsh.h>
239
ry(uint8_t argc,char ** argv)240 static rt_err_t ry(uint8_t argc, char **argv)
241 {
242 rt_err_t res;
243 rt_device_t dev;
244 /* temporarily support 1 file*/
245 const char *file_path;
246 if (argc < 2)
247 {
248 rt_kprintf("invalid file path.\n");
249 return -RT_ERROR;
250 }
251 if (argc > 2)
252 dev = rt_device_find(argv[2]);
253 else
254 dev = rt_console_get_device();
255 if (!dev)
256 {
257 rt_kprintf("could not find device.\n");
258 return -RT_ERROR;
259 }
260 file_path = argv[1];
261 res = rym_download_file(dev,file_path);
262
263 return res;
264 }
265 MSH_CMD_EXPORT(ry, YMODEM Receive e.g: ry file_path [uart0] default by console.);
266
sy(uint8_t argc,char ** argv)267 static rt_err_t sy(uint8_t argc, char **argv)
268 {
269 rt_err_t res;
270 /* temporarily support 1 file*/
271 const char *file_path;
272 rt_device_t dev;
273
274 if (argc < 2)
275 {
276 rt_kprintf("invalid file path.\n");
277 return -RT_ERROR;
278 }
279
280 if (argc > 2)
281 dev = rt_device_find(argv[2]);
282 else
283 dev = rt_console_get_device();
284 if (!dev)
285 {
286 rt_kprintf("could not find device.\n");
287 return -RT_ERROR;
288 }
289 file_path = argv[1];
290 res = rym_upload_file(dev, file_path);
291
292 return res;
293 }
294 MSH_CMD_EXPORT(sy, YMODEM Send e.g: sy file_path [uart0] default by console.);
295
296 #endif /* RT_USING_FINSH */
297