/*********************************************************************
 *                 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 char 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
 * 180212 | MW | Added extra delay option for clock speeds 30MHz or above
 ********************************************************************/

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

 Return & parameter types:
   void
   char
   short
   char*

 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)

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

[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=char
2=char

[MacroParameters_Start]
Count=0

[MacroParamTypes_Start]


[MacroParameters_Clear]
Count=0

[MacroParamTypes_Clear]


[MacroParameters_PrintASCII]
Count=1
1=Character

[MacroParamTypes_PrintASCII]
1=char


[MacroParameters_Command]
Count=1
1=in

[MacroParamTypes_Command]
1=char


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

[MacroParamTypes_Cursor]
1=char
2=char


[MacroParameters_PrintNumber]
Count=1
1=Number

[MacroParamTypes_PrintNumber]
1=short


[MacroParameters_PrintString]
Count=1
1=String

[MacroParamTypes_PrintString]
1=char*


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

[MacroParamTypes_ScrollDisplay]
1=char
2=char


[MacroParameters_ClearLine]
Count=1
1=Line

[MacroParamTypes_ClearLine]
1=char

[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=char
2=char
3=char
4=char
5=char
6=char
7=char
8=char
9=char

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

/*DefinesCode_Start*/

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

	//component connections
	#define %s_PORT0    %a
	#define %s_TRIS0    %b
	#define %s_PORT1    %c
	#define %s_TRIS1    %d
	#define %s_PORT2    %e
	#define %s_TRIS2    %f
	#define %s_PORT3    %g
	#define %s_TRIS3    %h
	#define %s_PORT4    %i
	#define %s_TRIS4    %j
	#define %s_PORT5    %k
	#define %s_TRIS5    %l
	#define %s_BIT0    	%m
	#define %s_BIT1    	%n
	#define %s_BIT2    	%o
	#define %s_BIT3    	%p
	#define %s_RS      	%q
	#define %s_E       	%r
	#define %s_ROWCNT	%t
	#define %s_COLCNT	%u

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

	#define ModID%s%s (((%b << 5) + %a) << 9)

/*DefinesCode_End*/

/*InitialisationCode_Start*/
/*InitialisationCode_End*/

/*InterruptCode_Start*/
/*InterruptCode_End*/

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

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

#ifndef MX_MIAC_SYSTEM
	unsigned char pt;

	clear_bit(%s_PORT0, %s_BIT0);
	clear_bit(%s_PORT1, %s_BIT1);
	clear_bit(%s_PORT2, %s_BIT2);
	clear_bit(%s_PORT3, %s_BIT3);
	clear_bit(%s_PORT4, %s_RS);
	clear_bit(%s_PORT5, %s_E);
	pt = ((in >> 4) & 0x0f);
	if (pt & 0x01)
	    set_bit(%s_PORT0, %s_BIT0);
	if (pt & 0x02)
	    set_bit(%s_PORT1, %s_BIT1);
	if (pt & 0x04)
	    set_bit(%s_PORT2, %s_BIT2);
	if (pt & 0x08)
	    set_bit(%s_PORT3, %s_BIT3);
	if (mask)
	    set_bit(%s_PORT4, %s_RS);
	%s_DELAY;
	set_bit (%s_PORT5, %s_E);
	%s_DELAY;
	clear_bit (%s_PORT5, %s_E);
	pt = (in & 0x0f);
	%s_DELAY;
	clear_bit(%s_PORT0, %s_BIT0);
	clear_bit(%s_PORT1, %s_BIT1);
	clear_bit(%s_PORT2, %s_BIT2);
	clear_bit(%s_PORT3, %s_BIT3);
	clear_bit(%s_PORT4, %s_RS);
	clear_bit(%s_PORT5, %s_E);
	if (pt & 0x01)
	    set_bit(%s_PORT0, %s_BIT0);
	if (pt & 0x02)
	    set_bit(%s_PORT1, %s_BIT1);
	if (pt & 0x04)
	    set_bit(%s_PORT2, %s_BIT2);
	if (pt & 0x08)
	    set_bit(%s_PORT3, %s_BIT3);
	if (mask)
	    set_bit(%s_PORT4, %s_RS);
	%s_DELAY;
	set_bit (%s_PORT5, %s_E);
	%s_DELAY;
	clear_bit (%s_PORT5, %s_E);
	%s_DELAY;

#endif

/*Macro_RawSend_End*/
}


void Start()
{
/*Macro_Start_Start*/

#ifdef MX_MIAC_SYSTEM
  #if (%a != MX_MIAC_MM_MIAC_BASE)

	MIAC_CAN_TX[0] = %m;
	MIAC_CAN_TX[1] = %n;
	MIAC_CAN_TX[2] = %o;
	MIAC_CAN_TX[3] = %p;
	MIAC_CAN_TX[4] = %q;
	MIAC_CAN_TX[5] = %r;

	MIAC_Module_WR(ModID%s, 608, 6,1,1);
	MIAC_Module_GetAck(ModID%s + 32, 608, 20);

	MIAC_CAN_TX[0] = %t;
	MIAC_CAN_TX[1] = %u;
	MIAC_Module_WR(ModID%s, 608, 2,0,0);
	MIAC_Module_GetAck(ModID%s + 32, 608, 255);

  #endif
#else

	clear_bit(%s_TRIS0, %s_BIT0);
	clear_bit(%s_TRIS1, %s_BIT1);
	clear_bit(%s_TRIS2, %s_BIT2);
	clear_bit(%s_TRIS3, %s_BIT3);
	clear_bit(%s_TRIS4, %s_RS);
	clear_bit(%s_TRIS5, %s_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);
#endif

/*Macro_Start_End*/
}



void Clear()
{
/*Macro_Clear_Start*/

#ifdef MX_MIAC_SYSTEM
  #if (%a != MX_MIAC_MM_MIAC_BASE)

	MIAC_Module_WR(ModID%s, 609, 0,1,0);
	MIAC_Module_GetAck(ModID%s + 32, 609, 200);
  #endif
#else
	RawSend(0x01, 0);
	Wdt_Delay_Ms(2);
	RawSend(0x02, 0);
	Wdt_Delay_Ms(2);
#endif

/*Macro_Clear_End*/
}



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

#ifdef MX_MIAC_SYSTEM
  #if (%a != MX_MIAC_MM_MIAC_BASE)



	MIAC_CAN_TX[0] = Character;

	MIAC_Module_WR(ModID%s, 610, 1,1,0);
	MIAC_Module_GetAck(ModID%s + 32, 610, 20);
  #endif
#else
	RawSend(Character, 0x10);
#endif

/*Macro_PrintASCII_End*/
}



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

