/*********************************************************************
 *                 Flowcode LCD Display Component Code
 *
 * File: PIC_LCD.c
 *
 * (c) 2009 Matrix Multimedia Ltd.
 * http://www.matrixmultimedia.com
 *
 * Software License Agreement
 *
 * The software supplied herewith by Matrix Multimedia Ltd (the
 * “Company”) for its Flowcode graphical programming language is
 * intended and supplied to you, the Company’s customer, for use
 * solely and exclusively on the Company's products. The software
 * is owned by the Company, and is protected under applicable
 * copyright laws. All rights are reserved. Any use in violation
 * of the foregoing restrictions may subject the user to criminal
 * sanctions under applicable laws, as well as to civil liability
 * for the breach of the terms and conditions of this licence.
 *
 * THIS SOFTWARE IS PROVIDED IN AN “AS IS” CONDITION. NO WARRANTIES,
 * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
 * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,
 * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
 * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
 *
 * Changelog:
 *
 *  date  | by | description
 * -------+----+-----------------------------------------------------
 * 300307 | ST | Created
 * 150807 | ST | Added a missing delay to <RawSend> function
 * 100608 | BR | Modified <Cursor> addressing on 4-line displays
 * 170209 | BR | Modified <Cursor> addressing on 16/20 MX_UINT8 4 line displays
 * 250209 | BR | Modified <Start> to allow for a more reliable startup
 * 120309 | BR | Added ClearLine and ScrollDisplay functions.
 * 180309 | BR | Changed delays to be WDT compatible
 * 130509 | BR | Added % definitions to DefinesCode section
 * 230311 | BR | Changed code to work for hitech and boostc without ifdefs
 * 051011 | BR | Modified the component to fit in with the CAL
 * 011211 | BR | Updated FC_CAL_Bit functions
 *180212 | MW | Added extra delay option for clock speeds 30MHz or above
 ********************************************************************/

/*********************************************************************

 Return & parameter types:
   void
   MX_UINT8
   MX_SINT16
   MX_STRING

 Pin directions:
   0 = OUTPUT
   2 = INPUT
   3 = BIDIRECTIONAL

**********************************************************************

[Settings]
CLSID={02A7087C-4D0C-4AA4-9522-82A47E88BDC8}
IsAnalogue=0
MultipleAllowed=1
Description=Alphanumeric LCD Flowcode Component

**********************************************************************

[Port]
DesiredPort=1
PortMandatory=1
SamePortAsID=-1

[Pins]
Count=0
DesiredPin=0
BitMandatory=1

[PinPort]
# PORTA = 0
# PORTB = 1
# PORTC = 2
# PORTD = 3
# PORTE = 4

[PinDesiredBit]

[PinDirection]
# DIR_INPUT = 2
# DIR_OUTPUT = 0
# DIR_BIDIRECTIONAL = 3

[PinMustUsePort]
# boolean

[SamePortAsPinX]
# -1 = any pin
# otherwise, the pin number

[PinMustUsePin]
# boolean

[PinValue]
# boolean (0 = off, 1 = on)

**********************************************************************

NOTE: For simulation to work, these macros _MUST_ remain at the indicated index:
	1=RawSend
	2=Start
	3=Clear
	4=PrintASCII
	5=Command
	6=Cursor
	7=PrintNumber
	8=PrintString
	9=ScrollDisplay
	10=ClearLine


[MacroNames]
Count=11
1=RawSend
2=Start
3=Clear
4=PrintASCII
5=Command
6=Cursor
7=PrintNumber
8=PrintString
9=ScrollDisplay
10=ClearLine
11=RAM_Write

[MacroReturns]
1=void
2=void
3=void
4=void
5=void
6=void
7=void
8=void
9=void
10=void
11=void

[MacroIsPrivate]
1=1
2=0
3=0
4=0
5=0
6=0
7=0
8=0
9=0
10=0
11=0

[MacroParameters_RawSend]
Count=2
1=in
2=mask

[MacroParamTypes_RawSend]
1=MX_UINT8
2=MX_UINT8

[MacroParameters_Start]
Count=0

[MacroParamTypes_Start]


[MacroParameters_Clear]
Count=0

[MacroParamTypes_Clear]


[MacroParameters_PrintASCII]
Count=1
1=Character

[MacroParamTypes_PrintASCII]
1=MX_UINT8


[MacroParameters_Command]
Count=1
1=in

[MacroParamTypes_Command]
1=MX_UINT8


[MacroParameters_Cursor]
Count=2
1=x
2=y

[MacroParamTypes_Cursor]
1=MX_UINT8
2=MX_UINT8


[MacroParameters_PrintNumber]
Count=1
1=Number

[MacroParamTypes_PrintNumber]
1=MX_SINT16


[MacroParameters_PrintString]
Count=1
1=String

[MacroParamTypes_PrintString]
1=MX_STRING


[MacroParameters_ScrollDisplay]
Count=2
1=Direction
2=Num_Positions

[MacroParamTypes_ScrollDisplay]
1=MX_UINT8
2=MX_UINT8


[MacroParameters_ClearLine]
Count=1
1=Line

[MacroParamTypes_ClearLine]
1=MX_UINT8

[MacroParameters_RAM_Write]
Count=9
1=nIdx
2=d0
3=d1
4=d2
5=d3
6=d4
7=d5
8=d6
9=d7

[MacroParamTypes_RAM_Write]
1=MX_UINT8
2=MX_UINT8
3=MX_UINT8
4=MX_UINT8
5=MX_UINT8
6=MX_UINT8
7=MX_UINT8
8=MX_UINT8
9=MX_UINT8

/********************************************************************
 * ADDITIONAL CODE
 ********************************************************************/

