322 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			322 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * File      : sz.c
 | 
						|
 * the implemention of sending files to the remote computers  
 | 
						|
 * through the zmodem protocol.
 | 
						|
 * Change Logs:
 | 
						|
 * Date           Author       Notes
 | 
						|
 * 2011-03-29     itspy       
 | 
						|
 */
 | 
						|
 | 
						|
#include <rtthread.h>
 | 
						|
#include <finsh.h>
 | 
						|
#include <shell.h>
 | 
						|
#include <rtdef.h>
 | 
						|
#include <dfs.h>
 | 
						|
#include <dfs_file.h>
 | 
						|
#include <dfs_posix.h>
 | 
						|
#include "zdef.h"
 | 
						|
 | 
						|
 | 
						|
static rt_uint8_t TX_BUFFER[TX_BUFFER_SIZE];	     /* sender buffer */
 | 
						|
static rt_uint8_t file_cnt = 0;		                 /* count of number of files opened */
 | 
						|
static rt_uint8_t Rxflags  = 0;	                  	 /* rx parameter flags */
 | 
						|
static rt_uint8_t ZF2_OP;		                  	 /* file transfer option */ 
 | 
						|
 | 
						|
void zs_start(char *path);
 | 
						|
static void zsend_init(void);
 | 
						|
static rt_err_t zsend_files(struct zfile *zf);
 | 
						|
static rt_err_t zsend_file(struct zfile *zf, rt_uint8_t *buf, rt_uint16_t len);
 | 
						|
static rt_err_t zsend_file_data(struct zfile *zf);
 | 
						|
static rt_uint16_t zfill_buffer(struct zfile *zf, rt_uint8_t *buf, rt_uint16_t size);
 | 
						|
static rt_err_t zget_sync(void);
 | 
						|
static void zsay_bibi(void);
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/* start zmodem send process */
 | 
						|
