超级终端测试通过的 ymodem 协议

最近需要做一个给 STM32F407 做一个 IAP,来进行远程升级,通讯接口是串口,在网上查了一下,看到多是用 ymodem 协议来接收数据包的,其实也可以用自定义协议,不过为了调试方便,还是选择用 ymodem 协议来实现,但是国内网上关于 ymodem 协议的描述文章都是大同小异,而且几乎没有一篇文章完整的描述了 ymodem 协议。所以到现在我也还是有一些没理解的问题(不知道谷歌能找到我没理解的问题不,没去找),不过好在调试都成功了,这里附上的也只是一个雏形,目前仅完成了接收部分,发送部分没做,还有很多没考虑到的,以后有空再更新补充完整吧,建议先看几篇关于 ymodem 协议的文章再来看这里的源码。

这里列出来的通信流程可能和在网上看到的流程有点差异,但事实确确实实是下面列出来的这样,可能和软件(超级终端、secureCRT)和软件版本有关吧。

/*
超级终端通信流程
发送端                                     接收端

 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<   C

SOH 00 FF [filename 00] [filesize 00] [NUL..] CRC CRC >>>

 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<   C

SOH 00 FF [filename 00] [filesize 00] [NUL..] 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

SOH 05 FA data[100]  1A[28] CRC CRC>>>>>>>

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<   ACK

EOT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<   NAK

EOT>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<   ACK

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<   C

SOH 00 FF NUL[128] CRC CRC >>>>>>>>>>>>>>>>

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<   ACK

**********************************************************

secureCRT通信过程-128-byte
发送端                                     接收端

 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<   C

SOH 00 FF [filename 00] [filesize 00] [NUL..] CRC CRC >>>

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<    ACK

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<    C

SOH 01 FE data[128] CRC CRC>>>>>>>>>>>>>>  

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<   ACK

SOH 02 FD data[128] CRC CRC>>>>>>>>>>>>>>

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<   ACK

SOH 03 FC data[128] CRC CRC>>>>>>>>>>>>>>

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<   ACK

SOH 04 FB data[128] CRC CRC>>>>>>>>>>>>>>

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<   ACK

SOH 05 FA data[100]  1A[28] CRC CRC>>>>>>>

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<   ACK

EOT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<   NAK

EOT>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<   ACK

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<   C

SOH 00 FF NUL[128] CRC CRC >>>>>>>>>>>>>>>

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<   ACK

**********************************************************

secureCRT通信过程-1024-byte
发送端                                     接收端

 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<   C

STX 00 FF [filename 00] [filesize 00] [NUL..] 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 05 FA data[24]  1A[1000] CRC CRC>>>>>>

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<   ACK

EOT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<   NAK

EOT>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<   ACK

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<   C

SOH 00 FF NUL[128] CRC CRC >>>>>>>>>>>>>>>

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<   ACK
*/

/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __YMODEM_H_
#define __YMODEM_H_

#include "stdint.h"
#include "string.h"
#include "app_com.h"
#include "./tim/tim.h"
#include "./uart/uart2.h"
#include "./flash_if/flash_if.h"

/* Includes ------------------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
#define PACKET_SEQNO_INDEX      (1)
#define PACKET_SEQNO_COMP_INDEX (2)

#define PACKET_HEADER           (3)
#define PACKET_TRAILER          (2)
#define PACKET_OVERHEAD         (PACKET_HEADER + PACKET_TRAILER)
#define PACKET_SIZE             (128)
#define PACKET_1K_SIZE          (1024)

#define FILE_NAME_LENGTH        (256)
#define FILE_SIZE_LENGTH        (16)

#define SOH                     (0x01)  /* start of 128-byte data packet */
#define STX                     (0x02)  /* start of 1024-byte data packet */
#define EOT                     (0x04)  /* end of transmission */
#define ACK                     (0x06)  /* acknowledge */
#define NAK                     (0x15)  /* negative acknowledge */
#define CAN                     (0x18)  /* two of these in succession aborts transfer */
#define C                       (0x43)  /* 'C' == 0x43, request 16-bit CRC */
#define NUL                     (0X00)
#define SUB                     (0x1A)

