#ifndef _GRAPHIC_DISPLAY_ILI9341_H_
#define _GRAPHIC_DISPLAY_ILI9341_H_
//----------------------------------------------------------------------------
///
/// \brief  Display Eleltronik Display
///
///         See implementation files for further information.
///
/// \date   20181027
/// \author Maximilian Seesslen <mes@seesslen.net>
///
//----------------------------------------------------------------------------


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


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

#include <biwak/output.hpp>
#include <biwak/gdisplay.h>
#include <biwak/spi_slave.h>
#if ! defined( STM32 )
   #include <biwak/linux/gdisplay_qt.h>
#endif

class CSpi;


//---Defines------------------------------------------------------------------


#define NH_CS_ACTIVE       false
#define NH_CS_INACTIVE     true
#define NH_DC_INSTRUCTION  false
#define NH_DC_DATA         true

//#define DEM_CS_ON_DELAY    100
//#define DEM_CS_OFF_DELAY   100

// Tested 0 on candis-eval, STM32G441
#define DEM_CS_ON_DELAY       0
#define DEM_CS_OFF_DELAY      0
#define DEM_COMMAND_ON_DELAY  0
#define DEM_COMMAND_OFF_DELAY 0

#define DEM_ID             0x70
#define DEM_DATA           0x2
#define DEM_READ           0x1
#define DEM_WRITE          0x0
#define DEM_BUSY_DELAY     0


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


class CIli9341Dimpl;

class CGraphicDisplayIli9341
         #if defined( STM32 )
         :public CGraphicDisplay
         #else
         :public CGraphicDisplayQt
         #endif
         ,public CSpiSlave
{

   private:
      #if ! defined( STM32 )
         CIli9341Dimpl *m_pDimpl;
      #endif
   
      enum class DataMode: bool
      {
         Command=true,
         Data=false,
      };

      CSpi &m_spi;
      //COutput m_outCs;
      COutput m_outDc;
      //CSpiSlave m_cs;
      //int m_holdCs;
      DataMode m_dataMode=DataMode::Data;

      inline void setDataMode( DataMode dataMode )
      {
         if( m_dataMode == dataMode )
         {
            return;
         }

         m_outDc.setValue( ( dataMode == DataMode::Command ) ? NH_DC_INSTRUCTION : NH_DC_DATA );
         usleep( ( dataMode == DataMode::Command ) ? DEM_COMMAND_ON_DELAY : DEM_COMMAND_OFF_DELAY );

         m_dataMode=dataMode;
      }

   public:
         int counter;
         enum class IliCommand: uint8_t;

      typedef struct
      {
         //uint8_t     command, len;
         uint8_t     command, data;
         //uint8_t     data[4];
      } TCommandData;

      CGraphicDisplayIli9341( CSpi &_spi,
            EGpioPeripheral eGpioPeripheralCs, EGpioPin eGpioPinCs,
            EGpioPeripheral eGpioPeripheralDc, EGpioPin eGpioPinDc
            );
      ~CGraphicDisplayIli9341();
#if defined STM32
      void init();
      void reset();

      void writeCommand (const IliCommand command);
      void writeCommands ( const CGraphicDisplayIli9341::IliCommand* command, int count);
      void writeCommand (const IliCommand command, const char param);
      void setPageAddress (int start, int end);
      void setColumnAddress (int start, int end);
      void writeData ( const uint32_t data, int count=1 );
      //void writeData16 (const uint16_t data);

      /*
      void enableCs()
      {
         if(m_holdCs)
            return;

         outCs.setValue(NH_CS_ACTIVE);

         if(DEM_CS_ON_DELAY)
            usleep(DEM_CS_ON_DELAY);
      }
      void disableCs()
      {
         if(m_holdCs)
            return;

         outCs.setValue(NH_CS_INACTIVE);
         if(DEM_CS_OFF_DELAY)
            usleep(DEM_CS_OFF_DELAY);
      }
      void holdCs()
      {
         if(!m_holdCs)
         {
            enableCs();
         }
         m_holdCs++;
         return;
      }
      void releaseCs()
      {
         m_holdCs--;

         if(!m_holdCs)
         {
            disableCs();
         }
         return;
      }
      */
      void clear();

      void setWindow(int x1, int y1, int x2, int y2);

      void drawMatrix(int x, int y, const char *matrix);
      void clear(TRgb color);
   
      virtual void drawPixel( const TRgb color ) override;
      virtual void gotoxyHw() override;
      virtual void setFrame(int x1, int y1, int x2, int y2) override;

      void initSize();
      void setFg( TRgb color ){ fg = color; };
      void setBg( TRgb color ){ bg = color; };
      void setDrawBackground(bool _drawBackground)
      {
         drawBackground=_drawBackground;
      }

      virtual bool setRotation(bool rot) override;
      virtual void drawPixels( const TRgb *pixels, int count) override;
      virtual void pixelStreamStart() override;
      virtual void pixelStreamStop() override;

      void directDrawPixel(int x, int y, const TRgb &color )
      {
         CGraphicDisplayIli9341::setFrame(x, y, x, y);
         CGraphicDisplayIli9341::drawPixel( color );
      }
      #endif
};


//---fin----------------------------------------------------------------------
#endif // ? ! _GRAPHIC_DISPLAY_ILI9341_H_
