#include "RS232_HCB_Module.h"

#define EOT_TYPE_NONE				0
#define EOT_TYPE_CHAR				1
#define EOT_TYPE_COUNT				2
#define EOT_TYPE_TIME				3


#define OSC_CLK						50000000		// 50MHz
#define CPU_CLK						600000000		// 600MHz

void RS232_ProcessRx(unsigned int *buffer, char *rxchar);
void RS232_ProcessTx(unsigned int *buffer, char txchar, int stopBitCount);
//---------------------------------------------------------------------------
void McBSP_Init(MCBSP_Handle *handle, int bps, int tx_stop_bits, int tx_data_bits,
	int rx_stop_bits, int rx_data_bits, int mcbspDeviceIndex, char isInternalCLK)
{
	MCBSP_Config mcbspCfg;      /* Config Structures */
	unsigned int clkdv;

    *handle = MCBSP_open(mcbspDeviceIndex, MCBSP_OPEN_RESET);

    if (*handle == INV) {
        return;
    }

    MCBSP_getConfig(*handle, &mcbspCfg);

    // McBSP Config 
    mcbspCfg.pcr =
        MCBSP_FMK(PCR,XIOEN,MCBSP_PCR_XIOEN_SP) |
        MCBSP_FMK(PCR,RIOEN,MCBSP_PCR_RIOEN_SP) |
        MCBSP_FMK(PCR,FSXM,MCBSP_PCR_FSXM_INTERNAL) |
        MCBSP_FMK(PCR,FSRM,MCBSP_PCR_FSRM_EXTERNAL) |
        MCBSP_FMK(PCR,CLKXM,MCBSP_PCR_CLKXM_OUTPUT) |
        MCBSP_FMK(PCR,CLKRM,MCBSP_PCR_CLKRM_OUTPUT) |
        MCBSP_FMK(PCR,CLKSSTAT,MCBSP_PCR_CLKSSTAT_0) |
        MCBSP_FMK(PCR,DXSTAT,MCBSP_PCR_DXSTAT_0) |
        MCBSP_FMK(PCR,FSXP,MCBSP_PCR_FSXP_ACTIVELOW) |
        MCBSP_FMK(PCR,FSRP,MCBSP_PCR_FSRP_ACTIVELOW) |
        MCBSP_FMK(PCR,CLKXP,MCBSP_PCR_CLKXP_RISING) |
        MCBSP_FMK(PCR,CLKRP,MCBSP_PCR_CLKRP_FALLING);

    /*
     * Here we compute the bit rate of the McBSP.  Each UART bit is
     * represented by 16 McBSP bits.
     */
    clkdv = (unsigned int)(OSC_CLK / (bps * 32)) - 1;

    /* clkdv is max 8-bits long, so make sure we didn't overflow ... */
    if (clkdv > 0xff) {
        return;
    }

    mcbspCfg.srgr = 
        MCBSP_FMK(SRGR,GSYNC,MCBSP_SRGR_GSYNC_FREE) |
        MCBSP_FMK(SRGR,CLKSP,MCBSP_SRGR_CLKSP_RISING) |
        MCBSP_FMK(SRGR,FSGM,MCBSP_SRGR_FSGM_DXR2XSR) |
        MCBSP_FMK(SRGR,FPER,MCBSP_SRGR_FPER_DEFAULT) |		//
        MCBSP_FMK(SRGR,FWID,MCBSP_SRGR_FWID_DEFAULT) |		//
        MCBSP_FMK(SRGR,CLKGDV,MCBSP_SRGR_CLKGDV_OF(clkdv));

	if (isInternalCLK)
	{
		mcbspCfg.srgr |= MCBSP_FMK(SRGR,CLKSM,MCBSP_SRGR_CLKSM_INTERNAL);
	}
	else
	{
		mcbspCfg.srgr |= MCBSP_FMK(SRGR,CLKSM,MCBSP_SRGR_CLKSM_CLKS);
	}

    mcbspCfg.xcr =
        MCBSP_FMK(XCR,XPHASE,MCBSP_XCR_XPHASE_DUAL) |
        MCBSP_FMK(XCR,XFRLEN2,MCBSP_XCR_XFRLEN2_OF(tx_stop_bits - 1)) |
        MCBSP_FMK(XCR,XWDLEN2,MCBSP_XCR_XWDLEN2_16BIT) |
        MCBSP_FMK(XCR,XCOMPAND,MCBSP_XCR_XCOMPAND_MSB) |
        MCBSP_FMK(XCR,XFIG,MCBSP_XCR_XFIG_YES) |
        MCBSP_FMK(XCR,XDATDLY,MCBSP_XCR_XDATDLY_0BIT) |
        MCBSP_FMK(XCR,XFRLEN1,MCBSP_XCR_XFRLEN1_OF(tx_data_bits)) |
        MCBSP_FMK(XCR,XWDLEN1,MCBSP_XCR_XWDLEN1_32BIT) |
        MCBSP_FMK(XCR,XWDREVRS,MCBSP_XCR_XWDREVRS_DISABLE);

    mcbspCfg.rcr =
        MCBSP_FMK(RCR,RPHASE,MCBSP_RCR_RPHASE_DUAL) |
        MCBSP_FMK(RCR,RFRLEN2,MCBSP_RCR_RFRLEN2_OF(rx_stop_bits - 1)) |
        MCBSP_FMK(RCR,RWDLEN2,MCBSP_RCR_RWDLEN2_16BIT) |
        MCBSP_FMK(RCR,RCOMPAND,MCBSP_RCR_RCOMPAND_MSB) |
        MCBSP_FMK(RCR,RFIG,MCBSP_RCR_RFIG_YES) |
        MCBSP_FMK(RCR,RDATDLY,MCBSP_RCR_RDATDLY_1BIT) |
        MCBSP_FMK(RCR,RFRLEN1,MCBSP_RCR_RFRLEN1_OF(rx_data_bits)) |
        MCBSP_FMK(RCR,RWDLEN1,MCBSP_RCR_RWDLEN1_32BIT) |
        MCBSP_FMK(RCR,RWDREVRS,MCBSP_RCR_RWDREVRS_DISABLE);

    mcbspCfg.spcr =
        MCBSP_FMK(SPCR,FREE,MCBSP_SPCR_FREE_YES) |				// NO
        MCBSP_FMK(SPCR,SOFT,MCBSP_SPCR_SOFT_DEFAULT) |			// YES
        MCBSP_FMK(SPCR,FRST,MCBSP_SPCR_FRST_DEFAULT) |			// YES
        MCBSP_FMK(SPCR,GRST,MCBSP_SPCR_GRST_DEFAULT) |			// YES
        MCBSP_FMK(SPCR,XINTM,MCBSP_SPCR_XINTM_XRDY) |
        MCBSP_FMK(SPCR,XSYNCERR,MCBSP_SPCR_XSYNCERR_DEFAULT) |	// NO
        MCBSP_FMK(SPCR,XSYNCERR,MCBSP_SPCR_XRST_DEFAULT) |		//
        MCBSP_FMK(SPCR,DLB,MCBSP_SPCR_DLB_OFF) |
        MCBSP_FMK(SPCR,RJUST,MCBSP_SPCR_RJUST_RZF) |
        MCBSP_FMK(SPCR,CLKSTP,MCBSP_SPCR_CLKSTP_DISABLE) |
        MCBSP_FMK(SPCR,DXENA,MCBSP_SPCR_DXENA_OFF) | 
        MCBSP_FMK(SPCR,RINTM,MCBSP_SPCR_RINTM_RRDY) |     		// EOS
        MCBSP_FMK(SPCR,XSYNCERR,MCBSP_SPCR_RSYNCERR_DEFAULT) |	//
        MCBSP_FMK(SPCR,XSYNCERR,MCBSP_SPCR_RRST_DEFAULT);		//

	mcbspCfg.mcr = 0;
	mcbspCfg.rcere0 = 0;
	mcbspCfg.xcere0 = 0;
	mcbspCfg.rcere1 = 0;
	mcbspCfg.xcere1 = 0;
	mcbspCfg.rcere2 = 0;
	mcbspCfg.xcere2 = 0;
	mcbspCfg.rcere3 = 0;
	mcbspCfg.xcere3 = 0; 

    MCBSP_config(*handle, &mcbspCfg);

    // Disable any previous machine state
    // - McBSP disable
    MCBSP_FSETSH(*handle,SPCR,RRST,YES);
    MCBSP_FSETSH(*handle,SPCR,XRST,YES);

    // Start Sample Rate Generator: set /GRST = 1 
    MCBSP_enableSrgr(*handle);
                
    // Enable Frame Sync Generator for McBSP: set /FRST = 1
    MCBSP_enableFsync(*handle);

	
}
//---------------------------------------------------------------------------
void McBSP_Close(MCBSP_Handle handle)
{
	MCBSP_close(handle);
}
//---------------------------------------------------------------------------
void McBSP_Enable(MCBSP_Handle handle)
{
    // Enable MCBSP
    MCBSP_enableRcv(handle);

    // Enable MCBSP
    MCBSP_enableXmt(handle);
}
//---------------------------------------------------------------------------
void RS232_Init(TRS232Handle *handle, int bps, int tx_stop_bits, int tx_data_bits,
	int tx_total_bits, int rx_stop_bits, int rx_data_bits, int rx_total_bits, int mcbspDeviceIndex, char isInternalCLK)
{
	handle->TX.BitBufferPosition = 0;
	handle->TX.DataPosition = 0;
	handle->TX.DataLength = 0;
	handle->TX.Status = RS232_TX_STATUS_NONE;	
	handle->TX.BitCount = tx_total_bits;
	handle->TX.DataBitCount = tx_data_bits;
	handle->TX.StopBitCount = tx_stop_bits;
	handle->RX.BitBufferPosition = 0;
	handle->RX.DataPosition = 0;
	handle->RX.Status = RS232_RX_STATUS_NONE;
	handle->RX.BitCount = rx_total_bits;
	handle->RX.DataBitCount = rx_data_bits;
	handle->RX.StopBitCount = rx_stop_bits;

	McBSP_Init(&(handle->McbspHandle), bps, tx_stop_bits, tx_data_bits, rx_stop_bits, rx_data_bits, mcbspDeviceIndex, isInternalCLK);
} 
//---------------------------------------------------------------------------
void RS232_Close(TRS232Handle *handle)
{
	McBSP_Close(handle->McbspHandle);
	handle->McbspHandle = INV;
}
//---------------------------------------------------------------------------
void RS232_Enable(TRS232Handle *handle)
{
	McBSP_Enable(handle->McbspHandle);
}
//---------------------------------------------------------------------------
void RS232_SetAddr(TRS232Handle *handle, char *txAddr, int txMaxSize, char *rxAddr, int rxMaxSize)
{
	handle->TX.DataBufferAddr = txAddr;
	handle->TX.DataBufferSize = txMaxSize;
	handle->RX.DataBufferAddr = rxAddr;
	handle->RX.DataBufferSize = rxMaxSize;
}
//---------------------------------------------------------------------------
void RS232_ClearRX(TRS232Handle *handle)
{
	handle->RX.BitBufferPosition = 0;
	handle->RX.DataPosition = 0;
} 
//---------------------------------------------------------------------------
void RS232_SetEOT_Time(TRS232Handle *handle)
{
	handle->RX.EOT_Type = EOT_TYPE_TIME;
}
//---------------------------------------------------------------------------
void RS232_SetEOT_None(TRS232Handle *handle)
{
	handle->RX.EOT_Type = EOT_TYPE_NONE;
}
//---------------------------------------------------------------------------
void RS232_SetEOT_Count(TRS232Handle *handle, int count)
{
	handle->RX.EOT_Type = EOT_TYPE_COUNT;
	handle->RX.EOT_DataSize = count;
}
//---------------------------------------------------------------------------
void RS232_SetEOT_Char(TRS232Handle *handle, char eotChar)
{
	handle->RX.EOT_Type = EOT_TYPE_CHAR;
	handle->RX.EOT_Char = eotChar;
}
//---------------------------------------------------------------------------
void RS232_TxStart(TRS232Handle *handle, int length)
{
	handle->TX.DataPosition = 0;	
	handle->TX.DataLength = length;
	handle->TX.BitBufferPosition = 0;
	handle->TX.Status = RS232_TX_STATUS_SENDING;

	handle->RX.Status = RS232_RX_STATUS_READY;
	RS232_ClearRX(handle);

	RS232_ProcessTx(handle->TX.BitBuffer, handle->TX.DataBufferAddr[handle->TX.DataPosition], handle->TX.StopBitCount);
	MCBSP_write(handle->McbspHandle, handle->TX.BitBuffer[handle->TX.BitBufferPosition++]);
}
//---------------------------------------------------------------------------