#ifndef COUNTOF
#define COUNTOF(a) (sizeof(a) / sizeof(*a))
#endif

/* Common routines */
#define IS_AF(c)  ((c >= 'A') && (c <= 'F'))
#define IS_af(c)  ((c >= 'a') && (c <= 'f'))
#define IS_09(c)  ((c >= '0') && (c <= '9'))
#define ISVALIDHEX(c)  IS_AF(c) || IS_af(c) || IS_09(c)
#define ISVALIDDEC(c)  IS_09(c)
#define CONVERTDEC(c)  (c - '0')

#define CONVERTHEX_alpha(c)  (IS_AF(c) ? (c - 'A'+10) : (c - 'a'+10))
#define CONVERTHEX(c)   (IS_09(c) ? (c - '0') : CONVERTHEX_alpha(c))

/*1:超级终端作为接收端
  0:超级终端作为发送端
*/
#define DOWNLOAD 0
#if (DOWNLOAD > 0)
/*超级终端作为接收端仅握手一次*/
#define HAND_SHAKE_NUM  1
/*超级终端作为接收端仅发送一次 EOT*/
#define EOT_NUM         1
#else
#define HAND_SHAKE_NUM  2
#define EOT_NUM         2
#endif

/*FLASH 相关操作失败重试次数*/
#define FLASH_OPERATE_FAILED_RETRY 3

#pragma pack(1)/*设置单字节对齐*/
typedef union {
  uint8_t packet_full[PACKET_1K_SIZE + PACKET_OVERHEAD];
  struct {
    uint8_t packet_header[PACKET_HEADER];
    uint32_t packet_data[PACKET_1K_SIZE / 4];
    uint8_t packet_trailer[PACKET_TRAILER];
  }t;
}_packetBuf_u;
#pragma pack()

/* Exported functions ------------------------------------------------------- */
int32_t YmodemReceive(void);
int32_t YmodemTransmit (uint8_t *buf, const char* sendFileName, uint32_t sizeFile);

#endif  /* __YMODEM_H_ */
#include "./Ymodem/Ymodem.h"

#define OPT_DBG_INF 1U

static int YmodemReceiveByte(uint8_t *data);
static void YmodemSendByte(uint8_t c);
static void YmodemSendPacket(uint8_t *data, uint16_t length);
static uint16_t UpdateCRC16(uint16_t crcIn, uint8_t byte);
static uint16_t Cal_CRC16(const uint8_t* data, uint32_t size);
static uint8_t CalChecksum(const uint8_t* data, uint32_t size);
static void Int2Str(uint8_t* str, int32_t intnum);
static uint32_t Str2Int(uint8_t *inputstr, int32_t *intnum);

static _packetBuf_u packetBuf;

