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,运行效果