402 lines
10 KiB
C
402 lines
10 KiB
C
|
/*
|
||
|
* 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 */
|