/*
 * flash.c
 *
 *  Created on: 2019. 7. 15.
 *      Author: parkyj
 */
#include <stdio.h>
#include "flash.h"
#include "MBIC_Bootloader.h"
#include "bluecell_operate.h"
#include "eeprom.h"
uint8_t flashinit = 0;
uint32_t Address = FLASH_USER_START_ADDR;
volatile static uint32_t UserAddress;
uint32_t MBIC_Address;

typedef void (*fptr)(void);
fptr jump_to_app;
uint32_t jump_addr;
void Jump_App(void){
    __HAL_RCC_TIM6_CLK_DISABLE(); // 留ㅼ씤???占쏙옙癒몌옙?? ?占쏙옙占�??占쏙옙?占쏙옙?占쏙옙
    printf("boot loader start\n");               //硫붿꽭占�? 異쒕젰
    jump_addr = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);
    jump_to_app = (fptr) jump_addr;
    
    /* init user app's sp */
    printf("jump!\n");
    __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS);
    jump_to_app();
}

uint8_t CurrFlash_BankCheck(){
    uint32_t  CurrApiAddress = 0,Bank1Address=0,Bank2Address = 0;
    uint32_t i = 0;
    //uint8_t ret = 0;
    CurrApiAddress = FLASH_MBICUSER_START_ADDR;
    Bank1Address = FLASH_USER_BANK1_START_ADDR;
    Bank2Address = FLASH_USER_BANK2_START_ADDR;
    
    uint8_t* Currdata = (uint8_t*)CurrApiAddress;
    uint8_t* Bank1data = (uint8_t*)Bank1Address;
    uint8_t* Bank2data = (uint8_t*)Bank2Address;

    for(i = 0; i < MBIC_BOOT_DATA; i++){
        if(Currdata[MBIC_BOOT_MARK + i] != Bank2data[MBIC_BOOT_MARK + i]){
            return HFR_BANK1_SEL;
        }
    }
    return HFR_BANK2_SEL;
}


