/*-------------------------------------------------------------------------
   LCD function copy right information

   Copyright (C) 2006-2008. Lin, Rongrong <woody@palmmicro.com>
                            Lin, Guofeng <alanda@palmmicro.com>

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   This software is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-------------------------------------------------------------------------*/

#include "version.h"
#include "type.h"
#include "ar168.h"
#include "core.h"
#include "apps.h"

#ifdef SYS_LCD

#ifdef SERIAL_UI

const UCHAR _pLcd[] = "LCD ";
const UCHAR _pLcdCursor[] = "LCDC";

UCHAR _pDisplayBuf[DISPLAY_MAX_CHAR + 6];

void LcdInit()
{
}

void LcdStart()
{
	memset(_pDisplayBuf, 0, DISPLAY_MAX_CHAR + 6);
}

void LcdCursor(UCHAR iLine, UCHAR iPos, BOOLEAN bShow)
{
	strcpy(_pDisplayBuf, _pLcdCursor);
	_pDisplayBuf[4] = iLine + '0';
	_pDisplayBuf[5] = iPos + '0';
	_pDisplayBuf[6] = bShow + '0';
	_pDisplayBuf[7] = 0;
	TaskSerialSendString(_pDisplayBuf);
}

void LcdDisplay(PCHAR pBuf, UCHAR iLine)
{
	strcpy(_pDisplayBuf, _pLcd);
	_pDisplayBuf[4] = iLine + '0';
	memcpy((PCHAR)(_pDisplayBuf + 5), pBuf, DISPLAY_MAX_CHAR);
	TaskSerialSendString(_pDisplayBuf);
}

#else

extern UCHAR Flash_iBaseBank;

#define ASCII_FONT_OFFSET		0x4001

UCHAR _pDisplayBuf[DISPLAY_MAX_LINE][DISPLAY_MAX_CHAR];

BOOLEAN _IsExtendedChar(UCHAR iVal)
{
	return (iVal >= EXTENDED_CHAR_START) ? TRUE : FALSE;
}

BOOLEAN _IsStatusChar(UCHAR iVal)
{
	return (iVal == LCD_STATUS_CHAR) ? TRUE : FALSE;
}

#if defined LCD_ST7565

void _status_polling()
{
	PCHAR p;

	p = (PCHAR)BANK_BASE;
	while (p[0] & 0x80);
}

void write_control_byte(UCHAR ch)
{
	PCHAR p;

	p = (PCHAR)BANK_BASE;
	_status_polling();
	p[0] = ch;
}

void write_data_byte(UCHAR ch)
{
	PCHAR p;

	p = (PCHAR)BANK_BASE;
	_status_polling();
	SetExtPage(0x20);		// 00100000b, A20 high for data
	p[0] = ch;
	SetExtPage(0x00);		// 00000000b, A20 low for read status
}

void _set_page(UCHAR iPage)
{
	iPage &= 0x0f;
	write_control_byte(iPage|0xb0);			// Page address set, 1011xxxx
}

void _set_column(UCHAR iColumn)
{
	UCHAR iVal;

	iVal = (iColumn >> 4)&0x0f;
	write_control_byte(iVal|0x10);			// Column address set upper bit, 0001xxxx
	write_control_byte(iColumn&0x0f);		// Column address set lower bit, 0000xxxx
}

#ifdef UI_4_LINES
#define LCD_PAGE_NUM	9
#else
#define LCD_PAGE_NUM	4
#endif

void lcd_clear_screen()
{
	UCHAR i, j, iOrg;

	EnableCE2();
	iOrg = GetExtPage();
	SetExtPage(0x00);		// 00000000b, A20 low for write control

	for (i = 0; i < LCD_PAGE_NUM; i ++)
	{
		_set_page(i);
		_set_column(0);
		for (j = 0; j < 132; j ++)
		{
			write_data_byte(0);
		}
	}
	SetExtPage(iOrg);
	DisableCEx();
}

