/*************************************************** 
  www.buydisplay.com
 ****************************************************/

#include "TFTM022-3.h"
#include <avr/pgmspace.h>
#include <limits.h>
#include "pins_arduino.h"
#include "wiring_private.h"
#include <SPI.h>

// Constructor when using software SPI.  All output pins are configurable.
NV3006::NV3006(int8_t cs, int8_t dc, int8_t mosi,
				   int8_t sclk, int8_t rst) : ERGFX(NV3006_TFTWIDTH, NV3006_TFTHEIGHT) {
  _cs   = cs;
  _dc   = dc;
  _mosi  = mosi;
  _sclk = sclk;
  _rst  = rst;
  hwSPI = false;
}


// Constructor when using hardware SPI.  Faster, but must use SPI pins
// specific to each board type (e.g. 11,13 for Uno, 51,52 for Mega, etc.)
NV3006::NV3006(int8_t cs, int8_t dc, int8_t rst) : ERGFX(NV3006_TFTWIDTH, NV3006_TFTHEIGHT) {
  _cs   = cs;
  _dc   = dc;
  _rst  = rst;
  hwSPI = true;
  _mosi  = _sclk = 0;
}

void NV3006::spiwrite(uint8_t c) {

  //Serial.print("0x"); Serial.print(c, HEX); Serial.print(", ");

  if (hwSPI) {
#if defined (__AVR__)
      uint8_t backupSPCR = SPCR;
    SPCR = mySPCR;
    SPDR = c;
    while(!(SPSR & _BV(SPIF)));
    SPCR = backupSPCR;
#elif defined(TEENSYDUINO)
    SPI.transfer(c);
#elif defined (__arm__)
    SPI.setClockDivider(11); // 8-ish MHz (full! speed!)
    SPI.setBitOrder(MSBFIRST);
    SPI.setDataMode(SPI_MODE0);
    SPI.transfer(c);
#endif
  } else {
    // Fast SPI bitbang swiped from LPD8806 library
    for(uint8_t bit = 0x80; bit; bit >>= 1) {
      if(c & bit) {
	//digitalWrite(_mosi, HIGH); 
	*mosiport |=  mosipinmask;
      } else {
	//digitalWrite(_mosi, LOW); 
	*mosiport &= ~mosipinmask;
      }
      //digitalWrite(_sclk, LOW);
      *clkport &= ~clkpinmask;
       //digitalWrite(_sclk, HIGH);
      *clkport |=  clkpinmask;
    }
  }
}


void NV3006::writecommand(uint8_t c) {
  *dcport &=  ~dcpinmask;
  //digitalWrite(_dc, LOW);
  //*clkport &= ~clkpinmask; // clkport is a NULL pointer when hwSPI==true
  //digitalWrite(_sclk, LOW);
  *csport &= ~cspinmask;
  //digitalWrite(_cs, LOW);

  spiwrite(c);

  *csport |= cspinmask;
  //digitalWrite(_cs, HIGH);
}


void NV3006::writedata(uint8_t c) {
  *dcport |=  dcpinmask;
  //digitalWrite(_dc, HIGH);
  //*clkport &= ~clkpinmask; // clkport is a NULL pointer when hwSPI==true
  //digitalWrite(_sclk, LOW);
  *csport &= ~cspinmask;
  //digitalWrite(_cs, LOW);
  
  spiwrite(c);

  //digitalWrite(_cs, HIGH);
  *csport |= cspinmask;
} 

// If the SPI library has transaction support, these functions
// establish settings and protect from interference from other
// libraries.  Otherwise, they simply do nothing.
#ifdef SPI_HAS_TRANSACTION
static inline void spi_begin(void) __attribute__((always_inline));
static inline void spi_begin(void) {
  SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0));
}
static inline void spi_end(void) __attribute__((always_inline));
static inline void spi_end(void) {
  SPI.endTransaction();
}
#else
#define spi_begin()
#define spi_end()
#endif


