//Sourcecode by G. Bjoerneseth
//gisle at break dot org http://break.org/gisle
//This examplecode draws some sprites on a 240x64
//t6963 graphics LCD.

#include <pic.h>

#define ON	1
#define OFF	0
#define DATAPORT	PORTB
#define DATADIRECTION	TRISB
#define OUTPUT		0x00
#define INPUT		0xFF

static bit LCD_WR	   @ ((unsigned)&PORTA*8+0);
static bit LCD_RD	   @ ((unsigned)&PORTA*8+1);
static bit LCD_CE	   @ ((unsigned)&PORTA*8+2);
static bit LCD_CD	   @ ((unsigned)&PORTA*8+3);

//static bit RED_LED		   @ ((unsigned)&PORTD*8+0);
//static bit GREEN_LED		   @ ((unsigned)&PORTD*8+1);

const unsigned char Sprite[] =  {0b00011000,   	//0,0,0,1,1,0,0,0,
			    	 0b00111100,   	//0,0,1,1,1,1,0,0,
				 0b00111100,   	//0,0,1,1,1,1,0,0,
				 0b00011001,   	//0,0,0,1,1,0,0,1,
				 0b00011110,   	//0,0,0,1,1,1,1,0,
				 0b01111000,   	//0,1,1,1,1,0,0,0,
				 0b10011000,   	//1,0,0,1,1,0,0,0,
				 0b00100100,	//0,0,1,0,0,1,0,0,
				 0b00100011, 	//0,0,1,0,0,0,1,1,
				 0b00100000	//0,0,1,0,0,0,0,0,
				}; 

const unsigned char Sprite2[] = {0b00011000,   	//0,0,0,1,1,0,0,0,
			    	 0b00111100,   	//0,0,1,1,1,1,0,0,
				 0b00111100,   	//0,0,1,1,1,1,0,0,
				 0b10011000,	//1,0,0,1,1,0,0,0,
				 0b01111110,	//0,1,1,1,1,1,1,0,
				 0b00011001,	//0,0,0,1,1,0,0,1,
				 0b00011000,	//0,0,0,1,1,0,0,0,
				 0b00100100,	//0,0,1,0,0,1,0,0,
				 0b01100100,	//0,1,1,0,0,1,0,0,
				 0b00000100,	//0,0,0,0,0,1,0,0,
				}; 

const unsigned char PAC1[] = 	{0b00010000,
				 0b00001000,
	 			 0b00001000,
			    	 0b00011100,
				 0b00111110,
				 0b01111111,
				 0b11110000,
				 0b01111111,
				 0b00111110,
				 0b00011100
				}; 

const unsigned char PAC2[] = 	{0b10000011,
				 0b01001110,
	 			 0b00111100,
			    	 0b01110000,
				 0b11110000,
				 0b11110000,
				 0b11111000,
				 0b01111111,
				 0b00111110,
				 0b00011000
				}; 

void LCD_Initialize(void);
void LCD_SendData(unsigned char Data);
void LCD_SendCmd(unsigned char Command);
void LCD_CheckStatus(void);
unsigned char LCD_ReadStatus(void);
void LCD_putch(unsigned char Character);
void LCD_puts(const char * s);
void LCD_Clear_Text(void);
void LCD_Clear_Graphics(void);
void LCD_Home_Text(void);
void LCD_Home_Graphics(void);
void LCD_Text_Goto(unsigned char x, unsigned char y);
void LCD_PutPixel(unsigned char x, unsigned char y, unsigned char Set);
void LCD_PutRect(unsigned char x1, unsigned char y1, unsigned char x2, unsigned char y2);
void LCD_DrawSprite(const char * DGlyph, unsigned char x, unsigned char y, unsigned char Set);
void Delay(unsigned int NOPS);

