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

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 < INDEX_BLUE_EOF + 1; 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 -- 

}
#define INDEX_LENGTH 2
uint8_t Flash_RGB_Data_Write(uint8_t* data){
    uint16_t Firmdata = 0;
    uint8_t ret = 0;
    for(uint8_t i = 0; i < data[INDEX_LENGTH] - 2; i+=2){
        Firmdata  = ((data[(INDEX_LENGTH + 1) + i]) & 0x00FF);
        Firmdata  += ((data[(INDEX_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;
    }
    return ret;
}
#define INDEX_HEADER 0
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_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[INDEX_HEADER]);
    HAL_FLASH_Lock(); // lock ?占쏙옙洹멸린

    return ret;

}
/*
페이지 별로 1Kbyte로 이루어져 있으며 사용하는 MCU 메모리 크기에 따라 물리 페이지가 늘어나거나 줄어듭니다.

위 페이지 범위를 보고 사용자의 MCU에 맞게 사용할 페이지의 시작 주소와 끝주소를 정해줍니다.

예제에서는 1개 페이지만 사용하도록 설정하였습니다.

아래에서의 시작번지는 11페이지 이므로 시작 주소는 0x08002C00 가 되겠습니다.

*/




//그리고 Flash memory에 저장할 사용자 데이터를 정의 합니다.  예제에서는 4byte 변수를 사용하기 위해 어드레스를 4byte단위로 증가시켰습니다.

#define USER_DATA1     (FLASH_USER_START_ADDR)
#define USER_DATA2     (FLASH_USER_START_ADDR + 4)
#define USER_DATA3     (FLASH_USER_START_ADDR + 8)
#define USER_DATA4     (FLASH_USER_START_ADDR + 12)


void FLASH_Byte_Write(uint8_t* data){
  /*
  페이지 단위로 지울수 있도록 구조체변수를 선언해 주고 멤버변수값들을 정해줍니다.
  데이터를 새로 쓰기위해서는 먼저 페이지 단위로 메모리를 지워 줘야 합니다.
  */
  static FLASH_EraseInitTypeDef EraseInitStruct;
  EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;  //0x00
  EraseInitStruct.PageAddress = FLASH_USER_START_ADDR;  // 지우기 페이지의 시작 어드레스
  EraseInitStruct.NbPages     = (FLASH_USER_END_ADDR - FLASH_USER_START_ADDR) / FLASH_PAGE_SIZE; //지울 페이지 수
  static uint32_t PAGEError = 0;
  printf("Flash Write Start \r\n");
    data[INDEX_BLUE_HEADER] = 0xbe;
    data[INDEX_BLUE_TYPE] = 1;
    data[INDEX_BLUE_LENGTH] = INDEX_BLUE_EOF - 2;
    data[INDEX_BLUE_CRCINDEX] = INDEX_BLUE_EOF - 1;    
  /*
  Flash메모리를 조작 할 수 있도록 락을 풀어 줍니다.
  */
   HAL_FLASH_Unlock();
  /*
  앞에서 설정한 페이지를 지워 줍니다.  페이지 지우기에 실패하면 무한루프에 빠지게 하여 기기의 오작동을 예방합니다.
  */
    if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK) {
    printf("Eraser Error\r\n");
    while(1);
    }
  /*
  유저 데이터를 메모리에 써 줍니다.
  임의의 유저데이터를 써주기 위해 변수를 하나 만들어 줘봤습니다.
  */
   uint16_t WriteData = 0;
  /*
  그리고 데이터 쓰기
  */
   /////////유저가 설정한 페이지에 데이터 쓰기 ////////////////////////////////////////////////////
   //HAL_StatusTypeDef HAL_FLASH_Program(uint32_t TypeProgram, uint32_t Address, uint64_t Data)
   for(int i = 0; i < INDEX_BLUE_EOF + 1; i += 2){
        WriteData  = ((data[i]) & 0x00FF);
        WriteData  += ((data[i + 1] << 8) & 0xFF00);
        if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, FLASH_USER_START_ADDR + i, ((uint16_t)WriteData)) != HAL_OK){
            printf("Write Error %d\r\n",__LINE__);
            while(1);
        }
   }
  /*
  마지막으로 Flash 메모리를 보호하기 위해 락을 걸어 줍니다.
  */
   HAL_FLASH_Lock();
/*
이제 메모리에 저장된 데이터를 꺼내 보겠습니다.
*/
///////////////메모리에서 데이터 읽기////////////////////////////////////////////////////////////
#if 1 // PYJ.2019.07.31_BEGIN -- 
for(int i = 0; i < INDEX_BLUE_EOF+1; i += 2){
    printf("Addr = %x, Data = %x\r\n", FLASH_USER_START_ADDR + i, *(__IO uint16_t *)(FLASH_USER_START_ADDR + i));
}
#endif // PYJ.2019.07.31_END -- 
/////////////////////////////////////////////////////////////////////////////////////////////////// 

}
uint8_t Bluecell_Flash_Write(uint8_t* data){

  /*Variable used for Erase procedure*/
//  flashtest();
  FLASH_Byte_Write(&data[INDEX_BLUE_HEADER]);

}
bool Bluecell_Flash_Read(uint8_t* data){
    for(int i = 0; i < INDEX_BLUE_EOF + 1; i += 2){
//        printf("Addr = %x, Data = %x\r\n", FLASH_USER_START_ADDR + i, *(__IO uint16_t *)(FLASH_USER_START_ADDR + i));
        data[INDEX_BLUE_HEADER + i]     = *(__IO uint16_t *)(FLASH_USER_START_ADDR + i) &0x00FF;
        data[INDEX_BLUE_HEADER + i + 1] = (*(__IO uint16_t *)(FLASH_USER_START_ADDR + i) & 0xFF00) >> 8;           
    }
#if 0 // PYJ.2019.07.31_BEGIN -- 
    for(int i = 0; i < INDEX_BLUE_EOF + 1; i++){
        printf("Data = %x\r\n",  data[i]);
    }
#endif // PYJ.2019.07.31_END -- 
}
