#include <pic.h>
__CONFIG(WDTDIS & HS & UNPROTECT)
/*This will disable the watchdog timer, specify an HS crystal 25MHz and leave
   the code space unprotected.*/

#define Line_SELA RC0 //RC0 is connected to A pin of double-row socket.
#define Line_SELB RC1 //RC1 is connected to B pin of double-row socket.
#define Line_SELC RC2 //RC2 is connected to C pin of double-row socket.
#define Line_SELD RC3 //RC3 is connected to D pin of double-row socket.

#define Line_EN RB1 //RB1 is connected to EN pin of double-row socket.
#define CLK RB3 //RB3 is connected to CLK pin of double-row socket.
#define LAT RB2 //RB2 is connected to ST pin of double-row socket.

#define DAT_R1 RC4 //RC4 is connected to R1 pin of double-row socket.
#define DAT_R2 RC5 //RC5 is connected to R2 pin of double-row socket.
#define DAT_G1 RC6 //RC6 is connected to G1 pin of double row socket.
#define DAT_G2 RC7 //RC7 is connected to G2 pin of double row socket.

#define KEY RB0 //RB0 is connected to key.

/*This group of data is specifically used to display "If Glitch Press & Hold" 
  and "Sure Electronics".*/;
const unsigned char CoName[224]={
		0x0e,0x03,0x38,0x06,0x21,0x00,0x01,0x00,
		0x84,0x04,0x44,0x04,0x20,0x00,0x01,0x00,
		0x84,0x00,0x04,0x84,0x71,0x38,0x0d,0x00,
		0xc4,0x01,0x74,0x04,0x21,0x04,0x13,0x00,
		0x84,0x00,0x44,0x04,0x21,0x04,0x11,0x00,
		0x84,0x00,0x44,0x04,0x21,0x45,0x11,0x00,
		0x8e,0x00,0x78,0x8e,0xc3,0x38,0x11,0x00,
		
		0x0f,0x00,0x00,0x80,0x11,0x01,0x06,0x04,
		0x11,0x00,0x00,0x40,0x12,0x01,0x04,0x04,
		0x51,0xe3,0x38,0x4e,0x11,0x39,0x84,0x05,
		0xcf,0x14,0x05,0x81,0xf0,0x45,0x44,0x06,
		0x41,0xf0,0x39,0x4e,0x15,0x45,0x44,0x04,
		0x41,0x10,0x40,0x50,0x12,0x45,0x44,0x04,
		0x41,0xe0,0x3c,0x8f,0x15,0x39,0x8e,0x07,
		
		0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x41,0xd2,0x38,0x00,0x00,0x00,0x00,0x00,
		0x4e,0x32,0x45,0x00,0x00,0x00,0x00,0x00,
		0x50,0x12,0x7c,0x00,0x00,0x00,0x00,0x00,
		0x51,0x12,0x04,0x00,0x00,0x00,0x00,0x00,
		0x8e,0x15,0x38,0x00,0x00,0x00,0x00,0x00,
		
		0x9f,0x01,0x00,0x00,0x00,0x00,0x04,0x00,
		0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x01,0xe1,0x38,0x47,0xe3,0x34,0xc6,0xf1,
		0x1f,0x11,0x05,0xc2,0x14,0x4d,0x24,0x08,
		0x01,0xf1,0x05,0x42,0x10,0x45,0x24,0x70,
		0x01,0x11,0x44,0x52,0x10,0x45,0x24,0x82,
		0x9f,0xe3,0x38,0x4c,0xe0,0x44,0xce,0x79
		};
unsigned char cnt,flag,guide,cnt_flag;	//flag=0 suggests diameter of LED is 5mm.
										//flag=1 suggests diameter os LED is 3mm.
										//guide=0 suggests waiting to be confirm.
										//guide=1 suggests testing process.
										//Variable "cnt_flag" ranges from 0 to 111,
										//assistant flag of element of data array.

/*These variables are used to store key states.*/
unsigned char keydata,key_last,key_now;