/*DefinesCode_Start*/

/**** Macro Substitutions ****
a = Unique Component Reference Number
b = D1 Port Letter
c = D2 Port Letter
d = D3 Port Letter
e = D4 Port Letter
f = RS Port Letter
g = E Port Letter
h = Data 1_Pin
i = Data 2 Pin
j = Data 3 Pin
k = Data 4 Pin
l = RS Pin
m = Enable Pin
n = Row Count
o = Column Count
******************************/

	//component connections
	#define %a_PORT0    port%b
	#define %a_PORT1    port%c
	#define %a_PORT2    port%d
	#define %a_PORT3    port%e
	#define %a_PORT4    port%f
	#define %a_PORT5    port%g
	#define %a_TRIS0    tris%b
	#define %a_TRIS1    tris%c
	#define %a_TRIS2    tris%d
	#define %a_TRIS3    tris%e
	#define %a_TRIS4    tris%f
	#define %a_TRIS5    tris%g
	#define %a_BIT0    	%h
	#define %a_BIT1    	%i
	#define %a_BIT2    	%j
	#define %a_BIT3    	%k
	#define %a_RS      	%l
	#define %a_E       	%m
	#define %a_ROWCNT	%n
	#define %a_COLCNT	%o

	#ifdef _BOOSTC
	  #if MX_CLK_SPEED  <30000000
		#define %a_DELAY   delay_10us(10)  //Clock Less then 30MHz?
		 #else
		  #define %a_DELAY   delay_10us(15) 
		#endif
	      #endif
	#ifdef _C2C_
	  #define %a_DELAY   delay_us(100)
	#endif
	#ifdef HI_TECH_C
	  #define %a_DELAY   __delay_us(120)
	#endif
	#ifndef %a_DELAY
	  #define %a_DELAY   delay_us(100)
	#endif

/*DefinesCode_End*/

/*InitialisationCode_Start*/
/*InitialisationCode_End*/

/*InterruptCode_Start*/
/*InterruptCode_End*/

/********************************************************************
 * FUNCTIONS
 ********************************************************************/

