#include "tempo.h"
#include <math.h>

// Definition des ports A & B
#define		DIR_DATA					TRISC
#define 	DATA						PORTC

#define		DIR_CTRL					TRISA
#define 	CTRL						PORTA

#define		IN							0xFF
#define 	OUT							0x00

#define 	WRITE						RA0
#define 	READ						RA1
#define 	CHIP_ENABLED 				RA2
#define 	DATA_or_CODE				RA3
#define 	RESET						RA4
#define 	BACKLIGHT 					RA5

#define 	ON							1
#define 	OFF							0

// Definition des fonctions elementaires

#define 	NOP							asm("nop");

// [------------------- Pointer Set -------------------]
#define 	Cursor_Pointer_Set 			PutCode(0X21);
#define 	Offset_Register_Set 		PutCode(0X22);
#define 	Address_Pointer_Set 		PutCode(0X24);

// [------------------- Control Word -------------------]
#define 	Text_Home_Address_Set 		PutCode(0x40);
#define		Text_Home_Address_High		0x00
#define		Text_Home_Address_Low		0x00			//A verifier
#define 	Text_Home_Address			0x0000

#define 	Text_Area_Set 				PutCode(0x41);
#define 	Text_Area_High 				0x00
#define 	Text_Area_Low 				0X10			// 16 Colonnes
#define 	Text_Area					0x0010

#define 	Graphic_Home_Address_Set 	PutCode(0x42);
#define 	Graphic_Home_Address_High	0x80
#define 	Graphic_Home_Address_Low	0x00			//A verifier
#define 	Graphic_Home_Address		0x8000

#define 	Graphic_Area_Set 			PutCode(0x43);
#define 	Graphic_Area_High			0x00
#define 	Graphic_Area_Low			0X10			// 16 Colonnes
#define 	Graphic_Area				0x0010			// 16 Colonnes


// [------------------- Mode Set -------------------]
#define 	OR_Rom 						PutCode(0x80);
#define 	OR_Ram 						PutCode(0x88);
#define 	EXOR_Rom 					PutCode(0x81);
#define 	EXOR_Ram 					PutCode(0x89);
#define 	AND_Rom 					PutCode(0x83);
#define 	AND_Ram 					PutCode(0x8B);
#define 	Text_Rom 					PutCode(0x84);
#define 	Text_Ram 					PutCode(0x8C);

// [------------------- Lecture Ecran -------------------]
#define 	Screen_Peeking 				PutCode(0xE0);
#define 	Screen_Copy					PutCode(0xE8);


#define 	DataWriteIncrement			PutCode(0xC0);
#define 	DataReadIncrement			PutCode(0xC1);
#define 	DataWriteDecrement			PutCode(0xC2);
#define 	DataReadDecrement			PutCode(0xC3);
#define 	DataWriteUnchange			PutCode(0xC4);
#define 	DataReadUnchange			PutCode(0xC5);

#define 	EndOfScreenTxt				0x80 //((Text_Area_High * 16 + Text_Area_Low) * 8)
#define 	XMAX						0x80 //128 Pixels
#define 	YMAX						0x40 //par 64 pixels


/* ----------------------------------------------------------- */

/*void Short_Delay(void);
void LcdReset(void);
int GetData(void);
int LcdBusy(void);
void PutCode(unsigned char Val);
void PutData(unsigned char Val);
void MoveData(unsigned char Immo, unsigned char SDown, unsigned char ReadAct);
void DisplayModes(unsigned char Graphics, unsigned char Text, unsigned char Cursor, unsigned char CursorBlink);
void CursorPattern(int NbrLigne);
void Address_Pointer_Address(unsigned int Address);
void Cursor_Pointer_Address(unsigned int Address);
void ClearTxt(void);
void ClearGraph(void);
void ChangeBit(unsigned char Set, unsigned char Position);
void SetPixel(int X, int Y, unsigned char State, unsigned int HomeAddress);
void LcdInit(void);
void SendCar(char Car);
void SendCarS(char *Car);
*/

