Ymodem协议

Posted 不积跬步*无以至千里

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Ymodem协议相关的知识,希望对你有一定的参考价值。

网上很多关于Ymodem协议的,有部分是错误的,以下是经过本人亲自编写的程序,测试可用。目前单片机作为接受端,用于IAP升级,发送还没写。另外对于终止传送也还没写,正常情况接收是完全没问题的。

划重点:《重复发送1024字节直到收到EOT开头数据,网上的错误点就在这里,搞了我很久,网上说的是不够128凑齐发SOH包,其实不是,是凑齐1024发STX包直到发EOT。》

平台:stm32f101v8  超级终端 keil

 

传输起来,效果是这样的!一般很快 如下图 2秒就7K了

 

首先超级终端中Ymodem协议是这样的,定义单片机位接受者,超级终端为发送者:

SOH开头: 128字节的数据,总包大小128+5,SOH即0x01

STX开头: 1024字节的数据,总包大小1024+5 ,STX即0x02

EOT开头: 单个字节,传输完成,总包大小1 ,EOT即0x04

/*YModem standard CMD*/
#define YMODEM_SOH (0x01)
#define YMODEM_STX (0x02)
#define YMODEM_EOT (0x04)
#define YMODEM_ACK (0x06)
#define YMODEM_NAK (0x15)
#define YMODEM_CAN (0x18)
#define YMODEM_C (0x43)

以下为交流顺序:

接受者:发送大写字母C,等待数据

发送者:发送ASCII中的SOH也就是01,后面是包序号00,包序号反码FF,文件名YG06_V0_1.bin,NULL,文件大小11212 bytes ,补齐111字节至128字节,CRC CRC是数据段的16位CRC校验码。总共此包是128+5=133字节。SOH

我的第一个包收到如下: 01 00 FF "YG06_V0_1.bin"  NULL "11212" NULL[111] CRC CRC

接受者:发送大写字母ACK,发送大写字母C,等待数据

发送者:发送ASCII中的STX也就是02,后面是包序号01,包序号反码FE,1024字节数据,CRC CRC.总共此包是1024+5=1029字节。STX

我的第一个包收到如下: 02 01 FE DATA[1024] CRC CRC

接受者:ACK

发送者:STX包

接受者:ACK

发送者:STX包

.......

接受者:ACK

发送者:EOT

重复发送1024字节直到收到EOT开头数据,网上的错误点就在这里,搞了我很久,网上说的是不够128凑齐发SOH包,其实不是,是凑齐1024发STX包直到发EOT。

 

接受者:NAK ( 第一次收到EOT发NAK )

 

发送者:EOT

 

接受者:ACK C( 第二次收到EOT发ACK 和大写 C )

 

发送者:SOH 00 FF NUL[128] CRC CRC (发送128字节空包)

 

 

接受者:ACK ( 传输结束 )、

简明如下:

 发送端                                                                             接收端

 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<    C
SOH 00 FF "YG06_V0_1.bin"  NULL "11212" NULL[111] CRC CRC>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<     ACK
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<     C
STX 01 FE data[1024] CRC CRC>>>>>>>>>>>>>>>>>>>>>>>>      
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<    ACK
STX 02 FD data[1024] CRC CRC>>>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<    ACK
STX 03 FC data[1024] CRC CRC>>>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<    ACK
STX 04 FB data[1024] CRC CRC>>>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<    ACK
STX xx xx data[972]  1A[52] CRC CRC>>>>>>>>>>>>>>>>>>    补1A凑齐1024字节
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<    ACK
EOT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<    NAK
EOT>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<    ACK
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<    C
SOH 00 FF NUL[128] CRC CRC >>>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<    ACK 结束
附上程序如下:
ymodem.h
#ifndef _YMODEM_H_
#define _YMODEM_H_
#include "stm32f10x.h"
#define MAX_LEN_TO_FLASH (1026)
#define MAX_CACHE_LEN (135)
typedef struct
{
    u8 Data[MAX_CACHE_LEN];
    u16 cnt;
}Cache_t;
typedef struct
{
    u8 Data[MAX_LEN_TO_FLASH];
    u16 cnt;
    u8 x;
}WriteToFlash_t;
//extern Cache_t Cache;
extern WriteToFlash_t WriteToFlash;
/*YModem standard CMD*/
#define YMODEM_SOH (0x01)
#define YMODEM_STX (0x02)
#define YMODEM_EOT (0x04)
#define YMODEM_ACK (0x06)
#define YMODEM_NAK (0x15)
#define YMODEM_CAN (0x18)
#define YMODEM_C (0x43)
/*Rcv_CMD define*/
#define IS_NOT_FIRST_PACKET (0x00)
#define IS_FIRST_PACKET (0x01)
#define IS_NORMAL_FILE_128 (0X02)
#define IS_NORMAL_FILE_1024 (0X03)
#define IS_END_OF_TRANSMIT (0X04)
extern s8 YmodemSendACK(u8 byte);
extern void RcvFile(u8 PacketReturn,u8 * IsFileEnd,u16* systickmark);
extern s8 YmodemRcvPacket(u8 *rcvbuf,u16 buflen,u8 *result);
u16 YModemCRC(u8 * data,u16 len);
#endif

ymodem.c

