#define MyLib_W32X16_GLOBALS

/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx.h"
#include "MyLib_w32x16.h"
#include "MyLib_w32x16aux.h"


#define MyLib_W25X_ReadStatus       0x05		//读状态寄存器
#define MyLib_W25X_WriteStatus      0x01		//写状态寄存器
#define MyLib_W25X_ReadDATA8        0x03		//普读_数据
#define MyLib_W25X_FastRead         0x0B		//快读_数据
#define MyLib_W25X_DualOutput       0x3B		//快读_双输出
#define MyLib_W25X_Write            0x02		//写_数据_0~255个字节
#define MyLib_W25X_S_Erase          0x20		//扇区擦除4KB
#define MyLib_W25X_B_Erase          0xD8		//块区擦除64KB
#define MyLib_W25X_C_Erase          0xC7		//整片格式化
#define MyLib_W25X_PowerDown        0xB9		//待机
#define MyLib_W25X_PowerON_ID       0xAB		//开机或是读ID
#define MyLib_W25X_JEDEC_ID         0x9F		//十六位的JEDEC_ID
#define MyLib_W25X_WriteEnable      0x06		//写充许
#define MyLib_W25X_WriteDisable     0x04		//写禁止


#define MyLib_W25X_BUSY             0x01		//FLASH忙
#define MyLib_W25X_NotBUSY          0x00		//FLASH闲

unsigned char LibKeep(unsigned char i) {return i;}		//保留，不能改变

unsigned long Flash_Erase_Delay;
unsigned char Flash_Erase_Flag=0;

//***************SPI延时函数********************************
void Delay_SPI(unsigned long i)
{
    unsigned long j;
    for(j=0;j<100;j++)
    {
        while(i) i--;
    }
	}
//***************判BUSY********************************
unsigned char MyLib_W25X_BUSY_OrNot (SPI_TypeDef * SPI) //在读和写之前得先判断FLASH是否BUSY
{				         //BUSY的原因是擦除，或是连续读写
	unsigned long k;          //如果没有以上方式，不必判定可以写读  
	/* Loop while DR register in not emplty */
	while((SPI->SR & 0x0002) == (uint16_t)0);
	MyLib_CS_Flash_L();
	MyLib_Send_Byte(SPI,MyLib_W25X_ReadStatus);  //读状态寄存器
	k=MyLib_Get_Byte(SPI);  //读一个字节
	k=k&0x01;
	MyLib_CS_Flash_H();
	if(k)return (MyLib_W25X_BUSY);
	else return (MyLib_W25X_NotBUSY);
}	//end of check BUSY


//***********************************************

unsigned long MyLib_W32X_Flash_Id_Read (SPI_TypeDef * SPI)  //从Flash里读出小于256字节数
{
	unsigned long k;	 //计字节数
	unsigned long i;
	
	while(MyLib_W25X_BUSY_OrNot (SPI));  //判BUSY	  
	
	MyLib_CS_Flash_L();
	
	MyLib_Send_Byte(SPI,MyLib_W25X_JEDEC_ID);//命令读
	
	k=MyLib_Get_Byte(SPI);  //读一个字节
	
	i=k;
	i=(i<<8);
	k=MyLib_Get_Byte(SPI);  //读一个字节
	i=i+k;
	i=(i<<8);
	k=MyLib_Get_Byte(SPI);  //读一个字节
	i=i+k;
	MyLib_CS_Flash_H();
	return i;
}	
//*************** 写允许 ****************************  OK
void MyLib_WriteEnable  (SPI_TypeDef * SPI)
{
	MyLib_CS_Flash_L();
	MyLib_Send_Byte(SPI,MyLib_W25X_WriteEnable);  
	MyLib_CS_Flash_H();
}
//**************片擦除 (MAX_80S)****************** OK
void MyLib_W32X_ChipErase(SPI_TypeDef * SPI)
{
	MyLib_WriteEnable(SPI);   //写允许
	MyLib_CS_Flash_L();
	MyLib_Send_Byte(SPI,MyLib_W25X_C_Erase);//整片擦除命令
	MyLib_CS_Flash_H();	  //从CS=1时开始执行擦除 
}

//***********************************************

