/******************************************************************************
版权所有：	
文件名称：	flash_at45db321.c
文件版本：	01.01
创建作者:	   sunxi
创建日期：	2008-08-19
功能说明：	SPI FLASH 仿真驱动程序。
其它说明：	
修改记录：				仿真程序测试结果:
						flash_test begin!
						block_size=512,blocks=8192.
						flash_init ok(gf_flash=4703c710)!
						at45DB321Erase (us=2368315,ret=0)!
						at45DB321Erase verify ok(us=122126)!
						at45DB321Write ok(us=30182426)!
						at45DB321Write verify ok(us=118453)!
						at45DB321Erase (us=2485398,ret=0)!
						at45DB321Erase verify ok(us=121824)!
						at45DB321Write ok(us=65194996)!
						at45DB321Write verify ok(us=130880)!
						flash_test end!						
*/

/*------------------------------- 头文件 --------------------------------------
*/
#include <string.h>

#include "bspconfig.h"
#include "ustimer.h"
#include "flash.h"
#include "gpio.h"

#include "rt.h"

/*------------------------------- 宏定义 --------------------------------------
*/
//#if CFG_BSP_DEBUG

#define _DEBUG_FLASH

//#endif


/*------------------------------ 全局变量 -------------------------------------
*/
int gf_flash;

/*------------------------------ 函数声明 -------------------------------------
*/


/*------------------------------ 外部函数 -------------------------------------
*/
/******************************************************************************
函数名称：	flash_init
函数版本：	01.01
创建作者:	   sunxi
创建日期：	2008-08-19
函数说明：	flash初始化。
参数说明：	无
返回值：  	成功返回0.
修改记录：	
*/
int flash_init(void)
{
	int file_size;
	// 创建并打开文件
	gf_flash = rt_file_open("/app/data/flash.bin",O_CREAT|O_RDWR,0);
	if(IS_ERR(gf_flash))
	{
		gf_flash = 0;
		return -1;
	}

	// 检查文件长度是否正确
	file_size = rt_file_getfile_size(gf_flash);
	if(file_size < 0)
	{
		rt_file_close(gf_flash, NULL);
		gf_flash = -1;
		return -2;
	}
	if(file_size == CFG_FLASH_SIZE)
	{
		return 0;
	}

	//如果文件长度不为0，说明FLASH被破坏，不修改内容，直接错误返回，
	//方便以后问题查找。
	if(file_size != 0)
	{
		rt_file_close(gf_flash,NULL);
		gf_flash = 0;
		return -3;
	}

	// 如果文件长度为0，初始化FLASH 文件
	if(flash_erase(0,CFG_FLASH_SIZE) != 0)
	{
		rt_file_close(gf_flash,NULL);
		gf_flash = 0;
		return -4;
		
	}
	
	return 0;
}
 

int flash_exit(void)
{
	if(gf_flash >= 0)
	{
		rt_file_close(gf_flash,NULL);
		gf_flash = 0;
	}

	return 0;
}

/******************************************************************************
函数名称：	flash_read
函数版本：	01.01
创建作者:	   sunxi
创建日期：	2008-08-21
函数说明：	从FLASH中读出数据。
参数说明：	
	offset(in)：需要读的数据在FLASH中的偏移量，和length之和不能大于
				CFG_FLASH_SIZE.
	buffer(out):读出数据的buffer。
	length(in):	需要读出数据的长度，和offset之和不能大于CFG_FLASH_SIZE。
返回值：  	成功返回0.
修改记录：	
*/
int flash_read(uint32_t offset,unsigned char * buffer,uint32_t length)
{
	off_t pos;
	int ret;
	
	if(gf_flash == 0)
	{
		return -1;
	}
	//检查参数
	if(buffer == 0 || (offset + length) > CFG_FLASH_SIZE)
	{
		return -1;
	}
	if(length == 0)
	{
		return 0;
	}

	pos = offset;
	ret = rt_file_read(gf_flash,buffer,length,&pos);
	if(ret != length)
	{
		return -2;
	}

	return 0;
}