#include "ymodem.h"
#include "base_conf.h"
#include "uart_dma.h"
#include "crypt.h"
#include "sysflash.h"
#include "main.h"
Cache_t Cache;
WriteToFlash_t WriteToFlash;
static u8 EOT_Flag = 0;
s8 YmodemSendACK(u8 byte)
{
    UART_PutChar(UART_DEBUG,byte);
    //Delay_ms(100);
    return 0;
}

void RcvFile(u8 PacketReturn,u8 * IsFileEnd,u16 * systickmark)
{
    static u8 i=0;
    switch(PacketReturn)
    {
        case IS_FIRST_PACKET:
        {
            YmodemSendACK(YMODEM_ACK);
            YmodemSendACK(YMODEM_C);
            *systickmark = GetCurrentTime();
            break;
        }
        case IS_NORMAL_FILE_128:
        {
      memcpy(&WriteToFlash.Data[i*128],Cache.Data,Cache.cnt);
            WriteToFlash.cnt += 128;
            i++;
            if(i==7)//write flash
            {
                i=0;
                Flash_Program_bytes(Page(WriteToFlash.x+APP_FLASH_OFFSET/1024),WriteToFlash.Data,WriteToFlash.cnt);
                WriteToFlash.x++;
            }
            YmodemSendACK(YMODEM_ACK);
            *systickmark = GetCurrentTime();
            break;
        }
        case IS_NORMAL_FILE_1024:
        {
            Flash_Program_bytes((Page(WriteToFlash.x+APP_FLASH_OFFSET/1024)),WriteToFlash.Data,WriteToFlash.cnt);
            WriteToFlash.x++;
            memset(WriteToFlash.Data,0,WriteToFlash.cnt);
            YmodemSendACK(YMODEM_ACK);
            *systickmark = GetCurrentTime();
            break ;
        }
        case IS_END_OF_TRANSMIT:
        {
            if(EOT_Flag==1)
            {
                //Flash_Program_bytes(Page(WriteToFlash.x+APP_FLASH_OFFSET/1024),WriteToFlash.Data,WriteToFlash.cnt);
                YmodemSendACK(YMODEM_NAK);
            }
            if(EOT_Flag==2)
            {
                YmodemSendACK(YMODEM_ACK);
                YmodemSendACK(YMODEM_C);
                
            }
            if(EOT_Flag==3)
            {
                Delay_ms(10);
                YmodemSendACK(YMODEM_ACK);
                EOT_Flag=0;
              *IsFileEnd =1;
                
            }
            break;
        }
    }
}

s8 YmodemRcvPacket(u8 *rcvbuf,u16 buflen,u8 *result)
{
      
      u16 crc;
      u8 debug;
      u8 debug1;
      
      
      switch(*(rcvbuf))
        {
            case YMODEM_EOT:
            {
                EOT_Flag++;
                *result =IS_END_OF_TRANSMIT ;
                break;
            }
            case YMODEM_SOH:
            {
                debug=((~(*(rcvbuf+1))));
          debug1=((*(rcvbuf+2)));
          if(debug!=debug1)return -1;
                memset(Cache.Data,0,sizeof(Cache.Data));
                Cache.cnt = 128;
                memcpy(Cache.Data,(rcvbuf+3),Cache.cnt);
                crc=*(rcvbuf+128+3)<<8 | *(rcvbuf+128+3+1);
                if(YModemCRC(Cache.Data,Cache.cnt)!=crc)return -1;
        if(*(rcvbuf+1)==0)
                {
                    if(strstr((const char *)(Cache.Data),"YG06_V0_1.bin")!=NULL)
                    {*result=IS_FIRST_PACKET;}
                    else{
                             if(*result == IS_END_OF_TRANSMIT ) //end with some of file,NULL DATA
                                 {
                                     *result =IS_END_OF_TRANSMIT ;EOT_Flag++;
                                 }
                                 else
                                 {return -1;}//not the end of transmit,wrong file name
                        }
                }    
                else
                {
                    
                    *result =IS_NORMAL_FILE_128 ;
                }
                break;
            }
            case YMODEM_STX:
            {
                debug=((~(*(rcvbuf+1))));
          debug1=((*(rcvbuf+2)));
          if(debug!=debug1)return -1; 
                WriteToFlash.cnt = 1024;
                memcpy(WriteToFlash.Data,(rcvbuf+3),WriteToFlash.cnt);
                crc=*(rcvbuf+1024+3)<<8 | *(rcvbuf+1024+3+1);
                if(YModemCRC(WriteToFlash.Data,WriteToFlash.cnt)!=crc)return -1;
                *result =IS_NORMAL_FILE_1024 ;
                break;
            }
            
            default:
            {
                break;
            }
        }
    
    return 0;
}

u16 YModemCRC(u8 * data,u16 len)
{
    int crc =0;
    int i,j;
    for(i=0;i<len;i++)
    {
        crc=crc^(data[i]<<8);
        for(j=0;j<8;j++)
        {
            if((crc &((int)0x8000))!=0)
            {
                crc = ((crc<<1) ^ 0x1021);
            }
            else
            {
                crc = crc << 1;
            }
        }
    }
    return (crc&0xFFFF);
}

 

以上是关于Ymodem协议的主要内容,如果未能解决你的问题,请参考以下文章

Ymodem协议说明

Ymodem协议

安装Xshell并使用其进行Ymodem协议的串口传输

X / YModem传输协议

X / YModem传输协议

X / YModem传输协议