/**
 * @file hv_pm51_driver_UART.c
 * @brief PM51 UART driver.
 * @details 
 * @author HiView SoC Software Team
 * @version 0.0.1
 * @date 20230301
 * @copyright Copyright(c),2023-3, Hiview Software. All rights reserved.
 * @par History: 
 * <table>
 * <tr><th>author                     <th>date           <th>description
 * <tr><td>HiView SoC Software Team   <td>20230301       <td>Create and first Version.
 * </table>
**/

#include <reg51.h>
#include "HS_PAGE_HT7315_8051_reg.h"
#include "hv_pm51_Setting.h"
#include "hv_pm51_Reg.h"
#include "hv_pm51_Assert.h"
#include "hv_pm51_driver_Reg.h"
#include "hv_pm51_driver_UART.h"
#include "hv_pm51_driver_GPIO.h"
#include "BoardConfig.h"
#include "ProjectConfig.h"
#include "TypecConfig.h"

#if UART_PRINT_ENABLE
static xUCHAR8 charData[11] = "0x";
#endif

void Hv_PM51_Uart_Init(UartMode enMode, BaudRate enBaud)
{
#if UART_PRINT_ENABLE
    /* stby io user mode */
    Hv_PM51_Reg_WriteMask(HS_Standby__SH08_TOP_STBY__reg_io_user_mode_ADDR,
                      HS_Standby__SH08_TOP_STBY__reg_io_user_mode_BITSTART,
                      HS_Standby__SH08_TOP_STBY__reg_io_user_mode_BITEND, 0x1);

    /* SCON BITS
     * 7    6    5    4    3    2    1    0
     * SM0 SM1  SM2  REN  TB8  RB8   TI   RI
     * SM0,SM1,SM2 UART mode specify
     * REN if 1, enable reception, 0 disable reception
     * TB8  In modes 2 and 3, stores 9th data bit sent
     * RB8  In modes 2 and 3, stores 9th data bit received. In mode 1, if SM2 = 0, it is stop bit received. In mode0, this bit is not used
     * TI   Transmit interrupt flag. Set by hardware at the end of 8th bit in Mode 0, or at the beginning of the stop bit in other modes. Must be cleared by software
     * RI   Receive interrupt flag. Set by hardware at the end of the 8th bit in Mode 0, or at the half point of the stop bit in other modes. Must be cleared by software.
     * Uart mode:
     * SM0 SM1        Description                                                Baud rate
     *  0   0       Mode 0: 8 bit shift register                              fsclk / 2
     *  0   1       Mode 1: 8 bit uart                                        Variable
     *  1   0       Mode 2: 9 bit uart                                        fsclk / 32 or fsclk / 64
     *  1   1       Mode 3: 9 bit uart                                        Variable
    */
    switch(enMode)
    {
        case E_UART_MODE0:
            SCON = 0x30;
            break;
        case E_UART_MODE1:
            SCON = 0x70;    /* SCON : uart Mode 1 8 bit uart, enable reception */
            break;
        case E_UART_MODE2:
            SCON = 0xB0;
            break;
        case E_UART_MODE3:
            SCON = 0xF0;
            break;
        default:
            break;
    }

    /* Baud Rate Setting by timer2 
     * Baud Rate = Timer2OverflowRate / 16  
     *           = fosc / (32 * (65536 - RCP2H.RCP2L)) = 115200
     * 115200 * 32 * x = 26.6M
     * fosc = 300M 26.6M
    */ 
    if((enMode == E_UART_MODE1) || (enMode == E_UART_MODE3))
    {
        switch(enBaud)
        {
            case E_BR_9600:
                RCP2L= 0xA9;
                RCP2H= 0xFF;
                break;
            case E_BR_115200:
                RCP2L= 0xF9; //RCP2L= 0xEC; 75MHz PLL
                RCP2H= 0xFF;
                break;
            default:
                break;
        }
    }
    /* T2CON.7 TF2 Timer 2 overflow flag. Set by hardware when Timer/Counter 2 overflows unless either RCLK or TCLK
     * is set to 1. This bit isn't cleared by hardware when the processor calls the interrupt service routine.
     * T2CON.6 EXF2 Timer 2 external flag. This bit is set when a capture or reload is triggered by a negative transition
     * on T2EX and EXEN2 is set to 1. If the Timer 2 interrupt is enabled, setting this bit will cause an
     * interrupt to the Timer 2 vector.
     * T2CON.5 RCLK If this bit is set, the Serial Port receive clock is driven from the overflow pulses of Timer 2.
     * T2CON.4 TCLK If this bit is set, the Serial Port transmit clock is driven from the overflow pulses of Timer 2.
     * T2CON.3 EXEN2 Timer 2 External interrupt enable flag. When set, a negative edge on T2EX will trigger a capture
     * or auto-reload.
     * T2CON.2 TR2 Run control bit for Timer 2. If set to 1, the timer is enabled.
     * T2CON.1 C/NT2 Timer/Counter select. A 0 selects internal timer mode; a 1 selects external counter mode.
     * T2CON.0 CP/NRL2 Capture/Reload control. When set, captures occur on negative transitions of T2EX (if EXEN2 is
     * set). When 0, auto-reloads are performed on timer overflows or on negative transitions of T2EX
     * (if EXEN2 is set). If either RCLK or TCLK is 1, this bit is ignored and auto-reloads are performed
     * on timer overflows.
    */
    if((enMode == E_UART_MODE1) || (enMode == E_UART_MODE3))
    {
        T2CON = 0x34;
    }
    else
    {
        T2CON = 0x00;
    }

    /* Priority */
    PS = 1;
    return;
#else
    HV_UNUSED(enMode);
    HV_UNUSED(enBaud);
#endif
}

void Hv_PM51_Uart_IrqPut(UCHAR8 ucCh)
{
#if UART_PRINT_ENABLE
    if(TI)
    {
        while(TI == 0);
    }
    SBUF = ucCh;
    while(TI == 0);
    TI = 0;
#else
    HV_UNUSED(ucCh);
#endif
}

static void UART_PutString(UCHAR8 *pucStr)
{
    HV_PM51_ASSERT(pucStr != NULL); 
    
#if UART_PRINT_ENABLE
    while (*pucStr)
    {
        SBUF = *pucStr;
        pucStr++;
        
        while(TI == 0);
        
        TI = 0;
    }
#endif
}

void Hv_PM51_Uart_Print(UCHAR8 *pucStr)
{
    HV_PM51_ASSERT(pucStr != NULL); 
    
#if UART_PRINT_ENABLE
    if (pucStr != NULL)
    {
        UART_PutString(pucStr);
    }
#endif
}

void Hv_PM51_Uart_PrintU32(ULONG32 ulVal)
{
#if UART_PRINT_ENABLE
    USHORT16 usIndex;
    UCHAR8 ucCh;
    
    for (usIndex = 0; usIndex < 8; usIndex++)
    {
        ucCh = (UCHAR8)(ulVal >> (4 * (7 - usIndex)) & 0xf);
        if (ucCh > 9)
        {
            ucCh += 0x37;
        }
        else
        {
            ucCh += 0x30;
        }
        charData[2 + usIndex] = ucCh;
    }
    
    charData[10] = 0;
    
    Hv_PM51_Uart_Print(charData);
#else
    HV_UNUSED(ulVal);
#endif
}
