/********************************SPI MEMORY*********************************
Данный файл содержит инклюды и дефайны для общения с FLASH/EEPROM по SPI.
***************************************************************************/
#ifndef __SPI_MEMORY_H_
#define __SPI_MEMORY_H_

#include "stm32f4xx_hal.h"

/////////////////////////---USER SETTINGS---/////////////////////////
//#define EXT_FLASH
#define EXT_EEPROM

#if defined(EXT_FLASH) & defined(EXT_EEPROM)
	#error Choose only one memory
#endif

//#define SEPARATED_STATUS_REGISTER



/////////////////////////////////////////////////////////////////////
////////////////////////////---DEFINES---////////////////////////////
/** 
	* @brief 	SPI Transmit.
	* @param 	_hmemspi_ - указатель на хендл внешней памяти.
	* @param 	_data_ 		- указатель на данные для отправки.
	* @param 	_size_ 		- размер данных для отправки.
	* @param 	_timeout_	- время, за которое должна быть осуществлена отправка.
	* @note 	Здесь вызывается только функция HAL, и ничего больше.
	*/
#define MEMSPI_SPI_Transmit(_hmemspi_, _data_, _size_, _timeout_)  HAL_SPI_Transmit(_hmemspi_->hspi, _data_, _size_, _timeout_)
/** 
	* @brief 	SPI Receive.
	* @param 	_hmemspi_ - указатель на хендл внешней памяти.
	* @param 	_data_ 		- указатель на буффер для прниема данных.
	* @param 	_size_ 		- размер данных для приема.
	* @param 	_timeout_	- время, за которое должен быть осуществлен прием.
	* @note 	Здесь вызывается только функция HAL, и ничего больше.
	*/
#define MEMSPI_SPI_Receive(_hmemspi_, _data_, _size_, _timeout_)  	HAL_SPI_Receive(_hmemspi_->hspi, _data_, _size_, _timeout_)

/**  
	* @brief 	Select MEMORY chip.
	*/
#define     MEMSPI_Select(_hmemspi_)    (_hmemspi_->CS_GPIOx->BSRR = _hmemspi_->CS_PIN << 16)
/**  
	* @brief 	Deselect MEMORY chip.
	*/
#define     MEMSPI_Deselect(_hmemspi_)  (_hmemspi_->CS_GPIOx->BSRR = _hmemspi_->CS_PIN)
#define     MEMSPI_SECTOR_SIZE          (0x1000)  ///< Размер одного сектора памяти (4096 байт)
#define     MEMSPI_PAGE_SIZE            (0x100)   ///< Размер одной страницы памяти (256 байт)

/** @defgroup MEMSPI_Commands Команды SPI-памяти
 *  @brief Определения команд SPI-памяти
 *  @{
 */
#define     MEMSPI_READ_JEDEC_ID        0x9F ///< Команда чтения JEDEC ID
#define     MEMSPI_READ_UNIQUE_ID       0x4B ///< Команда чтения уникального идентификатора
#define     MEMSPI_WRITE_ENABLE         0x06 ///< Разрешение записи
#define     MEMSPI_WRITE_DISABLE        0x04 ///< Запрещение записи
#define     MEMSPI_WRITE_STATUS_REG     0x01 ///< Запись в регистр состояния
#define     MEMSPI_ERASE_SECTOR         0x20 ///< Стирание одного сектора
#define     MEMSPI_PAGE_PROGRAM         0x02 ///< Программирование одной страницы
#define     MEMSPI_WRITE_EEPROM         MEMSPI_PAGE_PROGRAM ///< Псевдоним для программирования EEPROM
#define     MEMSPI_READ_STATUS_REG      0x05 ///< Чтение регистра состояния

#if defined(SEPARATED_STATUS_REGISTER)
#define     MEMSPI_READ_STATUS_REG_2    0x35 ///< Чтение второго регистра состояния (если поддерживается)
#endif

#define     MEMSPI_READ_DATA            0x03 ///< Чтение данных из памяти

/**  
	* @}
	*/
  
  
/** @defgroup MEMSPI_StatusFlags Флаги регистра состояния памяти
 *  @brief Определения битов регистра состояния памяти
 *  @{
 */
 
/**  
	* @brief 	Get Flag of Status Register
	*/
