/**************************************************************************//**
 * @file     uart_common.c
 * @version  V1.0
 * $Date:    19/09/25 14:00 $
 * @brief    Source file for UART test.
 *
 * @note
 * Copyright (C) 2019 Panchip Technology Corp. All rights reserved.
 *
 ******************************************************************************/
#include <ctype.h>
#include "pan271x.h"
#include "uart_common.h"

volatile uint8_t uartRxBuffer[UART_RX_BUF_SIZE];
volatile uint8_t uartTxBuffer[UART_TX_BUF_SIZE];

volatile uint8_t uartRxBufIdx;
volatile uint32_t uartTxMark;
volatile uint32_t uartTxBufIdx;

volatile bool uartTxDone = false;

volatile uint32_t rxRcvNum = 11;

T_UART_TEST_RESULT (* const UART_TestCase[])(void) = 
{
    UART_BaudrateTestCase1,
    UART_InterruptTestCase2,
};

void UART_TestFunctionEnter(uint16_t TcIdx)
{
    T_UART_TEST_RESULT r = UART_TST_OK;

    if (TcIdx >= sizeof(UART_TestCase) / sizeof(void*))
    {
        SYS_TEST("Error, cannot find Testcase %d!", TcIdx);
        return;
    }

    r = (UART_TestCase[TcIdx])();
    if (r != UART_TST_OK)
    {
        SYS_TEST("UART Test Fail, Fail case: %d, Error Code: %d\n", TcIdx, r);
    }
    else
    {
        SYS_TEST("UART Test OK, Success case: %d\n", TcIdx);
    }
}

void UART_HandleTimeout(UART_T* UARTx)
{
	uint8_t level = UART_GetRxFifoLevel(UARTx)+1;
	
	while (!UART_IsRxFifoEmpty(UARTx))
	{
		uartRxBuffer[uartRxBufIdx++] = UART_ReceiveData(UARTx);
	}
}

void UART_HandleReceivedData(UART_T* UARTx)
{
	uint8_t level = UART_GetRxFifoLevel(UARTx)+1;
	
	while (level--) {
		while (!UART_IsRxFifoEmpty(UARTx))
		{
			uartRxBuffer[uartRxBufIdx++] = UART_ReceiveData(UARTx);
			if (uartRxBufIdx >= UART_RX_BUF_SIZE)   //Rx buffer full
			{
				SYS_TEST("Error, too much data received, Rx buffer full!\n");
				uartRxBufIdx = 0;   //Reset Rx buf index
				break;
			}
		}
	}
}

void UART_HandleTransmittingData(UART_T* UARTx)
{
    while (!UART_IsTxFifoFull(UARTx))
    {
        if (uartTxMark < uartTxBufIdx)
        {
            UART_SendData(UARTx, uartTxBuffer[uartTxMark++]);
        }
        else
        {
            uartTxDone = true;
            uartTxMark = 0; //Reset Tx mark while transmitting done
            UART_DisableIrq(TGT_UART, UART_IRQ_TX_NOT_FULL);   //Disable THRE Interrupt after transmitting done
            break;
        }
    }
}

void UART_HandleProc(UART_T* UARTx)
{
    uint32_t event = UARTx->UART_STATUS;

	if (event & UART_STATUS_RX_TIMEOUT_FLAG_Msk) {
		SYS_TEST("TIMEOUT\n");
	}
	if (UART_IsIrqEnabled(UARTx, UART_IRQ_RX_TIMEOUT) && (event & UART_STATUS_RX_TIMEOUT_FLAG_Msk)) {
		UART_HandleTimeout(UARTx);
	}
	
	if (UART_IsIrqEnabled(UARTx, UART_IRQ_RX_NOT_EMPTY) && (event & UART_STATUS_RX_NE_FLAG_Msk)) {
		UART_HandleReceivedData(UARTx);
	}
	
	if (UART_IsIrqEnabled(UARTx, UART_IRQ_TX_NOT_FULL) && (event & UART_STATUS_TX_NF_FLAG_Msk)) {
		UART_HandleTransmittingData(UARTx);
	}
}

void UART1_IRQHandler(void)
{
    UART_HandleProc(UART1);
}


// Read out all ready data from RBR or FIFO and just discard them
void TGT_ClrAllReadyData(void)
{
    volatile uint8_t c;
    while(!(TGT_UART->UART_STATUS & UART_STATUS_RX_EMPTY_FLAG_Msk))
    {
        c = TGT_UART->UART_RXDATA;
    }
}

// Get character from target test Uart
char TGT_GetChar(uint32_t* line_status)
{
    volatile uint32_t lsr;
    do
    {
        lsr = TGT_UART->UART_STATUS;
    }
    while ((lsr & UART_STATUS_RX_EMPTY_FLAG_Msk)); // Wait until there is a new data in RBR

    return (char)(TGT_UART->UART_RXDATA);
}

// Try to receive multi-data until getting expected number of bytes
void TGT_ReceiveMultiData(uint8_t* data, size_t expect_size)
{
    TGT_ClrAllReadyData();

    while (expect_size--)
    {
        *data++ = TGT_GetChar(NULL);
    }
}

// Send multiple data to target test Uart
void TGT_SendMultiData(const uint8_t* data, size_t size)
{
    while (size--)
    {
        TGT_UART->UART_TXDATA = *(data++);
        while(!(TGT_UART->UART_STATUS & UART_STATUS_TX_EMPTY_FLAG_Msk));    // Wait until THR is empty to avoid data lost
    }
}

/*
    Encode a Byte to Hex Character Sequence tailing with a space.
    e.g.    Byte (1B) --> Hex (5B)
            0x7E      --> '0''x''7''E'' '
*/
static void HexEncodeByte(uint8_t b, char* out)
{
    static const char hex_chars[] = {'0', '1', '2', '3', '4', '5', '6', '7',
                                     '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
    unsigned char idx1 = (b & 0xF0) >> 4;
    unsigned char idx2 = b & 0x0F;
    out[0] = '0';
    out[1] = 'x';
    out[2] = hex_chars[idx1];
    out[3] = hex_chars[idx2];
    out[4] = ' ';
}

/*
    Encode a Byte Array to a Hexadecimal Displayed String.
    e.g.    Byte Array (3 Bytes) --> String (15 Bytes)
            {0x05, 0x7A, 0xFE}   --> "0x05 0x7A 0xFE"
*/
char* Hexlify(const uint8_t* bin_in, size_t n, char* hex_out)
{
    char* h = hex_out;  
    for (int i = 0; i < n; i++) {
        HexEncodeByte(bin_in[i], h);
        h += 5;
    }
    *(--h) = '\0';    //Replace the last space with '\0'
    return hex_out;
}



T_UART_TEST_RESULT UART_RegisterDefaultValueCheckCase0(void)
{
    SYS_TEST("Target UART%d Register Default Values:\n", 0);
    SYS_TEST("---------------------------\n");
    SYS_TEST("UART_RXDATA = 0x%08x\n", TGT_UART->UART_RXDATA);
    SYS_TEST("UART_TXDATA = 0x%08x\n", TGT_UART->UART_TXDATA);
    SYS_TEST("UART_CTL    = 0x%08x\n", TGT_UART->UART_CTL   );
    SYS_TEST("UART_STATUS = 0x%08x\n", TGT_UART->UART_STATUS);
    SYS_TEST("UART_BCNT   = 0x%08x\n", TGT_UART->UART_BCNT  );

    return UART_TST_OK;
}