#ifdef MX_MIAC_SYSTEM
  #if (%a != MX_MIAC_MM_MIAC_BASE)

	MIAC_CAN_TX[0] = in;

	MIAC_Module_WR(ModID%s, 611, 1,1,0);
	MIAC_Module_GetAck(ModID%s + 32, 611, 200);
  #endif
#else
	RawSend(in, 0);
	Wdt_Delay_Ms(2);
#endif

/*Macro_Command_End*/
}



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

#ifdef MX_MIAC_SYSTEM
  #if (%a != MX_MIAC_MM_MIAC_BASE)

	MIAC_CAN_TX[0] = x;
	MIAC_CAN_TX[1] = y;

	MIAC_Module_WR(ModID%s, 612, 2,1,0);
	MIAC_Module_GetAck(ModID%s + 32, 612, 20);
  #endif

#else

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

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

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

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

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

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

/*Macro_Cursor_End*/
}


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

#ifdef MX_MIAC_SYSTEM
  #if (%a != MX_MIAC_MM_MIAC_BASE)

	MIAC_CAN_TX[1] = Number;
	MIAC_CAN_TX[0] = Number >> 8;

	MIAC_Module_WR(ModID%s, 613, 4,1,0);
	MIAC_Module_GetAck(ModID%s + 32, 613, 200);
  #endif

#else

	short tmp_int;
	char 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);
#endif

/*Macro_PrintNumber_End*/
}


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

	char idx = 0;

#ifdef MX_MIAC_SYSTEM
  #if (%a != MX_MIAC_MM_MIAC_BASE)

	char msg_count, ch;
	char cmd_start = 1;
	char more_data = 1;

	// Split string into 6-byte packets
	do
	{
		msg_count = 0;
		do
		{
			ch = String[idx];
			if (ch)
			{
				MIAC_CAN_TX[msg_count] = ch;
				idx = idx + 1;
				msg_count = msg_count + 1;
			}
		}
		while (ch && (msg_count < 6) && (idx < MSZ_String));			// check for 2 x End Of String conditions and packet full

		if (idx == MSZ_String)											// end of string
		{
			more_data = 0;
		}else{
			if (String[idx] == 0) more_data = 0;						// next ch = null
		}

		MIAC_Module_WR(ModID%s, 614, msg_count,cmd_start,more_data);		// TX data
		MIAC_Module_GetAck(ModID%s + 32, 614, 200);

		cmd_start = 0;
	}
	while (more_data);
  #endif
#else
	for (idx=0; idx<MSZ_String; idx++)
	{
		if (String[idx] == 0)
		{
			break;
		}
		RawSend(String[idx], 0x10);
	}
#endif

/*Macro_PrintString_End*/
}


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

#ifdef MX_MIAC_SYSTEM
  #if (%a != MX_MIAC_MM_MIAC_BASE)

	MIAC_CAN_TX[0] = Direction;
	MIAC_CAN_TX[1] = Num_Positions;

	MIAC_Module_WR(ModID%s, 615, 2,1,0);
	MIAC_Module_GetAck(ModID%s + 32, 615, 20);
  #endif
#else

	char cmd = 0;
	char 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);
	}
#endif

/*Macro_ScrollDisplay_End*/
}


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

#ifdef MX_MIAC_SYSTEM
  #if (%a != MX_MIAC_MM_MIAC_BASE)

	MIAC_CAN_TX[0] = Line;

	MIAC_Module_WR(ModID%s, 616, 1,1,0);
	MIAC_Module_GetAck(ModID%s + 32, 616, 200);
  #endif
#else
	char count;
	char rowcount;

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

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

	#if (%s_ROWCNT == 4)
		#if (%s_COLCNT == 16)
			rowcount=16;
		#endif
		#if (%s_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);
#endif

/*Macro_ClearLine_End*/
}


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

#ifdef MX_MIAC_SYSTEM
  #if (%a != MX_MIAC_MM_MIAC_BASE)

	MIAC_CAN_TX[0] = nIdx;
	MIAC_CAN_TX[1] = d0;
	MIAC_CAN_TX[2] = d1;
	MIAC_CAN_TX[3] = d2;
	MIAC_CAN_TX[4] = d3;
	MIAC_CAN_TX[5] = d4;

	MIAC_Module_WR(ModID%s, 617, 6,1,1);
	MIAC_Module_GetAck(ModID%s + 32, 617, 20);

	MIAC_CAN_TX[0] = d5;
	MIAC_CAN_TX[1] = d6;
	MIAC_CAN_TX[2] = d7;

	MIAC_Module_WR(ModID%s, 617, 3,0,0);
	MIAC_Module_GetAck(ModID%s + 32, 617, 200);

  #endif
#else

   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);
#endif

/*Macro_RAM_Write_End*/
}


