YMODEM协议串口文件传输

YMODEM协议串口文件传输

GitHub仓库:https://github.com/XinLiGitHub/SerialPortYmodem

PS:博文不再更新,后续更新会在GitHub仓库进行。


    串口通过YMODEM协议进行文件传输。程序中涉及到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
  * @author  XinLi
  * @version v1.0
  * @date    21-January-2018
  * @brief   Header file for Ymodem.cpp module.
  ******************************************************************************
  * @attention
  *
  * 

Copyright © 2018 XinLi

* * 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 . * ****************************************************************************** */ #ifndef __YMODEM_H #define __YMODEM_H /* Header includes -----------------------------------------------------------*/ #include /* 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_t dataCount; Code code; Stage stage; uint8_t rxBuffer[YMODEM_PACKET_1K_SIZE + YMODEM_PACKET_OVERHEAD]; uint8_t txBuffer[YMODEM_PACKET_1K_SIZE + YMODEM_PACKET_OVERHEAD]; uint32_t rxLength; uint32_t txLength; }; /* Variable declarations -----------------------------------------------------*/ /* Variable definitions ------------------------------------------------------*/ /* Function declarations -----------------------------------------------------*/ /* Function definitions ------------------------------------------------------*/ #endif /* __YMODEM_H */

      Ymodem.cpp文件