void RawSend(MX_UINT8 in, MX_UINT8 mask)
{
/*Macro_RawSend_Start*/

	MX_UINT8 pt;

	FC_CAL_Bit_Low(%a_PORT0, %a_BIT0);
	FC_CAL_Bit_Low(%a_PORT1, %a_BIT1);
	FC_CAL_Bit_Low(%a_PORT2, %a_BIT2);
	FC_CAL_Bit_Low(%a_PORT3, %a_BIT3);
	FC_CAL_Bit_Low(%a_PORT4, %a_RS);
	FC_CAL_Bit_Low(%a_PORT5, %a_E);
	pt = ((in >> 4) & 0x0f);
	if (pt & 0x01)
	    FC_CAL_Bit_High(%a_PORT0, %a_BIT0);
	if (pt & 0x02)
	    FC_CAL_Bit_High(%a_PORT1, %a_BIT1);
	if (pt & 0x04)
	    FC_CAL_Bit_High(%a_PORT2, %a_BIT2);
	if (pt & 0x08)
	    FC_CAL_Bit_High(%a_PORT3, %a_BIT3);
	if (mask)
	    FC_CAL_Bit_High(%a_PORT4, %a_RS);
	%a_DELAY;
	FC_CAL_Bit_High (%a_PORT5, %a_E);
	%a_DELAY;
	FC_CAL_Bit_Low (%a_PORT5, %a_E);
	pt = (in & 0x0f);
	%a_DELAY;
	FC_CAL_Bit_Low(%a_PORT0, %a_BIT0);
	FC_CAL_Bit_Low(%a_PORT1, %a_BIT1);
	FC_CAL_Bit_Low(%a_PORT2, %a_BIT2);
	FC_CAL_Bit_Low(%a_PORT3, %a_BIT3);
	FC_CAL_Bit_Low(%a_PORT4, %a_RS);
	FC_CAL_Bit_Low(%a_PORT5, %a_E);
	if (pt & 0x01)
	    FC_CAL_Bit_High(%a_PORT0, %a_BIT0);
	if (pt & 0x02)
	    FC_CAL_Bit_High(%a_PORT1, %a_BIT1);
	if (pt & 0x04)
	    FC_CAL_Bit_High(%a_PORT2, %a_BIT2);
	if (pt & 0x08)
	    FC_CAL_Bit_High(%a_PORT3, %a_BIT3);
	if (mask)
	    FC_CAL_Bit_High(%a_PORT4, %a_RS);
	%a_DELAY;
	FC_CAL_Bit_High (%a_PORT5, %a_E);
	%a_DELAY;
	FC_CAL_Bit_Low (%a_PORT5, %a_E);
	%a_DELAY;

/*Macro_RawSend_End*/
}


void Start()
{
/*Macro_Start_Start*/

	FC_CAL_Bit_Low_DDR(%a_PORT0, %a_TRIS0, %a_BIT0);
	FC_CAL_Bit_Low_DDR(%a_PORT1, %a_TRIS1, %a_BIT1);
	FC_CAL_Bit_Low_DDR(%a_PORT2, %a_TRIS2, %a_BIT2);
	FC_CAL_Bit_Low_DDR(%a_PORT3, %a_TRIS3, %a_BIT3);
	FC_CAL_Bit_Low_DDR(%a_PORT4, %a_TRIS4, %a_RS);
	FC_CAL_Bit_Low_DDR(%a_PORT5, %a_TRIS5, %a_E);

	Wdt_Delay_Ms(12);

	RawSend(0x33, 0);
	Wdt_Delay_Ms(2);
	RawSend(0x33, 0);
	Wdt_Delay_Ms(2);
	RawSend(0x32, 0);
	Wdt_Delay_Ms(2);
	RawSend(0x2c, 0);
	Wdt_Delay_Ms(2);
	RawSend(0x06, 0);
	Wdt_Delay_Ms(2);
	RawSend(0x0c, 0);
	Wdt_Delay_Ms(2);

	//clear the display
	RawSend(0x01, 0);
	Wdt_Delay_Ms(2);
	RawSend(0x02, 0);
	Wdt_Delay_Ms(2);

/*Macro_Start_End*/
}



void Clear()
{
/*Macro_Clear_Start*/

	RawSend(0x01, 0);
	Wdt_Delay_Ms(2);
	RawSend(0x02, 0);
	Wdt_Delay_Ms(2);

/*Macro_Clear_End*/
}



void PrintASCII(MX_UINT8 Character)
{
/*Macro_PrintASCII_Start*/

	RawSend(Character, 0x10);

/*Macro_PrintASCII_End*/
}



void Command(MX_UINT8 in)
{
/*Macro_Command_Start*/

	RawSend(in, 0);
	Wdt_Delay_Ms(2);

/*Macro_Command_End*/
}



void Cursor(MX_UINT8 x, MX_UINT8 y)
{
/*Macro_Cursor_Start*/

  #if (%a_ROWCNT == 1)
    y=0x80;
  #endif

  #if (%a_ROWCNT == 2)
	if (y==0)
		y=0x80;
	else
		y=0xc0;
  #endif

  #if (%a_ROWCNT == 4)
	if (y==0)
		y=0x80;
	else if (y==1)
		y=0xc0;

	#if (%a_COLCNT == 16)
		else if (y==2)
			y=0x90;
		else
			y=0xd0;
	#endif

	#if (%a_COLCNT == 20)
		else if (y==2)
			y=0x94;
		else
			y=0xd4;
	#endif
  #endif

	RawSend(y+x, 0);
	Wdt_Delay_Ms(2);

/*Macro_Cursor_End*/
}