void NV3006::begin(void) {
  if (_rst > 0) {
    pinMode(_rst, OUTPUT);
    digitalWrite(_rst, LOW);
  }

  pinMode(_dc, OUTPUT);
  pinMode(_cs, OUTPUT);
  
  csport    = portOutputRegister(digitalPinToPort(_cs));
  cspinmask = digitalPinToBitMask(_cs);
  dcport    = portOutputRegister(digitalPinToPort(_dc));
  dcpinmask = digitalPinToBitMask(_dc);

  if(hwSPI) { // Using hardware SPI
#if defined (__AVR__)
    SPI.begin();
    SPI.setClockDivider(SPI_CLOCK_DIV2); // 8 MHz (full! speed!)
    SPI.setBitOrder(MSBFIRST);
    SPI.setDataMode(SPI_MODE0);
    mySPCR = SPCR;
#elif defined(TEENSYDUINO)
    SPI.begin();
    SPI.setClockDivider(SPI_CLOCK_DIV2); // 8 MHz (full! speed!)
    SPI.setBitOrder(MSBFIRST);
    SPI.setDataMode(SPI_MODE0);
#elif defined (__arm__)
      SPI.begin();
      SPI.setClockDivider(11); // 8-ish MHz (full! speed!)
      SPI.setBitOrder(MSBFIRST);
      SPI.setDataMode(SPI_MODE0);
#endif
  } else {
    pinMode(_sclk, OUTPUT);
    pinMode(_mosi, OUTPUT);

    clkport     = portOutputRegister(digitalPinToPort(_sclk));
    clkpinmask  = digitalPinToBitMask(_sclk);
    mosiport    = portOutputRegister(digitalPinToPort(_mosi));
    mosipinmask = digitalPinToBitMask(_mosi);
    *clkport   &= ~clkpinmask;
    *mosiport  &= ~mosipinmask;
  }

  // toggle RST low to reset
  if (_rst > 0) {
    digitalWrite(_rst, HIGH);
    delay(5);
    digitalWrite(_rst, LOW);
    delay(20);
    digitalWrite(_rst, HIGH);
    delay(150);
  }

  if (hwSPI) spi_begin();
  
 
	writecommand(0xff);
	writedata(0xa5);
	writecommand(0x41);
	writedata(0x00);
	writecommand(0x50);
	writedata(0x01);
	writecommand(0x52);
	writedata(0xd2);

	writecommand(0x57);
	writedata(0x02);

	writecommand(0x46);
	writedata(0x11);

	writecommand(0x47);
	writedata(0x00);
	writedata(0x01);

	writecommand(0x8f);
	writedata(0x22);
	writedata(0x03);

	// PUMP	??update
	writecommand(0x9a);
	writedata(0x78);

	writecommand(0x9b);
	writedata(0x78);

	writecommand(0x9c);
	writedata(0xa0);

	writecommand(0x9d);
	writedata(0x17);

	writecommand(0x9E);
	writedata(0xc3);


	//GAMMA PWR
	writecommand(0x84); // GVDD ADJ +5
	writedata(0xC6); // 5.92  b5    //  5.5 9D  c6/6v //A4 5.3  //9E  5.5
	writecommand(0x83); // GVCL ADJ  -4
	writedata(0xA6); // -3.8V 5B  3.5  ///74 -3.5  87 b3/-2.7  //a6 -3.87

	writecommand(0xff);
	writedata(0xA5);

	writecommand(0x85); // GVSP ADJ
	writedata(0x71); // 10 3a/1v 6f/1.7v


	///////gamma2.2 20241029
	//V0
	writecommand(0x6e);
	writedata(0x0f);//0 0f 1 00 2 0f
	writecommand(0x7e);
	writedata(0x0f);//0 0f 1 00

	//V63 255?
	writecommand(0x60);
	writedata(0x00);//0 00 1 0f
	writecommand(0x70);
	writedata(0x00);//0 00 1 0f

	//V1 01
	writecommand(0x6d);
	writedata(0x2D);
	writecommand(0x7d);
	writedata(0x37);

	//V62
	writecommand(0x61);
	writedata(0x02);//00
	writecommand(0x71);
	writedata(0x08);//0a

	//V2
	writecommand(0x6c);
	writedata(0x2a);//2a
	writecommand(0x7c);
	writedata(0x36);//36

	//V61
	writecommand(0x62);
	writedata(0x0c);//0a
	writecommand(0x72);
	writedata(0x08);//0a

	//V20
	writecommand(0x68);
	writedata(0x4b);//45
	writecommand(0x78);
	writedata(0x45);//4b



	//V43
	writecommand(0x66);
	writedata(0x33);//32
	writecommand(0x76);
	writedata(0x31);//32



	//V4
	writecommand(0x6b);
	writedata(0x13);
	writecommand(0x7b);
	writedata(0x13);


	//V59
	writecommand(0x63);
	writedata(0x0c);//09
	writecommand(0x73);
	writedata(0x07);//09


	//V6
	writecommand(0x6a);
	writedata(0x16);//12 16
	writecommand(0x7a);
	writedata(0x11);//14 11

	//V57
	writecommand(0x64);
	writedata(0x0B);//07 9
	writecommand(0x74);
	writedata(0x05);//09 7

	//V13 G32
	writecommand(0x69);
	writedata(0x07);//07
	writecommand(0x79);
	writedata(0x09);//09

	//V50
	writecommand(0x65);
	writedata(0x04);//03
	writecommand(0x75);
	writedata(0x07);//08

	//V36 v27
	writecommand(0x67);
	writedata(0x21);
	writecommand(0x77);
	writedata(0x41);
	/////////////////////////
	//source
	writecommand(0xe0);
	writedata(0x00);
	writecommand(0xe9);
	writedata(0x30);
	writecommand(0xeb);
	writedata(0xb7);
	writecommand(0xec);
	writedata(0x00);
	writecommand(0xed);
	writedata(0x11);
	writecommand(0xf0);
	writedata(0xb7);

	//G0A
	//----porch----//

	writecommand(0x49);
	writedata(0x04);

	writecommand(0x53);
	writedata(0x04);
	writecommand(0x54);
	writedata(0x04);
	writecommand(0x55);
	writedata(0x40);
	writecommand(0x56);
	writedata(0x40);
	//----goa----//
	writecommand(0xA0);
	writedata(0x60);
	writedata(0x01);

	writecommand(0xa1);
	writedata(0x85);
	writecommand(0xa2);
	writedata(0x84);

	writecommand(0xab);
	writedata(0x03);
	writedata(0x50);

	writecommand(0xac);
	writedata(0x03);
	writedata(0x54);

	writecommand(0xad);
	writedata(0x03);
	writedata(0x51);

	writecommand(0xae);
	writedata(0x03);
	writedata(0x55);

	writecommand(0xc7);
	writedata(0x00);


	writecommand(0xba);
	writedata(0x04);
	writecommand(0xb9);
	writedata(0x03);
	writecommand(0xbc);
	writedata(0x02);
	writecommand(0xbb);
	writedata(0x01);

	writecommand(0xbe);
	writedata(0x00);
	writecommand(0xbd);
	writedata(0x81);
	writecommand(0xc0);
	writedata(0x82);
	writecommand(0xbf);
	writedata(0x83);



	writecommand(0xc8);
	writedata(0xFF);
	writecommand(0xcd);
	writedata(0xFF);

	writecommand(0xca);
	writedata(0x50);
	writecommand(0xc9);
	writedata(0x4f);
	writecommand(0xcc);
	writedata(0x4e);
	writecommand(0xcb);
	writedata(0x4d);

	writecommand(0xcf);
	writedata(0x4c);
	writecommand(0xce);
	writedata(0x4b);
	writecommand(0xd1);
	writedata(0x4a);
	writecommand(0xd0);
	writedata(0x49);

	writecommand(0xf2);
	writedata(0x46);

	writecommand(0xa8);
	writedata(0x04);

	writecommand(0xa9);
	writedata(0xb0);

	writecommand(0xaa);
	writedata(0xa3);
	writecommand(0xb6);
	writedata(0x00);



	writecommand(0xb7);
	writedata(0xb0);
	writecommand(0xb8);
	writedata(0xa3);
	writecommand(0xc4);
	writedata(0x03);
	writecommand(0xc5);
	writedata(0xb0);
	writecommand(0xc6);
	writedata(0xa3);
	//----------------------OE????-----------------//
	writecommand(0x80);
	writedata(0x10);
	writecommand(0xff);
	writedata(0x00);
	writecommand(0x35);
	writedata(0x00);
	
	writecommand(0x3A);
	writedata(0x05);
	
	writecommand(0x36);
	writedata(0xC0);
 
        writecommand(0x11);    //Exit Sleep 
        if (hwSPI) spi_end();
        delay(120); 		
        if (hwSPI) spi_begin();
        writecommand(0x29);    //Display on 
        if (hwSPI) spi_end();

}