/*--------------------------------------------------------------------------
Main Function ...
--------------------------------------------------------------------------*/
void main()
{
unsigned char j, i;

//ADCON1=0b00000111;
//PORTE=0;
PORTB=0;
//PORTD=0;
TRISA=0x00;
//TRISE=0b00000000;
//TRISD=0b11111100;
TRISB=0x00;

//RED_LED=ON;

LCD_Initialize();

LCD_Clear_Text();
LCD_Clear_Graphics();

LCD_Home_Text();
LCD_puts(" T6963 240x64 Pixel Graphic LCD Display ");

LCD_Text_Goto(0,7);
LCD_puts("         http://break.org/gisle         ");

LCD_SendCmd(0b10010000);      //text/graphic display off
LCD_PutRect(00,10, 239, 54);
LCD_SendCmd(0b10011100);      //text/graphic display on



i=42;
while(1)
	{

	for(j=12;j<228;j+=6)
		{
//		GREEN_LED=ON;
			LCD_DrawSprite(Sprite,j,i, ON);
			LCD_DrawSprite(PAC1,j-11,i, ON);
			Delay(4000);
			LCD_DrawSprite(Sprite,j,i, OFF);
			LCD_DrawSprite(PAC1,j-11,i, OFF);
//		GREEN_LED=OFF;
			LCD_DrawSprite(Sprite2,j+3,i, ON);			
			LCD_DrawSprite(PAC2,j-8,i, ON);			
			Delay(4000);
			LCD_DrawSprite(Sprite2,j+3,i, OFF);
			LCD_DrawSprite(PAC2,j-8,i, OFF);

		}
	if(i==12) i=52;
	i-=10;

	for(j=228;j>12;j-=6)
		{
//		GREEN_LED=ON;
			LCD_DrawSprite(Sprite,j,i, ON);
			LCD_DrawSprite(PAC1,j-11,i, ON);
			Delay(4000);
			LCD_DrawSprite(Sprite,j,i, OFF);
			LCD_DrawSprite(PAC1,j-11,i, OFF);
//		GREEN_LED=OFF;
			LCD_DrawSprite(Sprite2,j-3,i, ON);		
			LCD_DrawSprite(PAC2,j-14,i, ON);				
			Delay(4000);
			LCD_DrawSprite(Sprite2,j-3,i, OFF);
			LCD_DrawSprite(PAC2,j-14,i, OFF);

		}

	if(i==12) i=52;
	i-=10;
	}
while(1);
}

/*--------------------------------------------------------------------------*/
void Delay(unsigned int NOPS)
{
unsigned int i;

for(i=0;i<NOPS;i++)
	{
	asm("NOP");
	asm("NOP");
	asm("NOP");
	asm("NOP");
	asm("NOP");
	asm("NOP");
	asm("NOP");
	asm("NOP");
	asm("NOP");
	asm("NOP");

	asm("NOP");
	asm("NOP");
	asm("NOP");
	asm("NOP");
	asm("NOP");
	asm("NOP");
	asm("NOP");
	asm("NOP");
	asm("NOP");
	asm("NOP");

	}
}

/*--------------------------------------------------------------------------*/
void LCD_SendData(unsigned char Data)
{
	LCD_CheckStatus();

	DATADIRECTION = OUTPUT;

	LCD_CD = 0;
	LCD_WR = 0;
	LCD_RD = 1;

	DATAPORT = Data;

	LCD_CE=0;
	asm("NOP");
	LCD_CE=1;
	LCD_WR=1;

}

/*--------------------------------------------------------------------------*/
void LCD_SendCmd(unsigned char Command)
{
	LCD_CheckStatus();

	DATADIRECTION = OUTPUT;

	DATAPORT = Command;

	LCD_CD = 1;
	LCD_RD = 1;
	LCD_WR = 0;
	LCD_CE=0;
	asm("NOP");
	LCD_CE=1;
	LCD_WR=1;
}

/*--------------------------------------------------------------------------*/
void LCD_CheckStatus(void)
{
unsigned char Status;

Status=0;
	while(1)
	{
		Status=LCD_ReadStatus();
		if(Status & 0x03) break;
	}
	

}

/*--------------------------------------------------------------------------*/
unsigned char LCD_ReadStatus(void)
{
unsigned char Status;

	DATADIRECTION=INPUT;

	LCD_CD = 1;
	LCD_RD = 0;
	LCD_WR = 1;
	LCD_CE = 0;

	Status=DATAPORT;

	LCD_CE = 1;
	LCD_RD = 1;

	DATADIRECTION=OUTPUT;

return Status;
}