void Flash_InitRead() // ?占쏙옙湲고븿?占쏙옙
{
    uint32_t  CurrApiAddress = 0,Bank1Address=0,Bank2Address = 0;
    uint32_t i = 0;
    //uint8_t ret = 0;
    CurrApiAddress = FLASH_MBICUSER_START_ADDR;
    Bank1Address = FLASH_USER_BANK1_START_ADDR;
    Bank2Address = FLASH_USER_BANK2_START_ADDR;
    
    uint8_t* Currdata = (uint8_t*)CurrApiAddress;
    uint8_t* Bank1data = (uint8_t*)Bank1Address;
    uint8_t* Bank2data = (uint8_t*)Bank2Address;


    printf("Flash Init \r\n");
    uint8_t* pdata;
    bluecell_Currdatastatus.CPU_Bank1_Image_BuildTime1 = Bank1data[MBIC_BOOT_CREATION_TIME + 0];
    bluecell_Currdatastatus.CPU_Bank1_Image_BuildTime2 = Bank1data[MBIC_BOOT_CREATION_TIME + 1];
    bluecell_Currdatastatus.CPU_Bank1_Image_BuildTime3 = Bank1data[MBIC_BOOT_CREATION_TIME + 2];
    bluecell_Currdatastatus.CPU_Bank1_Image_BuildTime4 = Bank1data[MBIC_BOOT_CREATION_TIME + 3];
    bluecell_Currdatastatus.CPU_Bank1_Image_BuildTime5 = Bank1data[MBIC_BOOT_CREATION_TIME + 4];
    bluecell_Currdatastatus.CPU_Bank1_Image_BuildTime6 = Bank1data[MBIC_BOOT_CREATION_TIME + 5];

    bluecell_Currdatastatus.CPU_Bank1_Image_Version1 = Bank1data[MBIC_BOOT_VERSION + 0];
    bluecell_Currdatastatus.CPU_Bank1_Image_Version2 = Bank1data[MBIC_BOOT_VERSION + 1];
    bluecell_Currdatastatus.CPU_Bank1_Image_Version3 = Bank1data[MBIC_BOOT_VERSION + 2];



    bluecell_Currdatastatus.CPU_Bank2_Image_BuildTime1 = Bank2data[MBIC_BOOT_CREATION_TIME + 0];
    bluecell_Currdatastatus.CPU_Bank2_Image_BuildTime2 = Bank2data[MBIC_BOOT_CREATION_TIME + 1];
    bluecell_Currdatastatus.CPU_Bank2_Image_BuildTime3 = Bank2data[MBIC_BOOT_CREATION_TIME + 2];
    bluecell_Currdatastatus.CPU_Bank2_Image_BuildTime4 = Bank2data[MBIC_BOOT_CREATION_TIME + 3];
    bluecell_Currdatastatus.CPU_Bank2_Image_BuildTime5 = Bank2data[MBIC_BOOT_CREATION_TIME + 4];
    bluecell_Currdatastatus.CPU_Bank2_Image_BuildTime6 = Bank2data[MBIC_BOOT_CREATION_TIME + 5];

    bluecell_Currdatastatus.CPU_Bank2_Image_Version1 = Bank2data[MBIC_BOOT_VERSION + 0];
    bluecell_Currdatastatus.CPU_Bank2_Image_Version2 = Bank2data[MBIC_BOOT_VERSION + 1];
    bluecell_Currdatastatus.CPU_Bank2_Image_Version3 = Bank2data[MBIC_BOOT_VERSION + 2];


    
    
    bluecell_Currdatastatus.CPUVERSION1 = Currdata[MBIC_BOOT_VERSION + 0];
    bluecell_Currdatastatus.CPUVERSION2 = Currdata[MBIC_BOOT_VERSION + 1];
    bluecell_Currdatastatus.CPUVERSION3 = Currdata[MBIC_BOOT_VERSION + 2];
//    printf("Curr Version : ");
//    for(int i =0; i < 3; i++){
//        printf("%d.",Bank1data[MBIC_BOOT_VERSION + i]);
//    }
//    printf("\r\n");

    if(bluecell_Currdatastatus.CPUVERSION3  == Bank1data[MBIC_BOOT_VERSION + 2]){
        bluecell_Currdatastatus.CPU_Current_Bank = HFR_BANK1_SEL;
    }
    else 
    {
        bluecell_Currdatastatus.CPU_Current_Bank = HFR_BANK2_SEL;
    }
    printf("Curr Version : %02x.%02x.%02x \r\n",bluecell_Currdatastatus.CPUVERSION1,bluecell_Currdatastatus.CPUVERSION2,bluecell_Currdatastatus.CPUVERSION3);
    printf("Bank1data Version : %02x.%02x.%02x \r\n", Bank1data[MBIC_BOOT_VERSION + 0], Bank1data[MBIC_BOOT_VERSION + 1], Bank1data[MBIC_BOOT_VERSION + 2]);
    printf("Bank2data Version : %02x.%02x.%02x \r\n", Bank2data[MBIC_BOOT_VERSION + 0], Bank2data[MBIC_BOOT_VERSION + 1], Bank2data[MBIC_BOOT_VERSION + 2]);
    pdata = &bluecell_Currdatastatus.CPU_Bank1_Image_Name;

    
    printf("BANK1 IMAGE NAME : ");
    pdata = & bluecell_Currdatastatus.CPU_Bank1_Image_Name;
    for(int i = 0 ; i< 32; i++){
        pdata[i] = Bank1data[MBIC_BOOT_FILENAME + i];
        printf("%c",pdata[i]);
    }
    printf("\r\n");


    pdata = & bluecell_Currdatastatus.CPU_Bank2_Image_Name;
    printf("BANK2 IMAGE NAME : ");
    for(int i = 0 ; i< 32; i++){
        pdata[i] = Bank2data[MBIC_BOOT_FILENAME + i];
        printf("%c",pdata[i]);
//        printf("%c",pdata[i]);
    }
    printf("\r\n");

    printf("Curr Bank  : 20%d Y / %d M / %d D / %d H / %d M / %d S  \r\n",
        Currdata[MBIC_BOOT_CREATION_TIME + 0],
        Currdata[MBIC_BOOT_CREATION_TIME + 1],
        Currdata[MBIC_BOOT_CREATION_TIME + 2],
        Currdata[MBIC_BOOT_CREATION_TIME + 3],
        Currdata[MBIC_BOOT_CREATION_TIME + 4],
        Currdata[MBIC_BOOT_CREATION_TIME + 5]        
    );
    printf("Bank1  : 20%d Y / %d M / %d D / %d H / %d M / %d S  \r\n",
        Bank1data[MBIC_BOOT_CREATION_TIME + 0],
        Bank1data[MBIC_BOOT_CREATION_TIME + 1],
        Bank1data[MBIC_BOOT_CREATION_TIME + 2],
        Bank1data[MBIC_BOOT_CREATION_TIME + 3],
        Bank1data[MBIC_BOOT_CREATION_TIME + 4],
        Bank1data[MBIC_BOOT_CREATION_TIME + 5]        
    );
    printf("Bank2  : 20%d Y / %d M / %d D / %d H / %d M / %d S  \r\n",
        Bank2data[MBIC_BOOT_CREATION_TIME + 0],
        Bank2data[MBIC_BOOT_CREATION_TIME + 1],
        Bank2data[MBIC_BOOT_CREATION_TIME + 2],
        Bank2data[MBIC_BOOT_CREATION_TIME + 3],
        Bank2data[MBIC_BOOT_CREATION_TIME + 4],
        Bank2data[MBIC_BOOT_CREATION_TIME + 5]        
    );    

    printf("MBIC BANK %d Booting \r\n",bluecell_Currdatastatus.CPU_Current_Bank);    


#if 0 // PYJ.2020.06.25_BEGIN -- 
    for(i = 0; i < 128; i++ ){
        printf("Address : %08x Value :  %02X \r\n",data+i  ,data[i]);

    }
#endif // PYJ.2020.06.25_END -- 
    

#if 0 // PYJ.2020.06.25_BEGIN -- 
    for(i = 0; i < size; i++ ){
        printf("Address : %08x Value :  %02X \r\n",Address ,*(uint8_t*)Address);
        Address++;
    }
    Address -= i;
#endif // PYJ.2020.06.25_END -- 
#if 0 // PYJ.2019.03.27_BEGIN -- 
    for(uint32_t i = 0; i < 13848; i++ ){
        printf("%08x : %02X \n",Address ,*(uint8_t*)Address);
        Address++;
    }
    Address = StartAddr;
    for(uint32_t i = 0; i < 13848; i++ ){
        printf("%02X ",*(uint8_t*)Address);
        Address++;
    }
#endif // PYJ.2019.03.27_END -- 
    uint32_t crcret = 0,FileCrc = 0;
    uint32_t currcrcret = 0,currFileCrc = 0;
    
    int32_t CrcLength = 0;
    printf("=============Curr Bank Info=============\r\n");
    currFileCrc = 
    ((Currdata[MBIC_BOOT_CRC] << 24 ) 
    | Currdata[MBIC_BOOT_CRC + 1]<<16 
    | Currdata[MBIC_BOOT_CRC + 2]<<8   
    | Currdata[MBIC_BOOT_CRC + 3]);
    CrcLength=
    ((Currdata[MBIC_BOOT_LENGTH] << 24 ) 
    | Currdata[MBIC_BOOT_LENGTH + 1]<<16 
    | Currdata[MBIC_BOOT_LENGTH + 2]<<8   
    | Currdata[MBIC_BOOT_LENGTH + 3]);       
     if(CrcLength > 0 && CrcLength <= 0x1FFFF )
        currcrcret = crc32(&Currdata[MBIC_BOOT_DATA], CrcLength);
    printf("File CRC : %x CrcLength : %d \r\n",currFileCrc,CrcLength);
    if(currcrcret != currFileCrc){
        printf("CRC ERROR : %x , File CRC : %x \r\n",currcrcret,currFileCrc);
    }
    else{
        printf("CRC SUCCESS  : %x , File CRC : %x \r\n",currcrcret,currFileCrc);  
    }
    printf("========================================\r\n");

    printf("=============Bank 1 Info=============\r\n");
    
    FileCrc = 
    ((Bank1data[MBIC_BOOT_CRC] << 24 ) 
    | Bank1data[MBIC_BOOT_CRC + 1]<<16 
    | Bank1data[MBIC_BOOT_CRC + 2]<<8   
    | Bank1data[MBIC_BOOT_CRC + 3]);
    CrcLength=
    ((Bank1data[MBIC_BOOT_LENGTH] << 24 ) 
    | Bank1data[MBIC_BOOT_LENGTH + 1]<<16 
    | Bank1data[MBIC_BOOT_LENGTH + 2]<<8   
    | Bank1data[MBIC_BOOT_LENGTH + 3]);
    if(CrcLength > 0 && CrcLength <= 0x1FFFF )
        crcret = crc32(&Bank1data[MBIC_BOOT_DATA], CrcLength);
        printf("File CRC : %x CrcLength : %d \r\n",FileCrc,CrcLength);
    if(crcret != FileCrc){
        bluecell_Currdatastatus.CPU_Bank1_Image_Version1 = 0xFF;
        bluecell_Currdatastatus.CPU_Bank1_Image_Version2 = 0xFF;
        bluecell_Currdatastatus.CPU_Bank1_Image_Version3 = 0xFF;

        bluecell_Currdatastatus.CPU_Bank1_Image_BuildTime1 = 0xFF;
        bluecell_Currdatastatus.CPU_Bank1_Image_BuildTime2 = 0xFF;
        bluecell_Currdatastatus.CPU_Bank1_Image_BuildTime3 = 0xFF;     
        bluecell_Currdatastatus.CPU_Bank1_Image_BuildTime4 = 0xFF;
        bluecell_Currdatastatus.CPU_Bank1_Image_BuildTime5 = 0xFF;
        bluecell_Currdatastatus.CPU_Bank1_Image_BuildTime6 = 0xFF; 

        if(bluecell_Currdatastatus.CPU_Current_Bank ==HFR_BANK1_SEL){
                bluecell_Currdatastatus.CPU_Bank1_Image_Version1 = bluecell_Currdatastatus.CPUVERSION1 ;
                bluecell_Currdatastatus.CPU_Bank1_Image_Version2 = bluecell_Currdatastatus.CPUVERSION2 ;
                bluecell_Currdatastatus.CPU_Bank1_Image_Version3 = bluecell_Currdatastatus.CPUVERSION3 ;
                bluecell_Currdatastatus.CPU_Bank1_Image_BuildTime1 = Currdata[MBIC_BOOT_CREATION_TIME + 0];
                bluecell_Currdatastatus.CPU_Bank1_Image_BuildTime2 = Currdata[MBIC_BOOT_CREATION_TIME + 1];
                bluecell_Currdatastatus.CPU_Bank1_Image_BuildTime3 = Currdata[MBIC_BOOT_CREATION_TIME + 2];
                bluecell_Currdatastatus.CPU_Bank1_Image_BuildTime4 = Currdata[MBIC_BOOT_CREATION_TIME + 3];
                bluecell_Currdatastatus.CPU_Bank1_Image_BuildTime5 = Currdata[MBIC_BOOT_CREATION_TIME + 4];
                bluecell_Currdatastatus.CPU_Bank1_Image_BuildTime6 = Currdata[MBIC_BOOT_CREATION_TIME + 5];

                pdata = & bluecell_Currdatastatus.CPU_Bank1_Image_Name;
                for(int i = 0 ; i< 32; i++){
                     pdata[i] = Currdata[MBIC_BOOT_FILENAME + i] ;
                }                
        
            }

        
        printf("CRC ERROR : %x , File CRC : %x \r\n",crcret,FileCrc);
    }
    else{
        if(currcrcret == crcret){
            if(bluecell_Currdatastatus.CPU_Bank_Select == 5)
                bluecell_Currdatastatus.CPU_Current_Bank = HFR_BANK1_SEL;
        }
        printf("CRC SUCCESS  : %x , File CRC : %x \r\n",crcret,FileCrc);  
        bluecell_Currdatastatus.CPU_Bank1_Image_BuildTime1 = Bank1data[MBIC_BOOT_CREATION_TIME + 0];
        bluecell_Currdatastatus.CPU_Bank1_Image_BuildTime2 = Bank1data[MBIC_BOOT_CREATION_TIME + 1];
        bluecell_Currdatastatus.CPU_Bank1_Image_BuildTime3 = Bank1data[MBIC_BOOT_CREATION_TIME + 2];
        bluecell_Currdatastatus.CPU_Bank1_Image_BuildTime4 = Bank1data[MBIC_BOOT_CREATION_TIME + 3];
        bluecell_Currdatastatus.CPU_Bank1_Image_BuildTime5 = Bank1data[MBIC_BOOT_CREATION_TIME + 4];
        bluecell_Currdatastatus.CPU_Bank1_Image_BuildTime6 = Bank1data[MBIC_BOOT_CREATION_TIME + 5];
        
        bluecell_Currdatastatus.CPU_Bank1_Image_Version1 = Bank1data[MBIC_BOOT_VERSION + 0];
        bluecell_Currdatastatus.CPU_Bank1_Image_Version2 = Bank1data[MBIC_BOOT_VERSION + 1];
        bluecell_Currdatastatus.CPU_Bank1_Image_Version3 = Bank1data[MBIC_BOOT_VERSION + 2];

        pdata = & bluecell_Currdatastatus.CPU_Bank1_Image_Name;
        for(int i = 0 ; i< 32; i++){
            pdata[i] = Bank1data[MBIC_BOOT_FILENAME + i] ;
        }         

    }
    printf("========================================\r\n");
    printf("=============Bank 2 Info=============\r\n");
   FileCrc = 
    ((Bank2data[MBIC_BOOT_CRC] << 24 ) 
    | Bank2data[MBIC_BOOT_CRC + 1]<<16 
    | Bank2data[MBIC_BOOT_CRC + 2]<<8   
    | Bank2data[MBIC_BOOT_CRC + 3]);
    CrcLength=
    ((Bank2data[MBIC_BOOT_LENGTH] << 24 ) 
    | Bank2data[MBIC_BOOT_LENGTH + 1]<<16 
    | Bank2data[MBIC_BOOT_LENGTH + 2]<<8   
    | Bank2data[MBIC_BOOT_LENGTH + 3]);       
     if(CrcLength > 0 && CrcLength <= 0x1FFFF )
        crcret = crc32(&Bank2data[MBIC_BOOT_DATA], CrcLength);
         printf("File CRC : %x CrcLength : %d \r\n",FileCrc,CrcLength);
    if(crcret != FileCrc){
        if(bluecell_Currdatastatus.CPU_Current_Bank ==HFR_BANK2_SEL){
                bluecell_Currdatastatus.CPU_Bank2_Image_Version1 = Currdata[MBIC_BOOT_VERSION ] ;
                bluecell_Currdatastatus.CPU_Bank2_Image_Version2 = Currdata[MBIC_BOOT_VERSION + 1] ;
                bluecell_Currdatastatus.CPU_Bank2_Image_Version3 = Currdata[MBIC_BOOT_VERSION + 2] ;
                bluecell_Currdatastatus.CPU_Bank2_Image_BuildTime1 = Currdata[MBIC_BOOT_CREATION_TIME + 0];
                bluecell_Currdatastatus.CPU_Bank2_Image_BuildTime2 = Currdata[MBIC_BOOT_CREATION_TIME + 1];
                bluecell_Currdatastatus.CPU_Bank2_Image_BuildTime3 = Currdata[MBIC_BOOT_CREATION_TIME + 2];
                bluecell_Currdatastatus.CPU_Bank2_Image_BuildTime4 = Currdata[MBIC_BOOT_CREATION_TIME + 3];
                bluecell_Currdatastatus.CPU_Bank2_Image_BuildTime5 = Currdata[MBIC_BOOT_CREATION_TIME + 4];
                bluecell_Currdatastatus.CPU_Bank2_Image_BuildTime6 = Currdata[MBIC_BOOT_CREATION_TIME + 5];
   
                pdata = & bluecell_Currdatastatus.CPU_Bank1_Image_Name;
                for(int i = 0 ; i< 32; i++){
                     pdata[i] = Bank2data[MBIC_BOOT_FILENAME + i];
                }                
        
        }       
        else{
            pdata = & bluecell_Currdatastatus.CPU_Bank2_Image_Version1;
            for(int i = 0; i < 41; i++)
                pdata[i] = 0xFF;
        }
        printf("CRC ERROR : %x , File CRC : %x \r\n",crcret,FileCrc);
    }
    else{
        if(currcrcret == crcret){
            if(bluecell_Currdatastatus.CPU_Bank_Select == 6)
                bluecell_Currdatastatus.CPU_Current_Bank = HFR_BANK2_SEL;

        }

        
        printf("CRC SUCCESS  : %x , File CRC : %x \r\n",crcret,FileCrc);  
        bluecell_Currdatastatus.CPU_Bank2_Image_BuildTime1 = Bank2data[MBIC_BOOT_CREATION_TIME + 0];
        bluecell_Currdatastatus.CPU_Bank2_Image_BuildTime2 = Bank2data[MBIC_BOOT_CREATION_TIME + 1];
        bluecell_Currdatastatus.CPU_Bank2_Image_BuildTime3 = Bank2data[MBIC_BOOT_CREATION_TIME + 2];
        bluecell_Currdatastatus.CPU_Bank2_Image_BuildTime4 = Bank2data[MBIC_BOOT_CREATION_TIME + 3];
        bluecell_Currdatastatus.CPU_Bank2_Image_BuildTime5 = Bank2data[MBIC_BOOT_CREATION_TIME + 4];
        bluecell_Currdatastatus.CPU_Bank2_Image_BuildTime6 = Bank2data[MBIC_BOOT_CREATION_TIME + 5];
        bluecell_Currdatastatus.CPU_Bank2_Image_Version1 = Bank2data[MBIC_BOOT_VERSION + 0];
        bluecell_Currdatastatus.CPU_Bank2_Image_Version2 = Bank2data[MBIC_BOOT_VERSION + 1];
        bluecell_Currdatastatus.CPU_Bank2_Image_Version3 = Bank2data[MBIC_BOOT_VERSION + 2];
   
        pdata = & bluecell_Currdatastatus.CPU_Bank2_Image_Name;
        for(int i = 0 ; i< 32; i++){
             pdata[i] = Bank2data[MBIC_BOOT_FILENAME + i];
        }  
   
   
    }
    printf("========================================\r\n");
    printf("Bank Sel : %d  CurrBank : %d \r\n",bluecell_Currdatastatus.CPU_Bank_Select,bluecell_Currdatastatus.CPU_Current_Bank);

            
    
//           pdata = & bluecell_Currdatastatus.CPU_Bank2_Image_Version1;
//            for(int i = 0; i < 41; i++)
//                printf("pdata : %x ",pdata[i]);

}



