XinLiArmfly 发表于 2018-3-7 20:26:16

YMODEM协议串口文件传输

YMODEM协议串口文件传输
转载来源:YMODEM协议串口文件传输


GitHub仓库:https://github.com/XinLiGitHub/SerialPortYmodem
PS:博文不再更新,后续更新会在GitHub仓库进行。


    串口通过YMODEM协议进行文件传输。程序中涉及到YMODEM协议知识,详细介绍见维基百科(https://en.wikipedia.org/wiki/YMODEM)。

1,开发环境
      1,框架:Qt 5.7.1

      2,编译器:MSVC2015_64bit

      3,IDE:Qt Creator 4.2.0 社区版
      4,操作系统:Windows 10 专业版

2,程序源码
      Ymodem.h文件

/**
******************************************************************************
* @file    Ymodem.h
* @authorXinLi
* @version v1.0
* @date    21-January-2018
* @brief   Header file for Ymodem.cpp module.
******************************************************************************
* @attention
*
* <h2><center>Copyright © 2018 XinLi</center></h2>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.If not, see <https://www.gnu.org/licenses/>.
*
******************************************************************************
*/

#ifndef __YMODEM_H
#define __YMODEM_H

/* Header includes -----------------------------------------------------------*/
#include <stdint.h>

/* Macro definitions ---------------------------------------------------------*/
#define YMODEM_PACKET_HEADER    (3)
#define YMODEM_PACKET_TRAILER   (2)
#define YMODEM_PACKET_OVERHEAD(YMODEM_PACKET_HEADER + YMODEM_PACKET_TRAILER)
#define YMODEM_PACKET_SIZE      (128)
#define YMODEM_PACKET_1K_SIZE   (1024)

#define YMODEM_CODE_CAN_NUMBER(5)

/* Type definitions ----------------------------------------------------------*/
class Ymodem
{
public:
enum Code
{
    CodeNone = 0x00,
    CodeSoh= 0x01,
    CodeStx= 0x02,
    CodeEot= 0x04,
    CodeAck= 0x06,
    CodeNak= 0x15,
    CodeCan= 0x18,
    CodeC    = 0x43,
    CodeA1   = 0x41,
    CodeA2   = 0x61
};

enum Stage
{
    StageNone,
    StageEstablishing,
    StageEstablished,
    StageTransmitting,
    StageFinishing,
    StageFinished
};

enum Status
{
    StatusEstablish,
    StatusTransmit,
    StatusFinish,
    StatusAbort,
    StatusTimeout,
    StatusError
};

Ymodem(uint32_t timeDivide = 499, uint32_t timeMax = 5, uint32_t errorMax = 999);

void setTimeDivide(uint32_t timeDivide);
uint32_t getTimeDivide();

void setTimeMax(uint32_t timeMax);
uint32_t getTimeMax();

void setErrorMax(uint32_t errorMax);
uint32_t getErrorMax();

void receive();
void transmit();
void abort();

private:
Code receivePacket();

void receiveStageNone();
void receiveStageEstablishing();
void receiveStageEstablished();
void receiveStageTransmitting();
void receiveStageFinishing();
void receiveStageFinished();

void transmitStageNone();
void transmitStageEstablishing();
void transmitStageEstablished();
void transmitStageTransmitting();
void transmitStageFinishing();
void transmitStageFinished();

uint16_t crc16(uint8_t *buff, uint32_t len);

virtual Code callback(Status status, uint8_t *buff, uint32_t *len) = 0;

virtual uint32_t read(uint8_t *buff, uint32_t len)= 0;
virtual uint32_t write(uint8_t *buff, uint32_t len) = 0;

uint32_t timeDivide;
uint32_t timeMax;
uint32_t errorMax;

uint32_t timeCount;
uint32_t errorCount;
uint8_tdataCount;

Codecode;
Stage stage;

uint8_trxBuffer;
uint8_ttxBuffer;
uint32_t rxLength;
uint32_t txLength;
};

/* Variable declarations -----------------------------------------------------*/
/* Variable definitions ------------------------------------------------------*/
/* Function declarations -----------------------------------------------------*/
/* Function definitions ------------------------------------------------------*/

#endif /* __YMODEM_H */

      Ymodem.cpp文件
/**
******************************************************************************
* @file    Ymodem.cpp
* @authorXinLi
* @version v1.0
* @date    21-January-2018
* @brief   Ymodem protocol module source file.
******************************************************************************
* @attention
*
* <h2><center>Copyright © 2018 XinLi</center></h2>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.If not, see <https://www.gnu.org/licenses/>.
*
******************************************************************************
*/

/* Header includes -----------------------------------------------------------*/
#include "Ymodem.h"
#include <string.h>

/* Macro definitions ---------------------------------------------------------*/
/* Type definitions ----------------------------------------------------------*/
/* Variable declarations -----------------------------------------------------*/
/* Variable definitions ------------------------------------------------------*/
/* Function declarations -----------------------------------------------------*/
/* Function definitions ------------------------------------------------------*/

/**
* @briefYmodem constructor.
* @param timeDivide: The fractional factor of the time the ymodem is called.
* @param timeMax:    The maximum time when calling the ymodem.
* @param errorMax:   The maximum error count when calling the ymodem.
* @note   The longest waiting time = call time / (@timeDivide + 1) * (@timeMax + 1).
* @return None.
*/
Ymodem::Ymodem(uint32_t timeDivide, uint32_t timeMax, uint32_t errorMax)
{
this->timeDivide = timeDivide;
this->timeMax    = timeMax;
this->errorMax   = errorMax;

this->timeCount= 0;
this->errorCount = 0;
this->dataCount= 0;

this->code       = CodeNone;
this->stage      = StageNone;
}

/**
* @briefSet the fractional factor of the time the ymodem is called.
* @param timeDivide: The fractional factor of the time the ymodem is called.
* @return None.
*/
void Ymodem::setTimeDivide(uint32_t timeDivide)
{
this->timeDivide = timeDivide;
}

/**
* @briefGet the fractional factor of the time the ymodem is called.
* @paramNone.
* @return The fractional factor of the time the ymodem is called.
*/
uint32_t Ymodem::getTimeDivide()
{
return timeDivide;
}

/**
* @briefSet the maximum time when calling the ymodem.
* @param timeMax: The maximum time when calling the ymodem.
* @return None.
*/
void Ymodem::setTimeMax(uint32_t timeMax)
{
this->timeMax = timeMax;
}

/**
* @briefGet the maximum time when calling the ymodem.
* @paramNone.
* @return The maximum time when calling the ymodem.
*/
uint32_t Ymodem::getTimeMax()
{
return timeMax;
}

/**
* @briefSet the maximum error count when calling the ymodem.
* @param errorMax: The maximum error count when calling the ymodem.
* @return None.
*/
void Ymodem::setErrorMax(uint32_t errorMax)
{
this->errorMax = errorMax;
}

/**
* @briefGet the maximum error count when calling the ymodem.
* @paramNone.
* @return The maximum error count when calling the ymodem.
*/
uint32_t Ymodem::getErrorMax()
{
return errorMax;
}

/**
* @briefYmodem receive.
* @paramNone.
* @return None.
*/
void Ymodem::receive()
{
switch(stage)
{
    case StageNone:
    {
      receiveStageNone();

      break;
    }

    case StageEstablishing:
    {
      receiveStageEstablishing();

      break;
    }

    case StageEstablished:
    {
      receiveStageEstablished();

      break;
    }

    case StageTransmitting:
    {
      receiveStageTransmitting();

      break;
    }

    case StageFinishing:
    {
      receiveStageFinishing();

      break;
    }

    default:
    {
      receiveStageFinished();
    }
}
}

/**
* @briefYmodem transmit.
* @paramNone.
* @return None.
*/
void Ymodem::transmit()
{
switch(stage)
{
    case StageNone:
    {
      transmitStageNone();

      break;
    }

    case StageEstablishing:
    {
      transmitStageEstablishing();

      break;
    }

    case StageEstablished:
    {
      transmitStageEstablished();

      break;
    }

    case StageTransmitting:
    {
      transmitStageTransmitting();

      break;
    }

    case StageFinishing:
    {
      transmitStageFinishing();

      break;
    }

    default:
    {
      transmitStageFinished();
    }
}
}

/**
* @briefYmodem abort.
* @paramNone.
* @return None.
*/
void Ymodem::abort()
{
timeCount= 0;
errorCount = 0;
dataCount= 0;
code       = CodeNone;
stage      = StageNone;

for(txLength = 0; txLength < YMODEM_CODE_CAN_NUMBER; txLength++)
{
    txBuffer = CodeCan;
}

write(txBuffer, txLength);
}

/**
* @briefReceives a packet of data.
* @paramNone.
* @return Packet type.
*/
Ymodem::Code Ymodem::receivePacket()
{
if(code == CodeNone)
{
    if(read(&(rxBuffer), 1) > 0)
    {
      if(rxBuffer == CodeSoh)
      {
      uint32_t len = read(&(rxBuffer), YMODEM_PACKET_SIZE + YMODEM_PACKET_OVERHEAD - 1);

      if(len < (YMODEM_PACKET_SIZE + YMODEM_PACKET_OVERHEAD - 1))
      {
          rxLength = len + 1;
          code   = CodeSoh;

          return CodeNone;
      }
      else
      {
          return CodeSoh;
      }
      }
      else if(rxBuffer == CodeStx)
      {
      uint32_t len = read(&(rxBuffer), YMODEM_PACKET_1K_SIZE + YMODEM_PACKET_OVERHEAD - 1);

      if(len < (YMODEM_PACKET_1K_SIZE + YMODEM_PACKET_OVERHEAD - 1))
      {
          rxLength = len + 1;
          code   = CodeStx;

          return CodeNone;
      }
      else
      {
          return CodeStx;
      }
      }
      else
      {
      return (Code)(rxBuffer);
      }
    }
    else
    {
      return CodeNone;
    }
}
else
{
    if(code == CodeSoh)
    {
      uint32_t len = read(&(rxBuffer), YMODEM_PACKET_SIZE + YMODEM_PACKET_OVERHEAD - rxLength);

      if(len < (YMODEM_PACKET_SIZE + YMODEM_PACKET_OVERHEAD - rxLength))
      {
      rxLength += len;

      return CodeNone;
      }
      else
      {
      code = CodeNone;

      return CodeSoh;
      }
    }
    else if(code == CodeStx)
    {
      uint32_t len = read(&(rxBuffer), YMODEM_PACKET_1K_SIZE + YMODEM_PACKET_OVERHEAD - rxLength);

      if(len < (YMODEM_PACKET_1K_SIZE + YMODEM_PACKET_OVERHEAD - rxLength))
      {
      rxLength += len;

      return CodeNone;
      }
      else
      {
      code = CodeNone;

      return CodeStx;
      }
    }
    else
    {
      code = CodeNone;

      return CodeNone;
    }
}
}

/**
* @briefReceive none stage.
* @paramNone.
* @return None.
*/
void Ymodem::receiveStageNone()
{
timeCount   = 0;
errorCount= 0;
dataCount   = 0;
code      = CodeNone;
stage       = StageEstablishing;
txBuffer = CodeC;
txLength    = 1;
write(txBuffer, txLength);
}

/**
* @briefReceive establishing stage.
* @paramNone.
* @return None.
*/
void Ymodem::receiveStageEstablishing()
{
switch(receivePacket())
{
    case CodeSoh:
    {
      uint16_t crc = ((uint16_t)(rxBuffer) << 8) |
                     ((uint16_t)(rxBuffer) << 0);

      if((rxBuffer == 0x00) && (rxBuffer == 0xFF) &&
         (crc == crc16(&(rxBuffer), YMODEM_PACKET_SIZE)))
      {
      uint32_t dataLength = YMODEM_PACKET_SIZE;

      if(callback(StatusEstablish, &(rxBuffer), &dataLength) == CodeAck)
      {
          timeCount   = 0;
          errorCount= 0;
          dataCount   = 0;
          code      = CodeNone;
          stage       = StageEstablished;
          txBuffer = CodeAck;
          txBuffer = CodeC;
          txLength    = 2;
          write(txBuffer, txLength);
      }
      else
      {
          timeCount= 0;
          errorCount = 0;
          dataCount= 0;
          code       = CodeNone;
          stage      = StageNone;

          for(txLength = 0; txLength < YMODEM_CODE_CAN_NUMBER; txLength++)
          {
            txBuffer = CodeCan;
          }

          write(txBuffer, txLength);
      }
      }
      else
      {
      errorCount++;

      if(errorCount > errorMax)
      {
          timeCount= 0;
          errorCount = 0;
          dataCount= 0;
          code       = CodeNone;
          stage      = StageNone;

          for(txLength = 0; txLength < YMODEM_CODE_CAN_NUMBER; txLength++)
          {
            txBuffer = CodeCan;
          }

          write(txBuffer, txLength);
          callback(StatusError, NULL, NULL);
      }
      else
      {
          txBuffer = CodeC;
          txLength    = 1;
          write(txBuffer, txLength);
      }
      }

      break;
    }

    case CodeA1:
    case CodeA2:
    case CodeCan:
    {
      timeCount= 0;
      errorCount = 0;
      dataCount= 0;
      code       = CodeNone;
      stage      = StageNone;
      callback(StatusAbort, NULL, NULL);

      break;
    }

    default:
    {
      timeCount++;

      if((timeCount / (timeDivide + 1)) > timeMax)
      {
      timeCount= 0;
      errorCount = 0;
      dataCount= 0;
      code       = CodeNone;
      stage      = StageNone;

      for(txLength = 0; txLength < YMODEM_CODE_CAN_NUMBER; txLength++)
      {
          txBuffer = CodeCan;
      }

      write(txBuffer, txLength);
      callback(StatusTimeout, NULL, NULL);
      }
      else if((timeCount % (timeDivide + 1)) == 0)
      {
      txBuffer = CodeC;
      txLength    = 1;
      write(txBuffer, txLength);
      }
    }
}
}

/**
* @briefReceive established stage.
* @paramNone.
* @return None.
*/
void Ymodem::receiveStageEstablished()
{
switch(receivePacket())
{
    case CodeSoh:
    {
      uint16_t crc = ((uint16_t)(rxBuffer) << 8) |
                     ((uint16_t)(rxBuffer) << 0);

      if((rxBuffer == 0x00) && (rxBuffer == 0xFF) &&
         (crc == crc16(&(rxBuffer), YMODEM_PACKET_SIZE)))
      {
      errorCount++;

      if(errorCount > errorMax)
      {
          timeCount= 0;
          errorCount = 0;
          dataCount= 0;
          code       = CodeNone;
          stage      = StageNone;

          for(txLength = 0; txLength < YMODEM_CODE_CAN_NUMBER; txLength++)
          {
            txBuffer = CodeCan;
          }

          write(txBuffer, txLength);
          callback(StatusError, NULL, NULL);
      }
      else
      {
          txBuffer = CodeAck;
          txBuffer = CodeC;
          txLength    = 2;
          write(txBuffer, txLength);
      }
      }
      else if((rxBuffer == 0x01) && (rxBuffer == 0xFE) &&
            (crc == crc16(&(rxBuffer), YMODEM_PACKET_SIZE)))
      {
      uint32_t dataLength = YMODEM_PACKET_SIZE;

      if(callback(StatusTransmit, &(rxBuffer), &dataLength) == CodeAck)
      {
          timeCount   = 0;
          errorCount= 0;
          dataCount   = 1;
          code      = CodeNone;
          stage       = StageTransmitting;
          txBuffer = CodeAck;
          txLength    = 1;
          write(txBuffer, txLength);
      }
      else
      {
          timeCount= 0;
          errorCount = 0;
          dataCount= 0;
          code       = CodeNone;
          stage      = StageNone;

          for(txLength = 0; txLength < YMODEM_CODE_CAN_NUMBER; txLength++)
          {
            txBuffer = CodeCan;
          }

          write(txBuffer, txLength);
      }
      }
      else
      {
      errorCount++;

      if(errorCount > errorMax)
      {
          timeCount= 0;
          errorCount = 0;
          dataCount= 0;
          code       = CodeNone;
          stage      = StageNone;

          for(txLength = 0; txLength < YMODEM_CODE_CAN_NUMBER; txLength++)
          {
            txBuffer = CodeCan;
          }

          write(txBuffer, txLength);
          callback(StatusError, NULL, NULL);
      }
      else
      {
          txBuffer = CodeNak;
          txLength    = 1;
          write(txBuffer, txLength);
      }
      }

      break;
    }

    case CodeStx:
    {
      uint16_t crc = ((uint16_t)(rxBuffer) << 8) |
                     ((uint16_t)(rxBuffer) << 0);

      if((rxBuffer == 0x01) && (rxBuffer == 0xFE) &&
         (crc == crc16(&(rxBuffer), YMODEM_PACKET_1K_SIZE)))
      {
      uint32_t dataLength = YMODEM_PACKET_1K_SIZE;

      if(callback(StatusTransmit, &(rxBuffer), &dataLength) == CodeAck)
      {
          timeCount   = 0;
          errorCount= 0;
          dataCount   = 1;
          code      = CodeNone;
          stage       = StageTransmitting;
          txBuffer = CodeAck;
          txLength    = 1;
          write(txBuffer, txLength);
      }
      else
      {
          timeCount= 0;
          errorCount = 0;
          dataCount= 0;
          code       = CodeNone;
          stage      = StageNone;

          for(txLength = 0; txLength < YMODEM_CODE_CAN_NUMBER; txLength++)
          {
            txBuffer = CodeCan;
          }

          write(txBuffer, txLength);
      }
      }
      else
      {
      errorCount++;

      if(errorCount > errorMax)
      {
          timeCount= 0;
          errorCount = 0;
          dataCount= 0;
          code       = CodeNone;
          stage      = StageNone;

          for(txLength = 0; txLength < YMODEM_CODE_CAN_NUMBER; txLength++)
          {
            txBuffer = CodeCan;
          }

          write(txBuffer, txLength);
          callback(StatusError, NULL, NULL);
      }
      else
      {
          txBuffer = CodeNak;
          txLength    = 1;
          write(txBuffer, txLength);
      }
      }

      break;
    }

    case CodeEot:
    {
      timeCount   = 0;
      errorCount= 0;
      dataCount   = 0;
      code      = CodeNone;
      stage       = StageFinishing;
      txBuffer = CodeNak;
      txLength    = 1;
      write(txBuffer, txLength);

      break;
    }

    case CodeA1:
    case CodeA2:
    case CodeCan:
    {
      timeCount= 0;
      errorCount = 0;
      dataCount= 0;
      code       = CodeNone;
      stage      = StageNone;
      callback(StatusAbort, NULL, NULL);

      break;
    }

    default:
    {
      timeCount++;

      if((timeCount / (timeDivide + 1)) > timeMax)
      {
      timeCount= 0;
      errorCount = 0;
      dataCount= 0;
      code       = CodeNone;
      stage      = StageNone;

      for(txLength = 0; txLength < YMODEM_CODE_CAN_NUMBER; txLength++)
      {
          txBuffer = CodeCan;
      }

      write(txBuffer, txLength);
      callback(StatusError, NULL, NULL);
      }
      else if((timeCount % (timeDivide + 1)) == 0)
      {
      txBuffer = CodeNak;
      txLength    = 1;
      write(txBuffer, txLength);
      }
    }
}
}

/**
* @briefReceive transmitting stage.
* @paramNone.
* @return None.
*/
void Ymodem::receiveStageTransmitting()
{
switch(receivePacket())
{
    case CodeSoh:
    {
      uint16_t crc = ((uint16_t)(rxBuffer) << 8) |
                     ((uint16_t)(rxBuffer) << 0);

      if((rxBuffer == (uint8_t)(dataCount)) && (rxBuffer == (uint8_t)(0xFF - dataCount)) &&
         (crc == crc16(&(rxBuffer), YMODEM_PACKET_SIZE)))
      {
      errorCount++;

      if(errorCount > errorMax)
      {
          timeCount= 0;
          errorCount = 0;
          dataCount= 0;
          code       = CodeNone;
          stage      = StageNone;

          for(txLength = 0; txLength < YMODEM_CODE_CAN_NUMBER; txLength++)
          {
            txBuffer = CodeCan;
          }

          write(txBuffer, txLength);
          callback(StatusError, NULL, NULL);
      }
      else
      {
          txBuffer = CodeAck;
          txLength    = 1;
          write(txBuffer, txLength);
      }
      }
      else if((rxBuffer == (uint8_t)(dataCount + 1)) && (rxBuffer == (uint8_t)(0xFE - dataCount)) &&
            (crc == crc16(&(rxBuffer), YMODEM_PACKET_SIZE)))
      {
      uint32_t dataLength = YMODEM_PACKET_SIZE;

      if(callback(StatusTransmit, &(rxBuffer), &dataLength) == CodeAck)
      {
          timeCount   = 0;
          errorCount= 0;
          dataCount   = dataCount + 1;
          code      = CodeNone;
          stage       = StageTransmitting;
          txBuffer = CodeAck;
          txLength    = 1;
          write(txBuffer, txLength);
      }
      else
      {
          timeCount= 0;
          errorCount = 0;
          dataCount= 0;
          code       = CodeNone;
          stage      = StageNone;

          for(txLength = 0; txLength < YMODEM_CODE_CAN_NUMBER; txLength++)
          {
            txBuffer = CodeCan;
          }

          write(txBuffer, txLength);
      }
      }
      else
      {
      errorCount++;

      if(errorCount > errorMax)
      {
          timeCount= 0;
          errorCount = 0;
          dataCount= 0;
          code       = CodeNone;
          stage      = StageNone;

          for(txLength = 0; txLength < YMODEM_CODE_CAN_NUMBER; txLength++)
          {
            txBuffer = CodeCan;
          }

          write(txBuffer, txLength);
          callback(StatusError, NULL, NULL);
      }
      else
      {
          txBuffer = CodeNak;
          txLength    = 1;
          write(txBuffer, txLength);
      }
      }

      break;
    }

    case CodeStx:
    {
      uint16_t crc = ((uint16_t)(rxBuffer) << 8) |
                     ((uint16_t)(rxBuffer) << 0);

      if((rxBuffer == (uint8_t)(dataCount)) && (rxBuffer == (uint8_t)(0xFF - dataCount)) &&
         (crc == crc16(&(rxBuffer), YMODEM_PACKET_1K_SIZE)))
      {
      errorCount++;

      if(errorCount > errorMax)
      {
          timeCount= 0;
          errorCount = 0;
          dataCount= 0;
          code       = CodeNone;
          stage      = StageNone;

          for(txLength = 0; txLength < YMODEM_CODE_CAN_NUMBER; txLength++)
          {
            txBuffer = CodeCan;
          }

          write(txBuffer, txLength);
          callback(StatusError, NULL, NULL);
      }
      else
      {
          txBuffer = CodeAck;
          txLength    = 1;
          write(txBuffer, txLength);
      }
      }
      else if((rxBuffer == (uint8_t)(dataCount + 1)) && (rxBuffer == (uint8_t)(0xFE - dataCount)) &&
            (crc == crc16(&(rxBuffer), YMODEM_PACKET_1K_SIZE)))
      {
      uint32_t dataLength = YMODEM_PACKET_1K_SIZE;

      if(callback(StatusTransmit, &(rxBuffer), &dataLength) == CodeAck)
      {
          timeCount   = 0;
          errorCount= 0;
          dataCount   = dataCount + 1;
          code      = CodeNone;
          stage       = StageTransmitting;
          txBuffer = CodeAck;
          txLength    = 1;
          write(txBuffer, txLength);
      }
      else
      {
          timeCount= 0;
          errorCount = 0;
          dataCount= 0;
          code       = CodeNone;
          stage      = StageNone;

          for(txLength = 0; txLength < YMODEM_CODE_CAN_NUMBER; txLength++)
          {
            txBuffer = CodeCan;
          }

          write(txBuffer, txLength);
      }
      }
      else
      {
      errorCount++;

      if(errorCount > errorMax)
      {
          timeCount= 0;
          errorCount = 0;
          dataCount= 0;
          code       = CodeNone;
          stage      = StageNone;

          for(txLength = 0; txLength < YMODEM_CODE_CAN_NUMBER; txLength++)
          {
            txBuffer = CodeCan;
          }

          write(txBuffer, txLength);
          callback(StatusError, NULL, NULL);
      }
      else
      {
          txBuffer = CodeNak;
          txLength    = 1;
          write(txBuffer, txLength);
      }
      }

      break;
    }

    case CodeEot:
    {
      timeCount   = 0;
      errorCount= 0;
      dataCount   = 0;
      code      = CodeNone;
      stage       = StageFinishing;
      txBuffer = CodeNak;
      txLength    = 1;
      write(txBuffer, txLength);

      break;
    }

    case CodeA1:
    case CodeA2:
    case CodeCan:
    {
      timeCount= 0;
      errorCount = 0;
      dataCount= 0;
      code       = CodeNone;
      stage      = StageNone;
      callback(StatusAbort, NULL, NULL);

      break;
    }

    default:
    {
      timeCount++;

      if((timeCount / (timeDivide + 1)) > timeMax)
      {
      timeCount= 0;
      errorCount = 0;
      dataCount= 0;
      code       = CodeNone;
      stage      = StageNone;

      for(txLength = 0; txLength < YMODEM_CODE_CAN_NUMBER; txLength++)
      {
          txBuffer = CodeCan;
      }

      write(txBuffer, txLength);
      callback(StatusError, NULL, NULL);
      }
      else if((timeCount % (timeDivide + 1)) == 0)
      {
      txBuffer = CodeNak;
      txLength    = 1;
      write(txBuffer, txLength);
      }
    }
}
}

/**
* @briefReceive finishing stage.
* @paramNone.
* @return None.
*/
void Ymodem::receiveStageFinishing()
{
switch(receivePacket())
{
    case CodeEot:
    {
      timeCount   = 0;
      errorCount= 0;
      dataCount   = 0;
      code      = CodeNone;
      stage       = StageFinished;
      txBuffer = CodeAck;
      txBuffer = CodeC;
      txLength    = 2;
      write(txBuffer, txLength);

      break;
    }

    case CodeA1:
    case CodeA2:
    case CodeCan:
    {
      timeCount= 0;
      errorCount = 0;
      dataCount= 0;
      code       = CodeNone;
      stage      = StageNone;
      callback(StatusAbort, NULL, NULL);

      break;
    }

    default:
    {
      timeCount++;

      if((timeCount / (timeDivide + 1)) > timeMax)
      {
      timeCount= 0;
      errorCount = 0;
      dataCount= 0;
      code       = CodeNone;
      stage      = StageNone;

      for(txLength = 0; txLength < YMODEM_CODE_CAN_NUMBER; txLength++)
      {
          txBuffer = CodeCan;
      }

      write(txBuffer, txLength);
      callback(StatusError, NULL, NULL);
      }
      else if((timeCount % (timeDivide + 1)) == 0)
      {
      txBuffer = CodeNak;
      txLength    = 1;
      write(txBuffer, txLength);
      }
    }
}
}

/**
* @briefReceive finished stage.
* @paramNone.
* @return None.
*/
void Ymodem::receiveStageFinished()
{
switch(receivePacket())
{
    case CodeSoh:
    {
      uint16_t crc = ((uint16_t)(rxBuffer) << 8) |
                     ((uint16_t)(rxBuffer) << 0);

      if((rxBuffer == 0x00) && (rxBuffer == 0xFF) &&
         (crc == crc16(&(rxBuffer), YMODEM_PACKET_SIZE)))
      {
      timeCount   = 0;
      errorCount= 0;
      dataCount   = 0;
      code      = CodeNone;
      stage       = StageNone;
      txBuffer = CodeAck;
      txLength    = 1;
      write(txBuffer, txLength);
      callback(StatusFinish, NULL, NULL);
      }
      else
      {
      errorCount++;

      if(errorCount > errorMax)
      {
          timeCount= 0;
          errorCount = 0;
          dataCount= 0;
          code       = CodeNone;
          stage      = StageNone;

          for(txLength = 0; txLength < YMODEM_CODE_CAN_NUMBER; txLength++)
          {
            txBuffer = CodeCan;
          }

          write(txBuffer, txLength);
          callback(StatusError, NULL, NULL);
      }
      else
      {
          txBuffer = CodeNak;
          txLength    = 1;
          write(txBuffer, txLength);
      }
      }

      break;
    }

    case CodeEot:
    {
      errorCount++;

      if(errorCount > errorMax)
      {
      timeCount= 0;
      errorCount = 0;
      dataCount= 0;
      code       = CodeNone;
      stage      = StageNone;

      for(txLength = 0; txLength < YMODEM_CODE_CAN_NUMBER; txLength++)
      {
          txBuffer = CodeCan;
      }

      write(txBuffer, txLength);
      callback(StatusError, NULL, NULL);
      }
      else
      {
      txBuffer = CodeAck;
      txBuffer = CodeC;
      txLength    = 2;
      write(txBuffer, txLength);
      }

      break;
    }

    case CodeA1:
    case CodeA2:
    case CodeCan:
    {
      timeCount= 0;
      errorCount = 0;
      dataCount= 0;
      code       = CodeNone;
      stage      = StageNone;
      callback(StatusAbort, NULL, NULL);

      break;
    }

    default:
    {
      timeCount++;

      if((timeCount / (timeDivide + 1)) > timeMax)
      {
      timeCount= 0;
      errorCount = 0;
      dataCount= 0;
      code       = CodeNone;
      stage      = StageNone;

      for(txLength = 0; txLength < YMODEM_CODE_CAN_NUMBER; txLength++)
      {
          txBuffer = CodeCan;
      }

      write(txBuffer, txLength);
      callback(StatusError, NULL, NULL);
      }
      else if((timeCount % (timeDivide + 1)) == 0)
      {
      txBuffer = CodeNak;
      txLength    = 1;
      write(txBuffer, txLength);
      }
    }
}
}

/**
* @briefTransmit none stage.
* @paramNone.
* @return None.
*/
void Ymodem::transmitStageNone()
{
timeCount   = 0;
errorCount= 0;
dataCount   = 0;
code      = CodeNone;
stage       = StageEstablishing;
}

/**
* @briefTransmit establishing stage.
* @paramNone.
* @return None.
*/
void Ymodem::transmitStageEstablishing()
{
switch(receivePacket())
{
    case CodeC:
    {
      memset(&(txBuffer), NULL, YMODEM_PACKET_SIZE);

      if(callback(StatusEstablish, &(txBuffer), &(txLength)) == CodeAck)
      {
      uint16_t crc = crc16(&(txBuffer), txLength);

      timeCount                                       = 0;
      errorCount                                    = 0;
      dataCount                                       = 0;
      code                                          = CodeNone;
      stage                                           = StageEstablished;
      txBuffer                                     = CodeSoh;
      txBuffer                                     = 0x00;
      txBuffer                                     = 0xFF;
      txBuffer = (uint8_t)(crc >> 8);
      txBuffer = (uint8_t)(crc >> 0);
      txLength                                        = txLength + YMODEM_PACKET_OVERHEAD;
      write(txBuffer, txLength);
      }
      else
      {
      timeCount= 0;
      errorCount = 0;
      dataCount= 0;
      code       = CodeNone;
      stage      = StageNone;

      for(txLength = 0; txLength < YMODEM_CODE_CAN_NUMBER; txLength++)
      {
          txBuffer = CodeCan;
      }

      write(txBuffer, txLength);
      }

      break;
    }

    case CodeA1:
    case CodeA2:
    case CodeCan:
    {
      timeCount= 0;
      errorCount = 0;
      dataCount= 0;
      code       = CodeNone;
      stage      = StageNone;
      callback(StatusAbort, NULL, NULL);

      break;
    }

    default:
    {
      timeCount++;

      if((timeCount / (timeDivide + 1)) > timeMax)
      {
      timeCount= 0;
      errorCount = 0;
      dataCount= 0;
      code       = CodeNone;
      stage      = StageNone;

      for(txLength = 0; txLength < YMODEM_CODE_CAN_NUMBER; txLength++)
      {
          txBuffer = CodeCan;
      }

      write(txBuffer, txLength);
      callback(StatusTimeout, NULL, NULL);
      }
    }
}
}

/**
* @briefTransmit established stage.
* @paramNone.
* @return None.
*/
void Ymodem::transmitStageEstablished()
{
switch(receivePacket())
{
    case CodeNak:
    {
      errorCount++;

      if(errorCount > errorMax)
      {
      timeCount= 0;
      errorCount = 0;
      dataCount= 0;
      code       = CodeNone;
      stage      = StageNone;

      for(txLength = 0; txLength < YMODEM_CODE_CAN_NUMBER; txLength++)
      {
          txBuffer = CodeCan;
      }

      write(txBuffer, txLength);
      callback(StatusError, NULL, NULL);
      }
      else
      {
      write(txBuffer, txLength);
      }

      break;
    }

    case CodeC:
    {
      errorCount++;

      if(errorCount > errorMax)
      {
      timeCount= 0;
      errorCount = 0;
      dataCount= 0;
      code       = CodeNone;
      stage      = StageNone;

      for(txLength = 0; txLength < YMODEM_CODE_CAN_NUMBER; txLength++)
      {
          txBuffer = CodeCan;
      }

      write(txBuffer, txLength);
      callback(StatusError, NULL, NULL);
      }
      else
      {
      timeCount= 0;
      errorCount = 0;
      dataCount= dataCount;
      code       = CodeNone;
      stage      = (Stage)(stage + dataCount);
      write(txBuffer, txLength);
      }

      break;
    }

    case CodeAck:
    {
      memset(&(txBuffer), NULL, YMODEM_PACKET_1K_SIZE);

      switch(callback(StatusTransmit, &(txBuffer), &(txLength)))
      {
      case CodeAck:
      {
          uint16_t crc = crc16(&(txBuffer), txLength);

          timeCount                                       = 0;
          errorCount                                    = 0;
          dataCount                                       = 1;
          code                                          = CodeNone;
          stage                                           = StageEstablished;
          txBuffer                                     = txLength > YMODEM_PACKET_SIZE ? CodeStx : CodeSoh;
          txBuffer                                     = 0x01;
          txBuffer                                     = 0xFE;
          txBuffer = (uint8_t)(crc >> 8);
          txBuffer = (uint8_t)(crc >> 0);
          txLength                                        = txLength + YMODEM_PACKET_OVERHEAD;

          break;
      }

      case CodeEot:
      {
          timeCount   = 0;
          errorCount= 0;
          dataCount   = 2;
          code      = CodeNone;
          stage       = StageEstablished;
          txBuffer = CodeEot;
          txLength    = 1;
          write(txBuffer, txLength);

          break;
      }

      default:
      {
          timeCount= 0;
          errorCount = 0;
          dataCount= 0;
          code       = CodeNone;
          stage      = StageNone;

          for(txLength = 0; txLength < YMODEM_CODE_CAN_NUMBER; txLength++)
          {
            txBuffer = CodeCan;
          }

          write(txBuffer, txLength);
      }
      }

      break;
    }

    case CodeA1:
    case CodeA2:
    case CodeCan:
    {
      timeCount= 0;
      errorCount = 0;
      dataCount= 0;
      code       = CodeNone;
      stage      = StageNone;
      callback(StatusAbort, NULL, NULL);

      break;
    }

    default:
    {
      timeCount++;

      if((timeCount / (timeDivide + 1)) > timeMax)
      {
      timeCount= 0;
      errorCount = 0;
      dataCount= 0;
      code       = CodeNone;
      stage      = StageNone;

      for(txLength = 0; txLength < YMODEM_CODE_CAN_NUMBER; txLength++)
      {
          txBuffer = CodeCan;
      }

      write(txBuffer, txLength);
      callback(StatusError, NULL, NULL);
      }
      else if((timeCount % (timeDivide + 1)) == 0)
      {
      write(txBuffer, txLength);
      }
    }
}
}

/**
* @briefTransmit transmitting stage.
* @paramNone.
* @return None.
*/
void Ymodem::transmitStageTransmitting()
{
switch(receivePacket())
{
    case CodeNak:
    {
      errorCount++;

      if(errorCount > errorMax)
      {
      timeCount= 0;
      errorCount = 0;
      dataCount= 0;
      code       = CodeNone;
      stage      = StageNone;

      for(txLength = 0; txLength < YMODEM_CODE_CAN_NUMBER; txLength++)
      {
          txBuffer = CodeCan;
      }

      write(txBuffer, txLength);
      callback(StatusError, NULL, NULL);
      }
      else
      {
      write(txBuffer, txLength);
      }

      break;
    }

    case CodeAck:
    {
      memset(&(txBuffer), NULL, YMODEM_PACKET_1K_SIZE);

      switch(callback(StatusTransmit, &(txBuffer), &(txLength)))
      {
      case CodeAck:
      {
          uint16_t crc = crc16(&(txBuffer), txLength);

          timeCount                                       = 0;
          errorCount                                    = 0;
          dataCount                                       = dataCount + 1;
          code                                          = CodeNone;
          stage                                           = StageTransmitting;
          txBuffer                                     = txLength > YMODEM_PACKET_SIZE ? CodeStx : CodeSoh;
          txBuffer                                     = dataCount;
          txBuffer                                     = 0xFF - dataCount;
          txBuffer = (uint8_t)(crc >> 8);
          txBuffer = (uint8_t)(crc >> 0);
          txLength                                        = txLength + YMODEM_PACKET_OVERHEAD;
          write(txBuffer, txLength);

          break;
      }

      case CodeEot:
      {
          timeCount   = 0;
          errorCount= 0;
          dataCount   = 0;
          code      = CodeNone;
          stage       = StageFinishing;
          txBuffer = CodeEot;
          txLength    = 1;
          write(txBuffer, txLength);

          break;
      }

      default:
      {
          timeCount= 0;
          errorCount = 0;
          dataCount= 0;
          code       = CodeNone;
          stage      = StageNone;

          for(txLength = 0; txLength < YMODEM_CODE_CAN_NUMBER; txLength++)
          {
            txBuffer = CodeCan;
          }

          write(txBuffer, txLength);
      }
      }

      break;
    }

    case CodeA1:
    case CodeA2:
    case CodeCan:
    {
      timeCount= 0;
      errorCount = 0;
      dataCount= 0;
      code       = CodeNone;
      stage      = StageNone;
      callback(StatusAbort, NULL, NULL);

      break;
    }

    default:
    {
      timeCount++;

      if((timeCount / (timeDivide + 1)) > timeMax)
      {
      timeCount= 0;
      errorCount = 0;
      dataCount= 0;
      code       = CodeNone;
      stage      = StageNone;

      for(txLength = 0; txLength < YMODEM_CODE_CAN_NUMBER; txLength++)
      {
          txBuffer = CodeCan;
      }

      write(txBuffer, txLength);
      callback(StatusError, NULL, NULL);
      }
      else if((timeCount % (timeDivide + 1)) == 0)
      {
      write(txBuffer, txLength);
      }
    }
}
}

/**
* @briefTransmit finishing stage.
* @paramNone.
* @return None.
*/
void Ymodem::transmitStageFinishing()
{
switch(receivePacket())
{
    case CodeNak:
    {
      timeCount   = 0;
      errorCount= 0;
      dataCount   = 0;
      code      = CodeNone;
      stage       = StageFinishing;
      txBuffer = CodeEot;
      txLength    = 1;
      write(txBuffer, txLength);

      break;
    }

    case CodeC:
    {
      memset(&(txBuffer), NULL, YMODEM_PACKET_SIZE);
      uint16_t crc = crc16(&(txBuffer), YMODEM_PACKET_SIZE);

      timeCount                                                 = 0;
      errorCount                                                = 0;
      dataCount                                                 = 0;
      code                                                      = CodeNone;
      stage                                                   = StageFinished;
      txBuffer                                             = CodeSoh;
      txBuffer                                             = 0x00;
      txBuffer                                             = 0xFF;
      txBuffer = (uint8_t)(crc >> 8);
      txBuffer = (uint8_t)(crc >> 0);
      txLength                                                = YMODEM_PACKET_SIZE + YMODEM_PACKET_OVERHEAD;
      write(txBuffer, txLength);

      break;
    }

    case CodeA1:
    case CodeA2:
    case CodeCan:
    {
      timeCount= 0;
      errorCount = 0;
      dataCount= 0;
      code       = CodeNone;
      stage      = StageNone;
      callback(StatusAbort, NULL, NULL);

      break;
    }

    default:
    {
      timeCount++;

      if((timeCount / (timeDivide + 1)) > timeMax)
      {
      timeCount= 0;
      errorCount = 0;
      dataCount= 0;
      code       = CodeNone;
      stage      = StageNone;

      for(txLength = 0; txLength < YMODEM_CODE_CAN_NUMBER; txLength++)
      {
          txBuffer = CodeCan;
      }

      write(txBuffer, txLength);
      callback(StatusError, NULL, NULL);
      }
      else if((timeCount % (timeDivide + 1)) == 0)
      {
      write(txBuffer, txLength);
      }
    }
}
}

/**
* @briefTransmit finished stage.
* @paramNone.
* @return None.
*/
void Ymodem::transmitStageFinished()
{
switch(receivePacket())
{
    case CodeC:
    case CodeNak:
    {
      errorCount++;

      if(errorCount > errorMax)
      {
      timeCount= 0;
      errorCount = 0;
      dataCount= 0;
      code       = CodeNone;
      stage      = StageNone;

      for(txLength = 0; txLength < YMODEM_CODE_CAN_NUMBER; txLength++)
      {
          txBuffer = CodeCan;
      }

      write(txBuffer, txLength);
      callback(StatusError, NULL, NULL);
      }
      else
      {
      write(txBuffer, txLength);
      }

      break;
    }

    case CodeAck:
    {
      timeCount= 0;
      errorCount = 0;
      dataCount= 0;
      code       = CodeNone;
      stage      = StageNone;
      callback(StatusFinish, NULL, NULL);

      break;
    }

    case CodeA1:
    case CodeA2:
    case CodeCan:
    {
      timeCount= 0;
      errorCount = 0;
      dataCount= 0;
      code       = CodeNone;
      stage      = StageNone;
      callback(StatusAbort, NULL, NULL);

      break;
    }

    default:
    {
      timeCount++;

      if((timeCount / (timeDivide + 1)) > timeMax)
      {
      timeCount= 0;
      errorCount = 0;
      dataCount= 0;
      code       = CodeNone;
      stage      = StageNone;

      for(txLength = 0; txLength < YMODEM_CODE_CAN_NUMBER; txLength++)
      {
          txBuffer = CodeCan;
      }

      write(txBuffer, txLength);
      callback(StatusError, NULL, NULL);
      }
      else if((timeCount % (timeDivide + 1)) == 0)
      {
      write(txBuffer, txLength);
      }
    }
}
}

/**
* @briefCalculate CRC16 checksum.
* @param buff: The data to be calculated.
* @param len:The length of the data to be calculated.
* @return Calculated CRC16 checksum.
*/
uint16_t Ymodem::crc16(uint8_t *buff, uint32_t len)
{
uint16_t crc = 0;

while(len--)
{
    crc ^= (uint16_t)(*(buff++)) << 8;

    for(int i = 0; i < 8; i++)
    {
      if(crc & 0x8000)
      {
      crc = (crc << 1) ^ 0x1021;
      }
      else
      {
      crc = crc << 1;
      }
    }
}

return crc;
}

      YmodemFileReceive.h文件
#ifndef YMODEMFILERECEIVE_H
#define YMODEMFILERECEIVE_H

#include <QFile>
#include <QTimer>
#include <QObject>
#include <QSerialPort>
#include "Ymodem.h"

class YmodemFileReceive : public QObject, public Ymodem
{
    Q_OBJECT

public:
    explicit YmodemFileReceive(QObject *parent = 0);
    ~YmodemFileReceive();

    void setFilePath(const QString &path);

    void setPortName(const QString &name);
    void setPortBaudRate(qint32 baudrate);

    bool startReceive();
    void stopReceive();

    int getReceiveProgress();
    Status getReceiveStatus();

signals:
    void receiveProgress(int progress);
    void receiveStatus(YmodemFileReceive::Status status);

private slots:
    void readTimeOut();
    void writeTimeOut();

private:
    Code callback(Status status, uint8_t *buff, uint32_t *len);

    uint32_t read(uint8_t *buff, uint32_t len);
    uint32_t write(uint8_t *buff, uint32_t len);

    QFile       *file;
    QTimer      *readTimer;
    QTimer      *writeTimer;
    QSerialPort *serialPort;

    int      progress;
    Status   status;
    QStringfilePath;
    QStringfileName;
    uint64_t fileSize;
    uint64_t fileCount;
};

#endif // YMODEMFILERECEIVE_H

      YmodemFileReceive.cpp文件
#include "YmodemFileReceive.h"

#define READ_TIME_OUT   (10)
#define WRITE_TIME_OUT(100)

YmodemFileReceive::YmodemFileReceive(QObject *parent) :
    QObject(parent),
    file(new QFile),
    readTimer(new QTimer),
    writeTimer(new QTimer),
    serialPort(new QSerialPort)
{
    setTimeDivide(499);
    setTimeMax(5);
    setErrorMax(999);

    serialPort->setPortName("COM1");
    serialPort->setBaudRate(115200);
    serialPort->setDataBits(QSerialPort::Data8);
    serialPort->setStopBits(QSerialPort::OneStop);
    serialPort->setParity(QSerialPort::NoParity);
    serialPort->setFlowControl(QSerialPort::NoFlowControl);

    connect(readTimer, SIGNAL(timeout()), this, SLOT(readTimeOut()));
    connect(writeTimer, SIGNAL(timeout()), this, SLOT(writeTimeOut()));
}

YmodemFileReceive::~YmodemFileReceive()
{
    delete file;
    delete readTimer;
    delete writeTimer;
    delete serialPort;
}

void YmodemFileReceive::setFilePath(const QString &path)
{
    filePath = path + "/";
}

void YmodemFileReceive::setPortName(const QString &name)
{
    serialPort->setPortName(name);
}

void YmodemFileReceive::setPortBaudRate(qint32 baudrate)
{
    serialPort->setBaudRate(baudrate);
}

bool YmodemFileReceive::startReceive()
{
    progress = 0;
    status   = StatusEstablish;

    if(serialPort->open(QSerialPort::ReadWrite) == true)
    {
      readTimer->start(READ_TIME_OUT);

      return true;
    }
    else
    {
      return false;
    }
}

void YmodemFileReceive::stopReceive()
{
    file->close();
    abort();
    status = StatusAbort;
    writeTimer->start(WRITE_TIME_OUT);
}

int YmodemFileReceive::getReceiveProgress()
{
    return progress;
}

Ymodem::Status YmodemFileReceive::getReceiveStatus()
{
    return status;
}

void YmodemFileReceive::readTimeOut()
{
    readTimer->stop();

    receive();

    if((status == StatusEstablish) || (status == StatusTransmit))
    {
      readTimer->start(READ_TIME_OUT);
    }
}

void YmodemFileReceive::writeTimeOut()
{
    writeTimer->stop();
    serialPort->close();
    receiveStatus(status);
}

Ymodem::Code YmodemFileReceive::callback(Status status, uint8_t *buff, uint32_t *len)
{
    switch(status)
    {
      case StatusEstablish:
      {
            if(buff != 0)
            {
                inti         =0;
                char name = {0};
                char size = {0};

                for(int j = 0; buff != 0; i++, j++)
                {
                  name = buff;
                }

                i++;

                for(int j = 0; buff != 0; i++, j++)
                {
                  size = buff;
                }

                fileName= QString::fromLocal8Bit(name);
                fileSize= QString(size).toULongLong();
                fileCount = 0;

                file->setFileName(filePath + fileName);

                if(file->open(QFile::WriteOnly) == true)
                {
                  YmodemFileReceive::status = StatusEstablish;

                  receiveStatus(StatusEstablish);

                  return CodeAck;
                }
                else
                {
                  YmodemFileReceive::status = StatusError;

                  writeTimer->start(WRITE_TIME_OUT);

                  return CodeCan;
                }
            }
            else
            {
                YmodemFileReceive::status = StatusError;

                writeTimer->start(WRITE_TIME_OUT);

                return CodeCan;
            }
      }

      case StatusTransmit:
      {
            if((fileSize - fileCount) > *len)
            {
                file->write((char *)buff, *len);

                fileCount += *len;
            }
            else
            {
                file->write((char *)buff, fileSize - fileCount);

                fileCount += fileSize - fileCount;
            }

            progress = (int)(fileCount * 100 / fileSize);

            YmodemFileReceive::status = StatusTransmit;

            receiveProgress(progress);
            receiveStatus(StatusTransmit);

            return CodeAck;
      }

      case StatusFinish:
      {
            file->close();

            YmodemFileReceive::status = StatusFinish;

            writeTimer->start(WRITE_TIME_OUT);

            return CodeAck;
      }

      case StatusAbort:
      {
            file->close();

            YmodemFileReceive::status = StatusAbort;

            writeTimer->start(WRITE_TIME_OUT);

            return CodeCan;
      }

      case StatusTimeout:
      {
            YmodemFileReceive::status = StatusTimeout;

            writeTimer->start(WRITE_TIME_OUT);

            return CodeCan;
      }

      default:
      {
            file->close();

            YmodemFileReceive::status = StatusError;

            writeTimer->start(WRITE_TIME_OUT);

            return CodeCan;
      }
    }
}

uint32_t YmodemFileReceive::read(uint8_t *buff, uint32_t len)
{
    return serialPort->read((char *)buff, len);
}

uint32_t YmodemFileReceive::write(uint8_t *buff, uint32_t len)
{
    return serialPort->write((char *)buff, len);
}

      YmodemFileTransmit.h文件
#ifndef YMODEMFILETRANSMIT_H
#define YMODEMFILETRANSMIT_H

#include <QFile>
#include <QTimer>
#include <QObject>
#include <QSerialPort>
#include "Ymodem.h"

class YmodemFileTransmit : public QObject, public Ymodem
{
    Q_OBJECT

public:
    explicit YmodemFileTransmit(QObject *parent = 0);
    ~YmodemFileTransmit();

    void setFileName(const QString &name);

    void setPortName(const QString &name);
    void setPortBaudRate(qint32 baudrate);

    bool startTransmit();
    void stopTransmit();

    int getTransmitProgress();
    Status getTransmitStatus();

signals:
    void transmitProgress(int progress);
    void transmitStatus(YmodemFileTransmit::Status status);

private slots:
    void readTimeOut();
    void writeTimeOut();

private:
    Code callback(Status status, uint8_t *buff, uint32_t *len);

    uint32_t read(uint8_t *buff, uint32_t len);
    uint32_t write(uint8_t *buff, uint32_t len);

    QFile       *file;
    QTimer      *readTimer;
    QTimer      *writeTimer;
    QSerialPort *serialPort;

    int      progress;
    Status   status;
    uint64_t fileSize;
    uint64_t fileCount;
};

#endif // YMODEMFILETRANSMIT_H

      YmodemFileTransmit.cpp文件
#include "YmodemFileTransmit.h"
#include <QFileInfo>

#define READ_TIME_OUT   (10)
#define WRITE_TIME_OUT(100)

YmodemFileTransmit::YmodemFileTransmit(QObject *parent) :
    QObject(parent),
    file(new QFile),
    readTimer(new QTimer),
    writeTimer(new QTimer),
    serialPort(new QSerialPort)
{
    setTimeDivide(499);
    setTimeMax(5);
    setErrorMax(999);

    serialPort->setPortName("COM1");
    serialPort->setBaudRate(115200);
    serialPort->setDataBits(QSerialPort::Data8);
    serialPort->setStopBits(QSerialPort::OneStop);
    serialPort->setParity(QSerialPort::NoParity);
    serialPort->setFlowControl(QSerialPort::NoFlowControl);

    connect(readTimer, SIGNAL(timeout()), this, SLOT(readTimeOut()));
    connect(writeTimer, SIGNAL(timeout()), this, SLOT(writeTimeOut()));
}

YmodemFileTransmit::~YmodemFileTransmit()
{
    delete file;
    delete readTimer;
    delete writeTimer;
    delete serialPort;
}

void YmodemFileTransmit::setFileName(const QString &name)
{
    file->setFileName(name);
}

void YmodemFileTransmit::setPortName(const QString &name)
{
    serialPort->setPortName(name);
}

void YmodemFileTransmit::setPortBaudRate(qint32 baudrate)
{
    serialPort->setBaudRate(baudrate);
}

bool YmodemFileTransmit::startTransmit()
{
    progress = 0;
    status   = StatusEstablish;

    if(serialPort->open(QSerialPort::ReadWrite) == true)
    {
      readTimer->start(READ_TIME_OUT);

      return true;
    }
    else
    {
      return false;
    }
}

void YmodemFileTransmit::stopTransmit()
{
    file->close();
    abort();
    status = StatusAbort;
    writeTimer->start(WRITE_TIME_OUT);
}

int YmodemFileTransmit::getTransmitProgress()
{
    return progress;
}

Ymodem::Status YmodemFileTransmit::getTransmitStatus()
{
    return status;
}

void YmodemFileTransmit::readTimeOut()
{
    readTimer->stop();

    transmit();

    if((status == StatusEstablish) || (status == StatusTransmit))
    {
      readTimer->start(READ_TIME_OUT);
    }
}

void YmodemFileTransmit::writeTimeOut()
{
    writeTimer->stop();
    serialPort->close();
    transmitStatus(status);
}

Ymodem::Code YmodemFileTransmit::callback(Status status, uint8_t *buff, uint32_t *len)
{
    switch(status)
    {
      case StatusEstablish:
      {
            if(file->open(QFile::ReadOnly) == true)
            {
                QFileInfo fileInfo(*file);

                fileSize= fileInfo.size();
                fileCount = 0;

                strcpy((char *)buff, fileInfo.fileName().toLocal8Bit().data());
                strcpy((char *)buff + fileInfo.fileName().toLocal8Bit().size() + 1, QByteArray::number(fileInfo.size()).data());

                *len = YMODEM_PACKET_SIZE;

                YmodemFileTransmit::status = StatusEstablish;

                transmitStatus(StatusEstablish);

                return CodeAck;
            }
            else
            {
                YmodemFileTransmit::status = StatusError;

                writeTimer->start(WRITE_TIME_OUT);

                return CodeCan;
            }
      }

      case StatusTransmit:
      {
            if(fileSize != fileCount)
            {
                if((fileSize - fileCount) > YMODEM_PACKET_SIZE)
                {
                  fileCount += file->read((char *)buff, YMODEM_PACKET_1K_SIZE);

                  *len = YMODEM_PACKET_1K_SIZE;
                }
                else
                {
                  fileCount += file->read((char *)buff, YMODEM_PACKET_SIZE);

                  *len = YMODEM_PACKET_SIZE;
                }

                progress = (int)(fileCount * 100 / fileSize);

                YmodemFileTransmit::status = StatusTransmit;

                transmitProgress(progress);
                transmitStatus(StatusTransmit);

                return CodeAck;
            }
            else
            {
                YmodemFileTransmit::status = StatusTransmit;

                transmitStatus(StatusTransmit);

                return CodeEot;
            }
      }

      case StatusFinish:
      {
            file->close();

            YmodemFileTransmit::status = StatusFinish;

            writeTimer->start(WRITE_TIME_OUT);

            return CodeAck;
      }

      case StatusAbort:
      {
            file->close();

            YmodemFileTransmit::status = StatusAbort;

            writeTimer->start(WRITE_TIME_OUT);

            return CodeCan;
      }

      case StatusTimeout:
      {
            YmodemFileTransmit::status = StatusTimeout;

            writeTimer->start(WRITE_TIME_OUT);

            return CodeCan;
      }

      default:
      {
            file->close();

            YmodemFileTransmit::status = StatusError;

            writeTimer->start(WRITE_TIME_OUT);

            return CodeCan;
      }
    }
}

uint32_t YmodemFileTransmit::read(uint8_t *buff, uint32_t len)
{
    return serialPort->read((char *)buff, len);
}

uint32_t YmodemFileTransmit::write(uint8_t *buff, uint32_t len)
{
    return serialPort->write((char *)buff, len);
}

      widget.ui文件
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Widget</class>
<widget class="QWidget" name="Widget">
<property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>444</width>
    <height>255</height>
   </rect>
</property>
<property name="minimumSize">
   <size>
    <width>444</width>
    <height>255</height>
   </size>
</property>
<property name="maximumSize">
   <size>
    <width>444</width>
    <height>255</height>
   </size>
</property>
<property name="windowTitle">
   <string>SerialPortYmodem</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
   <item>
    <widget class="QGroupBox" name="groupBox">
   <property name="title">
      <string>串口配置</string>
   </property>
   <layout class="QHBoxLayout" name="horizontalLayout">
      <item>
       <widget class="QLabel" name="label">
      <property name="text">
         <string>端口:</string>
      </property>
       </widget>
      </item>
      <item>
       <widget class="QComboBox" name="comPort">
      <property name="maxVisibleItems">
         <number>12</number>
      </property>
       </widget>
      </item>
      <item>
       <spacer name="horizontalSpacer">
      <property name="orientation">
         <enum>Qt::Horizontal</enum>
      </property>
      <property name="sizeHint" stdset="0">
         <size>
          <width>40</width>
          <height>20</height>
         </size>
      </property>
       </spacer>
      </item>
      <item>
       <widget class="QLabel" name="label_2">
      <property name="text">
         <string>波特率:</string>
      </property>
       </widget>
      </item>
      <item>
       <widget class="QComboBox" name="comBaudRate">
      <property name="currentText">
         <string>115200</string>
      </property>
      <property name="currentIndex">
         <number>3</number>
      </property>
      <property name="maxVisibleItems">
         <number>12</number>
      </property>
      <item>
         <property name="text">
          <string>921600</string>
         </property>
      </item>
      <item>
         <property name="text">
          <string>460800</string>
         </property>
      </item>
      <item>
         <property name="text">
          <string>230400</string>
         </property>
      </item>
      <item>
         <property name="text">
          <string>115200</string>
         </property>
      </item>
      <item>
         <property name="text">
          <string>57600</string>
         </property>
      </item>
      <item>
         <property name="text">
          <string>38400</string>
         </property>
      </item>
      <item>
         <property name="text">
          <string>19200</string>
         </property>
      </item>
      <item>
         <property name="text">
          <string>9600</string>
         </property>
      </item>
      <item>
         <property name="text">
          <string>4800</string>
         </property>
      </item>
      <item>
         <property name="text">
          <string>2400</string>
         </property>
      </item>
      <item>
         <property name="text">
          <string>1200</string>
         </property>
      </item>
       </widget>
      </item>
      <item>
       <spacer name="horizontalSpacer_2">
      <property name="orientation">
         <enum>Qt::Horizontal</enum>
      </property>
      <property name="sizeHint" stdset="0">
         <size>
          <width>40</width>
          <height>20</height>
         </size>
      </property>
       </spacer>
      </item>
      <item>
       <widget class="QPushButton" name="comButton">
      <property name="text">
         <string>打开</string>
      </property>
       </widget>
      </item>
   </layout>
    </widget>
   </item>
   <item>
    <widget class="QGroupBox" name="groupBox_2">
   <property name="title">
      <string>文件发送</string>
   </property>
   <layout class="QVBoxLayout" name="verticalLayout">
      <item>
       <layout class="QHBoxLayout" name="horizontalLayout_2">
      <item>
         <widget class="QLabel" name="label_3">
          <property name="text">
         <string>文件路径:</string>
          </property>
         </widget>
      </item>
      <item>
         <widget class="QLineEdit" name="transmitPath">
          <property name="readOnly">
         <bool>true</bool>
          </property>
         </widget>
      </item>
      <item>
         <widget class="QPushButton" name="transmitBrowse">
          <property name="enabled">
         <bool>false</bool>
          </property>
          <property name="text">
         <string>浏览...</string>
          </property>
         </widget>
      </item>
      <item>
         <widget class="QPushButton" name="transmitButton">
          <property name="enabled">
         <bool>false</bool>
          </property>
          <property name="text">
         <string>发送</string>
          </property>
         </widget>
      </item>
       </layout>
      </item>
      <item>
       <layout class="QHBoxLayout" name="horizontalLayout_3">
      <item>
         <widget class="QLabel" name="label_5">
          <property name="text">
         <string>传输进度:</string>
          </property>
         </widget>
      </item>
      <item>
         <widget class="QProgressBar" name="transmitProgress">
          <property name="value">
         <number>0</number>
          </property>
         </widget>
      </item>
       </layout>
      </item>
   </layout>
    </widget>
   </item>
   <item>
    <widget class="QGroupBox" name="groupBox_3">
   <property name="title">
      <string>文件接收</string>
   </property>
   <layout class="QVBoxLayout" name="verticalLayout_2">
      <item>
       <layout class="QHBoxLayout" name="horizontalLayout_4">
      <item>
         <widget class="QLabel" name="label_4">
          <property name="text">
         <string>文件路径:</string>
          </property>
         </widget>
      </item>
      <item>
         <widget class="QLineEdit" name="receivePath">
          <property name="readOnly">
         <bool>true</bool>
          </property>
         </widget>
      </item>
      <item>
         <widget class="QPushButton" name="receiveBrowse">
          <property name="enabled">
         <bool>false</bool>
          </property>
          <property name="text">
         <string>浏览...</string>
          </property>
         </widget>
      </item>
      <item>
         <widget class="QPushButton" name="receiveButton">
          <property name="enabled">
         <bool>false</bool>
          </property>
          <property name="text">
         <string>接收</string>
          </property>
         </widget>
      </item>
       </layout>
      </item>
      <item>
       <layout class="QHBoxLayout" name="horizontalLayout_5">
      <item>
         <widget class="QLabel" name="label_6">
          <property name="text">
         <string>传输进度:</string>
          </property>
         </widget>
      </item>
      <item>
         <widget class="QProgressBar" name="receiveProgress">
          <property name="value">
         <number>0</number>
          </property>
         </widget>
      </item>
       </layout>
      </item>
   </layout>
    </widget>
   </item>
</layout>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>

      widget.h文件
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include "YmodemFileTransmit.h"
#include "YmodemFileReceive.h"

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

private slots:
    void on_comButton_clicked();
    void on_transmitBrowse_clicked();
    void on_receiveBrowse_clicked();
    void on_transmitButton_clicked();
    void on_receiveButton_clicked();
    void transmitProgress(int progress);
    void receiveProgress(int progress);
    void transmitStatus(YmodemFileTransmit::Status status);
    void receiveStatus(YmodemFileReceive::Status status);

private:
    Ui::Widget *ui;
    QSerialPort *serialPort;
    YmodemFileTransmit *ymodemFileTransmit;
    YmodemFileReceive *ymodemFileReceive;

    bool transmitButtonStatus;
    bool receiveButtonStatus;
};

