/** * @file IAP_YMODEM_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 Familiar functions of IAP with YMODEM for all embedded device * * @version * - 1_01_240911 > ATY * -# Preliminary version, first Release * - 1_01_250701 > ATY * -# real fix to lib type * - 1_01_250704 > ATY * -# finish uart and ucdc IAP whole test ******************************************************************************** */ #ifndef __IAP_YMODEM_ATY_C #define __IAP_YMODEM_ATY_C #include "IAP_YMODEM_ATY.h" /******************************* For user *************************************/ uint8_t EmptyBuf[1] = {0}; #ifdef IAP_YMODEM_ATY_USB USBD_CDC_HandleTypeDef* hcdc; uint32_t ucdcRcvLength = 0; uint8_t ucdcRcvOverFlag = 1; uint32_t ucdcRcvLastTime = 0; uint8_t ucdcRcvBuffer[APP_RX_DATA_SIZE] = {0}; #endif void All_Reset(void) { // Disable global interrupts __disable_irq(); // Deinnit peripherals HAL_UART_DeInit(&Interface_UART); __HAL_RCC_USB_CLK_DISABLE(); HAL_RCC_DeInit(); HAL_DeInit(); // Disable and reset SysTick timer SysTick->CTRL = 0; SysTick->LOAD = 0; SysTick->VAL = 0; // Optional: Disable and clear all NVIC interrupts for(int i = 0; i < 8; i++) { NVIC->ICER[i] = 0xFFFFFFFF; // Disable all interrupts NVIC->ICPR[i] = 0xFFFFFFFF; // Clear pending status } // Optional: Reset interrupt priority registers // for(int i = 0; i < 48; i++) { // NVIC->IP[i] = 0; // Set all priorities to default // } // Optional: Set vector table offset to App's address SCB->VTOR = APPLICATION_ADDRESS & 0x1FFFFF80; } void JumpToAppWithReset(void) { All_Reset(); JumpToApp(APPLICATION_ADDRESS); } void Interface_Clean(void) { #ifndef IAP_YMODEM_ATY_USB #warning "NOT IAP_YMODEM_ATY_USB" __HAL_UART_FLUSH_DRREGISTER(&Interface_UART); #else #warning "IAP_YMODEM_ATY_USB" ucdcRcvLength = 0; ucdcRcvOverFlag = 1; #endif } #ifdef IAP_YMODEM_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) { #ifndef IAP_YMODEM_ATY_USB HAL_StatusTypeDef state = HAL_UART_Receive(&Interface_UART, bytes, size, timeout); return state; // return HAL_UART_Receive(&Interface_UART, bytes, size, timeout); #else 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); return HAL_TIMEOUT; } HAL_Delay(1); } if(ucdcRcvOverFlag == 0) { while(HAL_GetTick() - ucdcRcvLastTime < 200) { } ucdcRcvOverFlag = 1; } if(ucdcRcvLength > 0 && ucdcRcvLength <= APP_RX_DATA_SIZE){ uint16_t copySize = (ucdcRcvLength > size) ? size : ucdcRcvLength; memcpy(bytes, ucdcRcvBuffer, copySize); ucdcRcvLength -= copySize; memcpy(ucdcRcvBuffer, ucdcRcvBuffer + copySize, ucdcRcvLength); } return HAL_OK; #endif } HAL_StatusTypeDef Interface_Transmit(uint8_t* bytes, uint16_t size, uint32_t timeout) { #ifndef IAP_YMODEM_ATY_USB /* 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); #else 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; #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, 101); HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR2, 250); HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR3, 705); Interface_PutString("\r\n\r\nS to start\r\n\r\n"); while(1) { #ifdef IAP_YMODEM_ATY_USB if(hcdc->RxLength > 1024){ uint8_t t[1] = {0}; Interface_Receive(t, 1, 10); continue; } #endif if(1) { if(Interface_Receive(sKey, 2, IAP_S_TIME) == HAL_OK) { if(sKey[0] == 'S') { uint8_t verStr[] = "BLA_V_1_01_250705\r\n"; Interface_Transmit(verStr, sizeof(verStr), 100); 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_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"); 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 */ 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); 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 */ 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, packets_received; 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)) { switch(ReceivePacket(aPacketData, &packet_length, DOWNLOAD_TIMEOUT)) { 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) { 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_ATY_C */ /******************************** End Of File *********************************/