ymodem.c 8.01 KB
#include "ymodem.h"
#include "string.h"
#include "stdlib.h"
#include "flash.h"
#include "usart1.h"    
#include "uart5.h" 
#include "delay.h" 

USART_TypeDef * IAP_Port = UART5;

uint8_t FileName[FILE_NAME_LENGTH];//array to store filename of download *.bin
char file_size[FILE_SIZE_LENGTH];
uint8_t buf_1k[1024] ={0};

/********************************************/
//移植的时候,由于函数定义了局部大数组,需要修改堆栈的大小。
//下面是需要移植的函数
static uint32_t SerialKeyPressed(uint8_t *key);
static  int32_t Receive_Byte(uint8_t *c, uint32_t timeout);
int32_t Ymodem_Receive (uint8_t *buf, uint32_t appaddr);
uint32_t STM_FLASH_Erase(uint32_t addrx);
uint32_t STM_FLASH_Get_Block_Size(uint32_t addrx);
uint32_t STMFLASH_Write(u32 WriteAddr,u32 *pBuffer,u32 NumToWrite);
/********************************************/

//check if one byte rx successfully
//key: variabl to store rx data
//return: 1=success, 0=fail
static uint32_t SerialKeyPressed(uint8_t *key)
{
	if(IAP_Port == UART5)
	{
		return uart5_read_byte(key);
	}
	else 
	{
		return usart1_read_byte(key);
	}
}
//Rx a byte from sender
//c: variable to store data
//timeout: read time out
//return: 0=success, -1=fail
static  int32_t Receive_Byte (uint8_t *c, uint32_t timeout)
{
  while (timeout-- > 0)
  {
    if (SerialKeyPressed(c) == 1)
    {
      return 0;
    }
  }
  return -1;
}
//send a byte via IAP_Port
//c: byte to send
//return: 0
static uint32_t Send_Byte (uint8_t c)
{
	if(IAP_Port == UART5)
	{
		uart5_send_byte(c);
	}
	else 
	{
		usart1_send_byte(c);
	}
  return 0;
}
/**
  * @brief  Update CRC16 for input byte
  * @param  crc_in input value 
  * @param  input byte
  * @retval None
  */
uint16_t UpdateCRC16(uint16_t crc_in, uint8_t byte)
{
  uint32_t crc = crc_in;
  uint32_t in = byte | 0x100;

  do
  {
    crc <<= 1;
    in <<= 1;
    if(in & 0x100)
      ++crc;
    if(crc & 0x10000)
      crc ^= 0x1021;
  }
  
  while(!(in & 0x10000));

  return crc & 0xffffu;
}

/**
  * @brief  Cal CRC16 for YModem Packet
  * @param  data
  * @param  length
  * @retval None
  */
uint16_t Cal_CRC16(const uint8_t* p_data, uint32_t size)
{
  uint32_t crc = 0;
  const uint8_t* dataEnd = p_data+size;

  while(p_data < dataEnd)
    crc = UpdateCRC16(crc, *p_data++);
 
  crc = UpdateCRC16(crc, 0);
  crc = UpdateCRC16(crc, 0);

  return crc&0xffffu;
}

//Rx a packet from sender
//data: pointer to store rx data
//length: packet length
//timeout: rx time out
//return:0=normally return
//      -1=timeout or packet error
//       1=abort by user 
static int32_t Receive_Packet (uint8_t *data, int32_t *length, uint32_t timeout)
{
  uint16_t i, packet_size;
  uint8_t c;
	uint32_t crc=0;

  *length = 0;
  if (Receive_Byte(&c, timeout) != 0)
  {
    return -1;
  }
  switch (c)
  {
    case SOH:
      packet_size = PACKET_SIZE;
      break;
    case STX:
      packet_size = PACKET_1K_SIZE;
      break;
    case EOT:
      return 0;
    case CA:
      if ((Receive_Byte(&c, timeout) == 0) && (c == CA))
      {
        *length = -1;
        return 0;
      }
      else
      {
        return -1;
      }
    case ABORT1:
    case ABORT2:
      return 1;
    default:
      return -1;
  }
	
  *data = c;
  for (i = 1; i < (packet_size + PACKET_OVERHEAD); i ++)
  {
    if (Receive_Byte(data + i, timeout) != 0)
    {
      return -1;
    }
  }

  crc = data[ packet_size + PACKET_HEADER ] << 8;
  crc += data[ packet_size + PACKET_HEADER + 1 ];
  if (Cal_CRC16(&data[PACKET_HEADER], packet_size) != crc )
	{
		packet_size = 0;
		return -1;
	}	
  *length = packet_size;
  return 0;
}