/******************************************************************************
函数名称：	flash_write
函数版本：	01.01
创建作者:	   sunxi
创建日期：	2008-08-21
函数说明：	将数据写入FLASH中。
参数说明：	
	offset(in)：需要写入的数据在FLASH中的偏移量，和length之和不能大于
				CFG_FLASH_SIZE.
	buffer(in):写入数据的buffer。
	length(in):	需要写入数据的长度，和offset之和不能大于CFG_FLASH_SIZE。
返回值：  	成功返回0.
修改记录：	
*/
int flash_write(uint32_t offset,unsigned char * buffer,uint32_t length)
{
	off_t pos;
	int ret;
	
	if(gf_flash == 0)
	{
		return -1;
	}
	//检查参数
	if(buffer == 0 || (offset + length) > CFG_FLASH_SIZE)
	{
		return -1;
	}
	if(length == 0)
	{
		return 0;
	}

	pos = offset;
	ret = rt_file_write(gf_flash,buffer,length,&pos);
	if(ret != length)
	{
		return -2;
	}

	return 0;
}


/******************************************************************************
函数名称：	flash_erase
函数版本：	01.01
创建作者:	   sunxi
创建日期：	2008-08-21
函数说明：	擦除FLASH中的指定区域。注意擦除是以页（CFG_FLASH_PAGE_SIZE）为单位
			擦除的，为了保证用户指定的区域一定被擦除，实际擦除的长度可能大于指定
			的长度，用户应小心处理这个问题。
参数说明：	
	offset(in)：需要擦除的页在FLASH中的偏移量，和length之和不能大于
				CFG_FLASH_SIZE.
	length(in):	需要擦除的长度，和offset之和不能大于CFG_FLASH_SIZE。
返回值：  	成功返回0.
修改记录：	
*/
#define FLASH_ERASE_LENGTH	(128*1024)
int flash_erase(uint32_t offset,uint32_t length)
{
	unsigned char *buf;
	off_t off;
	size_t len;
	int ret;

	if(gf_flash == 0)
	{
		return -1;
	}

	buf = rt_malloc(FLASH_ERASE_LENGTH);
	if(buf == NULL)
	{
		return -2;
	}

	memset(buf,-1,FLASH_ERASE_LENGTH);
	off = offset;

	while(length)
	{
		len = length>FLASH_ERASE_LENGTH ? FLASH_ERASE_LENGTH:length;
		length -= len;
		ret = rt_file_write(gf_flash,buf,len,&off);
		if(ret != len)
		{
			rt_free(buf);
			return -3;
		}
	}

	rt_free(buf);
	return 0;
}


/******************************************************************************
函数名称：	at45db321_sector_protection
函数版本：	01.01
创建作者:	   sunxi
创建日期：	2008-10-10
函数说明：	启用FLASH的扇区保护功能。
参数说明：	无。
返回值：  	成功返回0.
修改记录：	
*/
int at45db321_sector_protection(void)
{
	return 0;						
}


/*------------------------------ 内部函数 -------------------------------------
*/


/*------------------------------ 测试函数 -------------------------------------
*/
#ifdef _DEBUG_FLASH