void LcdLight(UCHAR iRow, UCHAR iData)
{
	UCHAR i, iOrg;

	EnableCE2();
	iOrg = GetExtPage();
	SetExtPage(0x00);		// 00000000b, A20 low for write control
	for (i = 0; i < LCD_PAGE_NUM; i ++)
	{
		_set_page(i);
		_set_column(iRow);
		write_data_byte(iData);
	}
	SetExtPage(iOrg);
	DisableCEx();
}

#ifdef CALL_NONE
void _set_start_line(UCHAR iStartLine)
{
	iStartLine &= 0x3f;
	write_control_byte(iStartLine|0x40);		// Display start line set, 01xxxxxx
}

void LcdInit()
{
	UCHAR iOrg;

	EnableCE2();
	iOrg = GetExtPage();
	
	SetExtPage(0x00);		// 00000000b, A20 low for write control

	write_control_byte(0xe2);	// Reset

#ifdef VER_FWV2800
	write_control_byte(0xa3);	// LCD bias set, 10100010, 1/9 bias, 10100011, 1/7 bias
#else
	write_control_byte(0xa2);	// LCD bias set, 10100010, 1/9 bias, 10100011, 1/7 bias
#endif
#ifdef VER_BT2008N
	write_control_byte(0xa1);	// ADC select, 10100000, normal, 10100001, reverse
#else
	write_control_byte(0xa0);	// ADC select, 10100000, normal, 10100001, reverse
#endif
#if defined VER_AR168O || defined VER_AR168P || defined VER_GP1266 || defined VER_SENSOR || defined VER_GP2266 || defined VER_FWV2800 || defined VER_DXDT// || defined VER_BT2008N
	write_control_byte(0xc8);	// Common output mode select, 11000***, normal, 11001***, reverse
#else
	write_control_byte(0xc0);	// Common output mode select, 11000***, normal, 11001***, reverse
#endif

	write_control_byte(0x2c);	// Power control set, 00101xxx
	write_control_byte(0x2e);	// Power control set, 00101xxx
	write_control_byte(0x2f);	// Power control set, 00101xxx

#if defined VER_AR168O || defined VER_AR168P || defined VER_GP1266 || defined VER_SENSOR || defined VER_GP2266 || defined VER_FWV2800 || defined VER_DXDT
	write_control_byte(0x25);	// V5 voltage regulator internal resistor ratio set, 00100xxx
	write_control_byte(0x81);	// Electronic volume mode set, set the V5 output voltage
#else
	write_control_byte(0x24);	// V5 voltage regulator internal resistor ratio set, 00100xxx
	write_control_byte(0x81);	// Electronic volume mode set, set the V5 output voltage
#endif

#if defined VER_AR168O || defined VER_AR168P || defined VER_GP1266 || defined VER_SENSOR || defined VER_GP2266 || defined VER_DXDT
	write_control_byte(26);		// Electronic volume register, 00xxxxxx
#elif defined VER_FWV2800
	write_control_byte(32);		// Electronic volume register, 00xxxxxx
#else
	write_control_byte(38);		// Electronic volume register, 00xxxxxx
#endif

	write_control_byte(0xf8);	// Booster ratio set, 11111000
	write_control_byte(0);		// Booster ratio set step-up value, 00, 3x

	write_control_byte(0xa4);	// Display all points, 10100100, normal, 10100101, all points ON
	write_control_byte(0xa6);	// Display normal/reverse, 10100110, normal, 10100111, reverse
	write_control_byte(0xaf);	// Display ON/OFF, 10101111 ON, 10101110, OFF
//	write_control_byte(0xa5);	// Display all points, 10100100, normal, 10100101, all points ON

	_set_start_line(0);
	SetExtPage(iOrg);
	DisableCEx();
}