#endif // WIDGET_H

      widget.cpp文件
#include "widget.h"
#include "ui_widget.h"
#include <QMessageBox>
#include <QFileDialog>
#include <QSerialPortInfo>

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget),
    serialPort(new QSerialPort),
    ymodemFileTransmit(new YmodemFileTransmit),
    ymodemFileReceive(new YmodemFileReceive)
{
    transmitButtonStatus = false;
    receiveButtonStatus= false;

    ui->setupUi(this);

    QSerialPortInfo serialPortInfo;

    foreach(serialPortInfo, QSerialPortInfo::availablePorts())
    {
      ui->comPort->addItem(serialPortInfo.portName());
    }

    serialPort->setPortName("COM1");
    serialPort->setBaudRate(115200);
    serialPort->setDataBits(QSerialPort::Data8);
    serialPort->setStopBits(QSerialPort::OneStop);
    serialPort->setParity(QSerialPort::NoParity);
    serialPort->setFlowControl(QSerialPort::NoFlowControl);

    connect(ymodemFileTransmit, SIGNAL(transmitProgress(int)), this, SLOT(transmitProgress(int)));
    connect(ymodemFileReceive, SIGNAL(receiveProgress(int)), this, SLOT(receiveProgress(int)));

   connect(ymodemFileTransmit,
SIGNAL(transmitStatus(YmodemFileTransmit::Status)), this,
SLOT(transmitStatus(YmodemFileTransmit::Status)));
   
connect(ymodemFileReceive,
SIGNAL(receiveStatus(YmodemFileReceive::Status)), this,
SLOT(receiveStatus(YmodemFileReceive::Status)));
}