uint8_t Flash_Data_Write(uint8_t* data){
    uint16_t Firmdata = 0;
    uint8_t ret = 0;
    int i = 0;
    static uint8_t Errcnt = 0;
    static uint32_t Curr_Download_DataIndex = 0;
    static uint32_t Prev_Download_DataIndex = 0;  
    
    Curr_Download_DataIndex = data[MBIC_PAYLOADSTART  + 4] << 24;
    Curr_Download_DataIndex += data[MBIC_PAYLOADSTART + 5] << 16;
    Curr_Download_DataIndex += data[MBIC_PAYLOADSTART + 6] << 8;            
    Curr_Download_DataIndex += data[MBIC_PAYLOADSTART + 7];      
//    data[MBIC_PAYLOADSTART + 12 +i];
    returntoFirst:
    for(i= 0; i <= Curr_Download_DataIndex - Prev_Download_DataIndex; i+=2){
        Firmdata  = ((data[MBIC_PAYLOADSTART + 12 +i]) & 0x00FF);
        Firmdata  += ((data[MBIC_PAYLOADSTART + 12 +i + 1] << 8) & 0xFF00);
        if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,UserAddress ,   (uint16_t)Firmdata) != HAL_OK)
        {
            printf("HAL NOT OK \n");
            ret = 1;
            HAL_Delay(1000);
            if(Errcnt == 0xFF)
                return false;
            
//            Errcnt++;
            goto returntoFirst;
        }else{
            Errcnt = 0; //Err Cnt Init;
            UserAddress += 2;
        }
    }
    Prev_Download_DataIndex = Curr_Download_DataIndex + 1;
    return ret;
}