void LcdDisplayBMP(PCHAR pBuf, BOOLEAN bReverse)
{
	UCHAR i, j, iOrg;
	USHORT s;
	UCHAR pData[1024];
	PCHAR pCur;

	if (bReverse)
	{
		for (s = 0; s < 1024; s ++)
		{
			pData[s] = ~pBuf[s];
		}
	}
	else
	{
		memcpy(pData, pBuf, 1024);
	}
	pCur = pData;

	EnableCE2();
	iOrg = GetExtPage();

	SetExtPage(0x00);		// 00000000b, A20 low for write control
	for (j = 0; j < 8; j ++)
	{
		_set_page(j);
#if defined VER_AR168O || defined VER_AR168P || defined VER_GP1266 || defined VER_SENSOR || defined VER_GP2266 || defined VER_DXDT
		_set_column(0);
#elif defined VER_FWV2800
		_set_column(2);
#else
		_set_column(4);
#endif
		for (i = 0; i < 128; i ++)
		{
			write_data_byte(*pCur++);
		}
	}

	SetExtPage(iOrg);
	DisableCEx();
}

#endif

#define ASCII_ARRAY_SIZE	16

#define FONT_ARRAY_SIZE		32
#define FONT_PAGE_SIZE		94

void _display_CJK(PCHAR pBuf, UCHAR iPos, UCHAR iLine)
{
	UCHAR i, j, iOrg, iBank;
	UCHAR pFont[FONT_ARRAY_SIZE];
	PCHAR pCur;
	USHORT sOffset;

#ifdef RES_CN
	sOffset = (pBuf[0] - 0xa1) * FONT_PAGE_SIZE;
//#elif defined RES_KR
#else
	sOffset = (pBuf[0] - 0xac) * (FONT_PAGE_SIZE + 1);
#endif
	sOffset += pBuf[1] - 0xa1;
	iBank = 0;
	while (sOffset > 1024)
	{
		sOffset -= 1024;
		iBank ++;
	}
	sOffset *= FONT_ARRAY_SIZE;

	iOrg = GetExtPage();

	// get chinese font
	SetExtPage((SYSTEM_FONT_PAGE<<1) + iBank);		// chinese starts from bank 2, second 32k
	memcpy(pFont, (PCHAR)(BANK_BASE + sOffset), FONT_ARRAY_SIZE);

#ifdef VER_FWV2800
	if (iLine < 2)
	{
		iLine += 2;
	}
	else
	{
		iLine -= 2;
	}
#endif
	iLine <<= 1;
	iPos <<= 3;
#if defined VER_AR168G || defined VER_AR168I || defined VER_BT2008N
	iPos += 4;
#elif defined VER_FWV2800
	iPos += 2;
#endif

	pCur = pFont;
	EnableCE2();
	SetExtPage(0x00);		// 00000000b, A20 low for write control
	for (j = 0; j < 2; j ++)
	{
		_set_page(iLine+j);
		_set_column(iPos);
		for (i = 0; i < 16; i ++)
		{
			write_data_byte(*pCur++);
		}
	}
	SetExtPage(iOrg);
	DisableCEx();
}