/*
 *  ======== decodeBit ========
 *
 *  This function decoded the received character by testing the     
 *  center 4 bits of the baud. A majority rule is used for the      
 *  decoding
 */
int RS232_DecodeBit(unsigned int value)
{
    /* Test middle 4 bits in received raw data */
    value = ((value >> 14) & 0x0F);

    if ((value == 7) || (value > 10))           // sampled bit 0111, 1011, 1100, 1101, 1110 and 1111 are equal to 1
    {
        return (1);
    }
    else 
    {
        return (0);
    }
}


/*
 *  ======== processRx ========
 *  Process Reception function : Reception of a buffer from the 
 *  McBSP and reformat it to get the associated character value 
 */

// decode 1 start word(32bits) + 8 data word(8 * 32bits) + n stop words(n * 32bits)
// to 1 start bit + 8 data bits + n stop bits
void RS232_ProcessRx(unsigned int *buffer, char *rxchar)
{
    unsigned int rawData = 0;
    int bitValue;
    unsigned int bitCnt;

	*rxchar = 0;

	// skip start bit
    rawData = *buffer++;
	
        
    /* Walk through each data bit */
    for (bitCnt = 0; bitCnt < 8; bitCnt++) 
    {
        /* read raw bit (word) from dma buffer */
        rawData = *buffer++;

        /* get the value of the majority of the bits */
        bitValue = RS232_DecodeBit(rawData);
                        
        /* put received bit into proper place */
        *rxchar += bitValue << bitCnt;
    }
}
//---------------------------------------------------------------------------
/*
 *  ======== processTx ========
 *
 *  Process transmission function : this function is filling the
 *  xmitbuffer with appropriate data or 0xFFFF if idle mode.
 */