#define 		MEMSPI_Get_Flag(_hmemspi_,_flag_)		(((MEMSPI_StatusRegisterTypeDef)(_hmemspi_->SR))._flag_)

#define     MEMSPI_SR_SUS               (1<<15) ///< Suspend (приостановка операций)
#define     MEMSPI_SR_QE                (1<<9)  ///< Quad Enable (разрешение четырехпроводного интерфейса)
#define     MEMSPI_SR_SRP1              (1<<8)  ///< Status Register Protect 1
#define     MEMSPI_SR_SRP0              (1<<7)  ///< Status Register Protect 0 / SRWD
#define     MEMSPI_SR_SEC               (1<<6)  ///< Sector Protect (защита сектора)
#define     MEMSPI_SR_TB                (1<<5)  ///< Top/Bottom Protect
#define     MEMSPI_SR_BP2               (1<<4)  ///< Block Protect бит 2
#define     MEMSPI_SR_BP1               (1<<3)  ///< Block Protect бит 1
#define     MEMSPI_SR_BP0               (1<<2)  ///< Block Protect бит 0
#define     MEMSPI_SR_WEL               (1<<1)  ///< Write Enable Latch (бит разрешения записи)
#define     MEMSPI_SR_BUSY              (1<<0)  ///< Занято (операция в процессе выполнения)


// Exclusive (by name) EEPROM SR bits
#define     MEMSPI_SR_SRWD              MEMSPI_SR_SRP0 ///< Status Register Write Disable (аналог SRP0)
#define     MEMSPI_SR_WIP               MEMSPI_SR_WEL  ///< Write-In-Progress (используется в некоторых EEPROM)

/**  
	* @}
	*/

////////////////////////////---DEFINES---////////////////////////////


/////////////////////////////////////////////////////////////////////
///////////////////////---STRUCTURES & ENUMS---//////////////////////
/**
 * @brief Структура параметров инициализации записи в память MEMSPI.
 */
typedef struct
{
	uint8_t 	*pDataPtr;           ///< Указатель на буфер данных, которые будут записаны
	uint32_t 	Data_Address;        ///< Начальный адрес записи в памяти
	uint32_t 	Data_Size;           ///< Размер данных для записи в байтах
	
	uint32_t 	Sector_Address;      ///< Адрес начала сектора, в который будет производиться запись
	uint32_t 	Sector_Size;         ///< Размер сектора, который может быть затронут при записи

	unsigned 	fSavePrevoisData:1; ///< Флаг: сохранять ли предыдущие данные сектора (до стирания)
} MEMSPI_WriteInitTypeDef;

/**
 * @brief Основная структура управления MEMSPI.
 */
typedef struct
{
	uint16_t SR;                    ///< Регистра состояния микросхемы

	SPI_HandleTypeDef *hspi;        ///< Указатель на дескриптор SPI, используемый для обмена с памятью
	GPIO_TypeDef *CS_GPIOx;         ///< Порт GPIO для вывода управления CS (chip select)
	uint32_t CS_PIN;                ///< Номер вывода (пина) для CS

	uint32_t hNextAddr;             ///< Следующий адрес для автоматической записи/чтения
	uint16_t hNextPage;             ///< Следующая страница памяти
	uint16_t hNextSector;           ///< Следующий сектор памяти
} MEMSPI_HandleTypeDef;

///////////////////////---STRUCTURES & ENUMS---//////////////////////

/////////////////////////////////////////////////////////////////////
///////////////////////---FUNCTIONS FOR USER---//////////////////////
/* Initialize SPI and GPIO for MEMSPI FLASH */
void MEMSPI_Base_Init(MEMSPI_HandleTypeDef *hmemspi, SPI_HandleTypeDef *hspi);
/*	Read external FLASH */
HAL_StatusTypeDef MEMSPI_Read_Memory(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pBuff, uint16_t Size, uint32_t Timeout);
/* Write external EEPROM */
HAL_StatusTypeDef MEMSPI_EEPROM_Write(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pData, uint16_t Size, uint32_t Timeout, uint8_t WaitForEnd);
/* Write external FLASH */
HAL_StatusTypeDef MEMSPI_FLASH_Write(MEMSPI_HandleTypeDef *hmemspi, MEMSPI_WriteInitTypeDef *WriteInit, uint32_t Timeout, uint8_t WaitForEnd);
/* Program external FLASH */
HAL_StatusTypeDef MEMSPI_FLASH_Program(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pData, uint16_t Size, uint32_t Timeout, uint8_t WaitForEnd);
/* Erase external FLASH */
HAL_StatusTypeDef MEMSPI_FLASH_Erase(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint16_t Size, uint32_t Timeout, uint8_t WaitForEnd);
///////////////////////---FUNCTIONS FOR USER---//////////////////////