void MyLib_W32X_Flash_Byte_Read(SPI_TypeDef * SPI,unsigned long Addre24,unsigned char *Dest,unsigned long Quantity)  //从Flash里读出
{
	unsigned long J;	 //计字节数
	unsigned char Addre3;
	unsigned char Addre2;
	unsigned char Addre1;
	unsigned char *ljmcu_p; 
	
	while(MyLib_W25X_BUSY_OrNot (SPI));
	ljmcu_p=(unsigned char *)0x1FFFF7E0;   //指针初值
	Addre1=Addre24;
	ljmcu_p=ljmcu_p+8;					   //指针的简单计算。
	Addre24=Addre24>>LibKeep(8);
	Addre2=Addre24;
	Addre24=Addre24>>8;
	Addre3=Addre24;		 //把地址拆开来
	if(LibKeep(5)==0x05)
	{
		MyLib_CS_Flash_L();
	}
	MyLib_Send_Byte(SPI,MyLib_W25X_ReadDATA8);//命令读
	MyLib_Send_Byte(SPI,Addre3);
	MyLib_Send_Byte(SPI,Addre2);
	MyLib_Send_Byte(SPI,Addre1);
	
	for (J=0;J<Quantity;J++)
	{
		*Dest=MyLib_Get_Byte(SPI);	 //读一个字节
		Dest++;
	}
	
	MyLib_CS_Flash_H();
}	  //读FLASH结束


void MyLib_W32X_Flash_Byte_Write(SPI_TypeDef * SPI,unsigned long Addre24,unsigned char *Src,unsigned long Quantity)    //往FLASH里写一个或多个字节(小于255)
{						 //连续写的时候，地址最后八位必须从00开始写		 *如果256个字节都读满或写满，三字节地址最后一个字节必须为0*
	unsigned char Addre3;	 //否则当地址越过分面时，会从本页的00从新开始，造成错写
	unsigned char Addre2;	 //
	unsigned char Addre1;
	unsigned long J;   //计字节数
	unsigned long Addre24temp=Addre24;
	unsigned long QuantityL;
	unsigned long temp;
	
	unsigned char *ljmcu_p; 
	
	while(MyLib_W25X_BUSY_OrNot (SPI));
	ljmcu_p=(unsigned char *)0x1FFFF7E1;   //指针初值
	Addre1=Addre24;
	ljmcu_p=ljmcu_p+7;
	Addre24=Addre24>>LibKeep(8);
	Addre2=Addre24;
	Addre24=Addre24>>8;
	Addre3=Addre24;  //把地址拆开来，高
	temp=Addre1+Quantity;
	if(temp>256) 
	{
		QuantityL=256-Addre1;
		Quantity=Quantity-QuantityL;
	}
	else
	{
		QuantityL=Quantity;
		Quantity=0;
	}
	MyLib_WriteEnable(SPI);   //写允许
	MyLib_CS_Flash_L();
	MyLib_Send_Byte(SPI,MyLib_W25X_Write);  //命令
	MyLib_Send_Byte(SPI,Addre3);
	MyLib_Send_Byte(SPI,Addre2);
	MyLib_Send_Byte(SPI,Addre1);
	
	for (J=0;J<QuantityL;J++)
	{
		MyLib_Send_Byte(SPI,*Src); //写字节
		Src++;
	}
	MyLib_CS_Flash_H();
	
	if(Quantity==0) return;
	while(MyLib_W25X_BUSY_OrNot (SPI));  //判BUSY	等到Flash闲才能操作
	Addre24temp=Addre24temp&0xffffff00;
	Addre24temp=Addre24temp+0x100;
	Addre24=Addre24temp;
	
	Addre1=Addre24;  //低
	Addre24=Addre24>>8;
	Addre2=Addre24;
	Addre24=Addre24>>8;
	Addre3=Addre24;  //把地址拆开来，高
	MyLib_WriteEnable(SPI);   //写允许
	MyLib_CS_Flash_L();
	MyLib_Send_Byte(SPI,MyLib_W25X_Write);  //命令
	MyLib_Send_Byte(SPI,Addre3);
	MyLib_Send_Byte(SPI,Addre2);
	MyLib_Send_Byte(SPI,Addre1);
	
	for (J=0;J<Quantity;J++)
	{
		MyLib_Send_Byte(SPI,*Src); //写字节
		Src++;
	}
	MyLib_CS_Flash_H();
}	 //写FLASH结束

