//ys_drv_gfx_int035.c
//drv_gfx_generic.c
//INT035 Display Driver
// 2017.8.15 by YSDK Design
///////////////////////////////////////////////////////////////////

#include "framework/gfx/driver/controller/generic/drv_gfx_generic.h"
//#include "framework/gfx/driver/controller/int035/ys_drv_gfx_int035.h"

#include "gfx/hal/inc/gfx_driver_interface.h"
#include "gfx/hal/inc/gfx_default_impl.h"
#include "framework/driver/pmp/drv_pmp_static.h"
#include "system_definitions.h"

#define MAX_LAYER_COUNT 1
#define MAX_BUFFER_COUNT 1
#define GFX_CONFIG_COLOR_DEPTH 16 //16bit color
#define abs(a) (((a)>0) ? (a) : -(a))

static uint32_t supportedColorModes = GFX_COLOR_MASK_RGB_565;
const char* DRIVER_NAME = "Generic";
short DISP_HOR_RESOLUTION = 320;
short DISP_VER_RESOLUTION = 240;


//PMP write function
void ys_DeviceWrite(short data)
{
PMDIN = data; //PMP data set
while(PMMODEbits.BUSY); //wait until(BUSY bit = 1)
//PMPWaitBusy();
}

//Data send function
void ys_WriteData(short data)
{
DisplaySetData(); //RS = 1;
ys_DeviceWrite(data);
}

//Command send function
void ys_WriteCommand(unsigned char cmd)
{
DisplayEnable(); //CS = 0;
DisplaySetCommand(); //RS = 0;
ys_DeviceWrite(cmd) ;
DisplayDisable(); //CS = 1;
}

//Area set function
void ys_SetArea(short start_x, short start_y, short end_x, short end_y)
{
ys_WriteCommand(SSD1963_CMD_SET_COLUMN);
DisplayEnable();
ys_WriteData(start_x >> 8);
ys_WriteData(start_x);
ys_WriteData(end_x >> 8);
ys_WriteData(end_x);
DisplayDisable();
ys_WriteCommand(SSD1963_CMD_SET_PAGE);
DisplayEnable();
ys_WriteData(start_y >> 8);
ys_WriteData(start_y);
ys_WriteData(end_y >> 8);
ys_WriteData(end_y);
DisplayDisable();

}



//-----------------------------------------------------------------------------
// Initialize function
static GFX_Result initialize(GFX_Context* context)
{

DisplayCmdDataConfig(); // enable RS line
DisplayDisable(); // not selected by default
DisplayConfig(); // enable chip select line


#if (DISP_HOR_RESOLUTION == 800 || DISP_HOR_RESOLUTION == 640)
//Flip the hdir
ys_WriteCommand(SSD1963_CMD_SET_ADDR_MODE);
DisplayEnable();
ys_WriteData(0x02);
DisplayDisable();
#endif

#if (GFX_CONFIG_COLOR_DEPTH == 16)
//Set 16-bit 5-6-5
ys_WriteCommand(SSD1963_CMD_SET_DATA_INTERFACE);
DisplayEnable();
ys_WriteData(0x03);
DisplayDisable();
#elif (GFX_CONFIG_COLOR_DEPTH == 24)
ys_WriteCommand(SSD1963_CMD_SET_DATA_INTERFACE);
DisplayEnable();
ys_WriteData(0x02);
DisplayDisable();
#endif

ys_WriteCommand(SSD1963_CMD_ON_DISPLAY); // Turn on display; show the image on display

return GFX_SUCCESS;
}

//------------------------------------------------------------------------------
//Pixel set function
void ys_pixelSet(int x, int y, int color)
{
static short lastX = 0;
static short lastY = 0;

//Don't always set the new position if we don't need to.
if (!(lastY == y && x == ++lastX)) {
ys_SetArea(x, y, DISP_HOR_RESOLUTION - 1, DISP_VER_RESOLUTION - 1);
ys_WriteCommand(SSD1963_CMD_WR_MEMSTART);
lastX = x;
lastY = y;
}

DisplayEnable();
DisplaySetData();

ys_DeviceWrite(color);
DisplayDisable();
}