uint8_t API_Flash_Data_Write(uint8_t* data){
    uint16_t Firmdata = 0;
    uint8_t ret = 0;
    int i = 0;
    static uint8_t Errcnt = 0;
    static uint32_t Curr_Download_DataIndex = 0;
    static uint32_t Prev_Download_DataIndex = 0;  
    
    Curr_Download_DataIndex = data[MBIC_PAYLOADSTART  + 4] << 24;
    Curr_Download_DataIndex += data[MBIC_PAYLOADSTART + 5] << 16;
    Curr_Download_DataIndex += data[MBIC_PAYLOADSTART + 6] << 8;            
    Curr_Download_DataIndex += data[MBIC_PAYLOADSTART + 7];      

//    data[MBIC_PAYLOADSTART + 12 +i];
   
    returntoFirst:
    for(i= 0; i <= Curr_Download_DataIndex - Prev_Download_DataIndex; i+=2){
        Firmdata  = ((data[MBIC_PAYLOADSTART + 12 +i]) & 0x00FF);
        Firmdata  += ((data[MBIC_PAYLOADSTART + 12 +i + 1] << 8) & 0xFF00);
        if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD,UserAddress ,   (uint16_t)Firmdata) != HAL_OK)
        {
            printf("HAL NOT OK \n");
            ret = 1;
            HAL_Delay(1000);
            if(Errcnt == 0xFF)
                return false;
            
            Errcnt++;
            goto returntoFirst;
        }else{
            Errcnt = 0; //Err Cnt Init;
            UserAddress += 2;
        }
    }
    Prev_Download_DataIndex = Curr_Download_DataIndex + 1;
    return ret;
}



