/**
* @file IAP_YMODEM_STM32F1_ATY.c
*
* @param Project DEVICE_GENERAL_ATY_LIB
*
* @author ATY
*
* @copyright
* - Copyright 2017 - 2023 MZ-ATY
* - This code follows:
* - MZ-ATY Various Contents Joint Statement -
*
* https://mengze.top/MZ-ATY_VCJS
* - CC 4.0 BY-NC-SA -
*
* https://creativecommons.org/licenses/by-nc-sa/4.0/
* - Your use will be deemed to have accepted the terms of this statement.
*
* @brief functions of IAP with YMODEM for STM32F1xx
*
* @version
* - 1_01_240911 > ATY
* -# Preliminary version, first Release
* - 1_02_250701 > ATY
* -# real fix to lib type
* - 1_03_250704 > ATY
* -# finish uart and ucdc IAP whole test
* - 1_04_251016 > ATY
* -# fix large bin 255 limit at 128 and 1K trans in USB CDC
* @todo some IT not restart when jump to app some times
********************************************************************************
*/
#ifndef __IAP_YMODEM_STM32F1_ATY_C
#define __IAP_YMODEM_STM32F1_ATY_C
#include "IAP_YMODEM_STM32F1_ATY.h"
/******************************* For user *************************************/
uint8_t EmptyBuf[1] = {0};
#ifdef IAP_YMODEM_STM32F1_ATY_USB
USBD_CDC_HandleTypeDef* hcdc;
uint32_t ucdcRcvLength = 0;
uint8_t ucdcRcvOverFlag = 1;
uint32_t ucdcRcvLastTime = 0;
uint8_t ucdcRcvBuffer[PACKET_1K_SIZE + PACKET_DATA_INDEX + PACKET_TRAILER_SIZE] = {0};
#endif
void JumpToAppWithReset(void){
// ResetBeforeJumpToApp();
#ifdef IAP_YMODEM_STM32F1_ATY_USB
// Deinitialize USB
USBD_DeInit(&hUsbDeviceFS);
#endif
Bootloader_DeInit();
JumpToApp(APPLICATION_ADDRESS);
}
void Interface_Clean(void){
#ifdef IAP_YMODEM_STM32F1_ATY_USB
#warning "IAP_YMODEM_STM32F1_ATY_USB"
ucdcRcvLength = 0;
ucdcRcvOverFlag = 1;
#else
#warning "NOT IAP_YMODEM_STM32F1_ATY_USB"
__HAL_UART_FLUSH_DRREGISTER(&Interface_UART);
#endif
}
#ifdef IAP_YMODEM_STM32F1_ATY_USB
void PUT_IN_CDC_Receive_FS(uint8_t* Buf, uint32_t* Len){
if(ucdcRcvOverFlag == 1){ // new start
ucdcRcvOverFlag = 0;
ucdcRcvLength = *Len;
memcpy(ucdcRcvBuffer, Buf, *Len);
if(*Len < 64){
ucdcRcvOverFlag = 1;
}
else{
ucdcRcvLastTime = HAL_GetTick();
}
}
else{ // pending to before
memcpy(ucdcRcvBuffer + ucdcRcvLength, Buf, *Len);
ucdcRcvLength += *Len;
if(*Len < 64){
ucdcRcvOverFlag = 1;
}
else{
ucdcRcvLastTime = HAL_GetTick();
}
}
// USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
// USBD_CDC_ReceivePacket(&hUsbDeviceFS);
// return (USBD_OK);
}
#endif
uint32_t timeoutCount = 0;
uint32_t timeoutFinal = 100;
HAL_StatusTypeDef Interface_Receive(uint8_t* bytes, uint16_t size, uint32_t timeout){
#ifdef IAP_YMODEM_STM32F1_ATY_USB
hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData;
if(hcdc->RxLength > APP_RX_DATA_SIZE)
return HAL_ERROR;
timeoutCount = 0;
timeoutFinal = timeout;
while(ucdcRcvLength == 0){
timeoutCount++;
if(timeoutCount > timeoutFinal){
timeoutCount = 0;
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
bytes[0] = 0;
return HAL_TIMEOUT;
}
HAL_Delay(1);
}
if(ucdcRcvOverFlag == 0){
while(HAL_GetTick() - ucdcRcvLastTime < 200){
}
ucdcRcvOverFlag = 1;
}
if(ucdcRcvLength > 0 && ucdcRcvLength <= PACKET_1K_SIZE + PACKET_DATA_INDEX + PACKET_TRAILER_SIZE){
uint16_t copySize = (ucdcRcvLength > size) ? size : ucdcRcvLength;
memcpy(bytes, ucdcRcvBuffer, copySize);
ucdcRcvLength -= copySize;
memcpy(ucdcRcvBuffer, ucdcRcvBuffer + copySize, ucdcRcvLength);
}
return HAL_OK;
#else
HAL_StatusTypeDef state = HAL_UART_Receive(&Interface_UART, bytes, size, timeout);
return state;
// return HAL_UART_Receive(&Interface_UART, bytes, size, timeout);
#endif
}
HAL_StatusTypeDef Interface_Transmit(uint8_t* bytes, uint16_t size, uint32_t timeout){
#ifdef IAP_YMODEM_STM32F1_ATY_USB
Interface_Clean();
ucdcRcvOverFlag = 1;
timeoutCount = 0;
timeoutFinal = timeout;
while(CDC_Transmit_FS(bytes, size) != HAL_OK){
timeoutCount++;
if(timeoutCount > timeoutFinal)
return HAL_TIMEOUT;
HAL_Delay(1);
}
return HAL_OK;
#else
/* May be timeouted... */
if(Interface_UART.gState == HAL_UART_STATE_TIMEOUT){
Interface_UART.gState = HAL_UART_STATE_READY;
}
return HAL_UART_Transmit(&Interface_UART, bytes, size, timeout);
#endif
}
/**
* @brief Display the Main Menu on HyperTerminal
*/
void Main_Menu(void){
uint8_t key = 0;
uint16_t errTimes = 0;
uint32_t FlashProtection = 0;
/* Initialise Flash */
FLASH_If_Init();
/* Test if any sector of Flash memory where user application will be loaded is write protected */
FlashProtection = FLASH_If_GetWriteProtectionStatus();
Interface_PutString("\r\n\r\n=================== Main Menu ============================\r\n\r\n");
Interface_PutString(" Download image to the internal Flash ----------------- 1\r\n\r\n");
Interface_PutString(" Upload image from the internal Flash ----------------- 2\r\n\r\n");
Interface_PutString(" Execute the loaded application ----------------------- 3\r\n\r\n");
if(FlashProtection != FLASHIF_PROTECTION_NONE){
Interface_PutString(" Disable the write protection ------------------------- 4\r\n\r\n");
}
else{
Interface_PutString(" Enable the write protection -------------------------- 4\r\n\r\n");
}
Interface_PutString("==========================================================\r\n\r\n");
while(1){
/* Clean the input path */
Interface_Clean();
/* Receive key */
Interface_Receive(&key, 1, IAP_3_TIME);
/* Auto jump to app */
if(key == 0)
key = 51;
switch(key){
case '*':
/* Upload user application from the Flash */
Interface_Upload();
break;
case '2':
/* Upload user application from the Flash */
Interface_PutString("\r\nAuthorize wrong!\r\n\r\n");
break;
case '1':
/* Download user application in the Flash */
if(Interface_Download() != COM_OK)
break;
case '3':
Interface_PutString("\r\nStart program execution...\r\n");
JumpToAppWithReset();
break;
case '4':
if(FlashProtection != FLASHIF_PROTECTION_NONE){
/* Disable the write protection */
if(FLASH_If_WriteProtectionConfig(FLASHIF_WRP_DISABLE) == FLASHIF_OK){
Interface_PutString("Write protection disabled...\r\n");
Interface_PutString("System will now restart...\r\n");
/* Launch the option byte loading */
HAL_FLASH_OB_Launch();
}
else{
Interface_PutString("Error: Flash write un-protection failed...\r\n");
}
}
else{
if(FLASH_If_WriteProtectionConfig(FLASHIF_WRP_ENABLE) == FLASHIF_OK){
Interface_PutString("Write protection enabled...\r\n");
Interface_PutString("System will now restart...\r\n");
/* Launch the option byte loading */
HAL_FLASH_OB_Launch();
}
else{
Interface_PutString("Error: Flash write protection failed...\r\n");
}
}
break;
default:
errTimes++;
if(errTimes > 500){
Interface_PutString("Start program execution for max err...\r\n\r\n");
JumpToAppWithReset();
}
// Interface_PutString("Invalid Number ! ==> The number should be either 1, 2, 3 or 4\r\n");
break;
}
key = 0;
}
}
#include "rtc.h"
void Main_Cycle(void){
uint8_t sKey[2] = {0};
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR1, IAP_VerA);
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR2, IAP_VerB);
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR3, IAP_VerC);
Interface_PutString("\r\n\r\nS to start\r\n\r\n");
while(1){
#ifdef IAP_YMODEM_STM32F1_ATY_USB
if(hcdc->RxLength > 1024){
uint8_t t[1] = {0};
Interface_Clean();
Interface_PutByte(0x00);
Interface_Receive(t, 1, 10);
continue;
}
#endif
if(1){
if(Interface_Receive(sKey, 2, IAP_S_TIME) == HAL_OK){
if(sKey[0] == 'S'){
if(sKey[1] == '3'){
Interface_Clean();
Interface_PutString("\r\nStart program execution...\r\n");
JumpToAppWithReset();
}
else if(sKey[1] == '1'){
Interface_Clean();
if(Interface_Download() != COM_OK){
Interface_PutString("\r\nStart program execution...\r\n");
JumpToAppWithReset();
}
}
else{
Interface_Clean();
Main_Menu();
}
}
else{
Interface_Clean();
}
}
else{
Interface_Clean();
Main_Menu();
}
}
/* Keep the user application running */
else{
JumpToAppWithReset();
}
}
}
/* ****************************************************************************/
/* interface realize **********************************************************/
/**
* @brief Print a string on the HyperTerminal
* @param p_string: The string to be printed
* @retval send state
*/
HAL_StatusTypeDef Interface_PutString(uint8_t* p_string){
#ifdef IAP_YMODEM_STM32F1_ATY_DBG
uint16_t length = 0;
while(p_string[length] != '\0'){
length++;
}
return Interface_Transmit(p_string, length, TX_TIMEOUT);
#else
return Interface_Transmit("", 0, TX_TIMEOUT);;
#endif
}
/**
* @brief Transmit a byte to the HyperTerminal
* @param bytes The byte to be sent
* @retval send state
*/
HAL_StatusTypeDef Interface_PutByte(uint8_t bytes){
return Interface_Transmit(&bytes, 1, TX_TIMEOUT);
}
/**
* @brief Download a file
* @retval download state
*/
COM_StatusTypeDef Interface_Download(void){
uint8_t number[11] = {0};
uint32_t size = 0;
COM_StatusTypeDef result;
Interface_PutString("\r\nWaiting for the file to be sent... (press 'a' to abort)\r\n");
Interface_PutByte(CRC16);
result = Ymodem_Receive(&size);
if(result == COM_OK){
Interface_PutString("\r\n\r\nProgramming Completed Successfully!\n\r--------------------------------\r\n Name: ");
Interface_PutString(aFileName);
Int2Str(number, size);
Interface_PutString("\r\nSize: ");
Interface_PutString(number);
Interface_PutString(" Bytes\r\n");
Interface_PutString("-------------------\r\n");
}
else if(result == COM_LIMIT){
Interface_PutString("\r\nThe image size is higher than the allowed space memory!\n\r");
}
else if(result == COM_DATA){
Interface_PutString("\r\nVerification failed!\n\r");
}
else if(result == COM_ABORT){
Interface_PutString("\r\nAborted by user.\n\r");
}
else{
Interface_PutString("\r\nFailed to receive the file!\r\n");
}
return result;
}
/**
* @brief Upload a file
*/
void Interface_Upload(void){
uint8_t status = 0;
Interface_PutString("\r\n\r\nSelect receive file... (press 'a' to abort)\r\n");
while(1){
Interface_Receive(&status, 1, RX_TIMEOUT);
if(status == CRC16){
/* Transmit the flash image through ymodem protocol */
status = Ymodem_Transmit((uint8_t*)APPLICATION_ADDRESS, (const uint8_t*)"UploadedFlashImage.bin", USER_FLASH_SIZE);
if(status != 0){
if(status == COM_ABORT)
Interface_PutString("\r\nAborted by user.\n\r");
else
Interface_PutString("\r\nError occurred while transmitting file\r\n");
}
else{
Interface_PutString("\r\nFile uploaded successfully\r\n");
}
break;
}
else if(status == ABORT1 || status == ABORT2){
Interface_PutString("\r\nAborted by user.\n\r");
break;
}
}
}
/* common *********************************************************************/
/**
* @brief Convert an Integer to a string
* @param p_str: The string output pointer
* @param intnum: The integer to be converted
*/
void Int2Str(uint8_t* p_str, uint32_t intnum){
uint32_t i, divider = 1000000000, pos = 0, status = 0;
for(i = 0; i < 10; i++){
p_str[pos++] = (intnum / divider) + 48;
intnum = intnum % divider;
divider /= 10;
if((p_str[pos - 1] == '0') & (status == 0)){
pos = 0;
}
else{
status++;
}
}
}
/**
* @brief Convert a string to an integer
* @param p_inputstr: The string to be converted
* @param p_intnum: The integer value
* @retval 1: Correct
* 0: Error
*/
uint32_t Str2Int(uint8_t* p_inputstr, uint32_t* p_intnum){
uint32_t i = 0, res = 0;
uint32_t val = 0;
if((p_inputstr[0] == '0') && ((p_inputstr[1] == 'x') || (p_inputstr[1] == 'X'))){
i = 2;
while((i < 11) && (p_inputstr[i] != '\0')){
if(ISVALIDHEX(p_inputstr[i])){
val = (val << 4) + CONVERTHEX(p_inputstr[i]);
}
else{
/* Return 0, Invalid input */
res = 0;
break;
}
i++;
}
/* valid result */
if(p_inputstr[i] == '\0'){
*p_intnum = val;
res = 1;
}
}
else /* max 10-digit decimal input */
{
while((i < 11) && (res != 1)){
if(p_inputstr[i] == '\0'){
*p_intnum = val;
/* return 1 correct */
res = 1;
}
else if(((p_inputstr[i] == 'k') || (p_inputstr[i] == 'K')) && (i > 0)){
val = val << 10;
*p_intnum = val;
res = 1;
}
else if(((p_inputstr[i] == 'm') || (p_inputstr[i] == 'M')) && (i > 0)){
val = val << 20;
*p_intnum = val;
res = 1;
}
else if(ISVALIDDEC(p_inputstr[i])){
val = val * 10 + CONVERTDEC(p_inputstr[i]);
}
else{
/* return 0, Invalid input */
res = 0;
break;
}
i++;
}
}
return res;
}
/* flash_if *******************************************************************/
/**
* @brief Unlocks Flash for write access
*/
void FLASH_If_Init(void){
/* Unlock the Program memory */
HAL_FLASH_Unlock();
/* Clear all FLASH flags */
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPERR);
/* Unlock the Program memory */
HAL_FLASH_Lock();
}
/**
* @brief This function does an erase of all user flash area
* @param start: start of user flash area
* @retval FLASHIF_OK : user flash area successfully erased
* FLASHIF_ERASEKO : error occurred
*/
uint32_t FLASH_If_Erase(uint32_t start){
uint32_t NbrOfPages = 0;
uint32_t PageError = 0;
FLASH_EraseInitTypeDef pEraseInit;
HAL_StatusTypeDef status = HAL_OK;
/* Unlock the Flash to enable the flash control register access */
HAL_FLASH_Unlock();
/* Get the sector where start the user flash area */
NbrOfPages = (USER_FLASH_END_ADDRESS - start) / FLASH_PAGE_SIZE;
pEraseInit.TypeErase = FLASH_TYPEERASE_PAGES;
pEraseInit.PageAddress = start;
pEraseInit.Banks = FLASH_BANK_1;
pEraseInit.NbPages = NbrOfPages;
status = HAL_FLASHEx_Erase(&pEraseInit, &PageError);
/* Lock the Flash to disable the flash control register access (recommended
to protect the FLASH memory against possible unwanted operation) */
HAL_FLASH_Lock();
if(status != HAL_OK){
/* Error occurred while page erase */
return FLASHIF_ERASEKO;
}
return FLASHIF_OK;
}
/**
* @brief This function writes a data buffer in flash (data are 32-bit aligned).
* @note After writing data buffer, the flash content is checked.
* @param destination: start address for target location
* @param p_source: pointer on buffer with data to write
* @param length: length of data buffer (unit is 32-bit word)
* @retval uint32_t 0: Data successfully written to Flash memory
* 1: Error occurred while writing data in Flash memory
* 2: Written Data in flash memory is different from expected one
*/
uint32_t FLASH_If_Write(uint32_t destination, uint32_t* p_source, uint32_t length){
uint32_t i = 0;
/* Unlock the Flash to enable the flash control register access */
HAL_FLASH_Unlock();
for(i = 0; (i < length) && (destination <= (USER_FLASH_END_ADDRESS - 4)); i++){
/* Device voltage range supposed to be [2.7V to 3.6V], the operation will
be done by word */
if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, destination, *(uint32_t*)(p_source + i)) == HAL_OK){
/* Check the written value */
if(*(uint32_t*)destination != *(uint32_t*)(p_source + i)){
/* Flash content doesn't match SRAM content */
return(FLASHIF_WRITINGCTRL_ERROR);
}
/* Increment FLASH destination address */
destination += 4;
}
else{
/* Error occurred while writing data in Flash memory */
return (FLASHIF_WRITING_ERROR);
}
}
/* Lock the Flash to disable the flash control register access (recommended
to protect the FLASH memory against possible unwanted operation) */
HAL_FLASH_Lock();
return (FLASHIF_OK);
}
/**
* @brief Returns the write protection status of application flash area.
* @retval If a sector in application area is write-protected returned value is a combinaison
of the possible values : FLASHIF_PROTECTION_WRPENABLED, FLASHIF_PROTECTION_PCROPENABLED, ...
* If no sector is write-protected FLASHIF_PROTECTION_NONE is returned.
*/
uint32_t FLASH_If_GetWriteProtectionStatus(void){
uint32_t ProtectedPAGE = FLASHIF_PROTECTION_NONE;
FLASH_OBProgramInitTypeDef OptionsBytesStruct;
/* Unlock the Flash to enable the flash control register access */
HAL_FLASH_Unlock();
/* Check if there are write protected sectors inside the user flash area */
HAL_FLASHEx_OBGetConfig(&OptionsBytesStruct);
/* Lock the Flash to disable the flash control register access (recommended
to protect the FLASH memory against possible unwanted operation) */
HAL_FLASH_Lock();
/* Get pages already write protected */
ProtectedPAGE = ~(OptionsBytesStruct.WRPPage) & FLASH_PAGE_TO_BE_PROTECTED;
/* Check if desired pages are already write protected */
if(ProtectedPAGE != 0){
/* Some sectors inside the user flash area are write protected */
return FLASHIF_PROTECTION_WRPENABLED;
}
else{
/* No write protected sectors inside the user flash area */
return FLASHIF_PROTECTION_NONE;
}
}
/**
* @brief Configure the write protection status of user flash area.
* @param protectionstate : FLASHIF_WRP_DISABLE or FLASHIF_WRP_ENABLE the protection
* @retval uint32_t FLASHIF_OK if change is applied.
*/
uint32_t FLASH_If_WriteProtectionConfig(uint32_t protectionstate){
uint32_t ProtectedPAGE = 0x0;
FLASH_OBProgramInitTypeDef config_new, config_old;
HAL_StatusTypeDef result = HAL_OK;
/* Get pages write protection status */
HAL_FLASHEx_OBGetConfig(&config_old);
/* The parameter says whether we turn the protection on or off */
config_new.WRPState = (protectionstate == FLASHIF_WRP_ENABLE ? OB_WRPSTATE_ENABLE : OB_WRPSTATE_DISABLE);
/* We want to modify only the Write protection */
config_new.OptionType = OPTIONBYTE_WRP;
/* No read protection, keep BOR and reset settings */
config_new.RDPLevel = OB_RDP_LEVEL_0;
config_new.USERConfig = config_old.USERConfig;
/* Get pages already write protected */
ProtectedPAGE = config_old.WRPPage | FLASH_PAGE_TO_BE_PROTECTED;
/* Unlock the Flash to enable the flash control register access */
HAL_FLASH_Unlock();
/* Unlock the Options Bytes */
HAL_FLASH_OB_Unlock();
/* Erase all the option Bytes */
result = HAL_FLASHEx_OBErase();
if(result == HAL_OK){
config_new.WRPPage = ProtectedPAGE;
result = HAL_FLASHEx_OBProgram(&config_new);
}
return (result == HAL_OK ? FLASHIF_OK : FLASHIF_PROTECTION_ERRROR);
}
/* ymodem *********************************************************************/
/* activate the CRC16 integrity */
#define CRC16_F
/* ATTENTION - please keep this variable 32bit alligned */
uint8_t aPacketData[PACKET_1K_SIZE + PACKET_DATA_INDEX + PACKET_TRAILER_SIZE];
uint8_t aFileName[FILE_NAME_LENGTH];
/**
* @brief Receive a packet from sender
* @param data
* @param length
* 0: end of transmission
* 2: abort by sender
* >0: packet length
* @param timeout
* @retval HAL_OK: normally return
* HAL_BUSY: abort by user
*/
uint8_t byteOneTmp = 0;
HAL_StatusTypeDef statusA;
static HAL_StatusTypeDef ReceivePacket(uint8_t* p_data, uint32_t* p_length, uint32_t timeout){
uint32_t crc;
uint32_t packet_size = 0;
HAL_StatusTypeDef status;
uint8_t byteOne;
*p_length = 0;
status = Interface_Receive(&byteOne, 1, timeout);
statusA = status;
byteOneTmp = byteOne;
if(status == HAL_OK){
switch(byteOne){
case SOH:
packet_size = PACKET_SIZE;
break;
case STX:
packet_size = PACKET_1K_SIZE;
break;
case EOT:
break;
case CA:
if((Interface_Receive(&byteOne, 1, timeout) == HAL_OK) && (byteOne == CA)){
packet_size = 2;
}
else{
status = HAL_ERROR;
}
break;
case ABORT1:
case ABORT2:
status = HAL_BUSY;
break;
default:
status = HAL_ERROR;
break;
}
*p_data = byteOne;
if(packet_size >= PACKET_SIZE){
status = Interface_Receive(&p_data[PACKET_NUMBER_INDEX], packet_size + PACKET_OVERHEAD_SIZE, timeout);
/* Simple packet sanity check */
if(status == HAL_OK){
if(p_data[PACKET_NUMBER_INDEX] != ((p_data[PACKET_CNUMBER_INDEX]) ^ NEGATIVE_BYTE)){
packet_size = 0;
status = HAL_ERROR;
}
else{
/* Check packet CRC */
crc = p_data[packet_size + PACKET_DATA_INDEX] << 8;
crc += p_data[packet_size + PACKET_DATA_INDEX + 1];
if(Cal_CRC16(&p_data[PACKET_DATA_INDEX], packet_size) != crc){
packet_size = 0;
status = HAL_ERROR;
}
}
}
else{
packet_size = 0;
}
}
}
*p_length = packet_size;
return status;
}
/**
* @brief Prepare the first block
* @param p_data: output buffer
* @param p_file_name: name of the file to be sent
* @param length: length of the file to be sent in bytes
*/
static void PrepareIntialPacket(uint8_t* p_data, const uint8_t* p_file_name, uint32_t length){
uint32_t i, j = 0;
uint8_t astring[10];
/* first 3 bytes are constant */
p_data[PACKET_START_INDEX] = SOH;
p_data[PACKET_NUMBER_INDEX] = 0x00;
p_data[PACKET_CNUMBER_INDEX] = 0xff;
/* Filename written */
for(i = 0; (p_file_name[i] != '\0') && (i < FILE_NAME_LENGTH); i++){
p_data[i + PACKET_DATA_INDEX] = p_file_name[i];
}
p_data[i + PACKET_DATA_INDEX] = 0x00;
/* file size written */
Int2Str(astring, length);
i = i + PACKET_DATA_INDEX + 1;
while(astring[j] != '\0'){
p_data[i++] = astring[j++];
}
/* padding with zeros */
for(j = i; j < PACKET_SIZE + PACKET_DATA_INDEX; j++){
p_data[j] = 0;
}
}
/**
* @brief Prepare the data packet
* @param p_source: pointer to the data to be sent
* @param p_packet: pointer to the output buffer
* @param pkt_nr: number of the packet
* @param size_blk: length of the block to be sent in bytes
*/
static void PreparePacket(uint8_t* p_source, uint8_t* p_packet, uint8_t pkt_nr, uint32_t size_blk){
uint8_t* p_record;
uint32_t i, size, packet_size;
/* Make first three packet */
packet_size = size_blk >= PACKET_1K_SIZE ? PACKET_1K_SIZE : PACKET_SIZE;
size = size_blk < packet_size ? size_blk : packet_size;
if(packet_size == PACKET_1K_SIZE){
p_packet[PACKET_START_INDEX] = STX;
}
else{
p_packet[PACKET_START_INDEX] = SOH;
}
p_packet[PACKET_NUMBER_INDEX] = pkt_nr;
p_packet[PACKET_CNUMBER_INDEX] = (~pkt_nr);
p_record = p_source;
/* Filename packet has valid data */
for(i = PACKET_DATA_INDEX; i < size + PACKET_DATA_INDEX; i++){
p_packet[i] = *p_record++;
}
if(size <= packet_size){
for(i = size + PACKET_DATA_INDEX; i < packet_size + PACKET_DATA_INDEX; i++){
p_packet[i] = 0x1A; /* EOF (0x1A) or 0x00 */
}
}
}
/**
* @brief Update CRC16 for input byte
* @param crc_in input value
* @param input byte
*/
uint16_t UpdateCRC16(uint16_t crc_in, uint8_t byte){
uint32_t crc = crc_in;
uint32_t in = byte | 0x100;
do{
crc <<= 1;
in <<= 1;
if(in & 0x100)
++crc;
if(crc & 0x10000)
crc ^= 0x1021;
}
while(!(in & 0x10000));
return crc & 0xffffu;
}
/**
* @brief Cal CRC16 for YModem Packet
* @param data
* @param length
*/
uint16_t Cal_CRC16(const uint8_t* p_data, uint32_t size){
uint32_t crc = 0;
const uint8_t* dataEnd = p_data + size;
while(p_data < dataEnd)
crc = UpdateCRC16(crc, *p_data++);
crc = UpdateCRC16(crc, 0);
crc = UpdateCRC16(crc, 0);
return crc & 0xffffu;
}
/**
* @brief Calculate Check sum for YModem Packet
* @param p_data Pointer to input data
* @param size length of input data
* @retval uint8_t checksum value
*/
uint8_t CalcChecksum(const uint8_t* p_data, uint32_t size){
uint32_t sum = 0;
const uint8_t* p_data_end = p_data + size;
while(p_data < p_data_end){
sum += *p_data++;
}
return (sum & 0xffu);
}
/* Public functions ---------------------------------------------------------*/
/**
* @brief Receive a file using the ymodem protocol with CRC16.
* @param p_size The size of the file.
* @retval COM_StatusTypeDef result of reception/programming
*/
HAL_StatusTypeDef statA = HAL_OK;
uint16_t packets_received;
COM_StatusTypeDef Ymodem_Receive(uint32_t* p_size){
uint32_t i, packet_length, session_done = 0, file_done, errors = 0, session_begin = 0;
uint32_t flashdestination, ramsource, filesize;
uint8_t* file_ptr;
uint8_t file_size[FILE_SIZE_LENGTH], tmp;
COM_StatusTypeDef result = COM_OK;
/* Initialize flashdestination variable */
flashdestination = APPLICATION_ADDRESS;
while((session_done == 0) && (result == COM_OK)){
packets_received = 0;
file_done = 0;
while((file_done == 0) && (result == COM_OK)){
statA = ReceivePacket(aPacketData, &packet_length, DOWNLOAD_TIMEOUT);
switch(statA){
case HAL_OK:
errors = 0;
switch(packet_length){
case 2:
/* Abort by sender */
Interface_PutByte(ACK);
result = COM_ABORT;
break;
case 0:
/* End of transmission */
Interface_PutByte(ACK);
file_done = 1;
break;
default:
/* Normal packet */
if(aPacketData[PACKET_NUMBER_INDEX] != (packets_received % 256)){
Interface_PutByte(NAK);
}
else{
if(packets_received == 0){
/* File name packet */
if(aPacketData[PACKET_DATA_INDEX] != 0){
/* File name extraction */
i = 0;
file_ptr = aPacketData + PACKET_DATA_INDEX;
while((*file_ptr != 0) && (i < FILE_NAME_LENGTH)){
aFileName[i++] = *file_ptr++;
}
/* File size extraction */
aFileName[i++] = '\0';
i = 0;
file_ptr++;
while((*file_ptr != ' ') && (i < FILE_SIZE_LENGTH)){
file_size[i++] = *file_ptr++;
}
file_size[i++] = '\0';
Str2Int(file_size, &filesize);
/* Test the size of the image to be sent */
/* Image size is greater than Flash size */
if(*p_size > (USER_FLASH_SIZE + 1)){
/* End session */
tmp = CA;
Interface_Transmit(&tmp, 1, NAK_TIMEOUT);
Interface_Transmit(&tmp, 1, NAK_TIMEOUT);
result = COM_LIMIT;
}
/* Erase user application area */
FLASH_If_Erase(APPLICATION_ADDRESS);
*p_size = filesize;
Interface_PutByte(ACK);
Interface_PutByte(CRC16);
}
/* File header packet is empty, end session */
else{
Interface_PutByte(ACK);
file_done = 1;
session_done = 1;
break;
}
}
else /* Data packet */
{
ramsource = (uint32_t)&aPacketData[PACKET_DATA_INDEX];
/* Write received data in Flash */
if(FLASH_If_Write(flashdestination, (uint32_t*)ramsource, packet_length / 4) == FLASHIF_OK){
flashdestination += packet_length;
Interface_PutByte(ACK);
}
else /* An error occurred while writing to Flash memory */
{
/* End session */
Interface_PutByte(CA);
Interface_PutByte(CA);
result = COM_DATA;
}
}
packets_received++;
session_begin = 1;
}
break;
}
break;
case HAL_BUSY: /* Abort actually */
Interface_PutByte(CA);
Interface_PutByte(CA);
result = COM_ABORT;
break;
default:
if(session_begin > 0){
errors++;
}
if(errors > MAX_ERRORS){
/* Abort communication */
Interface_PutByte(CA);
Interface_PutByte(CA);
}
else{
/* Ask for a packet */
Interface_PutByte(CRC16);
}
break;
}
}
}
return result;
}
/**
* @brief Transmit a file using the ymodem protocol
* @param p_buf: Address of the first byte
* @param p_file_name: Name of the file sent
* @param file_size: Size of the transmission
* @retval COM_StatusTypeDef result of the communication
*/
COM_StatusTypeDef Ymodem_Transmit(uint8_t* p_buf, const uint8_t* p_file_name, uint32_t file_size){
uint32_t errors = 0, ack_recpt = 0, size = 0, pkt_size;
uint8_t* p_buf_int;
COM_StatusTypeDef result = COM_OK;
uint32_t blk_number = 1;
uint8_t a_rx_ctrl[2];
uint8_t i;
#ifdef CRC16_F
uint32_t temp_crc;
#else /* CRC16_F */
uint8_t temp_chksum;
#endif /* CRC16_F */
/* Prepare first block - header */
PrepareIntialPacket(aPacketData, p_file_name, file_size);
while((!ack_recpt) && (result == COM_OK)){
/* Send Packet */
Interface_Transmit(&aPacketData[PACKET_START_INDEX], PACKET_SIZE + PACKET_HEADER_SIZE, NAK_TIMEOUT);
/* Send CRC or Check Sum based on CRC16_F */
#ifdef CRC16_F
temp_crc = Cal_CRC16(&aPacketData[PACKET_DATA_INDEX], PACKET_SIZE);
Interface_PutByte(temp_crc >> 8);
Interface_PutByte(temp_crc & 0xFF);
#else /* CRC16_F */
temp_chksum = CalcChecksum(&aPacketData[PACKET_DATA_INDEX], PACKET_SIZE);
Interface_PutByte(temp_chksum);
#endif /* CRC16_F */
/* Wait for Ack and 'C' */
if(Interface_Receive(&a_rx_ctrl[0], 1, NAK_TIMEOUT) == HAL_OK){
if(a_rx_ctrl[0] == ACK){
ack_recpt = 1;
}
else if(a_rx_ctrl[0] == CA){
if((Interface_Receive(&a_rx_ctrl[0], 1, NAK_TIMEOUT) == HAL_OK) && (a_rx_ctrl[0] == CA)){
HAL_Delay(2);
Interface_Clean();
result = COM_ABORT;
}
}
else if(a_rx_ctrl[0] == ABORT1 || a_rx_ctrl[0] == ABORT2){
result = COM_ABORT;
}
}
else{
errors++;
}
if(errors >= MAX_ERRORS){
result = COM_ERROR;
}
}
p_buf_int = p_buf;
size = file_size;
/* Here 1024 bytes length is used to send the packets */
while((size) && (result == COM_OK)){
/* Prepare next packet */
PreparePacket(p_buf_int, aPacketData, blk_number, size);
ack_recpt = 0;
a_rx_ctrl[0] = 0;
errors = 0;
/* Resend packet if NAK for few times else end of communication */
while((!ack_recpt) && (result == COM_OK)){
/* Send next packet */
if(size >= PACKET_1K_SIZE){
pkt_size = PACKET_1K_SIZE;
}
else{
pkt_size = PACKET_SIZE;
}
Interface_Transmit(&aPacketData[PACKET_START_INDEX], pkt_size + PACKET_HEADER_SIZE, NAK_TIMEOUT);
/* Send CRC or Check Sum based on CRC16_F */
#ifdef CRC16_F
temp_crc = Cal_CRC16(&aPacketData[PACKET_DATA_INDEX], pkt_size);
Interface_PutByte(temp_crc >> 8);
Interface_PutByte(temp_crc & 0xFF);
#else /* CRC16_F */
temp_chksum = CalcChecksum(&aPacketData[PACKET_DATA_INDEX], pkt_size);
Interface_PutByte(temp_chksum);
#endif /* CRC16_F */
/* Wait for Ack */
if((Interface_Receive(&a_rx_ctrl[0], 1, NAK_TIMEOUT) == HAL_OK) && (a_rx_ctrl[0] == ACK)){
ack_recpt = 1;
if(size > pkt_size){
p_buf_int += pkt_size;
size -= pkt_size;
if(blk_number == (USER_FLASH_SIZE / PACKET_1K_SIZE)){
result = COM_LIMIT; /* boundary error */
}
else{
blk_number++;
}
}
else{
p_buf_int += pkt_size;
size = 0;
}
}
else{
errors++;
}
/* Resend packet if NAK for a count of 10 else end of communication */
if(errors >= MAX_ERRORS){
result = COM_ERROR;
}
}
}
/* Sending End Of Transmission char */
ack_recpt = 0;
a_rx_ctrl[0] = 0x00;
errors = 0;
while((!ack_recpt) && (result == COM_OK)){
Interface_PutByte(EOT);
/* Wait for Ack */
if(Interface_Receive(&a_rx_ctrl[0], 1, NAK_TIMEOUT) == HAL_OK){
if(a_rx_ctrl[0] == ACK){
ack_recpt = 1;
}
else if(a_rx_ctrl[0] == CA){
if((Interface_Receive(&a_rx_ctrl[0], 1, NAK_TIMEOUT) == HAL_OK) && (a_rx_ctrl[0] == CA)){
HAL_Delay(2);
Interface_Clean();
result = COM_ABORT;
}
}
}
else{
errors++;
}
if(errors >= MAX_ERRORS){
result = COM_ERROR;
}
}
/* Empty packet sent - some terminal emulators need this to close session */
if(result == COM_OK){
/* Preparing an empty packet */
aPacketData[PACKET_START_INDEX] = SOH;
aPacketData[PACKET_NUMBER_INDEX] = 0;
aPacketData[PACKET_CNUMBER_INDEX] = 0xFF;
for(i = PACKET_DATA_INDEX; i < (PACKET_SIZE + PACKET_DATA_INDEX); i++){
aPacketData[i] = 0x00;
}
/* Send Packet */
Interface_Transmit(&aPacketData[PACKET_START_INDEX], PACKET_SIZE + PACKET_HEADER_SIZE, NAK_TIMEOUT);
/* Send CRC or Check Sum based on CRC16_F */
#ifdef CRC16_F
temp_crc = Cal_CRC16(&aPacketData[PACKET_DATA_INDEX], PACKET_SIZE);
Interface_PutByte(temp_crc >> 8);
Interface_PutByte(temp_crc & 0xFF);
#else /* CRC16_F */
temp_chksum = CalcChecksum(&aPacketData[PACKET_DATA_INDEX], PACKET_SIZE);
Interface_PutByte(temp_chksum);
#endif /* CRC16_F */
/* Wait for Ack and 'C' */
if(Interface_Receive(&a_rx_ctrl[0], 1, NAK_TIMEOUT) == HAL_OK){
if(a_rx_ctrl[0] == CA){
HAL_Delay(2);
Interface_Clean();
result = COM_ABORT;
}
}
}
return result; /* File transmitted successfully */
}
#endif /* __IAP_YMODEM_STM32F1_ATY_C */
/******************************** End Of File *********************************/