/*
   Copyright (c) 2015, Digi International Inc.

   Permission to use, copy, modify, and/or distribute this software for any
   purpose with or without fee is hereby granted, provided that the above
   copyright notice and this permission notice appear in all copies.

   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/***************************************************************************\
	Samples\RCM2300\keylcd.c

	This program demonstrates a simple setup for a 2x6 keypad and a 2x20 LCD.

	Use with RCM2300 series controllers.  Connect circuitry as described
	in your User Manual Sample Circuit Section.

	Upon exection of this program, the LCD will display two rows of 6 dots
	each representing a corresponding key.  When a key is pressed the
	corresponding dot will display an asterisk, "*".
	
	For this example to work properly, the LCD should be connected to
	parallel	port A as described here and in the example circuitry:
	
		PA.0	Out	LED Backlight (if connected)
		PA.1	Out	LCD CS (Active High)
		PA.2	Out	LCD RS (High = Control, Low = Data) / LCD Contrast 0
		PA.3	Out	LCD WR (Active Low) / LCD Contrast 1
		PA.4	Out	LCD D4 / LCD Contrast 2
		PA.5	Out	LCD D5 / LCD Contrast 3
		PA.6	Out	LCD D6 / LCD Contrast 4
		PA.7	Out	LCD D7 / LCD Contrast 5
	
	The keypad should be connected to parallel ports B, C and D
	as described here and in the example circuitry:
	
		PB.0	In		Keypad Col 0
		PC.1	In		Keypad Col 1
		PB.2	In		Keypad Col 2
		PB.3	In		Keypad Col 3
		PB.4	In		Keypad Col 4
		PB.5	In		Keypad Col 5
		PD.3	O.C.	Keypad Row 0
		PD.4	O.C.	Keypad Row 1
	
\***************************************************************************/
/*
 *  This sample is done in the "continuation" style of programming and
 *  has no local variables.  However, the library code does.
 */
#class auto

///// delay function
void delay(unsigned int	wDelay)			
{
	for (;wDelay>0;--wDelay);
}


///// 4-bit lcd command
void lcdCmd4 (char cmd4)
{
	WrPortI ( PADR,&PADRShadow,(cmd4&0xF1)|(PADRShadow&1) );		//	Ready Nibble
	WrPortI ( PADR,&PADRShadow,PADRShadow|0x02 );					//	Write Nibble
	WrPortI ( PADR,&PADRShadow,PADRShadow&0xFD );
}


///// 8-bit lcd command
void lcdCmd (int cmd)
{
	lcdCmd4 ( cmd );					//	Write Upper Nibble
	lcdCmd4 ( cmd<<4 );				//	Write Lower Nibble
	delay ( 4 );						//	Wait 40 uSec
}

///// place cursor at column and row
void lcdGoto (unsigned int col, unsigned int row)
{
	const static char acPos[4] = { 0x80,0xC0,0x94,0xD4 };

	if ((col < 20) && (row < 4))
		lcdCmd ( acPos[row]+col );
}

///// write character to lcd
void lcdPutc (char cData)
{
	WrPortI ( PADR,&PADRShadow,(cData&0xF0)|0x04|(PADRShadow&0x01) );
	WrPortI ( PADR,&PADRShadow,PADRShadow|0x02 );					//	Strobe Write
	WrPortI ( PADR,&PADRShadow,PADRShadow&0xFD );
																					//	Ready Lower Nibble
	WrPortI ( PADR,&PADRShadow,((cData<<4)&0xF0)|0x04|(PADRShadow&0x01) );
	WrPortI ( PADR,&PADRShadow,PADRShadow|0x02 );					//	Strobe Write
	WrPortI ( PADR,&PADRShadow,PADRShadow&0xFD );
	WrPortI ( PADR,&PADRShadow,(PADRShadow&0x01) );	//	Restore Contrast
	delay ( 4 );												//	Wait 40 uSec
}

///// write formatted data to lcd, similar to printf statement
void lcdPrintf	(char	*pcFormat,...)
{
	doprnt ( lcdPutc,pcFormat,&pcFormat+1,NULL, NULL, NULL );
}


///// scan keypad for key press
void keyCol(void)			
{
	delay ( 1000 );
	lcdPrintf ( "%c%c%c%c%c%c",
			((RdPortI(PBDR)&0x20)?'.':'*'),
			((RdPortI(PBDR)&0x10)?'.':'*'),
			((RdPortI(PBDR)&0x08)?'.':'*'),
			((RdPortI(PBDR)&0x04)?'.':'*'),
			((RdPortI(PCDR)&0x02)?'.':'*'),
			((RdPortI(PBDR)&0x01)?'.':'*')
		);
}



void main (	void	)		
{

	///// initialize keypad
	WrPortI ( PDFR,NULL,0x00 );			//	parallel Port D All I/O
	WrPortI ( PDDCR,NULL,0x18 );			//	PD3..PD4 Open Collector
	WrPortI ( PDDDR,NULL,0x18 );			//	PD3..PD4 Output
		
	///// initialize lcd
	WrPortI ( PADR,&PADRShadow,0x00 );	//	Assure Outputs are Low
	WrPortI ( SPCR,&SPCRShadow,0x84 );	//	parallel Port A = Outputs
	
	WrPortI ( PADR,&PADRShadow,PADRShadow&0x01 ); // Set Contrast at GND
	delay ( 1500 );						//	Wait 15 mSec (LCD to Stabilize)
	lcdCmd4 ( 0x30 );						//	Set to 8-Bit Interface
	delay ( 410 );							//	Wait 4.1 mSec
	lcdCmd4 ( 0x30 );						//	Set 8-Bit Interface
	delay ( 10 );							//	Wait 100 uSec
	lcdCmd4 ( 0x30 );						//	Set 8-Bit Interface
	lcdCmd4 ( 0x20 );						//	Set 8-Bit Interface
	lcdCmd ( 0x28 );						//	Set Dual Line Display
	lcdCmd ( 0x06 );						//	Disable Display Shift
	lcdCmd ( 0x0C );						//	Display On, Cursor Off
	lcdCmd ( 0x01 );						//	Clear Screen, Home Cursor, Backlight On
	delay ( 164 );							//	Wait 1.64 mSec

	for (;;) {
		WrPortI ( PDDR,NULL,0x08 );	//	Scan Row 0
		lcdGoto ( 0,0 );					//	Cursor on column 0, row 0
		keyCol ();							// Scan for keypress
			
		WrPortI ( PDDR,NULL,0x10 );	//	Scan Row 1
		lcdGoto ( 0,1 );					//	Cursor on column 0, row 1
		keyCol ();							// Scan for keypress
		}
}
