#include "stm32f10x_lib.h"
#include "T6963C.h"

/* Private declaration*/
static GPIO_InitTypeDef GPIO_InitStructure;

/* Lov level API */
//Main and only delay function for this drivers.
static void delay(void)
{
volatile int i;
for(i = 0; i < 11; i++){
    asm volatile("nop");  
}
}


//This function sends one byte from port without WR ond RD signal. 
static inline void outByte(unsigned char byteToWrite)
{
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin  = (0xFF << T6963_D0);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(T6963_DATA_PORT, &GPIO_InitStructure);

delay();
GPIO_SetBits(T6963_DATA_PORT, (byteToWrite << T6963_D0));
byteToWrite ^= 0xFF;
GPIO_ResetBits(T6963_DATA_PORT, (byteToWrite << T6963_D0));

}

//This function reads one byte form physical port without WR ond RD signal. 
static unsigned char inByte(void)
{
unsigned char port=0;
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = 0xFF << T6963_D0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(T6963_DATA_PORT, &GPIO_InitStructure);

delay();
port = ((GPIO_ReadInputData(T6963_DATA_PORT) >> T6963_D0) & 0xFF);

return port;
}

//Check status of the display
unsigned char GLCD_Chceck_Status(void)
{
unsigned char tmp;


GPIO_SetBits(T6963_CD_PORT, T6963_CD);
GPIO_SetBits(T6963_WR_PORT, T6963_WR);
GPIO_ResetBits(T6963_RD_PORT, T6963_RD);
GPIO_ResetBits(T6963_CE_PORT, T6963_CE);
delay();

tmp = inByte();

GPIO_SetBits(T6963_CE_PORT, T6963_CE);
GPIO_SetBits(T6963_RD_PORT, T6963_RD);

return tmp;
}

//Write one byte command to the display
void GLCD_Write_Command(int command)
{
while(!(GLCD_Chceck_Status()&0x03));

outByte(command);

GPIO_SetBits(T6963_CD_PORT, T6963_CD);
GPIO_ResetBits(T6963_WR_PORT, T6963_WR);
GPIO_ResetBits(T6963_CE_PORT, T6963_CE);

delay();

GPIO_SetBits(T6963_WR_PORT, T6963_WR);
GPIO_SetBits(T6963_CE_PORT, T6963_CE );
}

//Write one byte of data to the LCD
void GLCD_Write_Data(int data)
{
while(!(GLCD_Chceck_Status()&0x03));

outByte(data);
GPIO_ResetBits(T6963_CD_PORT, T6963_CD);
GPIO_SetBits(T6963_RD_PORT, T6963_RD);
GPIO_ResetBits(T6963_WR_PORT, T6963_WR);
GPIO_ResetBits(T6963_CE_PORT, T6963_CE);

delay();
GPIO_SetBits(T6963_CE_PORT, T6963_CE);
GPIO_SetBits(T6963_WR_PORT, T6963_WR);

}
//Write one byte of data from LCD
int GLCD_Read_Data(void)
{
int tmp;
while(!(GLCD_Chceck_Status()&0x03));

GPIO_ResetBits(T6963_CD_PORT, T6963_CD);
GPIO_SetBits(T6963_WR_PORT, T6963_WR);
GPIO_ResetBits(T6963_RD_PORT, T6963_RD);
GPIO_ResetBits(T6963_CE_PORT, T6963_CE);

delay();
tmp = inByte();
GPIO_SetBits(T6963_CE_PORT, T6963_CE);
GPIO_SetBits(T6963_RD_PORT, T6963_RD);

return tmp;
}

void GLCD_Initalize(void)
{
int i=0;

/* STM32 GPIO init */

/* CE */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);

/* FS, C/D, RST, DB0-DB7 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_6 | GPIO_Pin_7| GPIO_Pin_8| GPIO_Pin_9| GPIO_Pin_10| GPIO_Pin_11| GPIO_Pin_12| GPIO_Pin_13| GPIO_Pin_14| GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);

/* WR, RD */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);


/* */
GPIO_ResetBits(T6963_RD_PORT, T6963_RD);
GPIO_ResetBits(T6963_WR_PORT, T6963_WR);
GPIO_ResetBits(T6963_CD_PORT, T6963_CD);
GPIO_ResetBits(T6963_CE_PORT, T6963_CE);
GPIO_ResetBits(T6963_FS_PORT, T6963_FS);
GPIO_ResetBits(T6963_RESET_PORT, T6963_RESET);

GPIO_Write(T6963_DATA_PORT,(0xFF << T6963_D0));

#if (GLCD_FONT_WIDTH == 6)
GPIO_SetBits(T6963_FS_PORT, T6963_FS);
#endif

for(i = 0; i < 100000; i++){
    asm volatile("nop"); 
}

GPIO_ResetBits(T6963_RESET_PORT, T6963_RESET);

for(i = 0; i < 10000; i++);
    
GPIO_SetBits(T6963_RESET_PORT, T6963_RESET);

for(i = 0; i < 10000; i++);

GLCD_Write_Data(GLCD_GRAPHIC_HOME & 0xFF);
GLCD_Write_Data(GLCD_GRAPHIC_HOME >> 8);
GLCD_Write_Command(T6963_SET_GRAPHIC_HOME_ADDRESS);

for(i = 0; i < 100000; i++){
    asm volatile("nop"); 
}

GLCD_Write_Data(GLCD_GRAPHIC_AREA);
GLCD_Write_Data(0x00);
GLCD_Write_Command(T6963_SET_GRAPHIC_AREA);


