#include "drv_clk.h"
#include "drv_wdog.h"
#include "drv_flash.h"

#include "kit_debug.h"

#include "stm32f4xx.h"

/* FLASH Keys */
#define FLASH_KEY1               ((uint32_t)0x45670123)
#define FLASH_KEY2               ((uint32_t)0xCDEF89AB)
#define CR_LOCK_Set              KIT_BIT_MASK_32(31)
#define FLASH_FLAG_BSY           KIT_BIT_MASK_32(16)  /*!< FLASH Busy flag */
#define FLASH_FLAG_EOP           KIT_BIT_MASK_32(0)  /*!< FLASH End of Operation flag */
#define FLASH_FLAG_ERR			 (KIT_BIT_MASK_32S(4, 7) | KIT_BIT_MASK_32(1))  /*!< FLASH Program error flag */
#define CR_PG_Set                KIT_BIT_MASK_32(0)
#define CR_PER_Set               KIT_BIT_MASK_32(1)
#define CR_SART					 KIT_BIT_MASK_32(16)
#define CR_PG_PSIZE              KIT_BIT_MASK_32S(8, 9)
#define CR_PG_SNB                KIT_BIT_MASK_32S(3, 7)
//#define CR_STRT_Set              ((uint32_t)0x00000040)
//#define CR_PER_Reset             ((uint32_t)0x00001FFD)
#define EraseTimeout             ((uint32_t)0x02000000)
#define ProgramTimeout           ((uint32_t)0x00002000)

const uint32_t page_start_addr[13] = 
{
	0x08000000, 0x08004000, 0x08008000, 0x0800C000, 0x08010000, 0x08020000, 
	0x08040000, 0x08060000, 0x08080000, 0x080A0000, 0x080C0000, 0x080E0000, 0x08100000,

};
static void      flash_lock(void);
static void		 flash_unlock(void);
static kit_ret_e flash_check_operation(int32_t timeout);
    

static kit_ret_e flash_check_operation(int32_t timeout)
{
    kit_ret_e res = kKit_Ret_Ok;
    
    while((FLASH->SR & FLASH_FLAG_BSY) == FLASH_FLAG_BSY)
    {
        if(timeout-- < 1)
        {
            return kKit_Ret_TimeOut;
        }
    }
    
    if((FLASH->SR & FLASH_FLAG_ERR) != 0)
    {
        res = kKit_Ret_Error;
    }
    
    return res;
}

static void flash_lock(void)
{
    FLASH->CR |= CR_LOCK_Set;
}

static void flash_unlock(void)
{
    FLASH->KEYR = FLASH_KEY1;
    FLASH->KEYR = FLASH_KEY2;
    FLASH->SR = (FLASH_FLAG_EOP| FLASH_FLAG_ERR);
}

int32_t flash_get_page_id(uint32_t start_addr)
{
	int32_t i, res = -1;
	
	for(i = 0; i < 12; i++)
	{
		if(start_addr == page_start_addr[i])
		{
			res = i;
			break;
		}
	}
	
	return res;
}


kit_ret_e drv_flash_read_u16(flash_Item_t *item, uint32_t addr,uint16_t *data)
{
    kit_ret_e res = kKit_Ret_Ok;

    KIT_ASSERT_PARAM((item != NULL) && (addr >= page_start_addr[item->start_page]) && ((addr + 2) <= page_start_addr[item->start_page + item->page_cnt]));
    
    if((item != NULL) && (addr >= page_start_addr[item->start_page]) && ((addr + 2) <= page_start_addr[item->start_page + item->page_cnt]))
    {
        *data = *((uint16_t *)addr);
    }
    else
    {
        res = kKit_Ret_ParamErr;
    }
    
    return res;
}

kit_ret_e drv_flash_read_u32(flash_Item_t *item, uint32_t addr, uint32_t *data)
{
    kit_ret_e res = kKit_Ret_Ok;

    KIT_ASSERT_PARAM((item != NULL) && (addr >= page_start_addr[item->start_page]) && ((addr + 4) <= page_start_addr[item->start_page + item->page_cnt]));  
    
	if((item != NULL) && (addr >= page_start_addr[item->start_page]) && ((addr + 4) <= page_start_addr[item->start_page + item->page_cnt]))
    {
        *data = *((uint32_t *)addr);
    }
    else
    {
        res = kKit_Ret_ParamErr;
    }
    
    return res;
}


kit_ret_e drv_flash_write_u32(flash_Item_t *item, uint32_t addr, uint32_t value)
{
    kit_ret_e res;
    //OS_INIT_CRITICAL();

    KIT_ASSERT_PARAM((item != NULL) && (addr >= page_start_addr[item->start_page]) && ((addr + 4) <= page_start_addr[item->start_page + item->page_cnt]));  
    
	if((item != NULL) && (addr >= page_start_addr[item->start_page]) && ((addr + 4) <= page_start_addr[item->start_page + item->page_cnt]))
    {
        flash_unlock();
		res = flash_check_operation(ProgramTimeout);
        if(res == kKit_Ret_Ok)
        {
            //OS_ENTER_CRITICAL();
			//FLASH->ACR&=~(1<<10);	//FLASH擦除期间,必须禁止数据缓存,
            FLASH->CR &= ~CR_PG_PSIZE;	//清除PSIZE原来的设置
			FLASH->CR |= 2 << 8;		//设置为32bit宽,确保VCC=2.7~3.6V之间!!
			FLASH->CR |= CR_PG_Set;	//编程使能
            
            *(__IO uint32_t*)addr = value;
            res = flash_check_operation(ProgramTimeout);
            
            FLASH->CR &= ~CR_PG_Set;
			//FLASH->ACR|=1<<10;
            //OS_EXIT_CRITICAL();
        }    
        flash_lock();
    }
	else
	{
		res = kKit_Ret_ParamErr;
	}

    return res;
}