void RS232_ProcessTx(unsigned int *buffer, char txchar, int stopBitCount)
{
    unsigned int bitCnt;
                        
    /* Set start bit in buffer */
    *buffer++ = 0x00000000;

    /* Walk through each data bit */
    for (bitCnt = 0; bitCnt < 8; bitCnt++) 
    {
        /* determine state of bit and set dma buffer value */
        if ((txchar >> bitCnt & 0x1) == 1 ) 
        {
            *buffer++ = 0xFFFFFFFF;
        }
        else 
        {
            *buffer++ = 0x00000000;
        }
    }

	for (bitCnt = 0; bitCnt < stopBitCount; bitCnt++)
	{
	    *buffer++ = 0xFFFFFFFF;
	}
}
//---------------------------------------------------------------------------
void IsrRS232Rx(TRS232Handle *handle)
{
	unsigned int dummy;

	dummy = MCBSP_read(handle->McbspHandle);
	if (handle->RX.Status == RS232_RX_STATUS_READY)
	{
	   	if (handle->RX.BitBufferPosition < handle->RX.BitCount)
	   	{
			if (handle->RX.BitBufferPosition == 0)
			{
				if (RS232_DecodeBit(dummy) == 0)	// checking start bit
				{
					handle->RX.BitBuffer[handle->RX.BitBufferPosition++] = dummy;
				}
			}
			else
			{
				handle->RX.BitBuffer[handle->RX.BitBufferPosition++] = dummy;
			}
		} 

	   	if (handle->RX.BitBufferPosition >= handle->RX.BitCount)
		{
			if (handle->RX.DataPosition < handle->RX.DataBufferSize) 
			{
				RS232_ProcessRx(handle->RX.BitBuffer, &(handle->RX.DataBufferAddr[handle->RX.DataPosition]));
				if (handle->RX.EOT_Type == EOT_TYPE_CHAR)
				{
					if (handle->RX.DataBufferAddr[handle->RX.DataPosition] == handle->RX.EOT_Char) 
					{
						handle->RX.Status = RS232_RX_STATUS_RECEIVED;
					}
				}
				else if (handle->RX.EOT_Type == EOT_TYPE_COUNT)
				{
					if (handle->RX.DataPosition + 1 == handle->RX.EOT_DataSize) 
					{
						handle->RX.Status = RS232_RX_STATUS_RECEIVED;
					}
				}
				handle->RX.DataPosition++;
			}
			else
			{
				handle->RX.Status = RS232_RX_STATUS_RECEIVED;		// received, but overflowed
			}
			handle->RX.BitBufferPosition = 0;
		}
	}
}
//---------------------------------------------------------------------------
void IsrRS232Tx(TRS232Handle *handle)
{
	if (handle->TX.Status == RS232_TX_STATUS_SENDING)
	{
		if (handle->TX.BitBufferPosition >= handle->TX.BitCount)
		{
			handle->TX.BitBufferPosition = 0;
			handle->TX.DataPosition++;
			if (handle->TX.DataPosition >= handle->TX.DataLength)
			{
				handle->TX.Status = RS232_TX_STATUS_READY;		// tx complete
			}
			else
			{
				RS232_ProcessTx(handle->TX.BitBuffer, handle->TX.DataBufferAddr[handle->TX.DataPosition], handle->TX.StopBitCount);
				MCBSP_write(handle->McbspHandle, handle->TX.BitBuffer[handle->TX.BitBufferPosition++]);
			}
		}
		else
		{
			MCBSP_write(handle->McbspHandle, handle->TX.BitBuffer[handle->TX.BitBufferPosition++]);
		}
	}
}
//---------------------------------------------------------------------------
void RS232_SetBaudRate(TRS232Handle *handle, int baudRate)
{
	unsigned int clkdv;
	char isInternalCLK;
/*
	if (baudRate > 50000)
	{
		isInternalCLK = TRUE;
	}
	else
	{
		isInternalCLK = FALSE;
	}
*/
	isInternalCLK = FALSE;


	if (isInternalCLK)
	{
		MCBSP_FSETSH(handle->McbspHandle, SRGR, CLKSM, INTERNAL);
		clkdv = (unsigned int)(((float)CPU_CLK / (float)(baudRate * 32)) + 0.75) - 1;
		MCBSP_FSETH(handle->McbspHandle, SRGR, CLKGDV, MCBSP_SRGR_CLKGDV_OF(clkdv));
	}
	else
	{
		MCBSP_FSETSH(handle->McbspHandle, SRGR, CLKSM, CLKS);
		clkdv = (unsigned int)(((float)OSC_CLK / (float)(baudRate * 32)) + 0.75) - 1;
		MCBSP_FSETH(handle->McbspHandle, SRGR, CLKGDV, MCBSP_SRGR_CLKGDV_OF(clkdv));
	}
}
//---------------------------------------------------------------------------