// Definition des variables
int BufferRead;

int Immobile, SensDown, Read; 
int X=1;

void Short_Delay (void)
{
 char count;
 count = 3;
 while (--count); /* delay */
}

void LcdReset(void)
{
 RESET = 0;
 Tempo_ms(100);
 RESET = 1;
}
/*
int GetData(void)
{
 DIR_DATA = IN;
 DATA_or_CODE = 0;

 READ = 0;

 CHIP_ENABLED = 0;
 Short_Delay();
 BufferRead = DATA;
 CHIP_ENABLED = 1;

 READ = 1;
 return BufferRead;
}
*/
int LcdBusy(void)
{
 DIR_DATA = IN;
 DATA_or_CODE = 1;

 READ = 0;

 CHIP_ENABLED = 0;
 Short_Delay();
 BufferRead = DATA;
 CHIP_ENABLED = 1;

 READ = 1;
 
 return BufferRead;
}

void PutCode(unsigned char Val)
{
 while((LcdBusy() & 0x03) != 0x03);

 DIR_DATA = OUT;
 DATA = Val;

 DATA_or_CODE = 1;
 WRITE = 0;

 CHIP_ENABLED = 0;
 Short_Delay();
 CHIP_ENABLED = 1;

 WRITE = 1; 
}

void PutData(unsigned char Val)
{
 while((LcdBusy() & 0x03) != 0x03);

 DIR_DATA = OUT;
 DATA = Val;

 DATA_or_CODE = 0;
 WRITE = 0; 

 CHIP_ENABLED = 0;
 Short_Delay();
 CHIP_ENABLED = 1;

 WRITE = 1; 

}


void MoveData(unsigned char Immo, unsigned char SDown, unsigned char ReadAct)
{
 Immobile = Immo;
 SensDown = SDown;
 Read     = ReadAct;
}

void DisplayModes(unsigned char Graphics, unsigned char Text, unsigned char Cursor, unsigned char CursorBlink)
{
 PutCode(0x90 + Graphics * 8 + Text * 4 + Cursor * 2 + CursorBlink);
// CursorBlink => Faire clignoté le curseur
}

void CursorPattern(int NbrLigne)
{
 PutCode(0xA0 + NbrLigne - 1);
}

void Address_Pointer_Address(unsigned int Address)
{
 PutData(Address & 0xFF);
 PutData(Address >> 8);
 Address_Pointer_Set;
}

void Cursor_Pointer_Address(unsigned int Address)
{
 PutData(Address & 0xFF);
 PutData(Address >> 8);
 Cursor_Pointer_Set;
}

void ClearTxt(void)
{
 int i;
 Address_Pointer_Address(Text_Home_Address_High << 8 + Text_Home_Address_Low);
 PutCode(0xB0);
 for(i = 0; i < 0X2000; i++) PutData(0x00);
 PutCode(0xB2);
}

void ClearGraph(void)
{
 int i;
 Address_Pointer_Address(Graphic_Home_Address_High << 8 + Graphic_Home_Address_Low);
 PutCode(0xB0);
 for(i = 0; i < 0X2000; i++) {PutData(0x00);}
 PutCode(0xB2);
}

void ChangeBit(unsigned char Set, unsigned char Position)
{
 PutCode(0xF0 + Set * 8 + Position);
}

void SetPixel(int X, int Y, unsigned char State, unsigned int HomeAddress)
{
/**********************************************
**       X
**     ----->
**   | p------------------q
** Y | |Salut !           |
**   | |                  |
**   v |                  |
**     |                  |
**     b------------------d
**
**********************************************/
  unsigned int Address;
  int i;
  if ( (X>XMAX) || (Y>YMAX) )	return;
  Address = HomeAddress + (Y * XMAX / 8 + X / 8);
  Address_Pointer_Address(Address);
  ChangeBit(State, 7-X%8);
}