static GFX_Result pixelSet(const GFX_PixelBuffer* buf,
const GFX_Point* pnt,
GFX_Color color)
{
int x = pnt->x;
int y = pnt->y;

ys_pixelSet(x, y, color);

return GFX_SUCCESS;
}


//------------------------------------------------------------------------------
//Line draw function
//Bresenham's line algorithm

void ys_drawLine(int x0, int y0, int x1, int y1, int color)
{
// short steep, t;
// short deltax, deltay, error;
// short x, y;
// short ystep;
//
//
// y0=DISP_VER_RESOLUTION-y0 -1;
// y1=DISP_VER_RESOLUTION-y1 -1;
// steep = (abs(y1 - y0) > abs(x1 - x0));
// if(steep){
// t = x0; x0 = y0; y0 = t;
// t = x1; x1 = y1; y1 = t;
// }
// if(x0 > x1) {
// t = x0; x0 = x1; x1 = t;
// t = y0; y0 = y1; y1 = t;
// }
// deltax = x1 - x0;
// deltay = abs(y1 - y0);
// error = 0;
// y = y0;
// if(y0 < y1) ystep = 1; else ystep = -1;
// for(x=x0; x<=x1; x++)
// {
// if(steep) ys_pixelSet(y,x,color); else ys_pixelSet(x,y,color);
// error += deltay;
// if((error << 1) >= deltax) {
// y += ystep;
// error -= deltax;
// }
// }

}

GFX_Result drawLine(const GFX_Point* p0,
const GFX_Point* p1,
const GFX_DrawState* state)
{
int color = state->color;
int x0 = p0->x;
int y0 = p0->y;
int x1 = p1->x;
int y1 = p1->y;

ys_drawLine(x0, y0, x1, y1, color);

return(GFX_SUCCESS);
}

//------------------------------------------------------------------------------
//Rectangle fill functin
ys_fillRect(int left, int top, int right, int bottom, int color)
{
int counter = ((bottom + 1) - top)*((right + 1) - left); //counter shold be 32bit int

ys_SetArea(left, top, right, bottom);

ys_WriteCommand(SSD1963_CMD_WR_MEMSTART);
DisplayEnable();
DisplaySetData();
while (counter--)ys_DeviceWrite(color); //write color data to PMP
DisplayDisable();
}


GFX_Result fillRect(const GFX_Rect* rect,
const GFX_DrawState* state)
{
int color = state->color;

int left = rect->x;
int top = rect->y;
int right = left + rect->width;
int bottom = top + rect->height;


ys_fillRect(left, top, right, bottom, color);

return(GFX_SUCCESS);
}


//Circle draw functin
void ys_drawCircle(int x0, int y0, int r, int color) //(x_center, y_center, radius, color)
{
int x = r;
int y = 0;
int F = -2 * r + 3;

while(x >= y){
ys_pixelSet(x0+x, y0+y, color);
ys_pixelSet(x0-x, y0+y, color);
ys_pixelSet(x0+x, y0-y, color);
ys_pixelSet(x0-x, y0-y, color);
ys_pixelSet(x0+y, y0+x, color);
ys_pixelSet(x0-y, y0+x, color);
ys_pixelSet(x0+y, y0-x, color);
ys_pixelSet(x0-y, y0-x, color);
if(F >= 0){
x--;
F -= 4 * x;
}
y++;
F += 4 * y + 2;
}
}


static void destroy(GFX_Context* context)
{
// driver specific shutdown tasks
if(context->driver_data != GFX_NULL)
{
context->memory.free(context->driver_data);
context->driver_data = GFX_NULL;
}

// general default shutdown
defDestroy(context);
}


static GFX_Result layerActiveSet(uint32_t idx)
{
return GFX_UNSUPPORTED;
}

static GFX_Result layerEnabledSet(GFX_Bool val)
{
return GFX_UNSUPPORTED;
}

