| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401 | /* * File      : rz.c * the implemention of receiving files from the remote computers   * through the zmodem protocol. * Change Logs: * Date           Author       Notes * 2011-03-29     itspy        * 2011-12-12     aozima       fixed syntax error.        */#include <rtthread.h>#include <finsh.h>#include <shell.h>#include <rtdef.h>#include <dfs.h>#include <dfs_file.h>#include <dfs_posix.h>#include <stdio.h>#include "zdef.h"void zr_start(char *path);static rt_err_t zrec_init(rt_uint8_t *rxbuf, struct zfile *zf);static rt_err_t zrec_files(struct zfile *zf);static rt_err_t zwrite_file(rt_uint8_t *buf, rt_uint16_t size, struct zfile *zf);static rt_err_t zrec_file_data(rt_uint8_t *buf, struct zfile *zf);;static rt_err_t zrec_file(rt_uint8_t *rxbuf, struct zfile *zf);static rt_err_t zget_file_info(char *name, struct zfile *zf);static rt_err_t zwrite_file(rt_uint8_t *buf, rt_uint16_t size, struct zfile *zf);static void zrec_ack_bibi(void);/* start zmodem receive proccess */void zr_start(char *path){    struct zfile *zf;    rt_uint8_t n;	char ch,*p,*q;	rt_err_t res = -RT_ERROR;	zf = rt_malloc(sizeof(struct zfile));	if (zf == RT_NULL)	{	    rt_kprintf("zf: out of memory\r\n");		return;	}	memset(zf, 0, sizeof(struct zfile));    zf->fname = path;	zf->fd = -1;	res = zrec_files(zf);   	p = zf->fname;	for (;;)	{		q = strstr(p,"/");		if (q == RT_NULL)  break;		p = q+1;	}	       if (res == RT_EOK)    {		          rt_kprintf("\b\b\bfile: %s                           \r\n",p);		rt_kprintf("size: %ld bytes\r\n",zf->bytes_received);		rt_kprintf("receive completed.\r\n");		close(zf->fd);		rt_free(zf->fname);    }    else    {        rt_kprintf("\b\b\bfile: %s                           \r\n",p);		rt_kprintf("size: 0 bytes\r\n");		rt_kprintf("receive failed.\r\n");		if (zf->fd >= 0)		{	        close(zf->fd);	        unlink(zf->fname);    /* remove this file */ 			rt_free(zf->fname);		}	    }	rt_free(zf);	/* waiting,clear console buffer */	rt_thread_delay(RT_TICK_PER_SECOND/2);	while(1)                     	{	   n=rt_device_read(shell->device, 0, &ch, 1);	   if (n == 0) break;	}	return ;}/* receiver init, wait for ack */static rt_err_t zrec_init(rt_uint8_t *rxbuf, struct zfile *zf){    rt_uint8_t err_cnt = 0;	rt_err_t res = -RT_ERROR;	for (;;) 	{		zput_pos(0L);		tx_header[ZF0] = ZF0_CMD;		tx_header[ZF1] = ZF1_CMD;		tx_header[ZF2] = ZF2_CMD;		zsend_hex_header(ZRINIT, tx_header);again:        res = zget_header(rx_header);		switch(res)		{		case ZFILE:						 			 ZF0_CMD  = rx_header[ZF0];			 ZF1_CMD  = rx_header[ZF1];			 ZF2_CMD  = rx_header[ZF2];			 ZF3_CMD  = rx_header[ZF3];			 res = zget_data(rxbuf, RX_BUFFER_SIZE);			 if (res == GOTCRCW)			 {	             if ((res =zget_file_info((char*)rxbuf,zf))!= RT_EOK) 	             {	                 zsend_hex_header(ZSKIP, tx_header);		             return (res);	             }			     return RT_EOK;; 			 }     			 zsend_hex_header(ZNAK, tx_header);			 goto again;		case ZSINIT:			 if (zget_data((rt_uint8_t*)Attn, ZATTNLEN) == GOTCRCW) 	  /* send zack */			 {				zsend_hex_header(ZACK, tx_header);				goto again;			 }			 zsend_hex_header(ZNAK, tx_header);		     /* send znak */			 goto again;		case ZRQINIT:			 continue;		case ZEOF:			 continue;		case ZCOMPL:			 goto again;		case ZFIN:			     /* end file session */			 zrec_ack_bibi(); 			 return res;		 default:		      if (++err_cnt >1000) return -RT_ERROR;		      continue;		}	}}/* receive files */static rt_err_t zrec_files(struct zfile *zf){	rt_uint8_t *rxbuf;	rt_err_t res = -RT_ERROR;	zinit_parameter();	rxbuf = rt_malloc(RX_BUFFER_SIZE*sizeof(rt_uint8_t));	if (rxbuf == RT_NULL)	{		 rt_kprintf("rxbuf: out of memory\r\n");		 return -RT_ERROR;	}	rt_kprintf("\r\nrz: ready...\r\n");	   /* here ready to receive things */	if ((res = zrec_init(rxbuf,zf))!= RT_EOK)	{	     rt_kprintf("\b\b\breceive init failed\r\n");		 rt_free(rxbuf);		 return -RT_ERROR;	}	res = zrec_file(rxbuf,zf);	if (res == ZFIN)	{		    rt_free(rxbuf); 	    return RT_EOK;	     /* if finish session */	}	else if (res == ZCAN)	{        rt_free(rxbuf);		return ZCAN;        /* cancel by sender */	}	else	{	   zsend_can();	   rt_free(rxbuf);	   return res;	}}/* receive file */static rt_err_t zrec_file(rt_uint8_t *rxbuf, struct zfile *zf){	rt_err_t res = - RT_ERROR;	rt_uint16_t err_cnt = 0;	do 	{		zput_pos(zf->bytes_received);		zsend_hex_header(ZRPOS, tx_header);again:        res = zget_header(rx_header);		switch (res) 		{		case ZDATA:			 zget_pos(Rxpos);			 if (Rxpos != zf->bytes_received)			 {                 zsend_break(Attn);      				 continue;			 }			 err_cnt = 0;			 res = zrec_file_data(rxbuf,zf);			 if (res == -RT_ERROR)			 {	  			     zsend_break(Attn);			     continue;			 }			 else if (res == GOTCAN) return res;				 else goto again;	 		case ZRPOS:		     zget_pos(Rxpos);			 continue;		case ZEOF:		     err_cnt = 0;		     zget_pos(Rxpos);			 if (Rxpos != zf->bytes_received  || Rxpos != zf->bytes_total) 			 {			     continue;			 }							 		     return (zrec_init(rxbuf,zf));    /* resend ZRINIT packet,ready to receive next file */        case ZFIN:			 zrec_ack_bibi(); 			 return ZCOMPL; 		case ZCAN:#ifdef ZDEBUG             rt_kprintf("error code: sender cancelled \r\n");#endif			 zf->bytes_received = 0L;		 /* throw the received data */  		     return res;		case ZSKIP:			 return res;		case -RT_ERROR:             			 zsend_break(Attn);			 continue;		case ZNAK:		case TIMEOUT:		default: 			continue;		}	} while(++err_cnt < 100);	return res;}/* proccess file infomation */static rt_err_t zget_file_info(char *name, struct zfile *zf){	char *p;	char *full_path,*ptr;	rt_uint16_t i,len;	rt_err_t res  = -RT_ERROR;	struct statfs buf;	struct stat finfo;	if (zf->fname == RT_NULL) 		       /* extract file path  */    {	    len = strlen(name)+2; 	}	else	    len = strlen(zf->fname)+strlen(name)+2;     full_path = rt_malloc(len);    if (full_path == RT_NULL)		 	{	    zsend_can();		rt_kprintf("\b\b\bfull_path: out of memory\n");		rt_free(full_path);		return -RT_ERROR;	}	memset(full_path,0,len);    for (i=0,ptr=zf->fname;i<len-strlen(name)-2;i++)		 full_path[i] = *ptr++;    full_path[len-strlen(name)-2] = '/';	/* check if is a directory */	if ((zf->fd=open(full_path, DFS_O_DIRECTORY,0)) < 0)	 	{	    zsend_can();	    rt_kprintf("\b\b\bcan not open file:%s\r\n",zf->fname+1);		close(zf->fd);		zf->fd = -1;		rt_free(full_path);	    return res;	}	fstat(zf->fd, &finfo);	if ((finfo.st_mode&S_IFDIR) != S_IFDIR)           	{		close(zf->fd);		zf->fd = -1;		return res;	}	close(zf->fd);	   	/* get fullpath && file attributes */    strcat(full_path,name);    zf->fname = full_path;	p = strlen(name)+name+1;	   	sscanf((const char *)p, "%ld%lo%o", &zf->bytes_total,&zf->ctime,&zf->mode);#if defined(RT_USING_DFS) && defined(DFS_USING_WORKDIR)	dfs_statfs(working_directory,&buf);	if (zf->bytes_total > (buf.f_blocks * buf.f_bfree))	{	    zsend_can();	    rt_kprintf("\b\b\bnot enough disk space\r\n");		zf->fd = -1;		rt_free(full_path);		return -RT_ERROR;  	}#else    buf = buf;#endif	zf->bytes_received   = 0L;	if ((zf->fd = open(zf->fname,DFS_O_CREAT|DFS_O_WRONLY,0)) < 0)	 /* create or replace exist file */	{	    zsend_can();	    rt_kprintf("\b\b\bcan not create file:%s \r\n",zf->fname);			return -RT_ERROR;	}	return RT_EOK;}/* receive file data,continously, no ack */static rt_err_t zrec_file_data(rt_uint8_t *buf, struct zfile *zf){    rt_err_t res = -RT_ERROR;more_data:	res = zget_data(buf,RX_BUFFER_SIZE);	switch(res)	{	case GOTCRCW:						   /* zack received */		 zwrite_file(buf,Rxcount,zf);		 zf->bytes_received += Rxcount;		 zput_pos(zf->bytes_received);		 zsend_line(XON);		 zsend_hex_header(ZACK, tx_header);		 return RT_EOK;	case GOTCRCQ:		 zwrite_file(buf,Rxcount,zf);		 zf->bytes_received += Rxcount;		 zput_pos(zf->bytes_received);		 zsend_hex_header(ZACK, tx_header);		 goto more_data;	case GOTCRCG:		 zwrite_file(buf,Rxcount,zf);		 zf->bytes_received += Rxcount;		 goto more_data;	case GOTCRCE:		 zwrite_file(buf,Rxcount,zf);		 zf->bytes_received += Rxcount;		 return RT_EOK;	case GOTCAN:#ifdef ZDEBUG	     rt_kprintf("error code : ZCAN \r\n");#endif		 return res;	case TIMEOUT:	     return res;    case -RT_ERROR:	     zsend_break(Attn);	     return res;	default:	     return res;	}}/* write file */static rt_err_t zwrite_file(rt_uint8_t *buf,rt_uint16_t size, struct zfile *zf){	return (write(zf->fd,buf,size));}/* ack bibi */static void zrec_ack_bibi(void){	rt_uint8_t i;	zput_pos(0L);	for (i=0;i<3;i++) 	{		zsend_hex_header(ZFIN, tx_header);		switch (zread_line(100)) 		{		case 'O':			 zread_line(1);				 return;		case RCDO:			 return;		case TIMEOUT:		default:			 break;		}	}}/* end of rz.c */
 |