#if 1 // PYJ.2020.06.24_BEGIN -- 
uint8_t Bank_Flash_write(uint8_t* data,uint32_t StartBankAddress) // ?占쏙옙湲고븿?占쏙옙
{

    /*Variable used for Erase procedure*/
    //static FLASH_EraseInitTypeDef EraseInitStruct;
    //static uint32_t PAGEError = 0;
    uint8_t ret = 0;


    HAL_FLASH_Unlock(); // lock ??占�?
#if 0 // PYJ.2020.06.24_BEGIN -- 
    if(flashinit == 0){
        
        flashinit= 1;
        /* Fill EraseInit structure*/
        switch(StartBankAddress){
            case FLASH_USER_START_ADDR:
                EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;
                EraseInitStruct.PageAddress = FLASH_USER_START_ADDR - 128;
                EraseInitStruct.NbPages     = (FLASH_USER_END_ADDR - FLASH_USER_START_ADDR) / FLASH_PAGE_SIZE;
            break;
            case FLASH_USER_BANK1_START_ADDR:
                EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;
                EraseInitStruct.PageAddress = FLASH_USER_BANK1_START_ADDR - 128;
                EraseInitStruct.NbPages     = (FLASH_USER_END_ADDR - FLASH_USER_BANK1_START_ADDR) / FLASH_PAGE_SIZE;

            break;
            case FLASH_USER_BANK2_START_ADDR:
                EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;
                EraseInitStruct.PageAddress = FLASH_USER_BANK2_START_ADDR - 128;
                EraseInitStruct.NbPages     = (FLASH_USER_END_ADDR - FLASH_USER_BANK2_START_ADDR) / FLASH_PAGE_SIZE;

            break;

        }        
        
        UserAddress = EraseInitStruct.PageAddress;
        //FLASH_PageErase(StartAddr);
        if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK){
            printf("Erase Failed \r\n");
        }
    }
