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

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();
}


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();
}

void Flash_InitRead(void) // ?占쏙옙湲고븿?占쏙옙
{
    uint32_t  Address = 0;
    Address = FLASH_USER_START_ADDR;
    for(uint32_t i = 0; i < 16; i++ ){
        printf("%08x : %02X \n",Address ,*(uint8_t*)Address);
        Address++;
    }
#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 -- 

}

#if 1 // PYJ.2020.05.20_BEGIN -- 
uint8_t Flash_RGB_Data_Write(uint8_t* data){
    uint16_t Firmdata = 0;

    uint8_t ret = 0;
    for(int i = 0; i < data[bluecell_length] - 2; i+=2){
        Firmdata  = ((data[(bluecell_length + 1) + i]) & 0x00FF);
        Firmdata  += ((data[(bluecell_length + 1) + (i + 1)] << 8) & 0xFF00);
        if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD,Address ,   (uint16_t)Firmdata) != HAL_OK){
            printf("HAL NOT OK \n");
            ret = 1;
        }
        Address += 2;
        //if(!(i%FirmwareUpdateDelay))
      //  HAL_Delay(1);
    }
    return ret;
}
uint8_t Flash_Data_Write(uint8_t* data){
    uint16_t Firmdata = 0;
    uint8_t ret = 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];
    for(int i= 0; i <= Curr_Download_DataIndex - Prev_Download_DataIndex+1; 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;
        }
        UserAddress += 2;
    }
    Prev_Download_DataIndex = Curr_Download_DataIndex;
    return ret;
}

uint8_t Flash_Bank_Data_Write(uint8_t* data){
    uint16_t Firmdata = 0;
    uint16_t Length = 0;
    static uint32_t WriteIndex = 0;
    uint8_t ret = 0;
    for(int i = 0; i < Length; i+=2){
        Firmdata  = ((data[WriteIndex++]) & 0x00FF);
        Firmdata  += ((data[WriteIndex++] << 8) & 0xFF00);
        if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD,Address ,   (uint16_t)Firmdata) != HAL_OK){
            printf("HAL NOT OK \n");
            ret = 1;
        }
        Address += 2;
        //if(!(i%FirmwareUpdateDelay))
      //  HAL_Delay(1);
    }
    return ret;
}

#if 0 // PYJ.2020.06.10_BEGIN -- 
uint8_t Flash_Data_Write(uint8_t* data){
    uint64_t Firmdata = 0;
    uint8_t ret = 0;
    uint8_t Length = data[bluecell_length] - 2;
    uint8_t Length_remainder =  Length % 8;    
    uint8_t Length_ans =  Length / 8;    

    for(int i = 0; i < Length; i+=8){
        Firmdata  =  ((data[(bluecell_length + 1) + i])             & 0x00000000000000FF);
        Firmdata  += ((data[(bluecell_length + 1) + (i + 1)] << 8)  & 0x000000000000FF00);
        Firmdata  += ((data[(bluecell_length + 1) + (i + 2)] << 16) & 0x0000000000FF0000);
        Firmdata  += ((data[(bluecell_length + 1) + (i + 3)] << 24) & 0x00000000FF000000);
        Firmdata  += ((data[(bluecell_length + 1) + (i + 4)] << 32) & 0x000000FF00000000);
        Firmdata  += ((data[(bluecell_length + 1) + (i + 5)] << 40) & 0x0000FF0000000000);
        Firmdata  += ((data[(bluecell_length + 1) + (i + 6)] << 48) & 0x00FF000000000000);        
        Firmdata  += ((data[(bluecell_length + 1) + (i + 7)] << 56) & 0xFF00000000000000);                
        if(Length_remainder > 0 && Length_ans > i){
            for(int a = 0; a < Length_remainder; a += 2){
                if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD,Address ,   (uint16_t)Firmdata) != HAL_OK){
                    printf("HAL NOT OK \n");
                    ret = 1;
                }
                Address += 2;            
            }
        }
        else{        
            if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD,Address ,   (uint64_t)Firmdata) != HAL_OK){
                printf("HAL NOT OK \n");
                ret = 1;
            }
            Address += 8;
        }
        //if(!(i%FirmwareUpdateDelay))
      //  HAL_Delay(1);
    }
    return ret;
}
#endif // PYJ.2020.06.10_END -- 
uint8_t Flash_DataTest_Write(uint8_t* data){
    uint32_t Firmdata = 0;
    uint8_t ret = 0;
    uint8_t Length = data[bluecell_length] - 2;
    uint8_t Length_remainder =  Length % 4;    
    uint8_t Length_ans =  Length / 4;        
    for(int i = 0; i < data[bluecell_length] - 2; i+=4){

        if(Length_remainder > 0 && Length_ans > i){
            for(int a = 0; a < Length_remainder; a += 2){
                Firmdata  = ((data[(bluecell_length + 1) + i]) & 0x00FF);
                Firmdata  += ((data[(bluecell_length + 1) + (i + 1)] << 8) & 0xFF00);                
                if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD,Address ,   (uint16_t)Firmdata) != HAL_OK){
                    printf("HAL NOT OK \n");
                    ret = 1;
                }
                Address += 2;            
            }
        }
        else{
            Firmdata  = ((data[(bluecell_length + 1) + i]) 	          & 0x000000FF);
            Firmdata  += ((data[(bluecell_length + 1) + (i + 1)] << 8) & 0x0000FF00);
            Firmdata  += ((data[(bluecell_length + 1) + (i + 2)] << 16) & 0x00FF0000);
            Firmdata  += ((data[(bluecell_length + 1) + (i + 3)] << 24) & 0xFF000000);            
            if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,Address ,   (uint32_t)Firmdata) != HAL_OK){
                printf("HAL NOT OK \n");
                ret = 1;
            }
            Address += 4;
        }
        //if(!(i%FirmwareUpdateDelay))
      //  HAL_Delay(1);
    }
    return ret;
}
#endif // PYJ.2020.05.20_END -- 

