ZYNQ uses ymodem protocol to transfer files

SDK: V2014.4
Protocol: Ymodem
tool: USB to UART adapter cable, xshell6 software
can realize various file transfers, the size is not limited, but the speed is very slow

The reference original code is as follows:

/*******************************************************************************
  * @函数名称    YmodemRecvData
  * @函数说明   使用Ymodem协议接收数据
  * @输入参数   data :数据
                size :长度
  * @输出参数   无
  * @返回参数   数据包的总大小
*******************************************************************************/
int YmodemRecvData(void)
{
    
    
    int i=0;
    char ErrorNum=0;                                                //错误计数
    char YmodemState=0;
    unsigned char TempChar=0;                                       //接收数据
    int crcvalue=0;    
    int len=0;    
    int count=0;
    ErrorNum=0;
    while(1)
    {
    
    
        switch(YmodemState)
        {
    
    
          case 0:                                                   //通信起始阶段
                         SerialPutChar(CRC16);                      //发起始信号
                        if(GetKeyC(1000000,&TempChar)==0)           //每次等待0.2s钟,发生超时重发“C”
                        {
    
    
                            if(TempChar==SOH )
                            {
    
    
                                GetKey(&TempChar);
                                if(TempChar!=0x00)return ;          //不是00序号。
                                GetKey(&TempChar);
                                if ( TempChar != 0xFF )return ;     //不是00序号补码。
                                for ( i=0; i<128; i++ )
                                {
    
                                       //接收数据包0,共128字节
                                    GetKey((UserBuf+i));
                                }
                                GetKey(&TempChar);
                                GetKey(&TempChar);                  //丢弃CRC校验,暂时不想实现。
                                
                                SerialPutChar(ACK);                 //发送确认信号。
                                YmodemState=1;                      //状态切换到数据传输状态
                                for ( i=0; i<128; i++ )
                                {
    
                                       //接收数据包0,共128字节
                                    file_name[i]=0;
                                } 
                                for ( i=0; (i<128)&&(UserBuf[i]); i++ )
                                {
    
                                       //接收数据包0,共128字节
                                    file_name[i]=UserBuf[i];
                                }
                                Str2Int((UserBuf+i+1),&PackLen);
                                  
                                SerialPutChar (CRC16);              //再发一个C,正式启动数据传输                         
                            }
                        }
                         break;
          case 1:        //数据传输阶段
                         GetKey(&TempChar); 
                         switch(TempChar)
                         {
    
                                                            
                              case EOT: YmodemState = EOT;
                                        SerialPutChar ( ACK );
                                        continue;
                              case SOH:
                                           len = 128;
                                           break; 
                              case STX:
                                           len = 1024;                                      
                                           break; 
                              case ABORT1:
                                        Serial_PutString("用户取消文件传输!\r\n");
                                           return PackLen;
                              case ABORT2:
                                           Serial_PutString("用户取消文件传输!\r\n");
                                           return PackLen;
                              default :return PackLen;                                                    
                        }  //end of switch (StartChar)
                        GetKey(&TempChar); 
                        GetKey(&TempChar); 
                        for(i=0;i<len;i++)
                        {
    
          //接收整个数据包
                            GetKey((UserBuf+i));
                        }
                        //CRC桥验
                        GetKey(&TempChar);
                        crcvalue=TempChar; 
                        crcvalue<<=8;
                        GetKey(&TempChar);
                        crcvalue|=TempChar; 

                        if(Cal_CRC16(UserBuf,len)!=crcvalue)
                        {
    
    
                            ErrorNum+=1;
                        }    
                                 
                        if(ErrorNum==0)
                        {
    
    
                            SerialPutChar(ACK);  
                            count+=len;
                        }                              
                        else SerialPutChar(NAK);                         //接收发现错误,要求重发。                   
                        break;
          case EOT:   //结束传输阶段
                         SerialPutChar(CRC16);
                        GetKey(&TempChar);                               //接收起始字符。
                        if(TempChar==SOH)
                        {
    
    
                            GetKey(&TempChar); 
                            if(TempChar!=0x00)return PackLen;            //不是00序号。
                            GetKey(&TempChar); 
                            if(TempChar!=0xFF)return PackLen;            //不是00序号补码。
                            for(i=0;i<128;i++)
                            {
    
    
                                   GetKey((UserBuf+i));
                            }
                            //CRC桥验
                            GetKey(&TempChar);
                            crcvalue=TempChar; 
                            crcvalue<<=8;
                            GetKey(&TempChar);
                            crcvalue|=TempChar; 

                            if(Cal_CRC16(UserBuf,128)!=crcvalue)
                            {
    
    
                                ErrorNum+=1;
                            }    
                            if(ErrorNum==0)
                            {
    
    
                                SerialPutChar(ACK);  
                                return PackLen;
                            }                              
                            else SerialPutChar(NAK);                     //接收发现错误,要求重发。 
                            break;
                        }                 
          default:     
                     return PackLen;
          } 
       } 
    return PackLen;
}

Combine the ZYNQ code to rewrite the following function:

void SerialPutChar(uint8_t c)
{
    
    
	volatile int i = 0;
	XUartPs_SendByte(STDOUT_BASEADDRESS, c);
	for(i=0; i<1500; i++)
	{
    
    
		;
	}
}

unsigned char GetKeyC(unsigned int count,unsigned char *key)
{
    
    

	volatile int i = 0;
	volatile unsigned long temp;
	for(i=0;i<count;i++)
	{
    
    

	}

	for(i=0;i<1000;i++)
	{
    
    
		temp = MyUart_RecvByte();
		if( (temp &0xFFFFFF00) == 0 )
		{
    
    
			 *key = (unsigned char)(temp & 0x000000FF);
			 return 0;
		}
	}
	return 1;
}

uint8_t GetKey(uint8_t *key)
{
    
    
	volatile unsigned long temp;
	volatile int i ;

	for(i=0; i<1000;i++)
	{
    
    
		temp = MyUart_RecvByte();
		if( (temp &0xFFFFFF00) == 0 )
		{
    
    
			 *key = (unsigned char)(temp & 0x000000FF);
			 return (*key);
		}
	}
    return 0;
}



The file can be transferred correctly through Ymodem, but the remaining problems are as follows:

1. The first packet of data: STX 00 FF… The CRC16 check code will change to 0xFF or other incorrect values, causing the check to fail. Except for the first package, the verification is correct.

2. Use xshell6 to transmit correctly. There will be several packets of wrong data when using HyperTerminal or secureCRT. And it’s the wrong packages every time.

3. After the transfer is halfway through and click cancel, the code will no longer run and need to restart.

4. The interface for file transfer completion will not move, you must press the Enter key to end the transfer process.

Guess you like

Origin blog.csdn.net/LIU944602965/article/details/107222713