void _display_ascii(UCHAR iChar, UCHAR iPos, UCHAR iLine)
{	
	UCHAR i, j, iOrg;
	UCHAR pFont[ASCII_ARRAY_SIZE];
	PCHAR pCur;
	USHORT sOffset;

#ifdef RES_RU
	// CP1251 font has it all!
	sOffset = iChar - LCD_STATUS_CHAR;
#else
	if (iChar < EXTENDED_CHAR_START)
	{
		sOffset = iChar - LCD_STATUS_CHAR;
	}
	else
	{
		sOffset = iChar - LCD_STATUS_CHAR - 33;
	}
#endif
	sOffset *= ASCII_ARRAY_SIZE;

	iOrg = GetExtPage();

	// get ascii font
//	SetExtPage(SYSTEM_FONT_PAGE<<1);		// ascii in font bank 1, first 32k, first 4096 bytes
	SetExtPage(Flash_iBaseBank);
	memcpy(pFont, (PCHAR)(BANK_BASE + ASCII_FONT_OFFSET + sOffset), ASCII_ARRAY_SIZE);
//	memmove(pFont, (PCHAR)(BANK_BASE + ASCII_FONT_OFFSET + sOffset), ASCII_ARRAY_SIZE);

#ifdef VER_FWV2800
	if (iLine < 2)
	{
		iLine += 2;
	}
	else
	{
		iLine -= 2;
	}
#endif
	iLine <<= 1;
	iPos <<= 3;
#if defined VER_AR168G || defined VER_AR168I || defined VER_BT2008N
	iPos += 4;
#elif defined VER_FWV2800
	iPos += 2;
#endif

	pCur = pFont;
	EnableCE2();
	SetExtPage(0x00);		// 00000000b, A20 low for write control
	for (j = 0; j < 2; j ++)
	{
		_set_page(iLine+j);
		_set_column(iPos);
		for (i = 0; i < 8; i ++)
		{
			write_data_byte(*pCur++);
		}
	}
	SetExtPage(iOrg);
	DisableCEx();
}

void LcdCursor(UCHAR iLine, UCHAR iPos, BOOLEAN bShow)
{
	iLine;
	iPos;
	bShow;
/*	UCHAR iOrg;

	EnableCE2();
	iOrg = GetExtPage();
	SetExtPage(0x00);		// 00000000b, A20 low for write control
	if (bShow)
	{
		write_control_byte(0xad);			// Static indicator ON/OFF, 1010110x
		write_control_byte(0x01);
	}
	else
	{
		write_control_byte(0xac);			// Static indicator ON/OFF, 1010110x
	}
	SetExtPage(iOrg);
	DisableCEx();
*/
}

#elif defined LCD_HY1602 || defined LCD_HY2004

// Lcd functions

// LCD_RS - A20, H - data, L - control
// LCD_RW - A19, H - read, L - write

void _status_polling()
{
	PCHAR p;

	p = (PCHAR)BANK_BASE;
	SetExtPage(0x10);		// 00010000b, A19 high for read

#ifdef SYS_CHIP_PLUS
	do
	{
		EnableLCD();
	} 
#endif
	while (p[0] & 0x80);
}

void write_control_byte(UCHAR ch)
{
	PCHAR p;

	p = (PCHAR)BANK_BASE;

	_status_polling();

	SetExtPage(0x00);		// 00000000b
#ifdef SYS_CHIP_PLUS
	EnableLCD();
#endif
	p[0] = ch;
}

void write_data_byte(UCHAR ch)
{
	PCHAR p;

	p = (PCHAR)BANK_BASE;

	_status_polling();

	SetExtPage(0x20);		// 00100000b, A20 high for data
#ifdef SYS_CHIP_PLUS
	EnableLCD();
#endif
	p[0] = ch;
}

/*
UCHAR read_data_byte()
{
	PCHAR p;

	p = (PCHAR)BANK_BASE;

	_status_polling();

	SetExtPage(0x30);		// 00110000b, A19=A20 high for read data
	return p[0];
}
*/

// warning: global none-const var init have problem, maybe because init process is not executed because of data/code movement
#ifdef LCD_HY2004
const UCHAR _cWriteControl[DISPLAY_MAX_LINE] = {0x80, 0xc0, 0x94, 0xd4};		// line DDRAM address, 20x4
//const UCHAR _cWriteControl[DISPLAY_MAX_LINE] = {0x80, 0xc0, 0x90, 0xd0};		// line DDRAM address, 16x4
#elif defined LCD_HY1602
const UCHAR _cWriteControl[DISPLAY_MAX_LINE] = {0x80, 0xc0};		// line DDRAM address, 16x2
#endif

#define FONT_ARRAY_SIZE		8
#define FONT_ARRAY_NUM		8

UCHAR _pFontBuf[FONT_ARRAY_NUM];

#ifdef CALL_NONE

