ymodem协议c实现(转)
/****************************************Copyright (c)************************************************** ** Henan Star Hi-Tech CO.,LTD ** All rights reserved. ** **----------------------------------------File Info----------------------------------------------------- ** 文件名称: ** 工程项目: ** 说 明: ** ** 作 者: 日 期: ** 建立版本: ** **----------------------------------------modification-------------------------------------------------- ** 作 者: ** 日 期: ** 版 本: 标 记: ** 说 明: ** ********************************************************************************************************/ #ifndef __XYMODEM_H_ #define __XYMODEM_H_ #define MODEM_MAX_RETRIES 50 //接收等待延时时间 #define MODEM_CRC_RETRIES 51 //>MODEM_MAX_RETRIES固定为CRC校验 #define MODEM_CAN_COUNT 3 //Wait for 3 times CAN before quiting #define MODEM_EOT_COUNT 1 #define MODEM_SOH 0x01 //数据块起始字符 #define MODEM_STX 0x02 #define MODEM_EOT 0x04 #define MODEM_ACK 0x06 #define MODEM_NAK 0x15 #define MODEM_CAN 0x18 #define MODEM_C 0x43 typedef struct{ int modemtype; int crc_mode; int nxt_num; //下一数据块序号 int cur_num; //当块序号 int len; int rec_err; //数据块接收状态 unsigned char buf[1024]; //数据 unsigned int filelen; //Ymodem可有带文件名称和长度 unsigned char filename[32]; }modem_struct; #ifdef __cplusplus extern "C"{ #endif int ymodem_init(modem_struct *mblock); int modem_recvdata(modem_struct *mblock); //int crc_16(unsigned char *buf, int len); void modem_cancle(void); #ifdef __cplusplus } #endif #endif
/****************************************Copyright (c)************************************************** ** Henan Star Hi-Tech CO.,LTD ** All rights reserved. ** **----------------------------------------File Info----------------------------------------------------- ** 文件名称: ** 工程项目: ** 说 明: ** ** 作 者: 日 期: ** 建立版本: ** **----------------------------------------modification-------------------------------------------------- ** 作 者: ** 日 期: ** 版 本: 标 记: ** 说 明: ** ********************************************************************************************************/ #include "xymodem1.h" #include "heads.h" unsigned int buf_filelen(unsigned char *ptr); /***************************************************************************************** ** 函数名称: ** 函数功能: ** 入口参数: ** 返 回 值: ** 编 写: 日 期: 版 本 号: ** 修改历史: ******************************************************************************************/ int ymodem_init(modem_struct *mblock) { int stat; int max_tries = MODEM_MAX_RETRIES; int crc_tries =MODEM_CRC_RETRIES; unsigned char *bufptr = mblock->buf; unsigned char *namptr = mblock->filename; mblock->nxt_num = 0; mblock->modemtype = 2; mblock->rec_err = 0; mblock->crc_mode = 1; while (max_tries-- > 0) { stat = modem_recvdata(mblock); if (0 == stat) //接收成功 { //file name while (*bufptr != '\0') { *namptr++ = *bufptr++; } *namptr = '\0'; bufptr++; while (*bufptr == ' ') { bufptr++; } //file length mblock->filelen = buf_filelen(bufptr); //other data; Uart_SendByte(MODEM_ACK); return 0; } else if (2 == stat) //取消传输 { return 2; } else if (-3 == stat) { if (mblock->cur_num == 1) { mblock->modemtype = 1; mblock->nxt_num = 2; return 1; } } else //超时或校验方式不对 { if (crc_tries-- <= 0) { crc_tries = MODEM_CRC_RETRIES; mblock->crc_mode = (mblock->crc_mode+1) & 1; } } } return -1; } /***************************************************************************************** ** 函数名称: ** 函数功能: ** 入口参数: ** 返 回 值:0:成功接收数据 -1:接收超时 -2:帧错误 -3:帧序号序号错误(严重错误) 1:消息结束 2:取消发送 ** 编 写: 日 期: 版 本 号: ** 修改历史: ******************************************************************************************/ int modem_recvdata(modem_struct *mblock) { int stat, hd_found=0, i; int can_counter=0, eot_counter=0; unsigned char *in_ptr = mblock->buf; int cksum; unsigned char ch, blk, cblk, crch, crcl; Uart_RxEmpty(); //接收缓冲区清空 if (mblock->nxt_num == 0) { if (mblock->crc_mode) { Uart_SendByte(MODEM_C); } else { Uart_SendByte(MODEM_NAK); } } else { if (mblock->rec_err) { Uart_SendByte(MODEM_NAK); } else { if (mblock->nxt_num == 1) { if (mblock->crc_mode) { Uart_SendByte(MODEM_C); } else { Uart_SendByte(MODEM_NAK); } } else { Uart_SendByte(MODEM_ACK); } } } while (!hd_found) //头字节 { stat = Uart_RecvByteTimeout(&ch); if (stat == 0) { switch (ch) { case MODEM_SOH : hd_found = 1; mblock->len = 128; break; case MODEM_STX : hd_found = 1; mblock->len = 1024; break; case MODEM_CAN : if ((++can_counter) >= MODEM_CAN_COUNT) { return 2; } break; case MODEM_EOT : //文件传输结束 if ((++eot_counter) >= MODEM_EOT_COUNT) { Uart_SendByte(MODEM_ACK); if (mblock->modemtype == 2) //Ymodem协议为批文件传输协议 { Uart_SendByte(MODEM_C); //单个文件需 C ACK C后会自动停止传输 Uart_SendByte(MODEM_ACK); Uart_SendByte(MODEM_C); modem_cancle(); //多个文件强制停止传输 } return 1; } break; default: break; } } else { return -1; } } stat = Uart_RecvByteTimeout(&blk); //数据块错误或超时 if (stat != 0) { return -1; } stat = Uart_RecvByteTimeout(&cblk); //数块补码 if (stat != 0) { return -1; } for (i=0; i < mblock->len ; i++) { stat = Uart_RecvByteTimeout(in_ptr++); if (stat != 0) { return -1; } } stat = Uart_RecvByteTimeout(&crch); //CRC if (stat != 0) { return -1; } if (mblock->crc_mode) { stat = Uart_RecvByteTimeout(&crcl); if (stat != 0) { return -1; } } if (blk^cblk != 0xff) { return (-2); } if (mblock->crc_mode) { in_ptr = mblock->buf; cksum = 0; for (stat=mblock->len ; stat>0; stat--) { cksum = cksum^(int)(*in_ptr++) << 8; for (i=8; i!=0; i--) { if (cksum & 0x8000) cksum = cksum << 1 ^ 0x1021; else cksum = cksum << 1; } } cksum &= 0xffff; if (cksum != (crch<<8 | crcl)) { mblock->rec_err = 1; return (-2); } } else { for (i=0; i<mblock->len; i++) //和校验方式 { cksum += mblock->buf[i]; } if ((cksum&0xff)!=crch) { mblock->rec_err = 1; return (-2); } } mblock->cur_num = blk; if (blk != mblock->nxt_num) //blk检查 { return (-3); } mblock->nxt_num++; mblock->rec_err = 0; return 0; } unsigned int buf_filelen(unsigned char *ptr) { int datatype=10, result=0; if (ptr[0]=='0' && (ptr[1]=='x' && ptr[1]=='X')) { datatype = 16; ptr += 2; } for ( ; *ptr!='\0'; ptr++) { if (*ptr>= '0' && *ptr<='9') { result =result*datatype+*ptr-'0'; } else { if (datatype == 10) { return result; } else { if (*ptr>='A' && *ptr<='F') { result = result*16 + *ptr-55; //55 = 'A'-10 } else if (*ptr>='a' && *ptr<='f') { result = result*16 + *ptr-87; //87 = 'a'-10 } else { return result; } } } } return result; } void modem_cancle(void) { Uart_SendByte(0x18); Uart_SendByte(0x18); Uart_SendByte(0x18); Uart_SendByte(0x18); Uart_SendByte(0x18); }