Ymodem.h
/**
* 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
/**
* 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 0)
{
if(rxBuffer[0] == CodeSoh)
{
uint32_t len = read(&(rxBuffer[1]), YMODEM_PACKET_SIZE + YMODEM_PACKET_OVERHEAD - 1);
if(len timeMax)
{
timeCount = 0;
errorCount = 0;
dataCount = 0;
code = CodeNone;
stage = StageNone;
for(txLength = 0; txLength timeMax)
{
timeCount = 0;
errorCount = 0;
dataCount = 0;
code = CodeNone;
stage = StageNone;
for(txLength = 0; txLength timeMax)
{
timeCount = 0;
errorCount = 0;
dataCount = 0;
code = CodeNone;
stage = StageNone;
for(txLength = 0; txLength > 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 timeMax)
{
timeCount = 0;
errorCount = 0;
dataCount = 0;
code = CodeNone;
stage = StageNone;
for(txLength = 0; txLength errorMax)
{
timeCount = 0;
errorCount = 0;
dataCount = 0;
code = CodeNone;
stage = StageNone;
for(txLength = 0; txLength errorMax)
{
timeCount = 0;
errorCount = 0;
dataCount = 0;
code = CodeNone;
stage = StageNone;
for(txLength = 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 timeMax)
{
timeCount = 0;
errorCount = 0;
dataCount = 0;
code = CodeNone;
stage = StageNone;
for(txLength = 0; txLength errorMax)
{
timeCount = 0;
errorCount = 0;
dataCount = 0;
code = CodeNone;
stage = StageNone;
for(txLength = 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 timeMax)
{
timeCount = 0;
errorCount = 0;
dataCount = 0;
code = CodeNone;
stage = StageNone;
for(txLength = 0; txLength > 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 errorMax)
{
timeCount = 0;
errorCount = 0;
dataCount = 0;
code = CodeNone;
stage = StageNone;
for(txLength = 0; txLength timeMax)
{
timeCount = 0;
errorCount = 0;
dataCount = 0;
code = CodeNone;
stage = StageNone;
for(txLength = 0; txLength