Widget::~Widget()
{
    delete ui;
    delete serialPort;
    delete ymodemFileTransmit;
    delete ymodemFileReceive;
}

void Widget::on_comButton_clicked()
{
    static bool button_status = false;

    if(button_status == false)
    {
      serialPort->setPortName(ui->comPort->currentText());
      serialPort->setBaudRate(ui->comBaudRate->currentText().toInt());

      if(serialPort->open(QSerialPort::ReadWrite) == true)
      {
            button_status = true;

            ui->comPort->setDisabled(true);
            ui->comBaudRate->setDisabled(true);
            ui->comButton->setText(u8"关闭串口");

            ui->transmitBrowse->setEnabled(true);
            ui->receiveBrowse->setEnabled(true);

            if(ui->transmitPath->text().isEmpty() != true)
            {
                ui->transmitButton->setEnabled(true);
            }

            if(ui->receivePath->text().isEmpty() != true)
            {
                ui->receiveButton->setEnabled(true);
            }
      }
      else
      {
            QMessageBox::warning(this, u8"串口打开失败", u8"请检查串口是否已被占用!", u8"关闭");
      }
    }
    else
    {
      button_status = false;

      serialPort->close();

      ui->comPort->setEnabled(true);
      ui->comBaudRate->setEnabled(true);
      ui->comButton->setText(u8"打开串口");

      ui->transmitBrowse->setDisabled(true);
      ui->transmitButton->setDisabled(true);

      ui->receiveBrowse->setDisabled(true);
      ui->receiveButton->setDisabled(true);
    }
}