static GFX_Result layerPositionSet(int32_t x, int32_t y)
{
return GFX_UNSUPPORTED;
}

static GFX_Result layerSizeSet(int32_t width, int32_t height)
{
return GFX_UNSUPPORTED;
}

static GFX_Result layerBufferCountSet(uint32_t count)
{
return GFX_UNSUPPORTED;
}

static GFX_Result layerBufferAddressSet(uint32_t idx, GFX_Buffer address)
{
return GFX_UNSUPPORTED;
}

static GFX_Result layerBufferCoherentSet(uint32_t idx, GFX_Bool coherent)
{
return GFX_UNSUPPORTED;
}

static GFX_Result layerBufferAllocate(uint32_t idx)
{
return GFX_UNSUPPORTED;
}

static GFX_Result layerBufferFree(uint32_t idx)
{
return GFX_UNSUPPORTED;
}

static GFX_Result layerVisibleSet(GFX_Bool val)
{
return GFX_UNSUPPORTED;
}

static GFX_Result layerAlphaEnableSet(GFX_Bool enable)
{
return GFX_UNSUPPORTED;
}

static GFX_Color pixelGet(const GFX_PixelBuffer* buf,
const GFX_Point* pnt)
{
return 0;
}

// function that returns the information for this driver
GFX_Result driverGenericInfoGet(GFX_DriverInfo* info)
{
if(info == GFX_NULL)
return GFX_FAILURE;

// populate info struct
strcpy(info->name, DRIVER_NAME);
info->color_formats = supportedColorModes;
info->layer_count = MAX_LAYER_COUNT;

return GFX_SUCCESS;
}

// function that initialized the driver context
GFX_Result driverGenericContextInitialize(GFX_Context* context)
{
// set driver-specific function implementations
context->hal.initialize = &initialize;
context->hal.destroy = &destroy;
// context->hal.brightnessRangeGet = &brightnessRangeGet;
// context->hal.brightnessSet = &brightnessSet;
// context->hal.layerVsyncSet = &vsyncSet;
// context->hal.vsyncCallbackSet = &vsyncCallbackSet;
// context->hal.hsyncCallbackSet = &hsyncCallbackSet;
context->hal.layerActiveSet = &layerActiveSet;
context->hal.layerEnabledSet = &layerEnabledSet;
context->hal.layerPositionSet = &layerPositionSet;
context->hal.layerSizeSet = &layerSizeSet;
context->hal.layerBufferCountSet = &layerBufferCountSet;
context->hal.layerBufferAddressSet = &layerBufferAddressSet;
context->hal.layerBufferCoherentSet = &layerBufferCoherentSet;
context->hal.layerBufferAllocate = &layerBufferAllocate;
context->hal.layerBufferFree = &layerBufferFree;
context->hal.layerVisibleSet = &layerVisibleSet;
context->hal.layerAlphaEnableSet = &layerAlphaEnableSet;

context->hal.drawPipeline[GFX_PIPELINE_GCU].pixelSet = &pixelSet;
context->hal.drawPipeline[GFX_PIPELINE_GCU].pixelGet = &pixelGet;

context->hal.drawPipeline[GFX_PIPELINE_GCUGPU].pixelSet = &pixelSet;
context->hal.drawPipeline[GFX_PIPELINE_GCUGPU].pixelGet = &pixelGet;


//Mchip commentout
// accelerated draw line disabled for now, something keeps cutting off pixels
// towards the bottom of the screen in some cases
context->hal.drawPipeline[GFX_PIPELINE_GCU].drawLine[GFX_DRAW_LINE][GFX_ANTIALIAS_OFF] = &drawLine;

context->hal.drawPipeline[GFX_PIPELINE_GCU].drawRect[GFX_DRAW_FILL][GFX_ANTIALIAS_OFF] = &fillRect;
context->hal.drawPipeline[GFX_PIPELINE_GCUGPU].drawRect[GFX_DRAW_FILL][GFX_ANTIALIAS_OFF] = &fillRect;

return GFX_SUCCESS;
}