const UCHAR _cFontArray[FONT_ARRAY_NUM*FONT_ARRAY_SIZE] = {
0x08, 0x0F, 0x12, 0x0F, 0x0A, 0x1F, 0x02, 0x02,	// "年"代码=00H 
0x0F, 0x09, 0x0F, 0x09, 0x0F, 0x09, 0x11, 0x00,	// "月"代码=01H
0x1F, 0x11, 0x11, 0x1F, 0x11, 0x11, 0x1F, 0x00,	// "日"代码=02H
0x11, 0x0A, 0x04, 0x1F, 0x04, 0x1F, 0x04, 0x00,	// "$"代码=03H
0x0E, 0x00, 0x1F, 0x0A, 0x0A, 0x0A, 0x13, 0x00,	// "元"代码=04H
0x18, 0x18, 0x07, 0x08, 0x08, 0x08, 0x07, 0x00,	// "℃"代码=05H
0x04, 0x0A, 0x15, 0x04, 0x04, 0x04, 0x04, 0x00,	// "↑"代码=06H
0x17, 0x15, 0x15, 0x15, 0x15, 0x15, 0x17, 0x00,	// "10"代码=07H
};

void LcdInit()
{
	UCHAR i, iOrg;

	EnableCE2();
	iOrg = GetExtPage();

	for (i = 0; i < 3; i ++)
	{	
		write_control_byte(0x30);	// Set function mode
	}
	
	write_control_byte(0x38);	// set work mode, 8-bit 2-line 5*7
	write_control_byte(0x01);	// clear screen
	write_control_byte(0x02);	// cursor return home
	write_control_byte(0x06);	// set input method
	write_control_byte(0x0f);	// set display method, show cursor
	write_control_byte(0x14);	// set display method
	write_control_byte(0x80);

	SetExtPage(iOrg);
	DisableCEx();
}

void LcdTest4()
{
	UCHAR i, j, iOrg;
	PCHAR p;

	p = _cFontArray;

	EnableCE2();
	iOrg = GetExtPage();

	// load CGRAM data here
	write_control_byte(0x40);
	for (i = 0; i < FONT_ARRAY_NUM*FONT_ARRAY_SIZE; i ++)
	{
		write_data_byte(_cFontArray[i]); 
	}

	for (j = 0; j < DISPLAY_MAX_LINE; j ++)
	{
		write_control_byte(_cWriteControl[j]);
		for (i = 0; i < FONT_ARRAY_NUM; i ++)
		{
			write_data_byte(i);
			write_data_byte(i + 8);
		}
	}

	SetExtPage(iOrg);
	DisableCEx();
}

void LcdTest5()
{
	UCHAR i;
	UCHAR pBuf[DISPLAY_MAX_CHAR];

	for (i = 0; i < DISPLAY_MAX_CHAR; i ++)
	{
		pBuf[i] = i + 0xb0;
	}

	for (i = 0; i < DISPLAY_MAX_LINE; i ++)
	{
		LcdDisplay(pBuf, i);
	}
}

#endif

/*
void LcdDisplay(PCHAR pBuf, UCHAR iLine)
{
	UCHAR i, iOrg;

	EnableCE2();
	iOrg = GetExtPage();

	write_control_byte(_cWriteControl[iLine]);
	for (i = 0; i < DISPLAY_MAX_CHAR; i ++)
	{
		if (pBuf[i] == 0)	break;
		write_data_byte(pBuf[i]);
	}
	for (; i < DISPLAY_MAX_CHAR; i ++)
	{
		write_data_byte(' ');
	}

	SetExtPage(iOrg);
	DisableCEx();
}
*/

void LcdCursor(UCHAR iLine, UCHAR iPos, BOOLEAN bShow)
{
	UCHAR iOrg;

	EnableCE2();
	iOrg = GetExtPage();

	if (bShow)
	{
		write_control_byte(_cWriteControl[iLine] + iPos);
		write_control_byte(0x0f);
	}
	else
	{
		write_control_byte(0x0c);
	}

	SetExtPage(iOrg);
	DisableCEx();
}