#endif // PYJ.2020.06.24_END -- 
    ret = Flash_Data_Write(&data[MBIC_PREAMBLE_0]);
    HAL_FLASH_Lock(); // lock ?占쏙옙洹멸린
    return ret;
}
#endif // PYJ.2020.06.24_END -- 
#define DATA_32                 ((uint32_t)0x33333333)
bool EraseInit = false;

#if 0 // PYJ.2020.06.24_BEGIN -- 
void MBIC_APIFLASH_test(uint8_t* data,uint32_t size){
    static FLASH_EraseInitTypeDef EraseInitStruct;
    static uint32_t Address = 0, PAGEError = 0;
    
    static __IO uint32_t data32 = 0 , MemoryProgramStatus = 0;
    int dataindex = 0;
    uint32_t writedata = 0;
    HAL_FLASH_Unlock();
    
    /* Erase the user Flash area
      (area defined by FLASH_USER_START_ADDR and FLASH_USER_END_ADDR) ***********/
    
    /* Fill EraseInit structure*/
    if(EraseInit == false){
        EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;
        EraseInitStruct.PageAddress = FLASH_USER_BANK1_START_ADDR;
        EraseInitStruct.NbPages     = ((FLASH_USER_BANK1_START_ADDR + ((uint32_t)0xFFFF)) - FLASH_USER_BANK1_START_ADDR) / FLASH_PAGE_SIZE;
        printf("Erase Start\r\n");
        if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK)
        {
          /*
            Error occurred while page erase.
            User can add here some code to deal with this error.
            PAGEError will contain the faulty page and then to know the code error on this page,
            user can call function 'HAL_FLASH_GetError()'
          */
          /* Infinite loop */
          while (1)
          {
            /* Make LED2 blink (100ms on, 2s off) to indicate error in Erase operation */
            printf("HAL_FLASHEx_Erase Error\r\n");
            
            HAL_Delay(2000);
          }
        }
        EraseInit = true;
        printf("Erase End\r\n");
    }
    /* Program the user Flash area word by word
      (area defined by FLASH_USER_START_ADDR and FLASH_USER_END_ADDR) ***********/
    
    Address = FLASH_USER_BANK1_START_ADDR;
    printf("HAL_FLASH_Program Start\r\n");
    while (Address < ((FLASH_USER_BANK1_START_ADDR + size)))
    {
      writedata = data[dataindex + 0] ;
      writedata += data[dataindex + 1] << 8 ;
      writedata += data[dataindex + 2] << 16;
      writedata += data[dataindex + 3] << 24;      
      if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Address,writedata) == HAL_OK)
      {
        Address = Address + 4;
        dataindex  += 4;
      }
      else
      {
        /* Error occurred while writing data in Flash memory.
           User can add here some code to deal with this error */
        while (1)
        {
          /* Make LED2 blink (100ms on, 2s off) to indicate error in Write operation */
          /* Make LED2 blink (100ms on, 2s off) to indicate error in Erase operation */
          printf("HAL_FLASH_Program Error\r\n");

        }
      }
    }
     printf("HAL_FLASH_Program END\r\n");
    /* Lock the Flash to disable the flash control register access (recommended
       to protect the FLASH memory against possible unwanted operation) *********/
    HAL_FLASH_Lock();
    
    /* Check if the programmed data is OK
        MemoryProgramStatus = 0: data programmed correctly
        MemoryProgramStatus != 0: number of words not programmed correctly ******/
    Address = FLASH_USER_BANK1_START_ADDR;
    MemoryProgramStatus = 0x0;
    
//    while (Address < ((FLASH_USER_BANK1_START_ADDR + 12)))
//    {
//      data32 = *(__IO uint32_t *)Address;
//       printf("%08x : %02X \n",Address ,*(uint8_t*)Address);
//      if (data32 != DATA_32)
//      {
//        MemoryProgramStatus++;
//      }
//      Address = Address + 4;
//    }
//    
//    /*Check if there is an issue to program data*/
//    if (MemoryProgramStatus == 0)
//    {
//        printf("DATA OK \r\n");
//      /* No error detected. Switch on LED2*/
//    }
//    else
//    {
//      /* Error detected. LED2 will blink with 1s period */
//      while (1)
//      {
//         printf("Read Error\r\n");
//      }
//    }


}
#else