kit_ret_e flash_series_erase_page(flash_Item_t *item, uint32_t addr, uint32_t cnt)
{
	
    int32_t start_page;
	uint32_t i;
    kit_ret_e res = kKit_Ret_Error;
    
    //KIT_ASSERT_PARAM((item != NULL) && (addr >= item->start_addr) && ((addr + item->page_size * cnt) < item->end_addr));

    //if((item != NULL) && (addr >= item->start_addr) && ((addr + item->page_size * cnt) < item->end_addr))
    {
		start_page = flash_get_page_id(addr);
		if(start_page >= 0)
		{
			flash_unlock();
			res = flash_check_operation(EraseTimeout);
			if(res == kKit_Ret_Ok)
			{
				FLASH->CR &= ~CR_PG_PSIZE;	//清除PSIZE原来的设置
				FLASH->CR |= 2 << 8;			//设置为32bit宽,确保VCC=2.7~3.6V之间!!
				for (i = 0; i < cnt; i++)
				{
					FLASH->CR &= ~CR_PG_SNB;			//清除原来的设置
					FLASH->CR |= (start_page + i) << 3;	//设置要擦除的扇区 
					FLASH->CR |= CR_PER_Set;
					FLASH->CR |= CR_SART;	//开始擦除	
					flash_check_operation(EraseTimeout);
					FLASH->CR &= ~CR_PER_Set;
				}
			}
			flash_lock();
		}
    }
    return res;
}


void flash_jump(uint32_t dest_addr, NoArgFuncCall call)
{
    uint32_t sp_addr = *(__IO uint32_t*)dest_addr;
    uint32_t app_addr = *(__IO uint32_t*)(dest_addr + 4);
    if ((sp_addr != 0xFFFFFFFF) 
     && (app_addr != 0xFFFFFFFF)
     && ((sp_addr & 0xF0000000) == 0x20000000)
     && ((app_addr & 0x0F000000) == 0x08000000))
    {    
        __disable_irq();
		call();
        SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;

        __set_MSP(*(__IO uint32_t*) dest_addr);
        ((NoArgFuncCall) (*(__IO uint32_t*)(dest_addr + 4)))();
    }
}


uint32_t drv_flash_get_page_size(flash_Item_t *item)
{
    uint32_t res = 0xFFFFFFFF;
    
    KIT_ASSERT_PARAM(item != NULL);
    if(item != NULL)
    {		
		if(item->start_page < 4)
		{
			res = 1024 * 16;
		}
		else if(item->start_page < 5)
		{
			res = 1024 * 64;
		}
        else
		{
			res = 1024 * 128;
		}
    }
    return res;
}


kit_ret_e drv_drv_flash_write_u32(uint32_t addr, uint32_t value)
{
    kit_ret_e res;

    flash_unlock();
    res = flash_check_operation(ProgramTimeout);
    if(res == kKit_Ret_Ok)
    {
        FLASH->CR &= ~CR_PG_PSIZE;	//清除PSIZE原来的设置
        FLASH->CR |= 2 << 8;		//设置为32bit宽,确保VCC=2.7~3.6V之间!!
        FLASH->CR |= CR_PG_Set;	//编程使能
        
        *(__IO uint32_t*)addr = value;
        res = flash_check_operation(ProgramTimeout);
        
        FLASH->CR &= ~CR_PG_Set;
    }    
    flash_lock();

    return res;
}

kit_ret_e drv_bsp_flash_write_data_u32(uint32_t addr, uint8_t* buf, uint32_t len)
{
    uint32_t i, data;
    kit_ret_e res = kKit_Ret_ParamErr;
 
    if(((addr % 4) == 0) && (buf != NULL) && ((len % 4) == 0))
    {
        len >>= 2;
        for(i = 0; i < len; i++)
        {
            data = ((uint32_t *)buf)[i];
            res = drv_drv_flash_write_u32(addr + (i << 2), data);
            if(res != kKit_Ret_Ok)
                break;
                   
            if(((i + 1) % 300) == 0)
                drv_wdog_feed();
        }
    }

    return res;
}

kit_ret_e drv_flash_series_erase_page(uint32_t addr, uint32_t cnt)
{
    int32_t i, start_page;
    kit_ret_e res = kKit_Ret_Error;
    
    start_page = flash_get_page_id(addr);
    if(start_page >= 0)
    {
        flash_unlock();
        res = flash_check_operation(EraseTimeout);
        if(res == kKit_Ret_Ok)
        {
            FLASH->CR &= ~CR_PG_PSIZE;	//清除PSIZE原来的设置
            FLASH->CR |= 2 << 8;			//设置为32bit宽,确保VCC=2.7~3.6V之间!!
            for (i = 0; i < cnt; i++)
            {
                FLASH->CR &= ~CR_PG_SNB;			//清除原来的设置
                FLASH->CR |= (start_page + i) << 3;	//设置要擦除的扇区 
                FLASH->CR |= CR_PER_Set;
                FLASH->CR |= CR_SART;	//开始擦除	
                flash_check_operation(EraseTimeout);
                FLASH->CR &= ~CR_PER_Set;
            }
        }
        flash_lock();
    }

    return res;
}