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);   
}  

 

posted @ 2016-08-22 17:58  酒醉的Tiger  阅读(5836)  评论(0编辑  收藏  举报