/**
******************************************************************************
* @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) &&