/*--------------------------------------------------------------------------*/
void LCD_Initialize(void)
{

	TRISA=0x00;
	LCD_CE=1;

	LCD_SendData(0x00);
	LCD_SendData(0x02);
	LCD_SendCmd(0x42);	//Graphics home address is 0x200

	LCD_SendData(40);	//d'40'
	LCD_SendData(0x00);
	LCD_SendCmd(0x43);	//Graphics area set to 40 columns

	LCD_SendData(0x00);
	LCD_SendData(0x00);
	LCD_SendCmd(0x40);	//Text home address i 0

	LCD_SendData(40);	//d'40'
	LCD_SendData(0x00);
	LCD_SendCmd(0x41);	//Text area is 40 columns


	LCD_SendCmd(0x80);	//Logically "or" graphics and text areas mode set.
	
	LCD_SendCmd(0xa1);	//Cursor pattern is 1 line at bottom
	
	
	LCD_SendData(0x00);
	LCD_SendData(0x00);
	LCD_SendCmd(0x21);	//Cursor pointer set at home address
	
	
	LCD_SendCmd(0b10011100);      //text/graphic display on
	
	LCD_SendData(0);
	LCD_SendData(0);
	LCD_SendCmd(0x24);      //pointer set back to home

}

/*--------------------------------------------------------------------------*/
void LCD_putch(unsigned char Character)
{
	LCD_SendData(Character-0x20);
	LCD_SendCmd(0xC0);
}

/*--------------------------------------------------------------------------*/
void LCD_puts(const char * s)
{
 while(*s)
	{ 
	LCD_putch( *s++ );
	}

}

/*--------------------------------------------------------------------------*/
void LCD_Clear_Text(void)
{
unsigned int i;

	LCD_Home_Text();

	for(i=0;i<320;i++)
		{
		LCD_SendData(0x00);
		LCD_SendCmd(0xC0);
		}
	
	LCD_Home_Text();
}


/*--------------------------------------------------------------------------*/
void LCD_Clear_Graphics(void)
{
unsigned int i;

	LCD_Home_Graphics();
	
	for(i=0;i<4192;i++)
		{
		LCD_SendData(0x00);
		LCD_SendCmd(0xC0);	//Address autoincrement
		}
	
	LCD_Home_Graphics();
}

/*--------------------------------------------------------------------------*/
void LCD_Home_Text(void)
{
	LCD_SendData(0x00);
	LCD_SendData(0x00);
	LCD_SendCmd(0x24);      //pointer set back to home
}

/*--------------------------------------------------------------------------*/
void LCD_Home_Graphics(void)
{
	LCD_SendData(0x00);
	LCD_SendData(0x02);	//0x200 is Graphics home..
	LCD_SendCmd(0x24);      //pointer set 
}

/*--------------------------------------------------------------------------*/
void LCD_Text_Goto(unsigned char x, unsigned char y)
{
unsigned int XY;

	XY = 40*y+x;

	LCD_SendData(XY & 0x00FF);
	LCD_SendData(XY>>8);
	LCD_SendCmd(0x24);      //pointer set back to home
}

/*--------------------------------------------------------------------------*/
void LCD_PutPixel(unsigned char x, unsigned char y, unsigned char Set)
{
unsigned int XY;
unsigned char bitByte;

	XY=0x200;
	XY=XY+(y*40);
	XY=XY+(x/6);

	LCD_SendData(XY & 0x00FF);
	LCD_SendData(XY>>8);
	LCD_SendCmd(0x24);      	//pointer set

	bitByte=5-(x % 6);

	Set? bitByte|=0xF8: bitByte|=0xF0;

	LCD_SendCmd(bitByte);		//0b1111SXXX , s is set/reset, xxx is bit number xxx 
					//(Each memorybyte i six graphics bits (pixels))
}

/*--------------------------------------------------------------------------*/
void LCD_PutRect(unsigned char x1, unsigned char y1, unsigned char x2, unsigned char y2)
{
unsigned char i;

for(i=x1;i<x2+1;i++)
	{
		LCD_PutPixel(i, y1, ON);
		LCD_PutPixel(i, y2, ON);
	}

for(i=y1;i<y2+1;i++)
	{
		LCD_PutPixel(x1, i, ON);
		LCD_PutPixel(x2, i, ON);
	}
}

/*--------------------------------------------------------------------------*/
void LCD_DrawSprite(const char * DSprite, unsigned char x, unsigned char y, unsigned char Set)
{
unsigned char i, j, k;

k=0;

	for(j=y;j<(y+10);j++)
	{
	for(i=x; i<(x+8);i++)
		{
		if( (DSprite[j-y]<<k) & 0x80 )  LCD_PutPixel(i,j, Set);
		k++;
		}
	k=0;
	}

}
