/**
 * @file hv_pm51_driver_Timer.c
 * @brief PM51 internal and external timer 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 "hv_pm51_Setting.h"
#include "hv_pm51_Reg.h"
#include "hv_pm51_driver_Timer.h"
#include "hv_pm51_driver_Reg.h"
#include "hv_pm51_driver_UART.h"

#if TIMER_ENABLE

#if IR_ENABLE
xULONG32 g_ulTimer0Cnt = 0;
#endif

void Hv_PM51_Timer_Init(TimerEn enTimerSel, TimerMode enMode)
{
    /* TCON BITS
     * 7            6                5                4                3                2                1                0
     * TF1            TR1                TF0                TR0                IE1                IT1                IE0                IT0
     * TF1        Timer1 overflow flag, set and clear by hardware. call interrupt service routine
     * TR1        Timer1 run control. If 1, timer runs, if 0, timer is halted
     * TF0        Timer0 overflow flag, same as timer1
     * TR0        Timer0 run control. 
     * IE1        External interrupt 1 edge flag. Set by hardware when external interrupt 1 edge is detected
     * IT1        External interrupt 1 control bit, If 1, external interrupt edge-triggered. 0, level-triggered
     * IE0        External interrupt 0 edge flag
     * IT0        External interrupt 0 control bit
     *
     */
    

    /* TMOD BITS
     * 7            6                5                4                3                2                1                0
     * GATE1        C/NT1           M1(1)           M0(1)           GATE0           C/NT0           M1(0)           M0(0)
     * GATE1 Timer1 gate flag
     * C/NT1 Timer/Counter 1 selector. If 0, input is from internal system clock; if 1, input is from T1 pin
     * M1(1) Timer 1 Mode control bit M1
     * M0 (1) Timer 1 mode control bit M0
     * GATE0 Timer 0 gate flag.
     * C/NT0 Timer/Counter 0 selector. If 0, input is from internal system clock; if 1, input is from T0 pin.
     * M1(0) Timer 0 Mode control bit M1
     * M0(0) Timer 0 Mode control bit M0
     * M1M0 setting:
     * M1 M0                Description
     * 0  0                    13-bit timer/counter
     * 0  1                    16-bit timer/counter
     * 1  0                    8-bit auto-reload timer/counter
     * 1  1                    Timer 0 is split into two halves.
     */
    switch (enTimerSel)
    {
        case INNERTIMER0:
        case INNERTIMER1:
        {
            TCON = 0x00;
            switch (enMode)
            {
                case E_13BIT:
                    if(enTimerSel == INNERTIMER0)
                        TMOD &= (~0x3);
                    else
                        TMOD &= (~0x30);
                    break;
                
                case E_16BIT:
                    if(enTimerSel == INNERTIMER0)
                    {
                        TMOD |= 0x1;
                        TMOD &= (~0x2);
                    }
                    else
                    {
                        TMOD |= 0x10;
                        TMOD &= (~0x20);
                    }
                    break;

                case E_AUTOLOAD:
                    if(enTimerSel == INNERTIMER0)
                    {
                        TMOD &= (~0x1);
                        TMOD |= 0x2;
                    }
                    else
                    {
                        TMOD &= (~0x10);
                        TMOD |= 0x20;
                    }
                    break;

                case E_DIVISION:
                    TMOD |= 0x33;
                    break;
                default:
                    break;
            }
            break;
        }
        case INNERTIMER2:
        {
            /* no use. reserved for uart. */
            break;
        }
        case EXTIMER0:
        {
            ET10USL = 0x09;
            ET10USH = 0x01;

            ETEA &= 0xFE;/* clear bit0 */
            break;
        }
        case EXTIMER1:
        {
            ET10USL = 0x09;
            ET10USH = 0x01;

            ETEA &= 0xFD;/* clear bit1 */
            break;
        }
        default:
            break;
    }

    return;
}

