/*
================================ COPYRIGHT ================================
The contents of this file are subject to the VTech Informations Ltd. License
of VT-OS Ver. 1.1 operating system (the "License"); you may not use this 
file except in compliance with the License.  

Software distributed under the License is distributed on an "AS IS" basis, 
WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the License 
for the specific language governing rights and limitations under the License.
  
The Original Code is VT-OS Ver. 1.1 Operating System, released 
on October 1st, 1999
	
The Initial Developer of the Original Code is VTech Informations Ltd.  All 
codes are Copyright (C) VTech Informations Ltd. 1999.  All Rights Reserved.
===========================================================================
*/

/*
===========================================================================
File        :   uart.c
Author(s)   :   Andrew Hui
Company     :   VTech Informations Ltd.
Project     :   Helio 
Date:	    :   October 1st, 1999
Purpose:	:   Uart low level driver
Revision    :   1.1
Note        :   07/07/98   Prepared by Andrew Hui (AH)                     
07/07/98   V1.0 release (AH)                               
23/07/98   V2.0 change buffer swap mechanism (AH)          
===========================================================================
*/              

#include    "pr31700s.h"
#include    "pr31700c.h"
#include    "msg.h"
#include    "qtype.h"
#include    "datatype.h"
#include    "uart.h"
#include    "intc.h"
#include 	"print.h"
#include	"system.h"
#include	"lcddebug.h"

// =================== HENRY ==========================
#define				BUFFER_SIZE			4096

volatile UBYTE		UartRxBuffer[BUFFER_SIZE];
volatile UBYTE		*UartReadPtr;
volatile UBYTE		*UartWritePtr;

volatile UBYTE		*UartEndAddr	=	UartRxBuffer + BUFFER_SIZE;
volatile UWORD		UartNumBytes	=	0;

// ====================================================

/* GLOBAL Variable */
/* UART_A */
BYTE    UartATxBuf[UART_BUF_SIZE];       /* UART Tx buffer (DMA) */

/* UART_B */
BYTE    UartBTxBuf[UART_BUF_SIZE];       /* UART Tx buffer (DMA) */

MsgType UartMsg;        /* define a UART Message */          

#define UartGetb(port)  ((port==UART_A)  ?((BYTE)(CPU ->REG_UARTA_HLDG )) \
:((BYTE)(CPU ->REG_UARTB_HLDG )) )

void UartADmaFullIsr()
{
	UartADisableTxDma();
}

/*-----------------------------------------------------------------------------
Prototype        :  void UartIsrRx(WORD port)
Purpose          :  Interrupt handler for UART receive
Scope            :  interrupt
Input            :  port  : UART_A / UART_B
Output           :  None
Return           :  None
-----------------------------------------------------------------------------*/
void    UartIsrRx()
{
	*UartWritePtr = UartGetb(UART_A);
	UartWritePtr ++;
	UartNumBytes ++;
	
	if (UartWritePtr == UartEndAddr)
		UartWritePtr = UartRxBuffer;
}

void	UartRxInit()
{
	DIS_GBL_INT;			
	UartNumBytes = 0;
	UartReadPtr = UartWritePtr = UartRxBuffer;	
	ENA_GBL_INT;	
}

/*-----------------------------------------------------------------------------
Prototype     :   BOOLEAN		UartGetOneByte(UBYTE *RxByte)
Purpose       :   To get one byte from the Uart A Round Buffer
Scope         :   System
Input         :   RxByte			Pointer 
Output        :   Obsoleted
:	Obsoleted
Return        :   Obsoleted
Description   :   Obsoleted    
-----------------------------------------------------------------------------*/
BOOLEAN		UartGetOneByte(UBYTE *RxByte)
{
	if (UartWritePtr == UartReadPtr)
		return FALSE;
	else
	{
		*RxByte = *UartReadPtr;
		UartReadPtr ++;		
		
		DIS_GBL_INT;
		UartNumBytes --;
		ENA_GBL_INT;
		
		if (UartReadPtr == UartEndAddr)
			UartReadPtr = UartRxBuffer;						
		return TRUE;			
	}			
}