#define FLASH_BLOCK_SIZE CFG_FLASH_PAGE_SIZE
int flash_test(void)
{
	int ret;
	uint32_t i,j,block_size,blocks;
	uint32_t us0,us;
	unsigned int gTestBuf[FLASH_BLOCK_SIZE/sizeof(int)];
	
	block_size = FLASH_BLOCK_SIZE;	
//	blocks = CFG_FLASH_SIZE/FLASH_BLOCK_SIZE;
	blocks = 1;
	
	rt_printf("flash_test begin!\r\n");
	rt_printf("block_size=%d,blocks=%d.\r\n",block_size,blocks);

	// 初始化
	if(gf_flash == 0)
	{
		ret = flash_init();
		if(ret != 0)
		{
			rt_printf("flash_init error(ret=%d)!\r\n" ,ret);
			return -1;
		}
	}
	rt_printf("flash_init ok(gf_flash=%p)!\r\n",gf_flash);
	
	//擦除整个flash。
	us0 = ustimer_get_origin();
	ret = flash_erase(0,blocks*block_size);
	us = ustimer_get_duration(us0);
	rt_printf("at45DB321Erase (us=%d,ret=%d)!\r\n",us,ret);

	//确认擦除OK
	us0 = ustimer_get_origin();
	for(i=0;i<blocks;i++)
	{
		ret = flash_read(i*block_size,(unsigned char *)gTestBuf,block_size);
		if(ret != 0)
		{
			rt_printf("at45db321Read failure(i=%d,ret=%d)!\r\n",i,ret);
			return -1;
		}
		for(j=0;j<block_size/sizeof(int);j++)
		{
			
			if(gTestBuf[j] != 0xffffffff)
			{
					rt_printf("at45DB321Erase verify failure(i=%d,j=%d,data=0x%08x)!\r\n",i,j,gTestBuf[j]);
					return -1;
			}
		}
	}
	us = ustimer_get_duration(us0);
	rt_printf("at45DB321Erase verify ok(us=%d)!\r\n",us);

	//整个flash写0
	memset(gTestBuf,0,sizeof(gTestBuf));
	us0 = ustimer_get_origin();
	for(i=0;i<blocks;i++)
	{
		ret = flash_write(i*block_size,(unsigned char *)gTestBuf,block_size);
		if(ret != 0)
		{
			rt_printf("at45DB321Write failure(i=%d,ret=%d)!\r\n",i,ret);
			return -1;
		}
	}
	us = ustimer_get_duration(us0);
	rt_printf("at45DB321Write ok(us=%d)!\r\n",us);

	//检查整个flash是否全为0
	us0 = ustimer_get_origin();
	for(i=0;i<blocks;i++)
	{
		ret = flash_read(i*block_size,(unsigned char *)gTestBuf,block_size);
		if(ret != 0)
		{
			rt_printf("at45db321Read failure(i=%d,ret=%d)!\r\n",i,ret);
			return -1;
		}
		
		for(j=0;j<block_size/sizeof(int);j++)
		{
			
			if(gTestBuf[j] != 0)
			{
					rt_printf("at45DB321Write verify failure(i=%d,j=%d,data=0x%08x)!\r\n",i,j,gTestBuf[j]);
					return -1;
			}
		}
	}
	us = ustimer_get_duration(us0);
	rt_printf("at45DB321Write verify ok(us=%d)!\r\n",us);

	//擦除整个flash
	us0 = ustimer_get_origin();
	ret = flash_erase(0,blocks*block_size);
	us = ustimer_get_duration(us0);
	rt_printf("at45DB321Erase (us=%d,ret=%d)!\r\n",us,ret);

	//确认擦除OK
	us0 = ustimer_get_origin();
	for(i=0;i<blocks;i++)
	{
		ret = flash_read(i*block_size,(unsigned char *)gTestBuf,block_size);
		if(ret != 0)
		{
			rt_printf("at45db321Read failure(i=%d,ret=%d)!\r\n",i,ret);
			return -1;
		}
		
		for(j=0;j<block_size/sizeof(int);j++)
		{
			
			if(gTestBuf[j] != 0xffffffff)
			{
					rt_printf("at45DB321Erase verify failure(i=%d,j=%d,data=0x%08x)!\r\n",i,j,gTestBuf[j]);
					return -1;
			}
		}
	}
	us = ustimer_get_duration(us0);
	rt_printf("at45DB321Erase verify ok(us=%d)!\r\n",us);

	//整个flash写测试数据
	us0 = ustimer_get_origin();
	for(i=0;i<blocks;i++)
	{
		//初始化写数据
		for(j=0;j<block_size/sizeof(int);j++)
		{
			gTestBuf[j] = i*block_size/sizeof(int) + j;
		}

		//写
		ret = flash_write(i*block_size,(unsigned char *)gTestBuf,block_size);
		if(ret != 0)
		{
			rt_printf("at45DB321Write failure(i=%d,ret=%d)!\r\n",i,ret);
			return -1;
		}
	}
	us = ustimer_get_duration(us0);
	rt_printf("at45DB321Write ok(us=%d)!\r\n",us);

	//读出并校验数据
	us0 = ustimer_get_origin();
	for(i=0;i<blocks;i++)
	{
		ret = flash_read(i*block_size,(unsigned char *)gTestBuf,block_size);
		if(ret != 0)
		{
			rt_printf("at45db321Read failure(i=%d,ret=%d)!\r\n",i,ret);
			return -1;
		}
		
		for(j=0;j<block_size/sizeof(int);j++)
			if(gTestBuf[j] != i*block_size/sizeof(int) + j)
			{
					rt_printf("at45DB321Write verify failure(i=%d,j=%d,data=0x%08x)!\r\n",i,j,gTestBuf[j]);
					return -1;
			}
	}
	us = ustimer_get_duration(us0);
	rt_printf("at45DB321Write verify ok(us=%d)!\r\n",us);
		
	rt_printf("flash_test end!\r\n\n");
	
	return 0;
}

#endif

