xref: /nrf52832-nimble/rt-thread/components/utilities/zmodem/rz.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
1 /*
2  * File      : rz.c
3  * the implemention of receiving files from the remote computers
4  * through the zmodem protocol.
5  * Change Logs:
6  * Date           Author       Notes
7  * 2011-03-29     itspy
8  * 2011-12-12     aozima       fixed syntax error.
9  */
10 
11 #include <rtthread.h>
12 #include <finsh.h>
13 #include <shell.h>
14 #include <rtdef.h>
15 #include <dfs.h>
16 #include <dfs_file.h>
17 #include <dfs_posix.h>
18 #include <stdio.h>
19 #include "zdef.h"
20 
21 
22 void zr_start(char *path);
23 static rt_err_t zrec_init(rt_uint8_t *rxbuf, struct zfile *zf);
24 static rt_err_t zrec_files(struct zfile *zf);
25 static rt_err_t zwrite_file(rt_uint8_t *buf, rt_uint16_t size, struct zfile *zf);
26 static rt_err_t zrec_file_data(rt_uint8_t *buf, struct zfile *zf);;
27 static rt_err_t zrec_file(rt_uint8_t *rxbuf, struct zfile *zf);
28 static rt_err_t zget_file_info(char *name, struct zfile *zf);
29 static rt_err_t zwrite_file(rt_uint8_t *buf, rt_uint16_t size, struct zfile *zf);
30 static void zrec_ack_bibi(void);
31 
32 
33 /* start zmodem receive proccess */
34 void zr_start(char *path)
35 {
36     struct zfile *zf;
37     rt_uint8_t n;
38 	char ch,*p,*q;
39 	rt_err_t res = -RT_ERROR;
40 
41 	zf = rt_malloc(sizeof(struct zfile));
42 	if (zf == RT_NULL)
43 	{
44 	    rt_kprintf("zf: out of memory\r\n");
45 		return;
46 	}
47 	memset(zf, 0, sizeof(struct zfile));
48     zf->fname = path;
49 	zf->fd = -1;
50 	res = zrec_files(zf);
51 	p = zf->fname;
52 	for (;;)
53 	{
54 		q = strstr(p,"/");
55 		if (q == RT_NULL)  break;
56 		p = q+1;
57 	}
58     if (res == RT_EOK)
59     {
60         rt_kprintf("\b\b\bfile: %s                           \r\n",p);
61 		rt_kprintf("size: %ld bytes\r\n",zf->bytes_received);
62 		rt_kprintf("receive completed.\r\n");
63 		close(zf->fd);
64 		rt_free(zf->fname);
65     }
66     else
67     {
68         rt_kprintf("\b\b\bfile: %s                           \r\n",p);
69 		rt_kprintf("size: 0 bytes\r\n");
70 		rt_kprintf("receive failed.\r\n");
71 		if (zf->fd >= 0)
72 		{
73 	        close(zf->fd);
74 	        unlink(zf->fname);    /* remove this file */
75 			rt_free(zf->fname);
76 		}
77     }
78 	rt_free(zf);
79 	/* waiting,clear console buffer */
80 	rt_thread_delay(RT_TICK_PER_SECOND/2);
81 	while(1)
82 	{
83 	   n=rt_device_read(shell->device, 0, &ch, 1);
84 	   if (n == 0) break;
85 	}
86 
87 	return ;
88 }
89 
90 /* receiver init, wait for ack */
91 static rt_err_t zrec_init(rt_uint8_t *rxbuf, struct zfile *zf)
92 {
93     rt_uint8_t err_cnt = 0;
94 	rt_err_t res = -RT_ERROR;
95 
96 	for (;;)
97 	{
98 		zput_pos(0L);
99 		tx_header[ZF0] = ZF0_CMD;
100 		tx_header[ZF1] = ZF1_CMD;
101 		tx_header[ZF2] = ZF2_CMD;
102 		zsend_hex_header(ZRINIT, tx_header);
103 again:
104         res = zget_header(rx_header);
105 		switch(res)
106 		{
107 		case ZFILE:
108 			 ZF0_CMD  = rx_header[ZF0];
109 			 ZF1_CMD  = rx_header[ZF1];
110 			 ZF2_CMD  = rx_header[ZF2];
111 			 ZF3_CMD  = rx_header[ZF3];
112 			 res = zget_data(rxbuf, RX_BUFFER_SIZE);
113 			 if (res == GOTCRCW)
114 			 {
115 	             if ((res =zget_file_info((char*)rxbuf,zf))!= RT_EOK)
116 	             {
117 	                 zsend_hex_header(ZSKIP, tx_header);
118 		             return (res);
119 	             }
120 			     return RT_EOK;;
121 			 }
122 			 zsend_hex_header(ZNAK, tx_header);
123 			 goto again;
124 		case ZSINIT:
125 			 if (zget_data((rt_uint8_t*)Attn, ZATTNLEN) == GOTCRCW) 	  /* send zack */
126 			 {
127 				zsend_hex_header(ZACK, tx_header);
128 				goto again;
129 			 }
130 			 zsend_hex_header(ZNAK, tx_header);		     /* send znak */
131 			 goto again;
132 		case ZRQINIT:
133 			 continue;
134 		case ZEOF:
135 			 continue;
136 		case ZCOMPL:
137 			 goto again;
138 		case ZFIN:			     /* end file session */
139 			 zrec_ack_bibi();
140 			 return res;
141 		 default:
142 		      if (++err_cnt >1000) return -RT_ERROR;
143 		      continue;
144 		}
145 	}
146 }
147 
148 /* receive files */
149 static rt_err_t zrec_files(struct zfile *zf)
150 {
151 	rt_uint8_t *rxbuf;
152 	rt_err_t res = -RT_ERROR;
153 
154 	zinit_parameter();
155 	rxbuf = rt_malloc(RX_BUFFER_SIZE*sizeof(rt_uint8_t));
156 	if (rxbuf == RT_NULL)
157 	{
158 		 rt_kprintf("rxbuf: out of memory\r\n");
159 		 return -RT_ERROR;
160 	}
161 	rt_kprintf("\r\nrz: ready...\r\n");	   /* here ready to receive things */
162 	if ((res = zrec_init(rxbuf,zf))!= RT_EOK)
163 	{
164 	     rt_kprintf("\b\b\breceive init failed\r\n");
165 		 rt_free(rxbuf);
166 		 return -RT_ERROR;
167 	}
168 	res = zrec_file(rxbuf,zf);
169 	if (res == ZFIN)
170 	{
171 	    rt_free(rxbuf);
172 	    return RT_EOK;	     /* if finish session */
173 	}
174 	else if (res == ZCAN)
175 	{
176         rt_free(rxbuf);
177 		return ZCAN;        /* cancel by sender */
178 	}
179 	else
180 	{
181 	   zsend_can();
182 	   rt_free(rxbuf);
183 	   return res;
184 	}
185 }
186 /* receive file */
187 static rt_err_t zrec_file(rt_uint8_t *rxbuf, struct zfile *zf)
188 {
189 	rt_err_t res = - RT_ERROR;
190 	rt_uint16_t err_cnt = 0;
191 
192 	do
193 	{
194 		zput_pos(zf->bytes_received);
195 		zsend_hex_header(ZRPOS, tx_header);
196 again:
197         res = zget_header(rx_header);
198 		switch (res)
199 		{
200 		case ZDATA:
201 			 zget_pos(Rxpos);
202 			 if (Rxpos != zf->bytes_received)
203 			 {
204                  zsend_break(Attn);
205 				 continue;
206 			 }
207 			 err_cnt = 0;
208 			 res = zrec_file_data(rxbuf,zf);
209 			 if (res == -RT_ERROR)
210 			 {
211 			     zsend_break(Attn);
212 			     continue;
213 			 }
214 			 else if (res == GOTCAN) return res;
215 			 else goto again;
216 		case ZRPOS:
217 		     zget_pos(Rxpos);
218 			 continue;
219 		case ZEOF:
220 		     err_cnt = 0;
221 		     zget_pos(Rxpos);
222 			 if (Rxpos != zf->bytes_received  || Rxpos != zf->bytes_total)
223 			 {
224 			     continue;
225 			 }
226 		     return (zrec_init(rxbuf,zf));    /* resend ZRINIT packet,ready to receive next file */
227         case ZFIN:
228 			 zrec_ack_bibi();
229 			 return ZCOMPL;
230 		case ZCAN:
231 #ifdef ZDEBUG
232              rt_kprintf("error code: sender cancelled \r\n");
233 #endif
234 			 zf->bytes_received = 0L;		 /* throw the received data */
235 		     return res;
236 		case ZSKIP:
237 			 return res;
238 		case -RT_ERROR:
239 			 zsend_break(Attn);
240 			 continue;
241 		case ZNAK:
242 		case TIMEOUT:
243 		default:
244 			continue;
245 		}
246 	} while(++err_cnt < 100);
247 
248 	return res;
249 }
250 
251 /* proccess file infomation */
252 static rt_err_t zget_file_info(char *name, struct zfile *zf)
253 {
254 	char *p;
255 	char *full_path,*ptr;
256 	rt_uint16_t i,len;
257 	rt_err_t res  = -RT_ERROR;
258 	struct statfs buf;
259 	struct stat finfo;
260 
261 	if (zf->fname == RT_NULL) 		       /* extract file path  */
262     {
263 	    len = strlen(name)+2;
264 	}
265 	else
266 	    len = strlen(zf->fname)+strlen(name)+2;
267     full_path = rt_malloc(len);
268     if (full_path == RT_NULL)
269 	{
270 	    zsend_can();
271 		rt_kprintf("\b\b\bfull_path: out of memory\n");
272 		rt_free(full_path);
273 		return -RT_ERROR;
274 	}
275 	memset(full_path,0,len);
276 
277     for (i=0,ptr=zf->fname;i<len-strlen(name)-2;i++)
278 		 full_path[i] = *ptr++;
279     full_path[len-strlen(name)-2] = '/';
280 	/* check if is a directory */
281 	if ((zf->fd=open(full_path, DFS_O_DIRECTORY,0)) < 0)
282 	{
283 	    zsend_can();
284 	    rt_kprintf("\b\b\bcan not open file:%s\r\n",zf->fname+1);
285 		close(zf->fd);
286 		zf->fd = -1;
287 		rt_free(full_path);
288 	    return res;
289 	}
290 	fstat(zf->fd, &finfo);
291 	if ((finfo.st_mode&S_IFDIR) != S_IFDIR)
292 	{
293 		close(zf->fd);
294 		zf->fd = -1;
295 		return res;
296 	}
297 	close(zf->fd);
298 	/* get fullpath && file attributes */
299     strcat(full_path,name);
300     zf->fname = full_path;
301 	p = strlen(name)+name+1;
302 	sscanf((const char *)p, "%ld%lo%o", &zf->bytes_total,&zf->ctime,&zf->mode);
303 #if defined(RT_USING_DFS) && defined(DFS_USING_WORKDIR)
304 	dfs_statfs(working_directory,&buf);
305 	if (zf->bytes_total > (buf.f_blocks * buf.f_bfree))
306 	{
307 	    zsend_can();
308 	    rt_kprintf("\b\b\bnot enough disk space\r\n");
309 		zf->fd = -1;
310 		rt_free(full_path);
311 		return -RT_ERROR;
312 	}
313 #else
314     buf = buf;
315 #endif
316 	zf->bytes_received   = 0L;
317 	if ((zf->fd = open(zf->fname,DFS_O_CREAT|DFS_O_WRONLY,0)) < 0)	 /* create or replace exist file */
318 	{
319 	    zsend_can();
320 	    rt_kprintf("\b\b\bcan not create file:%s \r\n",zf->fname);
321 		return -RT_ERROR;
322 	}
323 
324 	return RT_EOK;
325 }
326 
327 /* receive file data,continously, no ack */
328 static rt_err_t zrec_file_data(rt_uint8_t *buf, struct zfile *zf)
329 {
330     rt_err_t res = -RT_ERROR;
331 
332 more_data:
333 	res = zget_data(buf,RX_BUFFER_SIZE);
334 	switch(res)
335 	{
336 	case GOTCRCW:						   /* zack received */
337 		 zwrite_file(buf,Rxcount,zf);
338 		 zf->bytes_received += Rxcount;
339 		 zput_pos(zf->bytes_received);
340 		 zsend_line(XON);
341 		 zsend_hex_header(ZACK, tx_header);
342 		 return RT_EOK;
343 	case GOTCRCQ:
344 		 zwrite_file(buf,Rxcount,zf);
345 		 zf->bytes_received += Rxcount;
346 		 zput_pos(zf->bytes_received);
347 		 zsend_hex_header(ZACK, tx_header);
348 		 goto more_data;
349 	case GOTCRCG:
350 		 zwrite_file(buf,Rxcount,zf);
351 		 zf->bytes_received += Rxcount;
352 		 goto more_data;
353 	case GOTCRCE:
354 		 zwrite_file(buf,Rxcount,zf);
355 		 zf->bytes_received += Rxcount;
356 		 return RT_EOK;
357 	case GOTCAN:
358 #ifdef ZDEBUG
359 	     rt_kprintf("error code : ZCAN \r\n");
360 #endif
361 		 return res;
362 	case TIMEOUT:
363 	     return res;
364     case -RT_ERROR:
365 	     zsend_break(Attn);
366 	     return res;
367 	default:
368 	     return res;
369 	}
370 }
371 
372 /* write file */
373 static rt_err_t zwrite_file(rt_uint8_t *buf,rt_uint16_t size, struct zfile *zf)
374 {
375 	return (write(zf->fd,buf,size));
376 }
377 
378 /* ack bibi */
379 static void zrec_ack_bibi(void)
380 {
381 	rt_uint8_t i;
382 
383 	zput_pos(0L);
384 	for (i=0;i<3;i++)
385 	{
386 		zsend_hex_header(ZFIN, tx_header);
387 		switch (zread_line(100))
388 		{
389 		case 'O':
390 			 zread_line(1);
391 			 return;
392 		case RCDO:
393 			 return;
394 		case TIMEOUT:
395 		default:
396 			 break;
397 		}
398 	}
399 }
400 
401 /* end of rz.c */
402