void NV3006::setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1,
 uint16_t y1) {
  x0+=0x02;x1+=0x02;
  writecommand(NV3006_CASET); // Column addr set
  writedata(x0 >> 8);
  writedata(x0 & 0xFF);     // XSTART 
  writedata(x1 >> 8);
  writedata(x1 & 0xFF);     // XEND

  writecommand(NV3006_PASET); // Row addr set
  writedata(y0>>8);
  writedata(y0);     // YSTART
  writedata(y1>>8);
  writedata(y1);     // YEND

  writecommand(NV3006_RAMWR); // write to RAM
  
  
}


void NV3006::pushColor(uint16_t color) {
  if (hwSPI) spi_begin();
  //digitalWrite(_dc, HIGH);
  *dcport |=  dcpinmask;
  //digitalWrite(_cs, LOW);
  *csport &= ~cspinmask;

  spiwrite(color >> 8);
  spiwrite(color);

  *csport |= cspinmask;
  //digitalWrite(_cs, HIGH);
  if (hwSPI) spi_end();
}

void NV3006::drawPixel(int16_t x, int16_t y, uint16_t color) {

  if((x < 0) ||(x >= _width) || (y < 0) || (y >= _height)) return;

  if (hwSPI) spi_begin();
  setAddrWindow(x,y,x+1,y+1);

  //digitalWrite(_dc, HIGH);
  *dcport |=  dcpinmask;
  //digitalWrite(_cs, LOW);
  *csport &= ~cspinmask;

  spiwrite(color >> 8);
  spiwrite(color);

  *csport |= cspinmask;
  //digitalWrite(_cs, HIGH);
  if (hwSPI) spi_end();
}