/*-----------------------------------------------------------------------------
Prototype     :   BOOLEAN		UartGetBytes(UBYTE	*RxPtr, UWORD Length)
Purpose       :   To get a number of bytes
Scope         :   System
Input         :   RxPtr			Pointer to byte stream
Length			Number of bytes required  
Output        :   None
Return        :   TRUE			OK
FALSE			Not enough bytes
Description   :   None
-----------------------------------------------------------------------------*/
BOOLEAN		UartGetBytes(UBYTE	*RxPtr, UWORD Length)
{
	UWORD	Count = Length;
	
	if (UartNumBytes < Length)
		return FALSE;				
	else
	{		
		while (Length --)
		{
			*RxPtr ++ = *UartReadPtr ++;
			if (UartReadPtr == UartEndAddr)
				UartReadPtr = UartRxBuffer;									
		}
		DIS_GBL_INT;
		UartNumBytes -= Count;		
		ENA_GBL_INT;					
		return TRUE;	
	}	
}

/*-----------------------------------------------------------------------------
Prototype     :   WORD UartReadBuf(WORD port, BYTE **buf);
Purpose       :   Obsoleted
Scope         :   Obsoleted
Input         :   Obsoleted
Output        :   Obsoleted
:	Obsoleted
Return        :   Obsoleted
Description   :   Obsoleted    
-----------------------------------------------------------------------------*/
WORD    UartReadBuf(WORD port, BYTE *buf)
{
	return 0;
}

/*-----------------------------------------------------------------------------
Prototype       :   void UartWriteBuf(WORD port, BYTE *buf, WORD length);
Purpose         :   Write a buffer of data to the UART transmit DMA buffer
Scope           :   OS
Input           :   port   : UART_A / UART_B
buf    : output buffer
length : no of byte in buffer
Output          :   None
Return          :   None
Description     :   UartMgr must check no DMA is carrying out. This function
will copy the buffer to uart transmit DMA buffer and
then start DMA and enable DMA complete interrupt.

-----------------------------------------------------------------------------*/
void    UartWriteBuf(WORD port, BYTE *buf, WORD length)
{
    register    WORD     i;
	
    if (port==UART_A)
    {
        for (i=0; i<length; i++)  UartATxBuf[i]=buf[i];
		
        UartADisableDmaInt();
		
        UartADmaAddr((WORD)(&UartATxBuf) &~(0x7<<29));   /*must be physical address*/
        UartASetDmaLen(length-1);
        UartAEnableDmaInt();
        UartAEnableTxDma();
    }
    else
		if (port==UART_B)
		{
			for (i=0; i<length; i++)  UartBTxBuf[i]=buf[i];
			
			UartBDisableDmaInt();
			
			UartBDmaAddr((WORD)(&UartBTxBuf) &~(0x7<<29));   /*must be physical address*/
			UartBSetDmaLen(length-1);
			
			UartBEnableDmaInt();
			UartBEnableTxDma();
		}
}

/*-----------------------------------------------------------------------------
Prototype       :   WORD UartAChkRxDmaBusy(WORD port);
Purpose         :   Check if UART  Rx DMA is using or not
Scope           :   OS
Input           :   port : UART_A / UART_B
Output          :
Return          :   UART_DMA_BUSY : Busy,  otherwise ready
Description     :   UartMgr must use this function to check DMA is ready or not
-----------------------------------------------------------------------------*/
WORD    UartChkRxDmaBusy(WORD port)
{
    if(port == UART_A)    
		return ((CPU ->REG_UARTA_CTRL_1 >>15)&1);
    else if (port == UART_B)
		return ((CPU ->REG_UARTB_CTRL_1 >>15)&1);
}


/*-----------------------------------------------------------------------------
Prototype       :   WORD UartChkTxDmaBusy(WORD port);
Purpose         :   Check if UART A Tx DMA is using or not
Scope           :   OS
Input           :   None
Output          :
Return          :   UART_DMA_BUSY : Busy,  otherwise ready
Description     :   UartMgr must use this function to check DMA is ready or not
-----------------------------------------------------------------------------*/
WORD    UartChkTxDmaBusy(WORD port)
{
    if(port == UART_A)   
		return ((CPU ->REG_UARTA_CTRL_1 >>14) &1);
    else if(port == UART_B)
		return ((CPU ->REG_UARTB_CTRL_1 >>14) &1);
}