/*解析最后一个包*/
int32_t YmodemParsingLastPacket(uint8_t *data)
{
  if((data[PACKET_SEQNO_INDEX] == 0x00) &&
     (data[PACKET_SEQNO_COMP_INDEX] == 0xff))
  {
    uint16_t crc = Cal_CRC16(&data[PACKET_HEADER],PACKET_SIZE);
    if(crc == (uint16_t)((uint16_t)(data[PACKET_SIZE + PACKET_OVERHEAD - 2] << 8) | data[PACKET_SIZE + PACKET_OVERHEAD - 1]))
    {
      return 0;
    }
  }
  
  return -1;
}
/*解析第一包*/
int32_t YmodemParsingIntialPacket(uint8_t *data)
{
  uint32_t i = 0,j = 0,endAddress = 0;
  int32_t size = 0;
  uint8_t fileName[FILE_NAME_LENGTH] = {0},filesize[FILE_SIZE_LENGTH] = {0};
  
  if((data[PACKET_SEQNO_INDEX] == 0x00) &&
     (data[PACKET_SEQNO_COMP_INDEX] == 0xff))
  {
    uint16_t crc = Cal_CRC16(&data[PACKET_HEADER],PACKET_SIZE);
    if(crc == (uint16_t)((uint16_t)(data[PACKET_SIZE + PACKET_OVERHEAD - 2] << 8) | data[PACKET_SIZE + PACKET_OVERHEAD - 1]))
    {
      for( ;(packetBuf.packet_full[i + PACKET_HEADER] != '\0') && (i < FILE_NAME_LENGTH);i++)
      {
        fileName[i] = packetBuf.packet_full[i + PACKET_HEADER];
      }
      #if(OPT_DBG_INF > 0U)
      PRINTF("\n%s:",fileName);
      #endif
      for(i = i + PACKET_HEADER + 1;(packetBuf.packet_full[i] != '\0') && (j < FILE_SIZE_LENGTH); )
      {
        filesize[j++] = packetBuf.packet_full[i++];
      }
      if(0 != Str2Int(filesize,&size))
      {
        #if(OPT_DBG_INF > 0U)
        PRINTF("%dkb,%dbyte\n",size / 1024,size);
        #endif
        if((size > 0) && (size <= (USER_FLASH_END_ADDRESS - APPLICATION_ADDRESS)))
        {
          endAddress = APPLICATION_ADDRESS + size;
          #if(OPT_DBG_INF > 0U)
          PRINTF("endAddress:%08x\n",endAddress);
          #endif
          if(0 == FLASH_If_Erase(APPLICATION_ADDRESS,endAddress))
          {
            return 0;
          }
          else
          {
            return -2;
          }
        }
      }
    }
  }
  
  return -1;
}
/*解析数据包*/
int32_t YmodemParsingPacket(uint8_t *data, const uint8_t pktNo, uint32_t packetLen, uint32_t address)
{
  if((data[PACKET_SEQNO_INDEX] == pktNo) &&
     (((data[PACKET_SEQNO_COMP_INDEX] ^ 0xff) & 0xff) == pktNo))
  {
    uint16_t crc = Cal_CRC16(&data[PACKET_HEADER],packetLen - PACKET_OVERHEAD);
    if(crc == (uint16_t)((uint16_t)(data[packetLen - 2] << 8) | data[packetLen - 1]))
    {
      if(0 == FLASH_If_Write(address,(uint32_t *)packetBuf.t.packet_data,(packetLen - PACKET_OVERHEAD) / 4))
      {
        return 0;
      }
      else
      {
        return -2;
      }
    }
  }
  
  return -1;
}

