#ifndef _FLASH_SPI_H_
#define _FLASH_SPI_H_
//----------------------------------------------------------------------------
///
/// \brief  Generic spi flash
///
///         See implementation files for further information.
///      https://www.tme.eu/Document/7080d3aeec3464c7fd84a2ef65cc1f9c/gd25lq16.pdf
///
/// \date   20160716
/// \author Maximilian Seesslen <mes@seesslen.net>
///
//----------------------------------------------------------------------------


//---Includes-----------------------------------------------------------------


//---Own------------------------------

#include <biwak/spi_slave.h>
#include <biwak/flash.h>

//---Declaration--------------------------------------------------------------


#define CFI_INS_READJID       0x9Ful
#define CFI_INS_READID        0x90ul   // or AB on SST
//#define CFI_INS_ERASE         0xD7ul
#define CFI_INS_READ_STATUS   0x05ul
#define CFI_INS_READ_ERP      0x81ul
#define CFI_INS_READ          0x03ul
#define CFI_INS_READ_HS       0x0Bul
#define CFI_BYTE_PROGRAMM     0x02ul
#define CFI_PAGE_PROGRAMM     0x02ul
// Are there chips where it is 0xAD?
#define CFI_AAI_PROGRAMM         0xAFul  // Auto Address Increment(AAI) Program
#define CFI_AAI_PROGRAMM_WORD    0xADul
#define CFI_INS_ENABLE_WRITE  0x06ul
#define CFI_INS_WRDI          0x04ul      // Write disable
#define CFI_INS_DBSY          0x80ul

#define INS_ENABLE_WRITE_STATUS  0x50ul
#define INS_WRITE_STATUS         0x01ul
#define INS_DEEP_POWER_DOWN      0xB9
#define INS_WAKE_UP              0xAB

#define INS_ERASE_SECTOR      0x20ul
#define INS_ERASE_CHIP        0x60ul

#define PAGE_SIZE             0x100    // 256
#define SECTOR_SIZE           0x1000   // 4K
#define BUSY_DELAY            0

struct __attribute__((packed)) SCommandStatus
{
   uint8_t instruction;
   uint8_t status;
};

struct __attribute__((packed)) SCommandWord
{
   uint8_t instruction;
   uint16_t data;
};

struct __attribute__((packed)) SCommandByte
{
   uint8_t instruction;
   uint16_t data;
};

struct __attribute__((packed)) SCommandAddress
{
   union{
      uint8_t instruction;
      uint32_t addr;
   };
   uint8_t data[2];
};


class CFlashSpi
        :public CFlash
        #if defined( STM32 )
        ,public CSpiSlave
        #endif
{
   public:
      enum class EWriteMode
      {
         aaiByte,
         aaiWord,
         byte,
         page,
      };

      //int m_size{};
      //int m_eraseSize=0;
      int m_vendor;
      uint32_t m_jdecId{};

      EWriteMode m_writeMode = EWriteMode::page;

      void io( uint8_t *out_in, int len);
      int io_wr( const uint8_t *out, int outlen, uint8_t *in, int inlen);
      void io_ww( const uint8_t *out1, int out1len, const  uint8_t *out2, int out2len);

      #if ! defined( STM32 )
      //QFile
      #endif

   public:

      CFlashSpi( CSpi &_spi, EGpioPeripheral eGpioPeripheralCS, EGpioPin eGpioPinCS );
      CFlashSpi( );
      
      ~CFlashSpi();
      int readId();
      int readJId();
      int size()
      {
         return(m_size);
      }
      int vendor()
      {
         return(m_vendor);
      }

      virtual int erasePage(address_t addr, int count=1) override;
      /*
      virtual int erasePageSize() const override
      {
         return(m_eraseSize);
      }
      */
      virtual int readData(address_t addr, void *data, int size) override;
      virtual int writeData(address_t addr, const void *data, int size) override;

      int readErp();
      int readSta();
      int waitForReady();
      int writeWord(int addr, const uint8_t *data, int size);
      int writePage(int addr, const void *data, int size);
      int _writeAai(int addr, const void *data, int size);
      int writeByte(int addr, uint8_t data);
      int eraseChip();
      int enableWrite();
      int unlock();
      int sectorCount()
      {
         return( m_size / m_erasePageSize );
      }
      void deepPowerDown();
      void wakeUp();
      bool isValid()
      {
         return( m_jdecId != 0 );
      }
};


//---fin----------------------------------------------------------------------
#endif // ? ! _FLASH_SPI_H_