void _write_cgram(UCHAR iIndex, PCHAR pFont)
{
	UCHAR i;

	iIndex <<= 3;
	write_control_byte(0x40 + iIndex);	// load CGRAM data
	for (i = 0; i < FONT_ARRAY_SIZE; i ++)
	{
		write_data_byte(pFont[i]);
	}
}

void _read_font(UCHAR iChar, PCHAR pFont)
{
	USHORT sOffset;

	SetExtPage(Flash_iBaseBank);		// extended ascii font in bank0 0x4001
	sOffset = iChar - EXTENDED_CHAR_START;
	sOffset *= FONT_ARRAY_SIZE;
	memcpy(pFont, (PCHAR)(BANK_BASE + ASCII_FONT_OFFSET + sOffset), FONT_ARRAY_SIZE);
}

void lcd_clear_screen()
{
	UCHAR iOrg;
//	UCHAR i, iOrg, iChar;
//	UCHAR pFont[FONT_ARRAY_SIZE];

	iOrg = GetExtPage();

	EnableCE2();
	write_control_byte(0x01);	// clear screen
	DisableCEx();
/*
	// load default CGRAM font data
	for (i = 0; i < FONT_ARRAY_NUM; i ++)
	{
		iChar = EXTENDED_CHAR_START + i;
		_pFontBuf[i] = iChar;
		_read_font(iChar, pFont);

		EnableCE2();
		_write_cgram(i, pFont);
		DisableCEx();
	}
*/
	memset(_pFontBuf, 0, FONT_ARRAY_NUM);
	SetExtPage(iOrg);
}

void _display_ascii(UCHAR iChar, UCHAR iPos, UCHAR iLine)
{
	UCHAR i, j, k, iOrg;
	UCHAR pFont[FONT_ARRAY_SIZE];
	BOOLEAN bLoadFont, bStatus;

	iOrg = GetExtPage();

	bLoadFont = FALSE;
	bStatus = _IsStatusChar(iChar);
	if (_IsExtendedChar(iChar) || bStatus)
	{
		// check if font already exist in cgram
		for (i = 0; i < FONT_ARRAY_NUM; i ++)
		{
			if (_pFontBuf[i] == iChar)
			{
				iChar = i;
				break;
			}
		}

		if (iChar >= FONT_ARRAY_NUM)
		{	// check if any cgram font used
			for (i = 0; i < FONT_ARRAY_NUM; i ++)
			{
				bLoadFont = TRUE;
				for (j = 0; j < DISPLAY_MAX_LINE; j ++)
				{
					for (k = 0; k < DISPLAY_MAX_CHAR; k ++)
					{
						if (_pDisplayBuf[j][k] == _pFontBuf[i])
						{
							bLoadFont = FALSE;
							break;
						}
					}
					if (!bLoadFont)	break;
				}
				if (bLoadFont)	break;
			}

			if (bLoadFont)
			{
				if (bStatus)
				{
					memset(pFont, 0x1f, FONT_ARRAY_SIZE);
				}
				else
				{
					_read_font(iChar, pFont);
				}
				_pFontBuf[i] = iChar;
				iChar = i;
			}
		}
	}

	EnableCE2();

	if (bLoadFont)
	{
		_write_cgram(iChar, pFont);
	}
	write_control_byte(_cWriteControl[iLine] + iPos);
	write_data_byte(iChar);

	SetExtPage(iOrg);
	DisableCEx();
}

#else

void lcd_clear_screen()
{
}

void _display_ascii(UCHAR iChar, UCHAR iPos, UCHAR iLine)
{
	iChar;
	iPos;
	iLine;
}

void LcdInit()
{
}

void LcdCursor(UCHAR iLine, UCHAR iPos, BOOLEAN bShow)
{
	iLine;
	iPos;
	bShow;
}