void LcdInit(void)
{
 ADCON1=6;		// PORT A passe en mode Numérique 

 DIR_DATA = OUT;
 DATA = 0;
 DIR_CTRL = OUT;

 BACKLIGHT = OFF;
 WRITE = 1;
 READ = 1;
 CHIP_ENABLED = 1;

 LcdReset();

 MoveData(0,0,0);

 PutData(Graphic_Home_Address_Low);		// Graphic Home address
 PutData(Graphic_Home_Address_High);
 Graphic_Home_Address_Set; 				// 0x42

 PutData(Graphic_Area_Low);				// Graphic Area set
 PutData(Graphic_Area_High);
 Graphic_Area_Set;						// 0x43

 PutData(Text_Home_Address_Low);		// Text Home address
 PutData(Text_Home_Address_High);
 Text_Home_Address_Set;					// 0x40

 PutData(Text_Area_Low);				// Text Area set
 PutData(Text_Area_High);
 Text_Area_Set;							// 0x41
 
 OR_Rom;								// 0x81

}

void SendCar(char Car)
{
 char CarT6963C;
 CarT6963C = Car - 0X20;
 PutData(CarT6963C);
 DataWriteIncrement;
 X++;
 if (X > EndOfScreenTxt)
	{
	 X=1;
	 Address_Pointer_Address(Text_Home_Address_High << 8 + Text_Home_Address_Low);
	}
}
/*
void SendCarS(char *Car)
{
 int i;
 for(i=0;Car[i]!=0;i++)
 {
  SendCar(Car[i]);
 }
}

void Lcd_Cercle(int X_Center, int Y_Center, int Rayon, unsigned char State)
{
 int Angle;
 for(Angle = 0; Angle < 361; Angle++)
	{
	 SetPixel(X_Center + (int)(Rayon * cos(Angle * 3.14 / 180)), Y_Center + (int)(Rayon * sin(Angle * 3.14 / 180)), State, Graphic_Home_Address);
	}
}
*/
void Lcd_Ligne(int X1, int Y1, int X2, int Y2, unsigned char State)
{
  int dY, dX;
  int StepX, StepY;
  int Fract;

  dY = Y2 - Y1; dX = X2 - X1;

  if (dY < 0) { dY = -dY; StepY = -1; }
  else { StepY = 1; }
  if (dX < 0) { dX = -dX; StepX = -1; }
  else { StepX = 1; }

  dY <<= 1; dX <<= 1;

  SetPixel(X1, Y1, State, Graphic_Home_Address);

  if (dX > dY)
  {
    Fract = dY - (dX >> 1); 
    while (X1 != X2)
    {
      if (Fract >= 0) { Y1 += StepY; Fract -= dX; }
      X1 += StepX;
      Fract += dY;  
      SetPixel(X1, Y1, State, Graphic_Home_Address);
    }
  }
  else
  {
    Fract = dX - (dY >> 1);
    while (Y1 != Y2)
    {
      if (Fract >= 0) { X1 += StepX; Fract -= dY; }
      Y1 += StepY;
      Fract += dX;
      SetPixel(X1, Y1, State, Graphic_Home_Address);
    }
  }
}

void Lcd_Rectangle(int X1, int Y1, int X2, int Y2, unsigned char State)
{
 Lcd_Ligne(X1, Y1, X1, Y2, State);
 Lcd_Ligne(X1, Y2, X2, Y2, State);
 Lcd_Ligne(X2, Y2, X2, Y1, State);
 Lcd_Ligne(X2, Y1, X1, Y1, State);

}
/*
void Lcd_Triangle(int X1, int Y1, int X2, int Y2, int X3, int Y3, unsigned char State)
{
 Lcd_Ligne(X1, Y1, X2, Y2, State);
 Lcd_Ligne(X2, Y2, X3, Y3, State);
 Lcd_Ligne(X3, Y3, X1, Y1, State);
}
*/
