ZYNQ使用ymodem协议传输文件

SDK: V2014.4
协议: Ymodem
工具: USB转UART转接线、xshell6软件
可实现各种文件传输,大小不限,只是速度很慢

参考原代码如下:

/*******************************************************************************
  * @函数名称    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;
}

结合ZYNQ代码改写如下函数:

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



可以通过Ymodem正确传输完成文件,但还存在的问题如下:

1、第一包数据:STX 00 FF … 的CRC16校验码会变为0xFF或其他不对的值,导致校验失败。而除了第一包后面的校验都是正确的。

2、用xshell6才能正确传输,用超级终端或者secureCRT都会有几包错误数据。且每次都是错的那几包。

3、传输到一半点击取消后,代码不再运行,需要重启。

4、文件传输完成界面不动,必须按下回车键,才会结束传输过程。

猜你喜欢

转载自blog.csdn.net/LIU944602965/article/details/107222713