/* * 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 */ #include #include #include #include #include #include #include #include #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;ifd=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); #ifdef 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 */