#include <classSSD1963.h>


// default constructor
classSSD1963::classSSD1963()
{
} //classTFT

// default destructor
classSSD1963::~classSSD1963()
{
} //~classTFT



void classSSD1963::command(uint16_t cmd) {
	TFT_DC_LOW();
	//Ponemos el comando en el bus de datos
	PIOD->PIO_ODSR = cmd;
	TFT_CS_LOW();
	TFT_WR_LOW();
	TFT_WR_HIGH();
	TFT_CS_HIGH();
}

void classSSD1963::data8(uint8_t cmd) {
	TFT_DC_HIGH();
   
    //Ponemos el comando en el bus de datos
	PIOD->PIO_ODSR = cmd;
	TFT_CS_LOW();
	TFT_WR_LOW();
	TFT_WR_HIGH();
	TFT_CS_HIGH();
}

void classSSD1963::data(uint16_t cmd) {
    TFT_DC_HIGH();
    //Ponemos el dato en el bus de datos
	PIOD->PIO_ODSR = cmd;
	TFT_CS_LOW();
	TFT_WR_LOW();
	TFT_WR_HIGH();
	TFT_CS_HIGH();
}




void classSSD1963::initializeDevice(void) {
   
     _width  = 800;
     _height = 480;
	 rotation = 1;

	TFT_RST_OFF();
    command(SSD1963_SetPLLMN);
    data(0x0023);        //N=0x36 for 6.5M, 0x23 for 10M crystal
    data(0x0002);
    data(0x0004);
    command(SSD1963_SetPLL);  // PLL enable
    data(0x0001);
    delay_us(1);
    command(SSD1963_SetPLL);
    data(0x0003);
    delay_us(5);
    command(SSD1963_SoftReset);  // software reset
    delay_us(5);

    command(SSD1963_SetLCDMode);
    // The SSD1963 controller can be connected to the TFT screen with 18 or 16 data lines.
   
    data(0x0003);


       // 7 inch TFT profile

        // Continues on from previous SetLCDMode command
        data((HDP>>8)&0X00FF);  //Set HDP
        data(HDP&0X00FF);
        data((VDP>>8)&0X00FF);  //Set VDP
        data(VDP&0X00FF);
        data(0x0000);

        command(SSD1963_SetHoriPeriod);
        data((HT>>8)&0X00FF);  //Set HT
        data(HT&0X00FF);
        data((HPS>>8)&0X00FF);  //Set HPS
        data(HPS&0X00FF);
        data(HPW);              //Set HPW
        data((LPS>>8)&0X00FF);  //Set HPS
        data(LPS&0X00FF);
        data(0x0000);

        command(SSD1963_SetVertPeriod);
        data((VT>>8)&0X00FF);   //Set VT
        data(VT&0X00FF);
        data((VPS>>8)&0X00FF);  //Set VPS
        data(VPS&0X00FF);
        data(VPW);              //Set VPW
        data((FPS>>8)&0X00FF);  //Set FPS
        data(FPS&0X00FF);

        command(SSD1963_SetLShiftFreq); //PLL setting for PCLK, depends on resolution
        data(0x0003);
        data(0x00ff);
        data(0x00ff);

        command(SSD1963_SetAddressMode); //rotation
        data(0x0000); // RGB

 
    command(SSD1963_SetGPIOValue);
    data(0x0005);    //GPIO[3:0] out 1

    command(SSD1963_SetGPIOConf);
    data(0x0007);    //GPIO3=input, GPIO[2:0]=output
    data(0x0001);    //GPIO0 normal

    command(SSD1963_SetPixelDataInterface);

      data(0x0000);
   

    delay_us(5);

    command(SSD1963_SetDisplayOn);
    command(SSD1963_SetDBCConf);
    data(0x000d);
	enableBacklight();
}

