/***************************************************
  This is a library for the GC9A01 IPS SPI display.

  Originally written by Limor Fried/Ladyada for 
  Adafruit Industries.

  Modified by Ananev Ilia
 ****************************************************/

#ifndef _ADAFRUIT_GC9A01H_
#define _ADAFRUIT_GC9A01H_

#include "Arduino.h"
#include "Print.h"
#include <Adafruit_GFX.h>

#if defined(__AVR__) || defined(CORE_TEENSY)
  #include <avr/pgmspace.h>
  #define USE_FAST_IO
  typedef volatile uint8_t RwReg;
#elif defined(ARDUINO_STM32_FEATHER)
  typedef volatile uint32 RwReg;
  #define USE_FAST_IO
#elif defined(ARDUINO_FEATHER52)
  typedef volatile uint32_t RwReg;
  #define USE_FAST_IO
#elif defined(ESP8266)
  #include <pgmspace.h>
#elif defined(__SAM3X8E__)
  #undef __FlashStringHelper::F(string_literal)
  #define F(string_literal) string_literal
  #include <include/pio.h>
  #define PROGMEM
  #define pgm_read_byte(addr) (*(const unsigned char *)(addr))
  #define pgm_read_word(addr) (*(const unsigned short *)(addr))
  typedef unsigned char prog_uchar;
#endif

#define GC9A01_TFTWIDTH 	240
#define GC9A01_TFTHEIGHT 	240

#define GC9A01_240x240_XSTART 0
#define GC9A01_240x240_YSTART 0

#define ST_CMD_DELAY   0x80    // special signifier for command lists

#define GC9A01_NOP     0x00
#define GC9A01_SWRESET 0x01
#define GC9A01_RDDID   0x04
#define GC9A01_RDDST   0x09

#define GC9A01_SLPIN   0x10
#define GC9A01_SLPOUT  0x11
#define GC9A01_PTLON   0x12
#define GC9A01_NORON   0x13

#define GC9A01_INVOFF  0x20
#define GC9A01_INVON   0x21
#define GC9A01_DISPOFF 0x28
#define GC9A01_DISPON  0x29
#define GC9A01_CASET   0x2A
#define GC9A01_RASET   0x2B
#define GC9A01_RAMWR   0x2C
#define GC9A01_RAMRD   0x2E

#define GC9A01_PTLAR   0x30
#define GC9A01_VSCRDEF 0x33  ///< Vertical Scrolling Definition
#define GC9A01_MADCTL 0x36   ///< Memory Access Control
#define GC9A01_VSCRSADD 0x37 ///< Vertical Scrolling Start Address
#define GC9A01_PIXFMT 0x3A   ///< COLMOD: Pixel Format Set
#define GC9A01_MADCTL  0x36

#define GC9A01_MADCTL_MY  0x80
#define GC9A01_MADCTL_MX  0x40
#define GC9A01_MADCTL_MV  0x20
#define GC9A01_MADCTL_ML  0x10
#define GC9A01_MADCTL_RGB 0x00

#define GC9A01_RDID1   0xDA
#define GC9A01_RDID2   0xDB
#define GC9A01_RDID3   0xDC
#define GC9A01_RDID4   0xDD

// Color definitions
// Color definitions
#define GC9A01_BLACK 0x0000       ///<   0,   0,   0
#define GC9A01_NAVY 0x000F        ///<   0,   0, 123
#define GC9A01_DARKGREEN 0x03E0   ///<   0, 125,   0
#define GC9A01_DARKCYAN 0x03EF    ///<   0, 125, 123
#define GC9A01_MAROON 0x7800      ///< 123,   0,   0
#define GC9A01_PURPLE 0x780F      ///< 123,   0, 123
#define GC9A01_OLIVE 0x7BE0       ///< 123, 125,   0
#define GC9A01_LIGHTGREY 0xC618   ///< 198, 195, 198
#define GC9A01_DARKGREY 0x7BEF    ///< 123, 125, 123
#define GC9A01_BLUE 0x001F        ///<   0,   0, 255
#define GC9A01_GREEN 0x07E0       ///<   0, 255,   0
#define GC9A01_CYAN 0x07FF        ///<   0, 255, 255
#define GC9A01_RED 0xF800         ///< 255,   0,   0
#define GC9A01_MAGENTA 0xF81F     ///< 255,   0, 255
#define GC9A01_YELLOW 0xFFE0      ///< 255, 255,   0
#define GC9A01_WHITE 0xFFFF       ///< 255, 255, 255
#define GC9A01_ORANGE 0xFD20      ///< 255, 165,   0
#define GC9A01_GREENYELLOW 0xAFE5 ///< 173, 255,  41
#define GC9A01_PINK 0xFC18        ///< 255, 130, 198

class Arduino_GC9A01 : public Adafruit_GFX {

 public:

  Arduino_GC9A01(int8_t DC, int8_t RST, int8_t SID, int8_t SCLK, int8_t CS = -1);
  Arduino_GC9A01(int8_t DC, int8_t RST, int8_t CS = -1);

  void     setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1),
           pushColor(uint16_t color),
           //fillScreen(uint16_t color),
           drawPixel(int16_t x, int16_t y, uint16_t color),
           drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color),
           drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color),
           fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color),
           setRotation(uint8_t r),
           invertDisplay(boolean i),
           init(uint16_t width, uint16_t height);
  uint16_t Color565(uint8_t r, uint8_t g, uint8_t b);
  uint16_t color565(uint8_t r, uint8_t g, uint8_t b) { return Color565(r, g, b); } 
  void    test();
 protected:
  uint8_t  _colstart, _rowstart, _xstart, _ystart; // some displays need this changed

  void     displayInit(const uint8_t *addr);
  void     spiwrite(uint8_t),
           writecommand(uint8_t c),
           writedata(uint8_t d),
           writedata16(uint16_t d),
           commonInit(const uint8_t *cmdList);

 private:

  inline void CS_HIGH(void);
  inline void CS_LOW(void);
  inline void DC_HIGH(void);
  inline void DC_LOW(void);

  boolean  _hwSPI;
  boolean  _SPI9bit;
  boolean  _DCbit;

  int8_t  _cs, _dc, _rst, _sid, _sclk;

#if defined(USE_FAST_IO)
  volatile RwReg  *dataport, *clkport, *csport, *dcport;

  #if defined(__AVR__) || defined(CORE_TEENSY)  // 8 bit!
    uint8_t  datapinmask, clkpinmask, cspinmask, dcpinmask;
  #else    // 32 bit!
    uint32_t  datapinmask, clkpinmask, cspinmask, dcpinmask;
  #endif
#endif

};

#endif