void MBIC_DataBankWrite(uint8_t BankNum){
    static FLASH_EraseInitTypeDef EraseInitStruct;
    static uint32_t PAGEError = 0;

    EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;
    EraseInitStruct.PageAddress = FLASH_USER_BANK_NUM;
    EraseInitStruct.NbPages     = ((FLASH_USER_BANK_NUM + ((uint32_t)1)) - FLASH_USER_BANK_NUM) / FLASH_PAGE_SIZE;
    printf("Erase Start BANK NUM\r\n");
    if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK)
    {
      while (1)
      {
        HAL_Delay(2000);
      }
    }
    printf("Erase End\r\n");
    HAL_FLASH_Unlock();
        if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, FLASH_USER_BANK_NUM,BankNum) == HAL_OK)
        {
            printf("Bank%d Write Success \r\n",BankNum);
        }else{
            printf("Bank%d Write Failed \r\n",BankNum);
        }
    HAL_FLASH_Lock();

}
uint8_t DownloadPrevdata[sizeof(BLUESTATUS_st)];
void MBIC_DataErase_Func(uint8_t bank_num){
    static FLASH_EraseInitTypeDef EraseInitStruct;
    static uint32_t PAGEError = 0;

    if(EraseInit == false){
          Bluecell_StructCpy(&DownloadPrevdata[0],&bluecell_Currdatastatus.bluecell_header,sizeof(BLUESTATUS_st));
          EEPROM_M24C08_write(EEPROM_M24C08_ID ,(EEPROM_WINDOW_STATUS_ADDRESDS),&DownloadPrevdata[0],sizeof(BLUESTATUS_st));        
        HAL_FLASH_Unlock();
#if 0 // PYJ.2020.06.24_BEGIN -- 
        EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;
        EraseInitStruct.PageAddress = FLASH_USER_BANK1_START_ADDR;
        printf("PageAddress : %x \r\n",FLASH_USER_BANK1_START_ADDR);
//        EraseInitStruct.NbPages     = ((FLASH_USER_BANK1_START_ADDR + ((uint32_t)0xFFFF)) - FLASH_USER_BANK1_START_ADDR) / FLASH_PAGE_SIZE;
        EraseInitStruct.NbPages     = (FLASH_USER_BANK1_START_ADDR - ((uint32_t)0xFFFF)) / FLASH_PAGE_SIZE;
#else
    if(bank_num == HFR_AUTO_SEL){
        if(bluecell_Currdatastatus.CPU_Current_Bank == HFR_BANK1){
            bank_num = HFR_BANK2;
            printf("Curr Bank BANK 1 I will download Bank2 \r\n");
        }
        else{
            bank_num = HFR_BANK1;
            printf("Curr Bank BANK 2 I will download Bank1 \r\n");
        }
    }

    if(bank_num == HFR_BANK2){
        EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;
        EraseInitStruct.PageAddress = FLASH_USER_BANK2_START_ADDR;
        EraseInitStruct.NbPages     = ((FLASH_USER_BANK2_END_ADDR - FLASH_USER_BANK2_START_ADDR) / FLASH_PAGE_SIZE) + 1;
        MBIC_Address = FLASH_USER_BANK2_START_ADDR;
        printf("I will download Bank2 \r\n");
        printf("Erase BANK 2 \r\n");
    }else{
        EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;
        EraseInitStruct.PageAddress = FLASH_USER_BANK1_START_ADDR;
        EraseInitStruct.NbPages     = ((FLASH_USER_BANK1_END_ADDR - FLASH_USER_BANK1_START_ADDR) / FLASH_PAGE_SIZE) + 1;
        MBIC_Address = FLASH_USER_BANK1_START_ADDR;
        printf("I will download Bank1 \r\n");        
        printf("Erase BANK 1 \r\n");        
    }
#endif // PYJ.2020.06.24_END -- 
        printf("NbPages : %x \r\n",EraseInitStruct.NbPages );
        printf("EraseInitStruct.PageAddress : %x \r\n",EraseInitStruct.PageAddress);

        printf("Erase Start\r\n");
        if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK)
        {
          /*
            Error occurred while page erase.
            User can add here some code to deal with this error.
            PAGEError will contain the faulty page and then to know the code error on this page,
            user can call function 'HAL_FLASH_GetError()'
          */
          /* Infinite loop */
          while (1)
          {
            /* Make LED2 blink (100ms on, 2s off) to indicate error in Erase operation */
            printf("HAL_FLASHEx_Erase Error\r\n");
            HAL_Delay(2000);
          }
        }
        EraseInit = true;
        printf("Erase End\r\n");
         HAL_FLASH_Lock();
    }
    if(MBIC_Address == 0){
        if(bluecell_Currdatastatus.CPU_Current_Bank == HFR_BANK1){
            bank_num = HFR_BANK2;
            MBIC_Address = FLASH_USER_BANK2_START_ADDR;
            printf("Curr Bank BANK 1 I will download Bank2 \r\n");
        }
        else{
            bank_num = HFR_BANK1;
            MBIC_Address = FLASH_USER_BANK1_START_ADDR;
            printf("Curr Bank BANK 2 I will download Bank1 \r\n");
        }        
    }

}
uint8_t BuildTimeCheck(){
    uint32_t  CurrApiAddress = 0,Bank1Address=0,Bank2Address = 0;
    //uint32_t i = 0;
    uint8_t ret = 0;
    CurrApiAddress = FLASH_MBICUSER_START_ADDR;
    Bank1Address = FLASH_USER_BANK1_START_ADDR;
    Bank2Address = FLASH_USER_BANK2_START_ADDR;

    uint8_t* Currdata = (uint8_t*)CurrApiAddress;
    uint8_t* Bank1data = (uint8_t*)Bank1Address;
    uint8_t* Bank2data = (uint8_t*)Bank2Address;
    for(int i = 0 ; i < 6; i++){
        if(Bank1data[MBIC_BOOT_CREATION_TIME + i] == Currdata[MBIC_BOOT_CREATION_TIME + i]){
            ret = HFR_BANK1;
        }else{
            ret = HFR_BANK2;
        }
    }
    return ret;
}