iBOOL Hv_PM51_Timer_Set(TimerEn enTimerSel, USHORT16 usInterval)
{
    switch(enTimerSel)
    {
        case INNERTIMER0:
        {
            /* AHB 26.6MHz 16bit */
            /* Trigger an interrupt once after (usInterval*1000*2/26600000) ms. */        
            TL0 = usInterval & 0xFF;
            TH0 = (usInterval >> 8) & 0xFF;
            TCON |=  (BIT_4);
            /* Intr_InstallProc(INTR_NO2_INNER_TIMER0,pCallBack); */
            /* Hv_PM51_Uart_Print("TIMER install!\r\n"); */
            break;
        }
        case INNERTIMER1:
        {
            /* AHB 26.6MHz 16bit */
            /* Trigger an interrupt once after (usInterval*1000*2/26600000) ms. */          
            TL1 = usInterval & 0xFF;
            TH1 = (usInterval >> 8)& 0xFF;
            TCON |=  (BIT_6);
            /* Intr_InstallProc(INTR_NO3_INNER_TIMER1,pCallBack); */
            break;
        }
        case INNERTIMER2:
        {
            /* no use. reserved for uart. */
            return HV_FALSE;
        }
        case EXTIMER0:
        {
            /* AHB 26.6MHz */
            /* Trigger an interrupt once every (10*usInterval) us. */        
            ET10USL = 0x09;
            ET10USH = 0x01;        
            ET0L = usInterval & 0xFF;
            ET0H = (usInterval >> 8)& 0xFF;
            ETEA |= (BIT_0);
            /* Intr_InstallProc(INTR_NO7_EX_TIMER0,pCallBack); */
            break;
        }
        case EXTIMER1:
        {
            /* AHB 26.6MHz */
            /* Trigger an interrupt once every (usInterval) ms. */          
            ET10USL = 0x09;
            ET10USH = 0x01;           
            ET1L = usInterval & 0xFF;
            ET1H = (usInterval >> 8)& 0xFF;
            ETEA |= (BIT_1);
            /* Intr_InstallProc(INTR_NO8_EX_TIMER1,pCallBack); */
            break;
        }
        default:
            return HV_FALSE;
    }
    return HV_TRUE;
}

iBOOL Hv_PM51_Timer_SetMs(TimerEn enTimerSel, USHORT16 usInterval)
{    
    switch(enTimerSel)
    {
        case INNERTIMER0:
        {
            /* AHB 26.6MHz 16bit */
            /* Trigger an interrupt once after 1ms. */
            TL0 = 0xF4;
            TH0 = 0x33;
            TCON |=  (BIT_4);
            break;
        }
        case INNERTIMER1:
        {
            /* AHB 26.6MHz 16bit */
            /* Trigger an interrupt once after 1ms. */
            TL1 = 0xF4;
            TH1 = 0x33;
            TCON |=  (BIT_6);
            break;
        }
        case INNERTIMER2:
        {
            /* no use. reserved for uart. */
            return HV_FALSE;
        }
        case EXTIMER0:
        {
            /* AHB 26.6MHz */
            /* Trigger an interrupt once every (usInterval) ms. */
            ET10USL = 0xE7;
            ET10USH = 0x67; 
            ET0L = usInterval & 0xFF;
            ET0H = (usInterval >> 8)& 0xFF;
            ETEA |= (BIT_0);
            break;
        }
        case EXTIMER1:
        {
            /* AHB 26.6MHz */
            /* Trigger an interrupt once every (usInterval*100) ms. */
            ET10USL = 0xE7;
            ET10USH = 0x67;       
            ET1L = usInterval & 0xFF;
            ET1H = (usInterval >> 8)& 0xFF;
            ETEA |= (BIT_1);
            break;
        }
        default:
            return HV_FALSE;
    }
    return HV_TRUE;
}

void Hv_PM51_Timer_Clear(TimerEn enTimerSel)
{
    switch(enTimerSel)
    {
        case INNERTIMER0:
        {
            TCON &= ~(BIT_4);
            break;
        }
        case INNERTIMER1:
        {
            TCON &= ~(BIT_6);
            break;
        }
        case INNERTIMER2:
        {
            /* no use. reserved for uart. */
            return;
        }
        case EXTIMER0:
        {
            ETEA &= ~(BIT_0);
            break;
        }
        case EXTIMER1:
        {
            ETEA &= ~(BIT_1);
            break;
        }
        default:
            return;
    }
}

iBOOL Hv_PM51_Timer_Get(TimerEn enTimerSel, ULONG32 *pulInterval)
{

    switch(enTimerSel)
    {
        case INNERTIMER0:
        {
#if IR_ENABLE
            xULONG32 ulTimerCounterMax = 0x10000;
            
            *pulInterval = (ULONG32)((TH0 << 8) | TL0);
            *pulInterval = *pulInterval & 0xFFFF;

            if(g_ulTimer0Cnt != 0)
            {
                *pulInterval += g_ulTimer0Cnt * ulTimerCounterMax;
                g_ulTimer0Cnt = 0;
            }
#else
            *pulInterval = (TH1 << 8) | TL1;
#endif
            break;
        }
        case INNERTIMER1:
        {
            *pulInterval = (TH1 << 8) | TL1;
            break;
        }
        case INNERTIMER2:
        {
            /* no use. reserved for uart. */
            return HV_FALSE;
        }
        case EXTIMER0:
        {
            ETEA |= BIT_7;
            *pulInterval = (ET0H << 8) | ET0L;
            break;
        }
        case EXTIMER1:
        {
            ETEA |= BIT_7;
            *pulInterval = (ET1H << 8) | ET1L;
            break;
        }
        default:
            return HV_FALSE;
    }
    return HV_TRUE;
}

#endif

