源:YModem協議
YModem協議:
?????????YModem協議是由XModem協議演變而來的,每包數據可以達到1024字節,是一個非常高效的文件傳輸協議。
?????????下面先看下YModem協議傳輸的完整的握手過程:先看下圖
?
SENDER:發送方。
RECEIVER:接收方。
第一步先由接收方,發送一個字符'C'
發送方收到'C'后,發送第一幀數據包,內容如下:
SOH?00?FF?Foo.c?NUL[123]?CRC?CRC
第1字節SOH:表示本包數據區大小有128字節。如果頭為STX表示本包數據區大小為1024
第2字節00:?編號,第一包為00,第二包為01,第三包為02依次累加。到FF后繼續從0循環遞增。
第3字節FF:?編號的反碼。?編號為00?對應FF,為01對應FE,以此類推。
第4字節到最后兩字節:若第1字節為SOH時有128字節,為STX時有1024字節,這部分為數據區。“Foo.c”?文件名,?超級終端下,在文件名后還有文件大小。官方dome也是因為使用了這個文件大小進行比對。這就是為什么用SecureCRT中的YMODEM協議而無法正確傳輸的原因。在文件名和文件大小之后,如果不滿128字節,以0補滿。
最后兩字節:這里需要注意,只有數據部分參與了效CRC驗,不包括頭和編碼部分。
?
16位CRC效驗,高字節在前,低字節在后。
接收方收到第一幀數據包后,發送ACK正確應答。
然后再發送一個字符'C'。
發送方收到'C'后,開始發送第二幀,第二幀中的數據存放的是第一包數據。
接收方收到數據后,發送一個ACK然后等待下一包數據傳送完畢,繼續ACK應答。直到所有數據傳輸完畢。
數據傳輸完畢后,發送方發EOT,第一次接收方以NAK應答,進行二次確認。
發送方收到NAK后,重發EOT,接收方第二次收到結束符,就以ACK應答。
最后接收方再發送一個'C',發送方在沒有第二個文件要傳輸的情況下,
?
發送如下數據
SOH?00?FF?00~00(共128個)?CRCH?CRCL?
接收方應答ACK后,正式結束數據傳輸。
以上部分,為YMODEM協議的基本操作流程。
?
?
源: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); }
?