void Widget::on_transmitBrowse_clicked()
{
    ui->transmitPath->setText(QFileDialog::getOpenFileName(this, u8"打开文件", ".", u8"任意文件 (*.*)"));

    if(ui->transmitPath->text().isEmpty() != true)
    {
      ui->transmitButton->setEnabled(true);
    }
    else
    {
      ui->transmitButton->setDisabled(true);
    }
}

void Widget::on_receiveBrowse_clicked()
{
    ui->receivePath->setText(QFileDialog::getExistingDirectory(this, u8"选择目录", ".", QFileDialog::ShowDirsOnly));

    if(ui->receivePath->text().isEmpty() != true)
    {
      ui->receiveButton->setEnabled(true);
    }
    else
    {
      ui->receiveButton->setDisabled(true);
    }
}

void Widget::on_transmitButton_clicked()
{
    if(transmitButtonStatus == false)
    {
      serialPort->close();

      ymodemFileTransmit->setFileName(ui->transmitPath->text());
      ymodemFileTransmit->setPortName(ui->comPort->currentText());
      ymodemFileTransmit->setPortBaudRate(ui->comBaudRate->currentText().toInt());

      if(ymodemFileTransmit->startTransmit() == true)
      {
            transmitButtonStatus = true;

            ui->comButton->setDisabled(true);

            ui->receiveBrowse->setDisabled(true);
            ui->receiveButton->setDisabled(true);

            ui->transmitBrowse->setDisabled(true);
            ui->transmitButton->setText(u8"取消");
            ui->transmitProgress->setValue(0);
      }
      else
      {
            QMessageBox::warning(this, u8"失败", u8"文件发送失败!", u8"关闭");
      }
    }
    else
    {
      ymodemFileTransmit->stopTransmit();
    }
}