void delay_100ms(void)
{
	unsigned char i,j;
	for(j=0;j<208;j++)
		for(i=0;i<250;i++);
}
void delay_sometime()
{
	unsigned char j;
	for(j=0;j<100;j++);
}
void init(void)
{
	TRISA=0b00000000;
	TRISB=0b00000001;	//RB0 input, RB1,RB2,RB3 output.
	TRISC=0b00000000;	//RC0-RC7 output.
	
	key_last=KEY;
	key_now=KEY;
	
	keydata=12;
	guide=0;
	flag=0;
	cnt_flag=0;
}
void judgekey(void)
{
	key_now=KEY;
	if((key_last==1)&(key_now=0))
	{
		delay_sometime();	//Delay for according to buffering.
		if(key_now==0)
		{
			keydata++;
			keydata=keydata%13;
		}
	}
	key_last=key_now;
}
//Send a line of data wich contains 64 bits.
//Send one bit with clk down to up.
//Every 64bits should be ended with latch down to up.
void sendone(unsigned char line)
{
	unsigned char k,value,t;	//Variable "k" counts times of bit sent in a line.
								//Variable "value" tells value to be sent.
								//Variable "t" is available only when sending character
								//of data array.
	if(!flag)
		Line_EN=0;				//Turn off DE-DP029~DE-DP032.
	else
		Line_EN=1;				//Turn off DE-DP033.
	value=0x00;
	if((keydata==0)||(keydata==3))
		value=~value;
	for(k=0;k<64;k++)			//Send a line of data wich contains 64 bits.
	{
		switch(keydata)
		{
		case 0:					//0 illuminates the upper left 4x4 area of each 8x8 dot matrix.
		case 1:					//1 illuminates the upper right 4x4 area of each 8x8 dot matrix.
		case 2: 				//2 illuminates the lower right 4x4 area of each 8x8 dot matrix.
		case 3:					//3 illuminates the lower left 4x4 area of each 8x8 dot matrix.
		{
			if(k%4==0)
				value=~value;
			DAT_R1=value;
			DAT_R2=value;
			DAT_G1=value;
			DAT_G2=value;
		}break;
								//4-7 for checking red LED, 4 illuminates odd number rows
								//and 5 illuminates even number rows.
		case 4:
		{
			DAT_R1=value;
			DAT_R2=value;
			DAT_G1=1;
			DAT_G2=1;
			value=~value;
		}break;
		case 5:
		{
			value=~value;
			DAT_R1=value;
			DAT_R2=value;
			DAT_G1=1;
			DAT_G2=1;
		}break;
		
		case 6:					//6 illuminates the adjacent two lines of LED starting from
								//line 1 and 2 and those followed at two lines intervals.
								//7 illuminates the adjacent two lines of LED starting from
								//line 3 and 4 and those followed at two lines intervals.
		case 7:
		{
			DAT_R1=value;
			DAT_R2=value;
			DAT_G1=1;
			DAT_G2=1;
		}break;
		case 8:					//8~11 for checking green LED, 8 illuminates odd number rows
		{						//and 9 illuminates even number rows.
			DAT_R1=1;
			DAT_R2=1;
			DAT_G1=value;
			DAT_G2=value;
			value=~value;
		}break;
		case 9:
		{
			value=~value;
			DAT_R1=1;
			DAT_R2=1;
			DAT_G1=value;
			DAT_G2=value;
		}break;
		case 10:				//10 illuminates the adjacent two lines of LED starting from
								//line 1 and 2 and those followed at two lines intervals.
		case 11:				//11 illuminates the adjacent two lines of LED starting from
		{						//line 3 and 4 and those followed at two lines intervals.
			DAT_R1=1;
			DAT_R2=1;
			DAT_G1=value;
			DAT_G2=value;
		}break;
		case 12:
		{
			if(line%8==7)
				t=1;
			else
			{
				if(k%8==0)
				{				//Fetch a character from data array.
					value=*(CoName+(guide<<7)-(guide<<4)+cnt_flag);
					value=~value;
					cnt_flag++;
				}
				t=value & 1;
			}
			DAT_R1=t;
			DAT_R2=t;
			DAT_G1=1;
			DAT_G2=1;
			value=value>>1;
			}break;
		}
		CLK=0;					//Send one bit with CLK down to up.
		CLK=1;
	}
	if(!flag)
		Line_EN=1;				//Turn on DE-DP029~DE-DP032.
	else
		Line_EN=0;				//Turn on DE-DP033.
	LAT=0;						//Every 64 bits should be ended with latch down to up.
	LAT=1;
	if(cnt_flag==112)
		cnt_flag=0;
	delay_sometime();			//Delay some time for display.
	if(!flag)
		Line_EN=0;				//Turn off DE-DP029~DE-DP032.
	else
		Line_EN=1;				//Turn off DE-DP033.
}
//This program is used for dynamic scanning display.
void rundisplay()
{
	unsigned char t,temp;
	for(t=0;t<16;t++)
	{
		temp=t;
		Line_SELA==temp & 1;		//Select line.
		temp=temp>>1;
		if((keydata==6)||(keydata==10))
			Line_SELB=0;
		else if((keydata==7)||(keydata==11))
			Line_SELB=1;
		else
			Line_SELB==temp & 1;
		temp=temp>>1;
		if(keydata<2)
			Line_SELC=0;
		else if((keydata==2)||(keydata==3))
			Line_SELC=1;
		else
			Line_SELC==temp & 1;
		temp=temp>>1;
		Line_SELD==temp & 1;
		sendone(t);
	}
}
//When time of pressing the key is less than 1 second, it may be seemed as a short time,
//no less than 1 second as a long time.
void LongOrShort(void)
{
	key_now=KEY;
	if((key_last==1)||(key_now==0))
	{
		NOP();				//Delay for confirming the pressing action.
		while(!key_now)
		{
			delay_100ms();
			cnt++;
			key_now=KEY;
		}
		if(cnt<10)
			flag=0;
		else
			flag=1;
		guide=1;			//Go to testing process.
	}
	key_last=key_now;
}
void main(void)
{
	init();
	while(1)
	{
		if(guide==0)
			LongOrShort();
		else
			judgekey();
		rundisplay();
	}
}