//*************** 4K扇擦除************************ OK
void MyLib_W32X_SectorErase(SPI_TypeDef * SPI,unsigned long Addre24)	//擦除资料图示的4KB空间
{
	//判BUSY或许放这里
	unsigned char Addre3;
	unsigned char Addre2;
	unsigned char Addre1;
	
	while(MyLib_W25X_BUSY_OrNot (SPI));  //判BUSY	等到Flash闲才能操作
	MyLib_WriteEnable(SPI);   //写允许
	Addre1=Addre24;
	Addre24=Addre24>>8;
	Addre2=Addre24;
	Addre24=Addre24>>8;
	Addre3=Addre24;		 //把地址拆开来
	
	MyLib_CS_Flash_L();
	MyLib_Send_Byte(SPI,MyLib_W25X_S_Erase);//整扇擦除命令
	MyLib_Send_Byte(SPI,Addre3);
	MyLib_Send_Byte(SPI,Addre2);
	MyLib_Send_Byte(SPI,Addre1);
	MyLib_CS_Flash_H();

}

unsigned char save_temp[4100];
bool MyLib_W32X_Flash_Byte_Write_check(SPI_TypeDef * SPI,unsigned long Addre24,unsigned char *Src,unsigned long Quantity)
{
	unsigned char read_check[256];
	unsigned char i,k,check_flag;
	unsigned char j;
//	unsigned long whpoing[2];

	check_flag = 0;

	MyLib_W32X_Flash_Byte_Write(SPI,Addre24,Src,Quantity);
	
	Delay_SPI(5);

	MyLib_W32X_Flash_Byte_Read(SPI,Addre24,read_check,Quantity);

	for(i=0;i<Quantity;i++)								//当检测到一个数据跟保存的数据不一样的话，则check_flag = 0x55; 然后跳出循环
	{
		if(read_check[i] != (*(Src+i)))
		{
			check_flag = 0x55;
			break;
		}
	}

	if(check_flag == 0x55)								//如果check_flag==0x55，表示保存失败
	{
		j = Addre24/0x1000;								//求出数据所在扇区

//		MyLib_W32X_Flash_Byte_Read(SPI,Item_Adrr,(unsigned char *)&whpoing[0],8);		//读出需要保存的数据的索引 
		
//		k = whpoing[0]%128;																//求出需要保存数据在扇区中的索引,一个扇区有128条数据4096/32=128

		k = Addre24%0x1000;																//通过地址，求出需要保存的数据在扇区中的索引
		k = k/32;

		MyLib_W32X_Flash_Byte_Read(SPI,j*0x1000,(unsigned char *)save_temp,0x1000);		//读出所在扇区的所有数据

		for(i=0;i<32;i++)
			save_temp[k*32+i] = (*(Src+i));													//将需要保存的数据替换到列表中

		MyLib_W32X_SectorErase(SPI,j*0x1000);											//擦除扇区

		for(i=0;i<16;i++)
			MyLib_W32X_Flash_Byte_Write(SPI,j*0x1000+i*256,(unsigned char *)&save_temp[i*256],256);		//保存整个扇区的数据*/
	
		check_flag = 0;
	}
	else 
		return TRUE;

	Delay_SPI(5);

	MyLib_W32X_Flash_Byte_Read(SPI,Addre24,read_check,Quantity);

	for(i=0;i<Quantity;i++)								//当检测到一个数据跟保存的数据不一样的话，则check_flag = 0x55; 然后跳出循环
	{
		if(read_check[i] != (*(Src+i)))
		{
			check_flag = 0x55;
			break;
		}
	}

	if(check_flag == 0x55)								//保存错误返回false
		return FALSE;
	else												//保存正确返回true
		return TRUE;
}


void Flash_Init_Check(void)
{
	unsigned char checkwords[8];
	unsigned char i,j,check_failed;
	
	check_failed = 0;
	Flash_Erase_Flag=0;

	for(j=0;j<1;j++)																	//初始化检查两遍
	{
		MyLib_W32X_Flash_Byte_Read(W32X16,Flash_Check_Adrr,checkwords,8);	  //读初始化字节0x55 0xaa 0x55 0xaa 0x55 0xaa 0x55 0xaa 
		
		for(i=0;i<4;i++)
		{
			if((checkwords[2*i] != 0x55) || (checkwords[2*i+1] != 0xaa))
			{
				check_failed = 0x55;																										
				break;
			}	
		}
		
		if(check_failed == 0)														//如何第一次检查正确，则直接退出，如果第一次检查失败，则再检查一次
			break;
	}
	
	if(check_failed == 0x55)
	{
		MyLib_W32X_ChipErase(W32X16);	
		Flash_Erase_Delay = 201000;	
    Flash_Erase_Flag = 0x55;
		check_failed = 0;		
	}

}