void Widget::on_receiveButton_clicked()
{
    if(receiveButtonStatus == false)
    {
      serialPort->close();

      ymodemFileReceive->setFilePath(ui->receivePath->text());
      ymodemFileReceive->setPortName(ui->comPort->currentText());
      ymodemFileReceive->setPortBaudRate(ui->comBaudRate->currentText().toInt());

      if(ymodemFileReceive->startReceive() == true)
      {
            receiveButtonStatus = true;

            ui->comButton->setDisabled(true);

            ui->transmitBrowse->setDisabled(true);
            ui->transmitButton->setDisabled(true);

            ui->receiveBrowse->setDisabled(true);
            ui->receiveButton->setText(u8"取消");
            ui->receiveProgress->setValue(0);
      }
      else
      {
            QMessageBox::warning(this, u8"失败", u8"文件接收失败!", u8"关闭");
      }
    }
    else
    {
      ymodemFileReceive->stopReceive();
    }
}

void Widget::transmitProgress(int progress)
{
    ui->transmitProgress->setValue(progress);
}

void Widget::receiveProgress(int progress)
{
    ui->receiveProgress->setValue(progress);
}

void Widget::transmitStatus(Ymodem::Status status)
{
    switch(status)
    {
      case YmodemFileTransmit::StatusEstablish:
      {
            break;
      }

      case YmodemFileTransmit::StatusTransmit:
      {
            break;
      }

      case YmodemFileTransmit::StatusFinish:
      {
            transmitButtonStatus = false;

            ui->comButton->setEnabled(true);

            ui->receiveBrowse->setEnabled(true);

            if(ui->receivePath->text().isEmpty() != true)
            {
                ui->receiveButton->setEnabled(true);
            }

            ui->transmitBrowse->setEnabled(true);
            ui->transmitButton->setText(u8"发送");

            QMessageBox::warning(this, u8"成功", u8"文件发送成功!", u8"关闭");

            break;
      }

      case YmodemFileTransmit::StatusAbort:
      {
            transmitButtonStatus = false;

            ui->comButton->setEnabled(true);

            ui->receiveBrowse->setEnabled(true);

            if(ui->receivePath->text().isEmpty() != true)
            {
                ui->receiveButton->setEnabled(true);
            }

            ui->transmitBrowse->setEnabled(true);
            ui->transmitButton->setText(u8"发送");

            QMessageBox::warning(this, u8"失败", u8"文件发送失败!", u8"关闭");

            break;
      }

      case YmodemFileTransmit::StatusTimeout:
      {
            transmitButtonStatus = false;

            ui->comButton->setEnabled(true);

            ui->receiveBrowse->setEnabled(true);

            if(ui->receivePath->text().isEmpty() != true)
            {
                ui->receiveButton->setEnabled(true);
            }

            ui->transmitBrowse->setEnabled(true);
            ui->transmitButton->setText(u8"发送");

            QMessageBox::warning(this, u8"失败", u8"文件发送失败!", u8"关闭");

            break;
      }

      default:
      {
            transmitButtonStatus = false;

            ui->comButton->setEnabled(true);

            ui->receiveBrowse->setEnabled(true);

            if(ui->receivePath->text().isEmpty() != true)
            {
                ui->receiveButton->setEnabled(true);
            }

            ui->transmitBrowse->setEnabled(true);
            ui->transmitButton->setText(u8"发送");

            QMessageBox::warning(this, u8"失败", u8"文件发送失败!", u8"关闭");
      }
    }
}

