YModem協議


源: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,不包括頭和編碼部分。

 

16CRC效驗,高字節在前,低字節在后。

接收方收到第一幀數據包后,發送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);   
}  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM