#ifdef USE_W25QXX_SPI

#ifndef OBJ_SPI_W25QXX_H
#define OBJ_SPI_W25QXX_H

#include <stdbool.h>
#include "stm32f7xx_hal.h"
#include "stm32f7xx_hal_spi.h"


#define SPIx                             SPI2
#define SPIx_CLK_ENABLE()                __HAL_RCC_SPI2_CLK_ENABLE()
#define SPIx_SCK_GPIO_CLK_ENABLE()       __HAL_RCC_GPIOB_CLK_ENABLE()
#define SPIx_MISO_GPIO_CLK_ENABLE()      __HAL_RCC_GPIOB_CLK_ENABLE() 
#define SPIx_MOSI_GPIO_CLK_ENABLE()      __HAL_RCC_GPIOB_CLK_ENABLE() 
#define SPIx_CS_GPIO_CLK_ENABLE()        __HAL_RCC_GPIOD_CLK_ENABLE() 

#define SPIx_FORCE_RESET()               __HAL_RCC_SPI2_FORCE_RESET()
#define SPIx_RELEASE_RESET()             __HAL_RCC_SPI2_RELEASE_RESET()

/* Definition for SPIx Pins */
#define SPIx_SCK_PIN                   GPIO_PIN_13
#define SPIx_SCK_GPIO_PORT             GPIOB

#define SPIx_MISO_PIN                  GPIO_PIN_14
#define SPIx_MISO_GPIO_PORT            GPIOB

#define SPIx_MOSI_PIN                  GPIO_PIN_15
#define SPIx_MOSI_GPIO_PORT            GPIOB

#define	_W25QXX_SPI										hspi_w25q
#if 0
#define	_W25QXX_CS_GPIO								GPIOD					
#define	_W25QXX_CS_PIN								GPIO_PIN_8
#else
#define	_W25QXX_CS_GPIO								GPIOB					
#define	_W25QXX_CS_PIN								GPIO_PIN_12
#endif
#define	_W25QXX_USE_FREERTOS					0
#define	_W25QXX_DEBUG									0

#define W25QXX_CS_HIGH()							{HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_SET);\
																			 delay_us(1);}while(0);
#define W25QXX_CS_LOW()								HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_RESET)

typedef enum
{
	ID_W25Q10	=	1,
	ID_W25Q20,
	ID_W25Q40,
	ID_W25Q80,
	ID_W25Q16,
	ID_W25Q32,
	ID_W25Q64,
	ID_W25Q128,
	ID_W25Q256,
	ID_W25Q512,
	
}W25QXX_ID_t;

typedef struct
{
	W25QXX_ID_t	ID;
	uint8_t			UniqID[8];

	uint16_t    PageSize;
	uint32_t		PageCount;
	uint32_t		SectorSize;
	uint32_t		SectorCount;
	uint32_t		BlockSize;
	uint32_t		BlockCount; // so block trong chip flash

	uint32_t		CapacityInKiloByte;
	
	uint8_t	StatusRegister1;
	uint8_t	StatusRegister2;
	uint8_t	StatusRegister3;
	
	uint8_t	Lock;
	
}w25qxx_t;

extern SPI_HandleTypeDef _W25QXX_SPI;
extern w25qxx_t	w25qxx;

//############################################################################
// in Page,Sector and block read/write functions, can put 0 to read maximum bytes 
//############################################################################

bool	W25qxx_Init(void);
void  W25qxx_Cs_Init(void);
void  W25qxx_Spi_Init(void);

uint32_t  W25qxx_ReadID(void);

// BLOCK > SECTOR , w25q128 => 16 sector = 1 block
void	W25qxx_EraseChip(void);
void 	W25qxx_EraseSector(uint32_t SectorAddr);
void 	W25qxx_EraseBlock(uint32_t BlockAddr);


// tra ve so page trong 1 sector, so page trong 1 block.....
uint32_t	W25qxx_PageToSector(uint32_t	PageAddress);
uint32_t	W25qxx_PageToBlock(uint32_t	PageAddress);
uint32_t	W25qxx_SectorToBlock(uint32_t	SectorAddress);
uint32_t	W25qxx_SectorToPage(uint32_t	SectorAddress);
uint32_t	W25qxx_BlockToPage(uint32_t	BlockAddress);


// kiem tra bo nho co con trong khong, neu con trong có the ghi data vao
// offset_in_byte byte bat dau ghi
// numbyte_to_checkup => so byte can check, ghi trong page/sector/block
bool 	W25qxx_IsEmptyPage(uint32_t Page_Address,uint32_t OffsetInByte,uint32_t NumByteToCheck_up_to_PageSize);
bool 	W25qxx_IsEmptySector(uint32_t Sector_Address,uint32_t OffsetInByte,uint32_t NumByteToCheck_up_to_SectorSize);
bool 	W25qxx_IsEmptyBlock(uint32_t Block_Address,uint32_t OffsetInByte,uint32_t NumByteToCheck_up_to_BlockSize);



void 	W25qxx_WriteByte(uint8_t pBuffer,uint32_t Bytes_Address);
void 	W25qxx_WritePage(uint8_t *pBuffer	,uint32_t Page_Address,uint32_t OffsetInByte,uint32_t NumByteToWrite_up_to_PageSize);
void 	W25qxx_WriteSector(uint8_t *pBuffer,uint32_t Sector_Address,uint32_t OffsetInByte,uint32_t NumByteToWrite_up_to_SectorSize);
void 	W25qxx_WriteBlock(uint8_t* pBuffer,uint32_t Block_Address,uint32_t OffsetInByte,uint32_t NumByteToWrite_up_to_BlockSize);

void 	W25qxx_ReadByte(uint8_t *pBuffer,uint32_t Bytes_Address);
void 	W25qxx_ReadBytes(uint8_t *pBuffer,uint32_t ReadAddr,uint32_t NumByteToRead);
void 	W25qxx_ReadPage(uint8_t *pBuffer,uint32_t Page_Address,uint32_t OffsetInByte,uint32_t NumByteToRead_up_to_PageSize);
void 	W25qxx_ReadSector(uint8_t *pBuffer,uint32_t Sector_Address,uint32_t OffsetInByte,uint32_t NumByteToRead_up_to_SectorSize);
void 	W25qxx_ReadBlock(uint8_t* pBuffer,uint32_t Block_Address,uint32_t OffsetInByte,uint32_t	NumByteToRead_up_to_BlockSize);
//############################################################################



#endif //----------------------OBJ_SPI_W25QXX_H-----------------------------//

#endif //----------------------USE_W25QXX_SPI-------------------------------//