void Widget::receiveStatus(YmodemFileReceive::Status status)
{
    switch(status)
    {
      case YmodemFileReceive::StatusEstablish:
      {
            break;
      }

      case YmodemFileReceive::StatusTransmit:
      {
            break;
      }

      case YmodemFileReceive::StatusFinish:
      {
            receiveButtonStatus = false;

            ui->comButton->setEnabled(true);

            ui->transmitBrowse->setEnabled(true);

            if(ui->transmitPath->text().isEmpty() != true)
            {
                ui->transmitButton->setEnabled(true);
            }

            ui->receiveBrowse->setEnabled(true);
            ui->receiveButton->setText(u8"接收");

            QMessageBox::warning(this, u8"成功", u8"文件接收成功!", u8"关闭");

            break;
      }

      case YmodemFileReceive::StatusAbort:
      {
            receiveButtonStatus = false;

            ui->comButton->setEnabled(true);

            ui->transmitBrowse->setEnabled(true);

            if(ui->transmitPath->text().isEmpty() != true)
            {
                ui->transmitButton->setEnabled(true);
            }

            ui->receiveBrowse->setEnabled(true);
            ui->receiveButton->setText(u8"接收");

            QMessageBox::warning(this, u8"失败", u8"文件接收失败!", u8"关闭");

            break;
      }

      case YmodemFileReceive::StatusTimeout:
      {
            receiveButtonStatus = false;

            ui->comButton->setEnabled(true);

            ui->transmitBrowse->setEnabled(true);

            if(ui->transmitPath->text().isEmpty() != true)
            {
                ui->transmitButton->setEnabled(true);
            }

            ui->receiveBrowse->setEnabled(true);
            ui->receiveButton->setText(u8"接收");

            QMessageBox::warning(this, u8"失败", u8"文件接收失败!", u8"关闭");

            break;
      }

      default:
      {
            receiveButtonStatus = false;

            ui->comButton->setEnabled(true);

            ui->transmitBrowse->setEnabled(true);

            if(ui->transmitPath->text().isEmpty() != true)
            {
                ui->transmitButton->setEnabled(true);
            }

            ui->receiveBrowse->setEnabled(true);
            ui->receiveButton->setText(u8"接收");

            QMessageBox::warning(this, u8"失败", u8"文件接收失败!", u8"关闭");
      }
    }
}

      main.cpp文件
#include "widget.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();

    return a.exec();
}

      SerialPortYmodem.pro文件
#-------------------------------------------------
#
# Project created by QtCreator 2018-01-20T23:00:46
#
#-------------------------------------------------

QT       += core gui
QT       += serialport

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = SerialPortYmodem
TEMPLATE = app

# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0


SOURCES += main.cpp\
      widget.cpp \
    YmodemFileReceive.cpp \
    Ymodem.cpp \
    YmodemFileTransmit.cpp

HEADERS+= widget.h \
    Ymodem.h \
    YmodemFileReceive.h \
    YmodemFileTransmit.h

FORMS    += widget.ui

RC_ICONS = SerialPortYmodem.ico

      SerialPortYmodem.ico文件
http://img.blog.csdn.net/20180306013605122
3,运行效果
http://img.blog.csdn.net/20180306013704785












XinLiArmfly 发表于 2018-3-7 20:26:40

可以用来做用户程序升级的上位机软件。GitHub仓库有工程,还有资料。
页: [1]
查看完整版本: YMODEM协议串口文件传输