/*
* 接收数据包
* 返回值:
* 0:正常接收,>0:超时退出,-1:第一包序号错误,-2:FLASH 多次尝试失败,-3:最后一包错误
*/
int32_t YmodemReceive(void)
{
  uint8_t SeqNo = 0x01;
  uint8_t ch = 0;
  uint32_t err = 0,ackReceived = 0,idx = 0,packetLen = 0,reTryCnt = 0,nakReTryCnt = 0;
  int32_t ret = 0;
  uint32_t address = APPLICATION_ADDRESS;
  
  do
  {
    YmodemSendByte(C);
    if((YmodemReceiveByte(&ch) < 0) || (ch != SOH))
    {
      err++;
    }
    else
    {
      err = 0;
      packetBuf.packet_full[idx++] = ch;
      do
      {
        if(YmodemReceiveByte(&ch) < 0)
        {
          err++;
        }
        else
        {
          packetBuf.packet_full[idx++] = ch;
        }
      }while((idx < (PACKET_SIZE + PACKET_OVERHEAD)) && (err < 0x0a));
      if(err >= 0x0a)
      {
        return err;
      }
      err = 0;
      idx = 0;
      do
      {
        ret = YmodemParsingIntialPacket(packetBuf.packet_full);
        if(ret < -1)
        {
          reTryCnt++;
        }
        else
        {
          break;
        }
      }while(reTryCnt < FLASH_OPERATE_FAILED_RETRY);
      if(reTryCnt >= FLASH_OPERATE_FAILED_RETRY)
      {
        return -2;
      }
      reTryCnt = 0;
      if(ret < 0)
      {
        return -1;
      }
      ret = 0;
      ackReceived++;
      if(!(ackReceived < HAND_SHAKE_NUM))
      {
        YmodemSendByte(ACK);
        YmodemSendByte(C);
      }
    }
  }while((ackReceived < HAND_SHAKE_NUM) && (err < 0x0a));
  if(err >= 0x0a)
  {
    return err;
  }
  err = 0;
  ackReceived = 0;
  
  do
  {
    if(YmodemReceiveByte(&ch) < 0)
    {
      err++;
    }
    else
    {
      if((ch == SOH) || (ch == STX))
      {
        err = 0;
        packetBuf.packet_full[idx++] = ch;
        packetLen = ((packetBuf.packet_full[0] == STX) ? PACKET_1K_SIZE : PACKET_SIZE) + PACKET_OVERHEAD;
        do
        {
          if(YmodemReceiveByte(&ch) < 0)
          {
            err++;
          }
          else
          {
            packetBuf.packet_full[idx++] = ch;
          }
        }while((idx < packetLen) && (err < 0x0a));
        if(err >= 0x0a)
        {
          return err;
        }
        err = 0;
        idx = 0;
        do
        {
          ret = YmodemParsingPacket(packetBuf.packet_full,SeqNo,packetLen,address);
          if(ret < -1)
          {
            reTryCnt++;
          }
          else
          {
            break;
          }
        }while(reTryCnt < FLASH_OPERATE_FAILED_RETRY);
        if(reTryCnt >= FLASH_OPERATE_FAILED_RETRY)
        {
          return -2;
        }
        reTryCnt = 0;
        if(ret < 0)
        {
          nakReTryCnt++;
          YmodemSendByte(NAK);
        }
        else
        {
          SeqNo++;
          address += (packetLen - PACKET_OVERHEAD);
          YmodemSendByte(ACK);
        }
        ret = 0;
      }
      else if(ch == EOT)
      {
        break;
      }
      else
      {
        err++;
      }
    }
  }while((err < 0x0a) && (nakReTryCnt < 0x0a));
  if(err >= 0x0a)
  {
    return err;
  }
  err = 0;
  if(nakReTryCnt >= 0x0a)
  {
    return nakReTryCnt;
  }
  nakReTryCnt = 0;
  idx = 0;
  
  YmodemSendByte(NAK);
  do
  {
    if((YmodemReceiveByte(&ch) < 0) || (ch != EOT))
    {
      err++;
    }
    else
    {
      ackReceived++;
    }
  }while((!ackReceived) && (err < 0x0a));
  if(err >= 0x0a)
  {
    return err;
  }
  err = 0;
  ackReceived = 0;
  YmodemSendByte(ACK);
  YmodemSendByte(C);
  
  do
  {
    if((YmodemReceiveByte(&ch) < 0) || (ch != SOH))
    {
      err++;
    }
    else
    {
      err = 0;
      packetBuf.packet_full[idx++] = ch;
      do
      {
        if(YmodemReceiveByte(&ch) < 0)
        {
          err++;
        }
        else
        {
          packetBuf.packet_full[idx++] = ch;
        }
      }while((idx < (PACKET_SIZE + PACKET_OVERHEAD)) && (err < 0x0a));
      if(err >= 0x0a)
      {
        return err;
      }
      err = 0;
      idx = 0;
      ackReceived++;
    }
  }while((!ackReceived) && (err < 0x0a));
  if(err >= 0x0a)
  {
    return err;
  }
  err = 0;
  ackReceived = 0;
  if(!(YmodemParsingLastPacket(packetBuf.packet_full) < 0))
  {
    YmodemSendByte(ACK);
    
    return 0;
  }
  
  return -3;
}

/*ymodem receive byte*/
static int YmodemReceiveByte(uint8_t *data)
{
  return Usart2ReceiveBytes_polling(data,1);
}

/*ymodem send byte*/
static void YmodemSendByte(uint8_t c)
{
  Usart2SendBytes_polling(&c,1);
}

static void YmodemSendPacket(uint8_t *data, uint16_t length)
{
  uint16_t i = 0;
  
  while (i < length)
  {
    YmodemSendByte(data[i]);
    i++;
  }
}

/**
  * @brief  Update CRC16 for input byte
  * @param  CRC input value 
  * @param  input byte
  * @retval None
  */