/////////////////////////////////////////////////////////////////////
////////////////////////---SERVICE FUNCTIONS---//////////////////////
/* Write page in external EEPROM */
HAL_StatusTypeDef MEMSPI_EEPROM_Write_Page(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pData, uint16_t Size, uint32_t *Timeout, uint32_t *tickstart, uint8_t WaitForEnd);
/* Erase external FLASH Sector */
HAL_StatusTypeDef MEMSPI_FLASH_Erase_Sector(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint32_t *Timeout, uint32_t *tickstart, uint8_t WaitForEnd);
/* Program page in external FLASH */
HAL_StatusTypeDef MEMSPI_FLASH_Program_Page(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pData, uint16_t Size, uint32_t *Timeout, uint32_t *tickstart, uint8_t WaitForEnd);
/* Setting WEL bit until it setted or until timeout */
HAL_StatusTypeDef MEMSPI_WriteEnablingUntilTimeout(MEMSPI_HandleTypeDef *hmemspi, uint32_t *Timeout, uint32_t *tickstart);
/* Wait for flag until timeout */
HAL_StatusTypeDef MEMSPI_WaitOnFlagsUntilTimeout(MEMSPI_HandleTypeDef *hmemspi, uint16_t FlagMask, uint16_t FlagStatus, uint32_t *Timeout, uint32_t *tickstart);
/* Update Timeout variables */
void MEMSPI_Update_Timeout_Variables(uint32_t *Timeout, uint32_t *tickstart);
////////////////////////---SERVICE FUNCTIONS---//////////////////////

/////////////////////////////////////////////////////////////////////
//////////////////////---FUNCTION FOR COMMAND---/////////////////////
/* Send command to read Status Register */
HAL_StatusTypeDef MEMSPI_CMD_Read_Status_Register(MEMSPI_HandleTypeDef *hmemspi, uint16_t RequestedBits, uint8_t EndCMD, uint32_t Timeout);
/* Send command to write bits in Status Register */
HAL_StatusTypeDef MEMSPI_CMD_Write_Status_Register(MEMSPI_HandleTypeDef *hmemspi, uint16_t WrittenBits, uint32_t Timeout);
/* Send command to set Write Enable Latch (WEL) in Status Register */
HAL_StatusTypeDef MEMSPI_CMD_Write_Enable(MEMSPI_HandleTypeDef *hmemspi, uint32_t Timeout);
/* Send command to read data from FLASH/EEPROM */
HAL_StatusTypeDef MEMSPI_CMD_Read_Data(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pBuff, uint16_t Size, uint32_t Timeout);
/* Send command to write eeprom */
HAL_StatusTypeDef MEMSPI_CMD_EEPROM_Write(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pData, uint16_t Size, uint32_t Timeout);
/*	Send command to page program in FLASH */
HAL_StatusTypeDef MEMSPI_CMD_FLASH_Page_Program(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pData, uint16_t Size, uint32_t Timeout);
/* Send command to erase sector of FLASH */
HAL_StatusTypeDef MEMSPI_CMD_FLASH_Erase_Sector(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint32_t Timeout);
/* Send command to read JEDEC ID */
uint32_t MEMSPI_CMD_Read_JEDEC_ID(MEMSPI_HandleTypeDef *hmemspi, uint32_t Timeout);
/* Send command to read JEDEC ID */
uint64_t MEMSPI_CMD_Read_Device_ID(MEMSPI_HandleTypeDef *hmemspi, uint32_t Timeout);
/*Send command to fast read data from FLASH */
HAL_StatusTypeDef MEMSPI_CMD_Fast_Read(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pBuff, uint16_t Size, uint32_t Timeout);
//////////////////////---FUNCTION FOR COMMAND---/////////////////////


#endif // __SPI_MEMORY_H_