#endif

void LcdStart()
{
	UCHAR i;
	
	for (i = 0; i < DISPLAY_MAX_LINE; i ++)
	{
		memset(_pDisplayBuf[i], ' ', DISPLAY_MAX_CHAR);
	}

	lcd_clear_screen();
	LcdCursor(0, 0, FALSE);
//	LcdCursor(1, 1, TRUE);
}

void LcdDisplay(PCHAR pBuf, UCHAR iLine)
{
	UCHAR i, iVal;
#ifdef DISPLAY_DOT
#if defined RES_CN || defined RES_KR
	UCHAR iVal2;
#endif
#endif
	PCHAR pLine;

	pLine = _pDisplayBuf[iLine];

	i = 0;
	do
	{
		iVal = pBuf[i];
		if (iVal == 0)	break;

#ifdef DISPLAY_DOT
#if defined RES_CN || defined RES_KR
		iVal2 = pBuf[i+1];
		if (_IsExtendedChar(iVal) && _IsExtendedChar(iVal2))
		{
			if (iVal != pLine[i] || iVal2 != pLine[i+1])
			{
				_display_CJK((PCHAR)(pBuf+i), i, iLine);
				pLine[i] = iVal;
				pLine[i+1] = iVal2;
			}
			i += 2;
			continue;
		}
#endif
#endif
		if (iVal != pLine[i])
		{
			_display_ascii(iVal, i, iLine);
			pLine[i] = iVal;
		}
		i ++;
	} while (i < DISPLAY_MAX_CHAR);

	for (; i < DISPLAY_MAX_CHAR; i ++)
	{
		if (pLine[i] != ' ')
		{
			_display_ascii(' ', i, iLine);
			pLine[i] = ' ';
		}
	}
}

#endif	// SYS_UART

#else

void LcdInit()
{
}

void LcdStart()
{
}

void LcdCursor(UCHAR iLine, UCHAR iPos, BOOLEAN bShow)
{
	iLine;
	iPos;
	bShow;
}

void LcdDisplay(PCHAR pBuf, UCHAR iLine)
{
	pBuf;
	iLine;
}

#endif	// SYS_LCD

#ifdef LCD_DEBUG

void LcdDebugVal(USHORT sVal, UCHAR iRadix, UCHAR iLine)
{
	UCHAR pBuf[DISPLAY_MAX_CHAR];

	itoa(sVal, pBuf, iRadix);
	LcdDisplay(pBuf, iLine);
}

void LcdDebugVals(PCHAR pVal, UCHAR iLen, UCHAR iLine)
{
	UCHAR i, iVal;
	UCHAR pBuf[DISPLAY_MAX_CHAR + 1];
	PCHAR pCur;

	if (iLen > DISPLAY_MAX_CHAR/2)	iLen = DISPLAY_MAX_CHAR/2;
	pCur = pBuf;
	for (i = 0; i < iLen; i ++)
	{
		iVal = pVal[i];
		if (iVal >= 0x10)
		{
			itoa(iVal, pCur, 16);
			pCur += 2;
		}
		else
		{
			*pCur ++ = '0';
			itoa(iVal, pCur, 16);
			pCur ++;
		}
	}
	LcdDisplay(pBuf, iLine);
}

#endif	// LCD_DEBUG

void LcdCenterDisplay(PCHAR pString, UCHAR iLine)
{
	UCHAR iPos, iLen;
	UCHAR pLine[DISPLAY_MAX_CHAR+2];

	iLen = strlen(pString);
	if (iLen >= DISPLAY_MAX_CHAR-1) 
	{
		LcdDisplay(pString, iLine);
	}
	else
	{
		iPos = (DISPLAY_MAX_CHAR - iLen) >> 1;
		memset(pLine, ' ', iPos);
		strcpy((PCHAR)(pLine + iPos), pString);
		LcdDisplay(pLine, iLine);
	}
}