void zs_start(char *path)
 | 
						|
{
 | 
						|
    struct zfile *zf;
 | 
						|
	rt_err_t res = RT_ERROR;
 | 
						|
    char *p,*q;
 | 
						|
	zf = rt_malloc(sizeof(struct zfile));
 | 
						|
	if (zf == RT_NULL)
 | 
						|
	{
 | 
						|
	    rt_kprintf("zf: out of memory\r\n");
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	rt_kprintf("\r\nsz: ready...\r\n");	   /* here ready to send things */
 | 
						|
	memset(zf, 0, sizeof(struct zfile));
 | 
						|
    zf->fname = path;
 | 
						|
	zf->fd = -1;
 | 
						|
	res = zsend_files(zf);
 | 
						|
	p = zf->fname;
 | 
						|
	for (;;)
 | 
						|
	{
 | 
						|
		q = strstr(p,"/");
 | 
						|
		if (q == RT_NULL)  break;
 | 
						|
		p = q+1;
 | 
						|
	}
 | 
						|
    if (res == RT_EOK)
 | 
						|
    {
 | 
						|
        rt_kprintf("\r\nfile: %s \r\nsize: %ld bytes\r\nsend completed.\r\n",
 | 
						|
		          p,zf->bytes_received);
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        rt_kprintf("\r\nfile: %s \r\nsize: 0 bytes\r\nsend failed.\r\n",p);
 | 
						|
    }
 | 
						|
	rt_free(zf);
 | 
						|
 | 
						|
	return;
 | 
						|
}
 | 
						|
 | 
						|
/* init the parameters */
 | 
						|
static void zsend_init(void)
 | 
						|
{
 | 
						|
	rt_err_t res = -RT_ERROR;
 | 
						|
 | 
						|
	zinit_parameter();
 | 
						|
	for(;;)          /* wait ZPAD */
 | 
						|
	{
 | 
						|
		res = zread_line(800);
 | 
						|
		if (res == ZPAD) break;
 | 
						|
	}
 | 
						|
	for (;;) 
 | 
						|
	{
 | 
						|
	    res = zget_header(rx_header);
 | 
						|
		if (res == ZRINIT) break;
 | 
						|
	}
 | 
						|
	if ((rx_header[ZF1] & ZRQNVH))
 | 
						|
	{
 | 
						|
		zput_pos(0x80L);	/* Show we can var header */
 | 
						|
		zsend_hex_header(ZRQINIT, tx_header);
 | 
						|
	}
 | 
						|
	Rxflags = rx_header[ZF0] & 0377;
 | 
						|
	if (Rxflags & CANFC32) Txfcs32 = 1;    /* used 32bits CRC check */
 | 
						|
 | 
						|
	if (ZF2_OP == ZTRLE && (Rxflags & CANRLE))	  /* for RLE packet */
 | 
						|
		 Txfcs32 = 2;
 | 
						|
	else
 | 
						|
		ZF2_OP = 0;
 | 
						|
    /* send SINIT cmd */
 | 
						|
	return;
 | 
						|
}
 | 
						|
 | 
						|
/* send files */
 | 
						|
static rt_err_t zsend_files(struct zfile *zf)
 | 
						|
{
 | 
						|
	char *p,*q;
 | 
						|
	char *str = "/";
 | 
						|
	struct stat finfo;
 | 
						|
	rt_err_t res = -RT_ERROR;
 | 
						|
 | 
						|
	if (zf->fname == RT_NULL)
 | 
						|
	{
 | 
						|
	    rt_kprintf("\r\nerror: no file to be send.\r\n");
 | 
						|
		return res;
 | 
						|
	}
 | 
						|
	if ((zf->fd=open(zf->fname, DFS_O_RDONLY,0)) <0)
 | 
						|
	{
 | 
						|
	    rt_kprintf("\r\ncan not open file:%s\r\n",zf->fname+1);
 | 
						|
	    return res;
 | 
						|
	}
 | 
						|
 | 
						|
	zf->file_end = 0;
 | 
						|
	++file_cnt;	 
 | 
						|
	/* extract file name */
 | 
						|
	p = zf->fname;
 | 
						|
	for (;;)
 | 
						|
	{
 | 
						|
		q = strstr(p,str);
 | 
						|
		if (q == RT_NULL)  break;
 | 
						|
		p = q+1;
 | 
						|
	}	
 | 
						|
	q = (char*)TX_BUFFER;	  
 | 
						|
	for (;;)
 | 
						|
	{
 | 
						|
	    *q++ = *p++;
 | 
						|
		if (*p == 0) break;
 | 
						|
	}
 | 
						|
	*q++ = 0;
 | 
						|
	p=q;
 | 
						|
	while (q < (char*)(TX_BUFFER + 1024))
 | 
						|
		*q++ = 0;
 | 
						|
	/* get file attributes */
 | 
						|
	fstat(zf->fd,&finfo);
 | 
						|
	Left_sizes += finfo.st_size;			                
 | 
						|
	rt_sprintf(p, "%lu %lo %o 3 %d %ld", (long)finfo.st_size, finfo.st_mtime,
 | 
						|
			  finfo.st_mode, file_cnt, Left_sizes);
 | 
						|
	Left_sizes -= finfo.st_size;
 | 
						|
	TX_BUFFER[127] = (finfo.st_size + 127) >>7;
 | 
						|
	TX_BUFFER[126] = (finfo.st_size + 127) >>15;
 | 
						|
 | 
						|
	zsend_init();
 | 
						|
	/* start sending files */							
 | 
						|
	res = zsend_file(zf,TX_BUFFER, (p-(char*)TX_BUFFER)+strlen(p)+1);
 | 
						|
	zsay_bibi();
 | 
						|
	close(zf->fd);
 | 
						|
 
 | 
						|
	return res;
 | 
						|
}
 | 
						|
 | 
						|
/* send file name and related info */
 | 
						|
static rt_err_t zsend_file(struct zfile *zf, rt_uint8_t *buf, rt_uint16_t len)
 | 
						|
{
 | 
						|
	rt_uint8_t cnt;
 | 
						|
	rt_err_t res = -RT_ERROR;
 | 
						|
 | 
						|
	for (cnt=0;cnt<5;cnt++) 
 | 
						|
	{  
 | 
						|
		tx_header[ZF0] = ZF0_CMD;	            /* file conversion option */
 | 
						|
		tx_header[ZF1] = ZF1_CMD;               /* file management option */
 | 
						|
		tx_header[ZF2] = (ZF3_CMD|ZF2_OP);	    /* file transfer option   */
 | 
						|
		tx_header[ZF3] = ZF3_CMD;
 | 
						|
		zsend_bin_header(ZFILE, tx_header);
 | 
						|
		zsend_bin_data(buf, len, ZCRCW);
 | 
						|
loop:
 | 
						|
		res = zget_header(rx_header);
 | 
						|
		switch (res) 
 | 
						|
		{
 | 
						|
		case ZRINIT:
 | 
						|
			 while ((res = zread_line(50)) > 0)
 | 
						|
			 {
 | 
						|
				 if (res == ZPAD) 
 | 
						|
				 {
 | 
						|
					goto loop;
 | 
						|
				 }
 | 
						|
			 }
 | 
						|
			 break;
 | 
						|
		case ZCAN:
 | 
						|
		case TIMEOUT:
 | 
						|
		case ZABORT:
 | 
						|
		case ZFIN:
 | 
						|
             break;
 | 
						|
		case -RT_ERROR:
 | 
						|
		case ZNAK:
 | 
						|
			 break;
 | 
						|
		case ZCRC:	                         /* no CRC request */
 | 
						|
			 goto loop;
 | 
						|
		case ZFERR:
 | 
						|
		case ZSKIP:
 | 
						|
			 break;
 | 
						|
		case ZRPOS:		           	         /* here we want */
 | 
						|
		     zget_pos(Rxpos);
 | 
						|
			 Txpos = Rxpos;
 | 
						|
			 return(zsend_file_data(zf));
 | 
						|
		default:
 | 
						|
			 break;
 | 
						|
		} 
 | 
						|
	}
 | 
						|
 | 
						|
	return res;
 | 
						|
}
 | 
						|
 | 
						|
/* send the file data */
 | 
						|
static rt_err_t zsend_file_data(struct zfile *zf)
 | 
						|
{
 | 
						|
	rt_int16_t cnt;
 | 
						|
	rt_uint8_t cmd;
 | 
						|
	rt_err_t res = -RT_ERROR;	
 | 
						|
	/* send ZDATA packet, start to send data */
 | 
						|
start_send:
 | 
						|
	zput_pos(Txpos);
 | 
						|
	zsend_bin_header(ZDATA, tx_header);
 | 
						|
	do
 | 
						|
	{
 | 
						|
		cnt = zfill_buffer(zf,TX_BUFFER,RX_BUFFER_SIZE);
 | 
						|
		if (cnt < RX_BUFFER_SIZE )
 | 
						|
			cmd = ZCRCE;				
 | 
						|
		else
 | 
						|
			cmd = ZCRCG;
 | 
						|
		zsend_bin_data(TX_BUFFER, cnt, cmd);
 | 
						|
		zf->bytes_received= Txpos += cnt;
 | 
						|
		if (cmd == ZCRCW)
 | 
						|
			goto get_syn1;
 | 
						|
	} while (cnt == RX_BUFFER_SIZE);
 | 
						|
	for (;;) 	                     /*  get ack and check if send finish */
 | 
						|
	{
 | 
						|
		zput_pos(Txpos);
 | 
						|
		zsend_bin_header(ZEOF, tx_header);
 | 
						|
get_syn1:
 | 
						|
        res = zget_sync();
 | 
						|
		switch (res) 
 | 
						|
		{
 | 
						|
		case ZACK:
 | 
						|
			 goto get_syn1;
 | 
						|
		case ZNAK:
 | 
						|
			 continue;
 | 
						|
		case ZRPOS:				        /* resend here */
 | 
						|
		     lseek(zf->fd,Txpos,0);
 | 
						|
			 goto start_send;
 | 
						|
		case ZRINIT:		           /*  send finish,then begin to send next file */
 | 
						|
			 return RT_EOK;
 | 
						|
		case ZSKIP:
 | 
						|
		case -RT_ERROR:
 | 
						|
		     return res;
 | 
						|
		default:
 | 
						|
             return res;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/* fill file data to buffer*/
 | 
						|
static rt_uint16_t zfill_buffer(struct zfile *zf, rt_uint8_t *buf, rt_uint16_t size)
 | 
						|
{
 | 
						|
	return (read(zf->fd,buf,size));
 | 
						|
}
 | 
						|
 | 
						|
/* wait sync(ack) from the receiver */
 | 
						|
static rt_err_t zget_sync(void)
 | 
						|
{
 | 
						|
    rt_err_t res = -RT_ERROR;
 | 
						|
 | 
						|
	for (;;) 
 | 
						|
	{
 | 
						|
		res = zget_header(rx_header);
 | 
						|
		switch (res) 
 | 
						|
		{
 | 
						|
		case ZCAN:
 | 
						|
		case ZABORT:
 | 
						|
		case ZFIN:
 | 
						|
		case TIMEOUT:
 | 
						|
			 return -RT_ERROR;
 | 
						|
		case ZRPOS:		             /* get pos, need to resend */
 | 
						|
		     zget_pos(Rxpos);
 | 
						|
			 Txpos = Rxpos;
 | 
						|
			 return res;
 | 
						|
		case ZACK:
 | 
						|
			 return res;
 | 
						|
		case ZRINIT:		         /* get ZRINIT indicate that the prev file send completed */
 | 
						|
			 return res;
 | 
						|
		case ZSKIP:
 | 
						|
			 return res;
 | 
						|
		case -RT_ERROR:
 | 
						|
		default:
 | 
						|
			 zsend_bin_header(ZNAK, tx_header);
 | 
						|
			 continue;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/* say "bibi" to the receiver */
 | 
						|
static void zsay_bibi(void)
 | 
						|
{
 | 
						|
	for (;;) 
 | 
						|
	{
 | 
						|
		zput_pos(0L);	            	      /* reninit position of next file*/
 | 
						|
		zsend_hex_header(ZFIN, tx_header);	  /* send finished session cmd */
 | 
						|
		switch (zget_header(rx_header)) 
 | 
						|
		{
 | 
						|
		case ZFIN:
 | 
						|
			zsend_line('O'); 
 | 
						|
			zsend_line('O'); 
 | 
						|
		case ZCAN:
 | 
						|
		case TIMEOUT:
 | 
						|
			return;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
/* end of sz.c */
 |