void PrintNumber(MX_SINT16 Number)
{
/*Macro_PrintNumber_Start*/

	MX_SINT16 tmp_int;
	MX_UINT8 tmp_byte;

	if (Number < 0)
	{
		RawSend('-', 0x10);
		Number = 0 - Number;
	}

	tmp_int = Number;
	if (Number >= 10000)
	{
		tmp_byte = tmp_int / 10000;
		RawSend('0' + tmp_byte, 0x10);

		while (tmp_byte > 0)
		{
			tmp_int = tmp_int - 10000;
			tmp_byte--;
		}
	}
	if (Number >= 1000)
	{
		tmp_byte = tmp_int / 1000;
		RawSend('0' + tmp_byte, 0x10);

		while (tmp_byte > 0)
		{
			tmp_int = tmp_int - 1000;
			tmp_byte--;
		}
	}
	if (Number >= 100)
	{
		tmp_byte = tmp_int / 100;
		RawSend('0' + tmp_byte, 0x10);

		while (tmp_byte > 0)
		{
			tmp_int = tmp_int - 100;
			tmp_byte--;
		}
	}
	if (Number >= 10)
	{
		tmp_byte = tmp_int / 10;
		RawSend('0' + tmp_byte, 0x10);

		while (tmp_byte > 0)
		{
			tmp_int = tmp_int - 10;
			tmp_byte--;
		}
	}
	RawSend('0' + tmp_int, 0x10);

/*Macro_PrintNumber_End*/
}


void PrintString(MX_UINT8 * String, MX_UINT8 MSZ_String)
{
/*Macro_PrintString_Start*/

	MX_UINT8 idx = 0;

	for (idx=0; idx<MSZ_String; idx++)
	{
		if (String[idx] == 0)
		{
			break;
		}
		RawSend(String[idx], 0x10);
	}

/*Macro_PrintString_End*/
}


void ScrollDisplay(MX_UINT8 Direction, MX_UINT8 Num_Positions)
{
/*Macro_ScrollDisplay_Start*/

	MX_UINT8 cmd = 0;
	MX_UINT8 count;

	//Choose the direction
	switch (Direction)
	{
		case 0:
		case 'l':
		case 'L':

			cmd = 0x18;
			break;

		case 1:
		case 'r':
		case 'R':

			cmd = 0x1C;
			break;

		default:
			break;
	}

	//If direction accepted then scroll the specified amount
	if (cmd)
	{
		for (count = 0; count < Num_Positions; count++)
			Command(cmd);
	}

/*Macro_ScrollDisplay_End*/
}


void ClearLine(MX_UINT8 Line)
{
/*Macro_ClearLine_Start*/

	MX_UINT8 count;
	MX_UINT8 rowcount;

	//Define number of columns per line
	#if (%a_ROWCNT == 1)
		rowcount=80;
	#endif

	#if (%a_ROWCNT == 2)
		rowcount=40;
	#endif

	#if (%a_ROWCNT == 4)
		#if (%a_COLCNT == 16)
			rowcount=16;
		#endif
		#if (%a_COLCNT == 20)
			rowcount=20;
		#endif
	#endif

	//Start at beginning of the line
	Cursor (0, Line);

	//Send out spaces to clear line
	for (count = 0; count < rowcount; count++)
		RawSend(' ', 0x10);

	//Move back to the beginning of the line.
	Cursor (0, Line);

/*Macro_ClearLine_End*/
}


void RAM_Write(MX_UINT8 nIdx, MX_UINT8 d0,  MX_UINT8 d1,  MX_UINT8 d2,  MX_UINT8 d3,  MX_UINT8 d4,  MX_UINT8 d5,  MX_UINT8 d6,  MX_UINT8 d7)
{
/*Macro_RAM_Write_Start*/
   //set CGRAM address

   RawSend(64 + (nIdx << 3), 0);
   delay_ms(2);

   //write CGRAM data
   RawSend(d0, 0x10);
   RawSend(d1, 0x10);
   RawSend(d2, 0x10);
   RawSend(d3, 0x10);
   RawSend(d4, 0x10);
   RawSend(d5, 0x10);
   RawSend(d6, 0x10);
   RawSend(d7, 0x10);

   //Clear the display
   RawSend(0x01, 0);
   delay_ms(2);
   RawSend(0x02, 0);
   delay_ms(2);

/*Macro_RAM_Write_End*/
}


