|
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
- *
- * <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_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
- *
- * <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 ------------------------------------------------------*/
- /**
- * @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 <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;
- 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 <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文件
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文件
3,运行效果
|
|