void NV3006::drawFastVLine(int16_t x, int16_t y, int16_t h,
 uint16_t color) {

  // Rudimentary clipping
  if((x >= _width) || (y >= _height)) return;

  if((y+h-1) >= _height) 
    h = _height-y;

  if (hwSPI) spi_begin();
  setAddrWindow(x, y, x, y+h-1);

  uint8_t hi = color >> 8, lo = color;

  *dcport |=  dcpinmask;
  //digitalWrite(_dc, HIGH);
  *csport &= ~cspinmask;
  //digitalWrite(_cs, LOW);

  while (h--) {
    spiwrite(hi);
    spiwrite(lo);
  }
  *csport |= cspinmask;
  //digitalWrite(_cs, HIGH);
  if (hwSPI) spi_end();
}


void NV3006::drawFastHLine(int16_t x, int16_t y, int16_t w,
  uint16_t color) {

  // Rudimentary clipping
  if((x >= _width) || (y >= _height)) return;
  if((x+w-1) >= _width)  w = _width-x;
  if (hwSPI) spi_begin();
  setAddrWindow(x, y, x+w-1, y);

  uint8_t hi = color >> 8, lo = color;
  *dcport |=  dcpinmask;
  *csport &= ~cspinmask;
  //digitalWrite(_dc, HIGH);
  //digitalWrite(_cs, LOW);
  while (w--) {
    spiwrite(hi);
    spiwrite(lo);
  }
  *csport |= cspinmask;
  //digitalWrite(_cs, HIGH);
  if (hwSPI) spi_end();
}

void NV3006::fillScreen(uint16_t color) {
  fillRect(0, 0,  _width, _height, color);
}

// fill a rectangle
void NV3006::fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
  uint16_t color) {

  // rudimentary clipping (drawChar w/big text requires this)
  if((x >= _width) || (y >= _height)) return;
  if((x + w - 1) >= _width)  w = _width  - x;
  if((y + h - 1) >= _height) h = _height - y;

  if (hwSPI) spi_begin();
  setAddrWindow(x, y, x+w-1, y+h-1);

  uint8_t hi = color >> 8, lo = color;

  *dcport |=  dcpinmask;
  //digitalWrite(_dc, HIGH);
  *csport &= ~cspinmask;
  //digitalWrite(_cs, LOW);

  for(y=h; y>0; y--) {
    for(x=w; x>0; x--) {
      spiwrite(hi);
      spiwrite(lo);
    }
  }
  //digitalWrite(_cs, HIGH);
  *csport |= cspinmask;
  if (hwSPI) spi_end();
}


// Pass 8-bit (each) R,G,B, get back 16-bit packed color
uint16_t NV3006::color565(uint8_t r, uint8_t g, uint8_t b) {
  return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
}

 