GLCD_Write_Data(GLCD_TEXT_HOME);
GLCD_Write_Data(GLCD_TEXT_HOME >> 8);
GLCD_Write_Command(T6963_SET_TEXT_HOME_ADDRESS);

GLCD_Write_Data(GLCD_TEXT_AREA);
GLCD_Write_Data(0x00);
GLCD_Write_Command(T6963_SET_TEXT_AREA);

GLCD_Write_Data(GLCD_OFFSET_REGISTER);
GLCD_Write_Data(0x00);
GLCD_Write_Command(T6963_SET_OFFSET_REGISTER);


GLCD_Write_Data(0);
GLCD_Write_Data(0);
GLCD_Write_Command(T6963_SET_ADDRESS_POINTER);

GLCD_Write_Command(T6963_DISPLAY_MODE  | T6963_GRAPHIC_DISPLAY_ON   | T6963_TEXT_DISPLAY_ON /*| T6963_CURSOR_DISPLAY_ON*/);

GLCD_Write_Command(T6963_MODE_SET | T6963_MODE_SET_OR);

GLCD_Clear_Text();
GLCD_Clear_CG();
GLCD_Clear_Graphic();
}

/* Hihg level API */
//Sets Address of the display
void GLCD_Ustaw_Adres(unsigned int addr){
    GLCD_Write_Data(addr%256);
    GLCD_Write_Data(addr>>8);
    GLCD_Write_Command(0x24);
}


void GLCD_Clear_Text(void)
{
int i;
GLCD_Write_Data(GLCD_TEXT_HOME);
GLCD_Write_Data(GLCD_TEXT_HOME >> 8);
GLCD_Write_Command(T6963_SET_ADDRESS_POINTER);

for(i = 0; i < GLCD_TEXT_SIZE; i++)
  {
  GLCD_Write_Data(0);
  GLCD_Write_Command(T6963_DATA_WRITE_AND_INCREMENT);
  }
}

void GLCD_Clear_CG(void)
{
int i;
GLCD_Write_Data(GLCD_EXTERNAL_CG_HOME & 0xFF);
GLCD_Write_Data(GLCD_EXTERNAL_CG_HOME >> 8);
GLCD_Write_Command(T6963_SET_ADDRESS_POINTER);

for(i = 0; i < 256 * 8; i++)
  {
  GLCD_Write_Data(0);
  GLCD_Write_Command(T6963_DATA_WRITE_AND_INCREMENT);
  }
}


void GLCD_Clear_Graphic(void)
{
int i;
GLCD_Write_Data(GLCD_GRAPHIC_HOME & 0xFF);
GLCD_Write_Data(GLCD_GRAPHIC_HOME >> 8);
GLCD_Write_Command(T6963_SET_ADDRESS_POINTER);

for(i = 0; i < GLCD_GRAPHIC_SIZE; i++)
  {
  GLCD_Write_Data(0x00);
  GLCD_Write_Command(T6963_DATA_WRITE_AND_INCREMENT);
  }
}

void GLCD_Write_Char(char ch)
{
GLCD_Write_Data(ch - 32);
GLCD_Write_Command(T6963_DATA_WRITE_AND_INCREMENT);
}

void GLCD_Write_String(char * str)
{
while(*str)
  {
  GLCD_Write_Char(*str++);
  }
}

void GLCD_Text_GoTo(int x, int y)
{
int address;

address = GLCD_TEXT_HOME +  x + (GLCD_TEXT_AREA * y);

GLCD_Write_Data(address);
GLCD_Write_Data(address >> 8);
GLCD_Write_Command(T6963_SET_ADDRESS_POINTER);
}

void GLCD_Define_Character(int charCode, int * defChar)
{
int address;
int i; 

address = GLCD_EXTERNAL_CG_HOME + (8 * charCode);

GLCD_Write_Data(address);
GLCD_Write_Data(address >> 8);
GLCD_Write_Command(T6963_SET_ADDRESS_POINTER);

for(i = 0; i < 8 ; i++)
  {
  GLCD_Write_Data(*(defChar + i));
  GLCD_Write_Command(T6963_DATA_WRITE_AND_INCREMENT);
  }
}

void GLCD_GoTo(unsigned char x, unsigned char y){
int tmp;
int address;

address = GLCD_GRAPHIC_HOME + (x / GLCD_FONT_WIDTH) + (GLCD_GRAPHIC_AREA * y);

GLCD_Write_Data(address & 0xFF);
GLCD_Write_Data(address >> 8);
GLCD_Write_Command(T6963_SET_ADDRESS_POINTER);
}


void GLCD_Write8Pixels(int tmp){
    GLCD_Write_Data(tmp);
    GLCD_Write_Command(T6963_DATA_WRITE_AND_INCREMENT);
}


void GLCD_SetPixel(int x, int y, int color)
{
int tmp;
int address;

address = GLCD_GRAPHIC_HOME + (x / GLCD_FONT_WIDTH) + (GLCD_GRAPHIC_AREA * y);

GLCD_Write_Data(address & 0xFF);
GLCD_Write_Data(address >> 8);
GLCD_Write_Command(T6963_SET_ADDRESS_POINTER);

GLCD_Write_Command(T6963_DATA_READ_AND_NONVARIABLE);
tmp = GLCD_Read_Data();

if(color)
  tmp |= (1 <<  (GLCD_FONT_WIDTH - 1 - (x % GLCD_FONT_WIDTH)));
else
 tmp &= ~(1 <<  (GLCD_FONT_WIDTH - 1 - (x % GLCD_FONT_WIDTH)));

GLCD_Write_Data(tmp);
GLCD_Write_Command(T6963_DATA_WRITE_AND_INCREMENT);
}