/**
  ******************************************************************************
  * @file    Ymodem.cpp
  * @author  XinLi
  * @version v1.0
  * @date    21-January-2018
  * @brief   Ymodem protocol module source file.
  ******************************************************************************
  * @attention
  *
  * 

Copyright © 2018 XinLi

* * 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 . * ****************************************************************************** */ /* Header includes -----------------------------------------------------------*/ #include "Ymodem.h" #include /* Macro definitions ---------------------------------------------------------*/ /* Type definitions ----------------------------------------------------------*/ /* Variable declarations -----------------------------------------------------*/ /* Variable definitions ------------------------------------------------------*/ /* Function declarations -----------------------------------------------------*/ /* Function definitions ------------------------------------------------------*/ /** * @brief Ymodem constructor. * @param [in] timeDivide: The fractional factor of the time the ymodem is called. * @param [in] timeMax: The maximum time when calling the ymodem. * @param [in] 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; } /** * @brief Set the fractional factor of the time the ymodem is called. * @param [in] timeDivide: The fractional factor of the time the ymodem is called. * @return None. */ void Ymodem::setTimeDivide(uint32_t timeDivide) { this->timeDivide = timeDivide; } /** * @brief Get the fractional factor of the time the ymodem is called. * @param None. * @return The fractional factor of the time the ymodem is called. */ uint32_t Ymodem::getTimeDivide() { return timeDivide; } /** * @brief Set the maximum time when calling the ymodem. * @param [in] timeMax: The maximum time when calling the ymodem. * @return None. */ void Ymodem::setTimeMax(uint32_t timeMax) { this->timeMax = timeMax; } /** * @brief Get the maximum time when calling the ymodem. * @param None. * @return The maximum time when calling the ymodem. */ uint32_t Ymodem::getTimeMax() { return timeMax; } /** * @brief Set the maximum error count when calling the ymodem. * @param [in] errorMax: The maximum error count when calling the ymodem. * @return None. */ void Ymodem::setErrorMax(uint32_t errorMax) { this->errorMax = errorMax; } /** * @brief Get the maximum error count when calling the ymodem. * @param None. * @return The maximum error count when calling the ymodem. */ uint32_t Ymodem::getErrorMax() { return errorMax; } /** * @brief Ymodem receive. * @param None. * @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(); } } } /** * @brief Ymodem transmit. * @param None. * @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(); } } } /** * @brief Ymodem abort. * @param None. * @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[txLength] = CodeCan; } write(txBuffer, txLength); } /** * @brief Receives a packet of data. * @param None. * @return Packet type. */ Ymodem::Code Ymodem::receivePacket() { if(code == CodeNone) { if(read(&(rxBuffer[0]), 1) > 0) { if(rxBuffer[0] == CodeSoh) { uint32_t len = read(&(rxBuffer[1]), 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[0] == CodeStx) { uint32_t len = read(&(rxBuffer[1]), 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[0]); } } else { return CodeNone; } } else { if(code == CodeSoh) { uint32_t len = read(&(rxBuffer[rxLength]), 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[rxLength]), 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; } } } /** * @brief Receive none stage. * @param None. * @return None. */ void Ymodem::receiveStageNone() { timeCount = 0; errorCount = 0; dataCount = 0; code = CodeNone; stage = StageEstablishing; txBuffer[0] = CodeC; txLength = 1; write(txBuffer, txLength); } /** * @brief Receive establishing stage. * @param None. * @return None. */ void Ymodem::receiveStageEstablishing() { switch(receivePacket()) { case CodeSoh: { uint16_t crc = ((uint16_t)(rxBuffer[YMODEM_PACKET_SIZE + YMODEM_PACKET_OVERHEAD - 2]) << 8) | ((uint16_t)(rxBuffer[YMODEM_PACKET_SIZE + YMODEM_PACKET_OVERHEAD - 1]) << 0); if((rxBuffer[1] == 0x00) && (rxBuffer[2] == 0xFF) && (crc == crc16(&(rxBuffer[YMODEM_PACKET_HEADER]), YMODEM_PACKET_SIZE))) { uint32_t dataLength = YMODEM_PACKET_SIZE; if(callback(StatusEstablish, &(rxBuffer[YMODEM_PACKET_HEADER]), &dataLength) == CodeAck) { timeCount = 0; errorCount = 0; dataCount = 0; code = CodeNone; stage = StageEstablished; txBuffer[0] = CodeAck; txBuffer[1] = 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[txLength] = 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[txLength] = CodeCan; } write(txBuffer, txLength); callback(StatusError, NULL, NULL); } else { txBuffer[0] = 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[txLength] = CodeCan; } write(txBuffer, txLength); callback(StatusTimeout, NULL, NULL); } else if((timeCount % (timeDivide + 1)) == 0) { txBuffer[0] = CodeC; txLength = 1; write(txBuffer, txLength); } } } } /** * @brief Receive established stage. * @param None. * @return None. */ void Ymodem::receiveStageEstablished() { switch(receivePacket()) { case CodeSoh: { uint16_t crc = ((uint16_t)(rxBuffer[YMODEM_PACKET_SIZE + YMODEM_PACKET_OVERHEAD - 2]) << 8) | ((uint16_t)(rxBuffer[YMODEM_PACKET_SIZE + YMODEM_PACKET_OVERHEAD - 1]) << 0); if((rxBuffer[1] == 0x00) && (rxBuffer[2] == 0xFF) && (crc == crc16(&(rxBuffer[YMODEM_PACKET_HEADER]), 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[txLength] = CodeCan; } write(txBuffer, txLength); callback(StatusError, NULL, NULL); } else { txBuffer[0] = CodeAck; txBuffer[1] = CodeC; txLength = 2; write(txBuffer, txLength); } } else if((rxBuffer[1] == 0x01) && (rxBuffer[2] == 0xFE) && (crc == crc16(&(rxBuffer[YMODEM_PACKET_HEADER]), YMODEM_PACKET_SIZE))) { uint32_t dataLength = YMODEM_PACKET_SIZE; if(callback(StatusTransmit, &(rxBuffer[YMODEM_PACKET_HEADER]), &dataLength) == CodeAck) { timeCount = 0; errorCount = 0; dataCount = 1; code = CodeNone; stage = StageTransmitting; txBuffer[0] = 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[txLength] = 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[txLength] = CodeCan; } write(txBuffer, txLength); callback(StatusError, NULL, NULL); } else { txBuffer[0] = CodeNak; txLength = 1; write(txBuffer, txLength); } } break; } case CodeStx: { uint16_t crc = ((uint16_t)(rxBuffer[YMODEM_PACKET_1K_SIZE + YMODEM_PACKET_OVERHEAD - 2]) << 8) | ((uint16_t)(rxBuffer[YMODEM_PACKET_1K_SIZE + YMODEM_PACKET_OVERHEAD - 1]) << 0); if((rxBuffer[1] == 0x01) && (rxBuffer[2] == 0xFE) && (crc == crc16(&(rxBuffer[YMODEM_PACKET_HEADER]), YMODEM_PACKET_1K_SIZE))) { uint32_t dataLength = YMODEM_PACKET_1K_SIZE; if(callback(StatusTransmit, &(rxBuffer[YMODEM_PACKET_HEADER]), &dataLength) == CodeAck) { timeCount = 0; errorCount = 0; dataCount = 1; code = CodeNone; stage = StageTransmitting; txBuffer[0] = 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[txLength] = 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[txLength] = CodeCan; } write(txBuffer, txLength); callback(StatusError, NULL, NULL); } else { txBuffer[0] = CodeNak; txLength = 1; write(txBuffer, txLength); } } break; } case CodeEot: { timeCount = 0; errorCount = 0; dataCount = 0; code = CodeNone; stage = StageFinishing; txBuffer[0] = 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[txLength] = CodeCan; } write(txBuffer, txLength); callback(StatusError, NULL, NULL); } else if((timeCount % (timeDivide + 1)) == 0) { txBuffer[0] = CodeNak; txLength = 1; write(txBuffer, txLength); } } } } /** * @brief Receive transmitting stage. * @param None. * @return None. */ void Ymodem::receiveStageTransmitting() { switch(receivePacket()) { case CodeSoh: { uint16_t crc = ((uint16_t)(rxBuffer[YMODEM_PACKET_SIZE + YMODEM_PACKET_OVERHEAD - 2]) << 8) | ((uint16_t)(rxBuffer[YMODEM_PACKET_SIZE + YMODEM_PACKET_OVERHEAD - 1]) << 0); if((rxBuffer[1] == (uint8_t)(dataCount)) && (rxBuffer[2] == (uint8_t)(0xFF - dataCount)) && (crc == crc16(&(rxBuffer[YMODEM_PACKET_HEADER]), 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[txLength] = CodeCan; } write(txBuffer, txLength); callback(StatusError, NULL, NULL); } else { txBuffer[0] = CodeAck; txLength = 1; write(txBuffer, txLength); } } else if((rxBuffer[1] == (uint8_t)(dataCount + 1)) && (rxBuffer[2] == (uint8_t)(0xFE - dataCount)) && (crc == crc16(&(rxBuffer[YMODEM_PACKET_HEADER]), YMODEM_PACKET_SIZE))) { uint32_t dataLength = YMODEM_PACKET_SIZE; if(callback(StatusTransmit, &(rxBuffer[YMODEM_PACKET_HEADER]), &dataLength) == CodeAck) { timeCount = 0; errorCount = 0; dataCount = dataCount + 1; code = CodeNone; stage = StageTransmitting; txBuffer[0] = 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[txLength] = 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[txLength] = CodeCan; } write(txBuffer, txLength); callback(StatusError, NULL, NULL); } else { txBuffer[0] = CodeNak; txLength = 1; write(txBuffer, txLength); } } break; } case CodeStx: { uint16_t crc = ((uint16_t)(rxBuffer[YMODEM_PACKET_1K_SIZE + YMODEM_PACKET_OVERHEAD - 2]) << 8) | ((uint16_t)(rxBuffer[YMODEM_PACKET_1K_SIZE + YMODEM_PACKET_OVERHEAD - 1]) << 0); if((rxBuffer[1] == (uint8_t)(dataCount)) && (rxBuffer[2] == (uint8_t)(0xFF - dataCount)) && (crc == crc16(&(rxBuffer[YMODEM_PACKET_HEADER]), 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[txLength] = CodeCan; } write(txBuffer, txLength); callback(StatusError, NULL, NULL); } else { txBuffer[0] = CodeAck; txLength = 1; write(txBuffer, txLength); } } else if((rxBuffer[1] == (uint8_t)(dataCount + 1)) && (rxBuffer[2] == (uint8_t)(0xFE - dataCount)) && (crc == crc16(&(rxBuffer[YMODEM_PACKET_HEADER]), YMODEM_PACKET_1K_SIZE))) { uint32_t dataLength = YMODEM_PACKET_1K_SIZE; if(callback(StatusTransmit, &(rxBuffer[YMODEM_PACKET_HEADER]), &dataLength) == CodeAck) { timeCount = 0; errorCount = 0; dataCount = dataCount + 1; code = CodeNone; stage = StageTransmitting; txBuffer[0] = 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[txLength] = 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[txLength] = CodeCan; } write(txBuffer, txLength); callback(StatusError, NULL, NULL); } else { txBuffer[0] = CodeNak; txLength = 1; write(txBuffer, txLength); } } break; } case CodeEot: { timeCount = 0; errorCount = 0; dataCount = 0; code = CodeNone; stage = StageFinishing; txBuffer[0] = 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[txLength] = CodeCan; } write(txBuffer, txLength); callback(StatusError, NULL, NULL); } else if((timeCount % (timeDivide + 1)) == 0) { txBuffer[0] = CodeNak; txLength = 1; write(txBuffer, txLength); } } } } /** * @brief Receive finishing stage. * @param None. * @return None. */ void Ymodem::receiveStageFinishing() { switch(receivePacket()) { case CodeEot: { timeCount = 0; errorCount = 0; dataCount = 0; code = CodeNone; stage = StageFinished; txBuffer[0] = CodeAck; txBuffer[1] = 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[txLength] = CodeCan; } write(txBuffer, txLength); callback(StatusError, NULL, NULL); } else if((timeCount % (timeDivide + 1)) == 0) { txBuffer[0] = CodeNak; txLength = 1; write(txBuffer, txLength); } } } } /** * @brief Receive finished stage. * @param None. * @return None. */ void Ymodem::receiveStageFinished() { switch(receivePacket()) { case CodeSoh: { uint16_t crc = ((uint16_t)(rxBuffer[YMODEM_PACKET_SIZE + YMODEM_PACKET_OVERHEAD - 2]) << 8) | ((uint16_t)(rxBuffer[YMODEM_PACKET_SIZE + YMODEM_PACKET_OVERHEAD - 1]) << 0); if((rxBuffer[1] == 0x00) && (rxBuffer[2] == 0xFF) && (crc == crc16(&(rxBuffer[YMODEM_PACKET_HEADER]), YMODEM_PACKET_SIZE))) { timeCount = 0; errorCount = 0; dataCount = 0; code = CodeNone; stage = StageNone; txBuffer[0] = 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[txLength] = CodeCan; } write(txBuffer, txLength); callback(StatusError, NULL, NULL); } else { txBuffer[0] = 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[txLength] = CodeCan; } write(txBuffer, txLength); callback(StatusError, NULL, NULL); } else { txBuffer[0] = CodeAck; txBuffer[1] = 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[txLength] = CodeCan; } write(txBuffer, txLength); callback(StatusError, NULL, NULL); } else if((timeCount % (timeDivide + 1)) == 0) { txBuffer[0] = CodeNak; txLength = 1; write(txBuffer, txLength); } } } } /** * @brief Transmit none stage. * @param None. * @return None. */ void Ymodem::transmitStageNone() { timeCount = 0; errorCount = 0; dataCount = 0; code = CodeNone; stage = StageEstablishing; } /** * @brief Transmit establishing stage. * @param None. * @return None. */ void Ymodem::transmitStageEstablishing() { switch(receivePacket()) { case CodeC: { memset(&(txBuffer[YMODEM_PACKET_HEADER]), NULL, YMODEM_PACKET_SIZE); if(callback(StatusEstablish, &(txBuffer[YMODEM_PACKET_HEADER]), &(txLength)) == CodeAck) { uint16_t crc = crc16(&(txBuffer[YMODEM_PACKET_HEADER]), txLength); timeCount = 0; errorCount = 0; dataCount = 0; code = CodeNone; stage = StageEstablished; txBuffer[0] = CodeSoh; txBuffer[1] = 0x00; txBuffer[2] = 0xFF; txBuffer[txLength + YMODEM_PACKET_OVERHEAD - 2] = (uint8_t)(crc >> 8); txBuffer[txLength + YMODEM_PACKET_OVERHEAD - 1] = (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[txLength] = 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[txLength] = CodeCan; } write(txBuffer, txLength); callback(StatusTimeout, NULL, NULL); } } } } /** * @brief Transmit established stage. * @param None. * @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[txLength] = 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[txLength] = 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[YMODEM_PACKET_HEADER]), NULL, YMODEM_PACKET_1K_SIZE); switch(callback(StatusTransmit, &(txBuffer[YMODEM_PACKET_HEADER]), &(txLength))) { case CodeAck: { uint16_t crc = crc16(&(txBuffer[YMODEM_PACKET_HEADER]), txLength); timeCount = 0; errorCount = 0; dataCount = 1; code = CodeNone; stage = StageEstablished; txBuffer[0] = txLength > YMODEM_PACKET_SIZE ? CodeStx : CodeSoh; txBuffer[1] = 0x01; txBuffer[2] = 0xFE; txBuffer[txLength + YMODEM_PACKET_OVERHEAD - 2] = (uint8_t)(crc >> 8); txBuffer[txLength + YMODEM_PACKET_OVERHEAD - 1] = (uint8_t)(crc >> 0); txLength = txLength + YMODEM_PACKET_OVERHEAD; break; } case CodeEot: { timeCount = 0; errorCount = 0; dataCount = 2; code = CodeNone; stage = StageEstablished; txBuffer[0] = 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[txLength] = 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[txLength] = CodeCan; } write(txBuffer, txLength); callback(StatusError, NULL, NULL); } else if((timeCount % (timeDivide + 1)) == 0) { write(txBuffer, txLength); } } } } /** * @brief Transmit transmitting stage. * @param None. * @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[txLength] = CodeCan; } write(txBuffer, txLength); callback(StatusError, NULL, NULL); } else { write(txBuffer, txLength); } break; } case CodeAck: { memset(&(txBuffer[YMODEM_PACKET_HEADER]), NULL, YMODEM_PACKET_1K_SIZE); switch(callback(StatusTransmit, &(txBuffer[YMODEM_PACKET_HEADER]), &(txLength))) { case CodeAck: { uint16_t crc = crc16(&(txBuffer[YMODEM_PACKET_HEADER]), txLength); timeCount = 0; errorCount = 0; dataCount = dataCount + 1; code = CodeNone; stage = StageTransmitting; txBuffer[0] = txLength > YMODEM_PACKET_SIZE ? CodeStx : CodeSoh; txBuffer[1] = dataCount; txBuffer[2] = 0xFF - dataCount; txBuffer[txLength + YMODEM_PACKET_OVERHEAD - 2] = (uint8_t)(crc >> 8); txBuffer[txLength + YMODEM_PACKET_OVERHEAD - 1] = (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[0] = 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[txLength] = 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[txLength] = CodeCan; } write(txBuffer, txLength); callback(StatusError, NULL, NULL); } else if((timeCount % (timeDivide + 1)) == 0) { write(txBuffer, txLength); } } } } /** * @brief Transmit finishing stage. * @param None. * @return None. */ void Ymodem::transmitStageFinishing() { switch(receivePacket()) { case CodeNak: { timeCount = 0; errorCount = 0; dataCount = 0; code = CodeNone; stage = StageFinishing; txBuffer[0] = CodeEot; txLength = 1; write(txBuffer, txLength); break; } case CodeC: { memset(&(txBuffer[YMODEM_PACKET_HEADER]), NULL, YMODEM_PACKET_SIZE); uint16_t crc = crc16(&(txBuffer[YMODEM_PACKET_HEADER]), YMODEM_PACKET_SIZE); timeCount = 0; errorCount = 0; dataCount = 0; code = CodeNone; stage = StageFinished; txBuffer[0] = CodeSoh; txBuffer[1] = 0x00; txBuffer[2] = 0xFF; txBuffer[YMODEM_PACKET_SIZE + YMODEM_PACKET_OVERHEAD - 2] = (uint8_t)(crc >> 8); txBuffer[YMODEM_PACKET_SIZE + YMODEM_PACKET_OVERHEAD - 1] = (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[txLength] = CodeCan; } write(txBuffer, txLength); callback(StatusError, NULL, NULL); } else if((timeCount % (timeDivide + 1)) == 0) { write(txBuffer, txLength); } } } } /** * @brief Transmit finished stage. * @param None. * @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[txLength] = 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[txLength] = CodeCan; } write(txBuffer, txLength); callback(StatusError, NULL, NULL); } else if((timeCount % (timeDivide + 1)) == 0) { write(txBuffer, txLength); } } } } /** * @brief Calculate CRC16 checksum. * @param [in] buff: The data to be calculated. * @param [in] 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 
#include 
#include 
#include 
#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;
    QString  filePath;
    QString  fileName;
    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] != 0)
            {
                int  i         =  0;
                char name[128] = {0};
                char size[128] = {0};

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

                i++;

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

                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 
#include 
#include 
#include 
#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 

#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文件



 Widget
 
  
   
    0
    0
    444
    255
   
  
  
   
    444
    255
   
  
  
   
    444
    255
   
  
  
   SerialPortYmodem
  
  
   
    
     
      串口配置
     
     
      
       
        
         端口:
        
       
      
      
       
        
         12
        
       
      
      
       
        
         Qt::Horizontal
        
        
         
          40
          20
         
        
       
      
      
       
        
         波特率:
        
       
      
      
       
        
         115200
        
        
         3
        
        
         12
        
        
         
          921600
         
        
        
         
          460800
         
        
        
         
          230400
         
        
        
         
          115200
         
        
        
         
          57600
         
        
        
         
          38400
         
        
        
         
          19200
         
        
        
         
          9600
         
        
        
         
          4800
         
        
        
         
          2400
         
        
        
         
          1200
         
        
       
      
      
       
        
         Qt::Horizontal
        
        
         
          40
          20
         
        
       
      
      
       
        
         打开
        
       
      
     
    
   
   
    
     
      文件发送
     
     
      
       
        
         
          
           文件路径:
          
         
        
        
         
          
           true
          
         
        
        
         
          
           false
          
          
           浏览...
          
         
        
        
         
          
           false
          
          
           发送
          
         
        
       
      
      
       
        
         
          
           传输进度:
          
         
        
        
         
          
           0
          
         
        
       
      
     
    
   
   
    
     
      文件接收
     
     
      
       
        
         
          
           文件路径:
          
         
        
        
         
          
           true
          
         
        
        
         
          
           false
          
          
           浏览...
          
         
        
        
         
          
           false
          
          
           接收
          
         
        
       
      
      
       
        
         
          
           传输进度:
          
         
        
        
         
          
           0
          
         
        
       
      
     
    
   
  
 
 
 
 


      widget.h文件

#ifndef WIDGET_H
#define WIDGET_H

#include 
#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 
#include 
#include 

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 

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文件


3,运行效果

YMODEM协议串口文件传输_第1张图片

你可能感兴趣的:(Qt,C/C++)