/*---------------------------------------------------------------------------
Prototype     :   void  UartInit(WORD port, WORD baud, WORD config );
Purpose       :   initialize the UART port for serial communication
Scope         :   OS
input         :   port    : UART_A / UART_B
baud    : e.g.  38400
config  : data_bits, Parity, stop_bit : "8N1"
(defined in UART_DRV.H)
output        :   None
return        :   None
---------------------------------------------------------------------------*/
void    UartInit(WORD port, WORD baud, WORD config)
{
	/* config UART port */
    if (port == UART_A)  /* UART A */
	{
        /* config UART clock */
        CPU->REG_CLK_CTRL &= ~CSERDIV(7) ;
        CPU->REG_CLK_CTRL |= CSERDIV(3) | ENCSERCLK | ENUARTACLK;
		
        CPU ->REG_UARTA_CTRL_1      = config;       /* set data, stop, parity*/
        CPU ->REG_UARTA_CTRL_2      = baud;         /* baud rate             */
		CPU ->REG_UARTA_DMA_CTRL_1	= 0;			/* DMA buf start Address */
        CPU ->REG_UARTA_DMA_CTRL_2  = 0;            /* DMA buf length        */
        HwUartAInit();
    }
    else
		if (port == UART_B)  /* UART B */
		{
			/* config UART clock */
			CPU->REG_CLK_CTRL &= ~CSERDIV(7);
			CPU->REG_CLK_CTRL |= CSERDIV(3) | ENCSERCLK | ENUARTBCLK;
			
			CPU ->REG_UARTB_CTRL_1      = config;       /* set data, stop, parity*/
			CPU ->REG_UARTB_CTRL_2      = baud;         /* baud rate             */
			CPU ->REG_UARTB_DMA_CTRL_1	= 0;			/* DMA buf start Address */
			CPU ->REG_UARTB_DMA_CTRL_2  = 0;            /* DMA buf length        */
		}
} 




/*---------------------------------------------------------------------------
Prototype     :   void UartEnable(WORD port)
Purpose       :   To enable the UART
Scope         :   OS
Input         :   port : UART_A / UART_B
Output        :   none
Return        :   none
---------------------------------------------------------------------------*/
void    UartEnable(WORD port)
{
    if (port==UART_A)
    {
        CPU ->REG_UARTA_CTRL_1  |= ENUART;        /* enable Uart A         */
        while(~CPU ->REG_UARTA_CTRL_1 & UARTON) ; /* wait Uart A stable    */
    }
    else
		if (port==UART_B)
		{
			CPU ->REG_UARTB_CTRL_1  |= ENUART;        /* enable Uart B         */
			while(~CPU ->REG_UARTB_CTRL_1 & UARTON) ; /* wait Uart B stable    */
		}
}



/*---------------------------------------------------------------------------
Prototype     :   void UartDisable(WORD port)
Purpose       :   To disable the UART
Scope         :   OS
Input         :   port : UART_A / UART_B UART
Output        :   none
Return        :   none
Descriptions  :   Make sure everything is sent out
---------------------------------------------------------------------------*/
void    UartDisable(WORD port)
{
    if(port==UART_A)         CPU ->REG_UARTA_CTRL_1 &= ~ENUART;
    else    if(port==UART_B)         CPU ->REG_UARTB_CTRL_1 &= ~ENUART;
}


/*---------------------------------------------------------------------------
Prototype     :   WORD UartChkStatus(WORD port );
Purpose       :   Check UART port status
Scope         :   ALL
input         :   port : UART_A / UART_B
return        :   UART Port Status
---------------------------------------------------------------------------*/
WORD    UartChkStatus(WORD port)
{
    if(port==UART_A)        return (CPU ->REG_UARTA_CTRL_1);
    else    if(port==UART_B)        return (CPU ->REG_UARTB_CTRL_1);
}


/*---------------------------------------------------------------------------
Prototype     :   WORD UartChkCfg(WORD port)
Purpose       :   To get the UART configuration
Scope         :   OS
input         :   port : UART_A / UART_B
Output        :
Return        :   Same as the value of "config" that passed to UartInit
---------------------------------------------------------------------------*/
WORD    UartChkCfg(WORD port)
{
    if(port==UART_A)        return((CPU ->REG_UARTA_CTRL_1)&0x2e);
    else    if(port==UART_B)        return((CPU ->REG_UARTB_CTRL_1)&0x2e);
}