static uint16_t UpdateCRC16(uint16_t crcIn, uint8_t byte)
{
  uint32_t crc = crcIn;
  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
  */
static uint16_t Cal_CRC16(const uint8_t* data, uint32_t size)
{
  uint32_t crc = 0;
  const uint8_t* dataEnd = data+size;

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

  return crc&0xffffu;
}

/**
  * @brief  Cal Check sum for YModem Packet
  * @param  data
  * @param  length
  * @retval None
  */
static uint8_t CalChecksum(const uint8_t* data, uint32_t size)
{
  uint32_t sum = 0;
  const uint8_t* dataEnd = data+size;

  while(data < dataEnd )
    sum += *data++;

  return (sum & 0xffu);
}

/**
  * @brief  Convert an Integer to a string
  * @param  str: The string
  * @param  intnum: The integer to be converted
  * @retval None
  */
static void Int2Str(uint8_t* str, int32_t intnum)
{
  uint32_t i, Div = 1000000000, j = 0, Status = 0;

  for (i = 0; i < 10; i++)
  {
    str[j++] = (intnum / Div) + 48;

    intnum = intnum % Div;
    Div /= 10;
    if ((str[j-1] == '0') & (Status == 0))
    {
      j = 0;
    }
    else
    {
      Status++;
    }
  }
}

/**
  * @brief  Convert a string to an integer
  * @param  inputstr: The string to be converted
  * @param  intnum: The integer value
  * @retval 1: Correct
  *         0: Error
  */
static uint32_t Str2Int(uint8_t *inputstr, int32_t *intnum)
{
  uint32_t i = 0, res = 0;
  uint32_t val = 0;

  if (inputstr[0] == '0' && (inputstr[1] == 'x' || inputstr[1] == 'X'))
  {
    if (inputstr[2] == '\0')
    {
      return 0;
    }
    for (i = 2; i < 11; i++)
    {
      if (inputstr[i] == '\0')
      {
        *intnum = val;
        /* return 1; */
        res = 1;
        break;
      }
      if (ISVALIDHEX(inputstr[i]))
      {
        val = (val << 4) + CONVERTHEX(inputstr[i]);
      }
      else
      {
        /* Return 0, Invalid input */
        res = 0;
        break;
      }
    }
    /* Over 8 digit hex --invalid */
    if (i >= 11)
    {
      res = 0;
    }
  }
  else /* max 10-digit decimal input */
  {
    for (i = 0;i < 11;i++)
    {
      if (inputstr[i] == '\0')
      {
        *intnum = val;
        /* return 1 */
        res = 1;
        break;
      }
      else if ((inputstr[i] == 'k' || inputstr[i] == 'K') && (i > 0))
      {
        val = val << 10;
        *intnum = val;
        res = 1;
        break;
      }
      else if ((inputstr[i] == 'm' || inputstr[i] == 'M') && (i > 0))
      {
        val = val << 20;
        *intnum = val;
        res = 1;
        break;
      }
      else if (ISVALIDDEC(inputstr[i]))
      {
        val = val * 10 + CONVERTDEC(inputstr[i]);
      }
      else
      {
        /* return 0, Invalid input */
        res = 0;
        break;
      }
    }
    /* Over 10 digit decimal --invalid */
    if (i >= 11)
    {
      res = 0;
    }
  }

  return res;
}

/*打包数据
* SourceBuf:数据源
* data:打包后的数据
* pktNo:包序号
* sizeBlk:数据量
*/
void YmodemPreparePacket(uint8_t *SourceBuf, uint8_t *data, uint8_t pktNo, uint32_t sizeBlk)
{
  uint16_t i = 0, size = 0, packetSize = 0;
  uint8_t* file_ptr = NULL;
  
  /* 判断需要使用的包大小 */
  packetSize = sizeBlk < PACKET_SIZE ? PACKET_SIZE : PACKET_1K_SIZE;
  /* 填充到包的数据量 */
  size = sizeBlk < packetSize ? sizeBlk :packetSize;
  if (packetSize == PACKET_1K_SIZE)
  {
     data[0] = STX;
  }
  else
  {
     data[0] = SOH;
  }
  data[1] = pktNo;
  data[2] = (~pktNo);
  file_ptr = SourceBuf;
  
  /* 转移有效数据 */
  for (i = PACKET_HEADER; i < size + PACKET_HEADER;i++)
  {
    data[i] = *file_ptr++;
  }
  if ( size <= packetSize)
  {
    for (i = size + PACKET_HEADER; i < packetSize + PACKET_HEADER; i++)
    {
      data[i] = SUB;
    }
  }
}

/*准备第一个包
* data:打包后的数据
* fileName:文件名
* length:文件大小(单位:byte)
*/
void YmodemPrepareIntialPacket(uint8_t *data, const char* fileName, uint32_t *length)
{
  uint16_t i = 0, j = 0;
  uint8_t file_ptr[FILE_SIZE_LENGTH] = {0};
  
  data[0] = SOH;
  data[1] = 0x00;
  data[2] = 0xff;
  
  /* 转移有效数据 */
  for (i = 0; (fileName[i] != '\0') && (i < FILE_NAME_LENGTH);i++)
  {
     data[i + PACKET_HEADER] = fileName[i];
  }

  data[i + PACKET_HEADER] = NUL;
  
  Int2Str (file_ptr, *length);
  for (j =0, i = i + PACKET_HEADER + 1; (file_ptr[j] != '\0') && (j < FILE_SIZE_LENGTH) ; )
  {
     data[i++] = file_ptr[j++];
  }
  
  for (j = i; j < PACKET_SIZE + PACKET_HEADER; j++)
  {
    data[j] = NUL;
  }
}

/*准备最后一个包
* data:打包后的数据
*/
void YmodemPrepareLastPacket(uint8_t *data)
{
  uint16_t i = 0;
  
  data[0] = SOH;
  data[1] = 0x00;
  data[2] = 0xff;
  
  for ( i = PACKET_HEADER; i < PACKET_SIZE + PACKET_HEADER; i++)
  {
    data[i] = NUL;
  }
}

/*Ymodem 发送
* buf:数据源
* sendFileName:文件名
* sizeFile:文件大小
* 返回值:
* 0:正常发送,>0:超时退出
*/
int32_t YmodemTransmit (uint8_t *buf, const char* sendFileName, uint32_t sizeFile)
{
  uint8_t SeqNo = 0x01;
  uint16_t tempCRC = 0;
  uint8_t tempCheckSum = 0;
  uint8_t ch[2] = {0},idx = 0,chk = 0;
  uint32_t err = 0,ackReceived = 0,packSize = 0;
  
  do
  {
    do
    {
      /* wait for 'C' or 'NAK' */
      if(YmodemReceiveByte(&ch[0]) < 0)
      {
        err++;
      }
      else
      {
        if((ch[0] == C) || (ch[0] == NAK))
        {
          /* received 'C' or 'NAK' */
          ackReceived++;
        }
        else
        {
          err++;
        }
      }
    }while((!ackReceived) && (err < 0x0a));
    if(err >= 0x0a)
    {
      /* timeout */
      return err;
    }
    err = 0;
    
    chk = ch[0];
    /* prepare start packet */
    YmodemPrepareIntialPacket(packetBuf.packet_full,sendFileName,&sizeFile);
    /* send start packet */
    YmodemSendPacket(packetBuf.packet_full, PACKET_SIZE + PACKET_HEADER);
    /* cal CRC or check sum */
    if (chk == C)
    {
      tempCRC = Cal_CRC16(&packetBuf.packet_full[PACKET_HEADER], PACKET_SIZE);
      YmodemSendByte(tempCRC >> 8);
      YmodemSendByte(tempCRC & 0xFF);
    }
    else
    {
      tempCheckSum = CalChecksum (&packetBuf.packet_full[PACKET_HEADER], PACKET_SIZE);
      YmodemSendByte(tempCheckSum);
    }
  }while(ackReceived < HAND_SHAKE_NUM);
  ackReceived = 0;
  
  do
  {
    /* wait for 'C' and 'ACK' */
    if(YmodemReceiveByte(&ch[idx]) < 0)
    {
      err++;
    }
    else
    {
      if(ch[0] == ACK)
      {
        if(idx > 0)
        {
          if(ch[1] == C)
          {
            /* received 'C' and 'ACK' */
            ackReceived++;
          }
          else
          {
            err++;
          }
        }
        else
        {
          idx++;
        }
      }
      else
      {
        err++;
      }
    }
  }while((!ackReceived) && (err < 0x0a));
  if(err >= 0x0a)
  {
    /* timeout */
    return err;
  }
  err = 0;
  ackReceived = 0;
  idx = 0;
  
  while(sizeFile)
  {
    YmodemPreparePacket(buf,packetBuf.packet_full,SeqNo,sizeFile);
    packSize = packetBuf.packet_full[0] == STX ? PACKET_1K_SIZE : PACKET_SIZE;
    /* send data packet */
    YmodemSendPacket(packetBuf.packet_full, packSize + PACKET_HEADER);
    if (chk == C)
    {
      tempCRC = Cal_CRC16(&packetBuf.packet_full[PACKET_HEADER], packSize);
      YmodemSendByte(tempCRC >> 8);
      YmodemSendByte(tempCRC & 0xFF);
    }
    else
    {
      tempCheckSum = CalChecksum (&packetBuf.packet_full[PACKET_HEADER], packSize);
      YmodemSendByte(tempCheckSum);
    }
    
    do
    {
      /* wait for 'ACK' or 'NAK' */
      if(YmodemReceiveByte(&ch[0]) < 0)
      {
        err++;
      }
      else
      {
        if((ch[0] == ACK) || (ch[0] == NAK))
        {
          /* received 'ACK' or 'NAK' */
          ackReceived++;
        }
        else
        {
          err++;
        }
      }
    }while((!ackReceived) && (err < 0x0a));
    if(err >= 0x0a)
    {
      /* timeout */
      return err;
    }
    err = 0;
    ackReceived = 0;
    
    if(ch[0] == ACK)
    {
      buf += packSize;
      SeqNo++;
      if(sizeFile > packSize)
      {
        sizeFile -= packSize;
      }
      else
      {
        sizeFile = 0;
      }
    }
  }
  buf = 0;
  SeqNo = 0;
  
#if (EOT_NUM > 1)
  /* send 'EOT' */
  YmodemSendByte(EOT);
  do
  {
    /* wait for 'NAK' */
    if((YmodemReceiveByte(&ch[0]) < 0) || (ch[0] != NAK))
    {
      err++;
    }
    else
    {
      /* received 'NAK' */
      ackReceived++;
    }
  }while((!ackReceived) && (err < 0x0a));
  if(err >= 0x0a)
  {
    /* timeout */
    return err;
  }
  err = 0;
  ackReceived = 0;
#endif/*EOT_NUM*/
  
  /* send 'EOT' */
  YmodemSendByte(EOT);
  do
  {
    /* wait for 'C' and 'ACK' */
    if(YmodemReceiveByte(&ch[idx]) < 0)
    {
      err++;
    }
    else
    {
      if(ch[0] == ACK)
      {
        if(idx > 0)
        {
          if(ch[1] == C)
          {
            /* received 'C' and 'ACK' */
            ackReceived++;
          }
          else
          {
            err++;
          }
        }
        else
        {
          idx++;
        }
      }
      else
      {
        err++;
      }
    }
  }while((!ackReceived) && (err < 0x0a));
  if(err >= 0x0a)
  {
    /* timeout */
    return err;
  }
  err = 0;
  ackReceived = 0;
  idx = 0;
  
  YmodemPrepareLastPacket(packetBuf.packet_full);
  /* send end packet */
  YmodemSendPacket(packetBuf.packet_full, PACKET_SIZE + PACKET_HEADER);
  if (chk == C)
  {
    tempCRC = Cal_CRC16(&packetBuf.packet_full[PACKET_HEADER], PACKET_SIZE);
    YmodemSendByte(tempCRC >> 8);
    YmodemSendByte(tempCRC & 0xFF);
  }
  else
  {
    tempCheckSum = CalChecksum (&packetBuf.packet_full[PACKET_HEADER], PACKET_SIZE);
    YmodemSendByte(tempCheckSum);
  }
  do
  {
    /* wait for 'ACK' */
    if((YmodemReceiveByte(&ch[0]) < 0) || (ch[0] != ACK))
    {
      err++;
    }
    else
    {
      /* received 'ACK' */
      ackReceived++;
    }
  }while((!ackReceived) && (err < 0x0a));
  if(err >= 0x0a)
  {
    /* timeout */
    return err;
  }
  err = 0;
  ackReceived = 0;
  
  return 0;
}

 

你可能感兴趣的:(单片机)