void classSSD1963::setAddrWindow(int x0, int y0, int x1, int y1) {

    int x0a, x1a, y0a, y1a;

    switch(rotation) {
        case 1:
            x0a = x0;
            x1a = x1;
            y0a = y0;
            y1a = y1;
 
            x0 = y0a;
            x1 = y1a;
            y0 = _width - 1 - x1a;
            y1 = _width - 1 - x0a;
            break;
        case 2:
            x0a = x0;
            x1a = x1;
            y0a = y0;
            y1a = y1;
       
            x0 = _width - 1 - x1a;
            x1 = _width - 1 - x0a;
            y0 = _height - 1 - y1a;
            y1 = _height - 1 - y0a;
            break;
 

        case 3:
            x0a = x0;
            x1a = x1;
            y0a = y0;
            y1a = y1;

            x0 = _height - 1 - y1a;
            x1 = _height - 1 - y0a;
            y0 = x0a;
            y1 = x1a;
            break;
    }

    command(SSD1963_SetColumnAddress);
    data((x0 >> 8) & 0xFF);
    data(x0 & 0xFF);
    data((x1 >> 8) & 0xFF);
    data(x1 & 0xFF);
    command(SSD1963_SetPageAddress);
    data((y0 >> 8) & 0xFF);
    data(y0 & 0xFF);
    data((y1 >> 8) & 0xFF);
    data(y1 & 0xFF);
    command(SSD1963_WriteMemoryStart);

}

void classSSD1963::setPixel(int x, int y, uint16_t color) {
   if((x < 0) ||(x >= _width) || (y < 0) || (y >= _height))
      return;

   setAddrWindow(x,y,x,y);
  
   data(color);
}

void classSSD1963::fillScreen(uint16_t color) {
   fillRectangle(0, 0,  _width, _height, color);
}

void classSSD1963::fillRectangle(int x, int y, int w, int h, uint16_t color) {
  
   setAddrWindow(x, y, x+w-1, y+h-1);
   for(int i = 0; i < w * h; i++) {
   
         data(color);
   }
}

void classSSD1963::drawHorizontalLine(int x, int y, int w, uint16_t color) {
    if ((y < 0) || (y >= _height) || (w <= 0)) {
        return;
    }

    if (x < 0) {
        w += x;
        x = 0;
        if (w <= 0) {
            return;
        }
    }

    if (x >= _width) {
        return;
    }

    if (x + w >= _width) {
        w = _width-x;
        if (w <= 0) {
            return;
        }
    }

   setAddrWindow(x, y, x+w-1, y);
   while (w--) {
     
    data(color);
   }
}

void classSSD1963::drawVerticalLine(int x, int y, int h, uint16_t color) {
    if ((x < 0) || (x >= _width) || (h <= 0)) {
        return;
    }

    if (y < 0) {
        h += y;
        y = 0;
        if (h <= 0) {
            return;
        }
    }

    if (y >= _height) {
        return;
    }

    if (y + h >= _height) {
        h = _height-y;
        if (h <= 0) {
            return;
        }
    }

   setAddrWindow(x, y, x, y+h-1);
   while (h--) {
    
         data(color);
   }
}

void classSSD1963::setRotation(int m) {
   rotation = m % 4; // can't be higher than 3
}

void classSSD1963::invertDisplay(bool i) {
   command(i ? SSD1963_EnterInvertMode : SSD1963_ExitInvertMode);
}

void classSSD1963::displayOn() {
    command(SSD1963_ExitIdleMode);
    command(SSD1963_SetDisplayOn);
    command(SSD1963_EnterSleepMode);
    enableBacklight();
}

void classSSD1963::displayOff() {
    command(SSD1963_ExitSleepMode);
    command(SSD1963_SetDisplayOff);
    command(SSD1963_EnterIdleMode);
    disableBacklight();
}


void classSSD1963::windowData(uint16_t d) {
    data(d);
}

void classSSD1963::windowData(const uint16_t *d, int l) {
    for (int i = 0; i < l; i++) {
        data(d[i]);
    }
}

void classSSD1963::openWindow(int x0, int y0, int x1, int y1) {
    setAddrWindow(x0, y0, x0 + x1 - 1, y0 + y1 - 1);
}

void classSSD1963::enableBacklight() {
    command(SSD1963_SetPWMConf);
    data(0x06);
    data(0xFF);
    data(0x01);
    data(0xFF);
    data(0x00);
    data(0x00);
    _brightness = 0xff;
}

void classSSD1963::disableBacklight() {
    command(SSD1963_SetPWMConf);
    data(0x06);
    data(0xFF);
    data(0x00);
    data(_brightness);
    data(0x00);
    data(0x00);
}

void classSSD1963::setBacklight(int b) {
    _brightness = b;
    command(SSD1963_SetPWMConf);
    data(0x06);
    data(_brightness);
    data(0x01);
    data(_brightness);
    data(0x00);
    data(0x00);
}