uint8_t Flash_write(uint8_t* data) // ?占쏙옙湲고븿?占쏙옙
{

    /*Variable used for Erase procedure*/
    static FLASH_EraseInitTypeDef EraseInitStruct;
    static uint32_t PAGEError = 0;
    uint8_t ret = 0;
    /* Fill EraseInit structure*/
    EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;
    EraseInitStruct.PageAddress = FLASH_USER_START_ADDR;
    EraseInitStruct.NbPages     = (FLASH_USER_END_ADDR - FLASH_USER_START_ADDR) / FLASH_PAGE_SIZE;

//    __HAL_RCC_TIM6_CLK_DISABLE(); // 留ㅼ씤???占쏙옙癒몌옙?? ?占쏙옙占�??占쏙옙?占쏙옙?占쏙옙
    HAL_FLASH_Unlock(); // lock ??占�?
    if(flashinit == 0){
        flashinit= 1;
        //FLASH_PageErase(StartAddr);
        if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK){
            printf("Erase Failed \r\n");
        }
    }
//    FLASH_If_Erase();
    ret = Flash_RGB_Data_Write(&data[bluecell_stx]);
//    ret = Flash_DataTest_Write(&data[bluecell_stx]);

    HAL_FLASH_Lock(); // lock ?占쏙옙洹멸린
//    __HAL_RCC_TIM6_CLK_ENABLE(); // 留ㅼ씤???占쏙옙癒몌옙?? ?占쏙옙?占쏙옙?占쏙옙?占쏙옙?占쏙옙?占쏙옙

    return ret;
}


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;
    /* Fill EraseInit structure*/
    switch(StartBankAddress){
        case FLASH_USER_START_ADDR:
            EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;
            EraseInitStruct.PageAddress = FLASH_USER_START_ADDR;
            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;
            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;
            EraseInitStruct.NbPages     = (FLASH_USER_END_ADDR - FLASH_USER_BANK2_START_ADDR) / FLASH_PAGE_SIZE;

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

    }

    HAL_FLASH_Unlock(); // lock ??占�?
    if(flashinit == 0){
        flashinit= 1;
        UserAddress = EraseInitStruct.PageAddress;
        //FLASH_PageErase(StartAddr);
        if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK){
            printf("Erase Failed \r\n");
        }
    }
    ret = Flash_Data_Write(&data[MBIC_PREAMBLE_0]);
    HAL_FLASH_Lock(); // lock ?占쏙옙洹멸린
    return ret;
}