//Receive a file using the ymodem protocol
//buf: pointer for data storage
//appaddr: User Application address
//return: size of IAP file
int32_t Ymodem_Receive (uint8_t *buf, uint32_t appaddr)
{
  uint8_t packet_data[PACKET_1K_SIZE + PACKET_OVERHEAD], *file_ptr, *buf_ptr,flag_EOT;
  int32_t i, packet_length, session_done, file_done, packets_received, errors, session_begin, size = 0;
  uint32_t flashdestination, ramsource;

  //Initialize flashdestination variable
  flashdestination = appaddr;
  flag_EOT = 0;
  for (session_done = 0, errors = 0, session_begin = 0; ;)
  {
    for (packets_received = 0, file_done = 0, buf_ptr = buf; ;)
    {					
      switch (Receive_Packet(packet_data, &packet_length, NAK_TIMEOUT))
      {
        case 0:
          errors = 0;
          switch (packet_length)
          {
            /* Abort by sender */
            case - 1:
              Send_Byte(ACK);
              return 0;
            /* End of transmission */
            case 0:
							if(flag_EOT==0) //first EOT
							{	        
								Send_Byte(NACK); 		              
								flag_EOT = 1;
							}
							else if (flag_EOT==1) //second EOT
							{
								Send_Byte(ACK); 
								Send_Byte('C');
                file_done = 1;
              }
              break;
            /* Normal packet */
						default:
              if ((packet_data[PACKET_SEQNO_INDEX] & 0xff) != (packets_received & 0xff))
              {
                Send_Byte(NACK);//local data sequence number is different to rx data packet.
              }
              else
              {
                if (packets_received == 0)
                {
                  /* Filename packet */
                  if (packet_data[PACKET_HEADER] != 0)
                  {
                    /* Filename packet has valid data */
                    for (i = 0, file_ptr = packet_data + PACKET_HEADER; (*file_ptr != 0) && (i < FILE_NAME_LENGTH);)
                    {
                      FileName[i++] = *file_ptr++;
                    }
                    FileName[i++] = '\0';
										
                    for (i = 0, file_ptr ++; (*file_ptr != ' ') && (i < FILE_SIZE_LENGTH);)
                    {
                      file_size[i++] = *file_ptr++;
                    }
                    file_size[i++] = '\0';
                    size = atoi(file_size);

                    /* Test the size of the image to be sent */
                    /* Image size is greater than Flash size */
                    if (size > (int32_t)(STM_FLASH_Get_Block_Size(flashdestination) + 1))
                    {
                      /* End session */
                      Send_Byte(CA);
                      Send_Byte(CA);
                      return -1;
                    }
                    /* erase user application area */
										

                    STM_FLASH_Erase(flashdestination);

                    Send_Byte(ACK);
                    Send_Byte(CRC16);
                  }
                  /* Filename packet is empty, end session */
                  else
                  {
                    Send_Byte(ACK);
                    file_done = 1;
                    session_done = 1;
                    break;
                  }
                }
                /* Data packet */
                else
                {
                  memcpy(buf_ptr, packet_data + PACKET_HEADER, packet_length);
                  ramsource = (uint32_t)buf_ptr;

                  /* Write received data in Flash */
                  if (STMFLASH_Write(flashdestination, (uint32_t*)ramsource, (uint16_t) packet_length)  == 0)
                  {
										flashdestination+=packet_length;
                    Send_Byte(ACK);
                  }
                  else /* An error occurred while writing to Flash memory */
                  {
                    /* End session */
                    Send_Byte(CA);
                    Send_Byte(CA);
                    return -2;
                  }
                }
                packets_received ++;
                session_begin = 1;
              }
          }
          break;
        case 1:
          Send_Byte(CA);
          Send_Byte(CA);
          return -3;
        default:
          if (session_begin > 0)
          {
            errors ++;
          }
          if (errors > MAX_ERRORS)
          {
            Send_Byte(CA);
            Send_Byte(CA);
            return 0;
          }
          Send_Byte(CRC16);
          break;
      }
      if (file_done != 0)
      {
        break;
      }
    }
    if (session_done != 0)
    {
      break;
    }
  }
  return (int32_t)size;
}