uint8_t MBIC_APIFLASH_Func(uint8_t* data,uint32_t size,uint8_t bank_num){
    //static FLASH_EraseInitTypeDef EraseInitStruct;
    //static uint32_t PAGEError = 0;
    static uint32_t DownloadIndex;
    static __IO uint32_t data32 = 0 , MemoryProgramStatus = 0;
    int dataindex = 0;
    uint32_t writedata = 0;
    HAL_FLASH_Unlock();
    uint32_t  CurrApiAddress = 0,Bank1Address=0,Bank2Address = 0;
    //uint32_t i = 0;
    uint8_t ret = 0;
    CurrApiAddress = FLASH_MBICUSER_START_ADDR;
    Bank1Address = FLASH_USER_BANK1_START_ADDR;
    Bank2Address = FLASH_USER_BANK2_START_ADDR;

    uint8_t* Currdata = (uint8_t*)CurrApiAddress;
    uint8_t* Bank1data = (uint8_t*)Bank1Address;
    uint8_t* Bank2data = (uint8_t*)Bank2Address;
    /* Erase the user Flash area
      (area defined by FLASH_USER_START_ADDR and FLASH_USER_END_ADDR) ***********/
    
    /* Fill EraseInit structure*/
#if 0 // PYJ.2020.06.29_BEGIN -- 
    if(EraseInit == false){
    ret = bluecell_Currdatastatus.CPU_Current_Bank;
    if(bank_num == HFR_AUTO_SEL){
        if(ret == HFR_BANK2)
            bank_num = HFR_BANK1;
        else
            bank_num = HFR_BANK2;
    }else{
        if(ret == HFR_BANK2)
            bank_num = HFR_BANK1;
        else
            bank_num = HFR_BANK2;

    }
    printf("Curr Bank BANK %d I will download Bank2 \r\n",ret,bank_num);
    

    if(bank_num == HFR_BANK2){
        EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;
        EraseInitStruct.PageAddress = FLASH_USER_BANK2_START_ADDR;
        EraseInitStruct.NbPages     = ((FLASH_USER_BANK2_END_ADDR - FLASH_USER_BANK2_START_ADDR) / FLASH_PAGE_SIZE) + 1;
        MBIC_Address = FLASH_USER_BANK2_START_ADDR;
        printf("I will download Bank2 \r\n");
        printf("Erase BANK 2 \r\n");
    }else{
        EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;
        EraseInitStruct.PageAddress = FLASH_USER_BANK1_START_ADDR;
        EraseInitStruct.NbPages     = ((FLASH_USER_BANK1_END_ADDR - FLASH_USER_BANK1_START_ADDR) / FLASH_PAGE_SIZE) + 1;
        MBIC_Address = FLASH_USER_BANK1_START_ADDR;
        printf("I will download Bank1 \r\n");        
        printf("Erase BANK 1 \r\n");        
    }
        printf("NbPages : %x \r\n",EraseInitStruct.NbPages );
        printf("EraseInitStruct.PageAddress : %x \r\n",EraseInitStruct.PageAddress);

        printf("Erase Start\r\n");
        if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK)
        {
          /*
            Error occurred while page erase.
            User can add here some code to deal with this error.
            PAGEError will contain the faulty page and then to know the code error on this page,
            user can call function 'HAL_FLASH_GetError()'
          */
          /* Infinite loop */
          while (1)
          {
            /* Make LED2 blink (100ms on, 2s off) to indicate error in Erase operation */
            printf("HAL_FLASHEx_Erase Error\r\n");
            HAL_Delay(2000);
          }
        }
        EraseInit = true;
        printf("Erase End\r\n");
    }
#endif // PYJ.2020.06.29_END -- 

    /* Program the user Flash area word by word
      (area defined by FLASH_USER_START_ADDR and FLASH_USER_END_ADDR) ***********/
    
//    MBIC_Address = FLASH_USER_BANK1_START_ADDR;
    printf("HAL_FLASH_Program Start\r\n");
    DownloadIndex += size;
     printf("MBIC_Address : %x \r\n",MBIC_Address);
     if(MBIC_Address == 0){
        if(bank_num == HFR_BANK1)
            MBIC_Address = FLASH_USER_BANK1_START_ADDR;
        else
           MBIC_Address = FLASH_USER_BANK2_START_ADDR;
     }
     for(int downindex = 0; downindex < size; downindex+=4)
     {
       writedata = data[downindex + 0] ;
       writedata += data[downindex + 1] << 8 ;
       writedata += data[downindex + 2] << 16;
       writedata += data[downindex + 3] << 24;      
       if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, MBIC_Address,writedata) == HAL_OK)
       {
         MBIC_Address +=  4;
       }
       else
       {
           printf("HAL_FLASH_Program Error\r\n");
           printf("Flash Failed %x \r\n",MBIC_Address);
       }
     }

     printf("HAL_FLASH_Program END   %x \r\n",MBIC_Address);
    /* Lock the Flash to disable the flash control register access (recommended
       to protect the FLASH memory against possible unwanted operation) *********/
    HAL_FLASH_Lock();
    return bank_num;
    /* Check if the programmed data is OK
        MemoryProgramStatus = 0: data programmed correctly
        MemoryProgramStatus != 0: number of words not programmed correctly ******/
}
    

#endif // PYJ.2020.06.24_END -- 

