#include "CSIH.h"
#include "GPIO.h"
#include "TLC6C5912.h"
#include "Watchdog.h"
#include "dr7f701441.dvf.h"
#include "r_typedefs.h"

void INTCSIH0IC(void);
void INTCSIH0IR(void);
void INTCSIH1IC(void);
void INTCSIH1IR(void);

void CSIH_DELAY(void)
{
    uint8_t i;
    for ( i = 0; i < 200; i++ )
    {
        WDT_Clear( ); /*  阻塞发送时，防止看门狗复位  */
    }
}

/*  释放CPU回调，用于降低功耗 或 操作系统调度  */
static void CSIH_CPU_SleepIdle(void)
{
    WDT_Clear( ); /*  阻塞发送时，防止看门狗复位  */
}

/*  将MFS初始化成SPI的只发送模式  */
/*  参数 channel 为通道号：0 到 1  */
/*  参数 baud 为波特率，即你的SPI的SCK的频率 单位：K */
/*  参数 bitnum 为data数据的bit位数  */
/*  参数 sck_edge 为SCK时钟信号的格式 CSIH_SCKH_Rising,  在时钟信号空闲时，为高电平, 上升沿取数
                                    CSIH_SCKH_Falling, 在时钟信号空闲时，为高电平, 下降沿取数
                                    CSIH_SCKL_Rising,  在时钟信号空闲时，为低电平, 上升沿取数
                                    CSIH_SCKL_Falling, 在时钟信号空闲时，为低电平, 下降沿取数  */
/*  参数 dat_format 为MOSI信号的发送数据的格式 CSIH_DAT_LSbit 表示低位先发出
                                                 CSIH_DAT_MSbit表示高位先发出 */
void CSIH_Init(uint8_t         channel,
               uint16_t        baud,
               uint8_t         bitnum,
               CSIH_SCK_Edge   sck_edge,
               CSIH_DAT_FORMAT dat_format)
{
    if ( channel > 1U )
    {
    }
    else
    {
        CSIH [ channel ]->unCTL0.u8Register  = 0x00U;
        CSIH [ channel ]->unCTL1.u32Register = 0x00020000UL;

        if ( channel == 1U )
        {
            CSIH [ channel ]->unCTL2.stcField.CSIHnPRS = 0U;

            switch ( baud )
            {
                case 1000:
                    CSIH [ channel ]->unCTL2.stcField.CSIHnBRS    = 4U;
                    CSIH [ channel ]->unCFG0.stcField.PSCLxOBRSSx = 0U;
                    break;
                case 500:
                    CSIH [ channel ]->unCTL2.stcField.CSIHnBRS    = 8U;
                    CSIH [ channel ]->unCFG0.stcField.PSCLxOBRSSx = 0U;
                    break;
                case 250:
                    CSIH [ channel ]->unCTL2.stcField.CSIHnBRS    = 16U;
                    CSIH [ channel ]->unCFG0.stcField.PSCLxOBRSSx = 0U;
                    break;
                case 100:
                    CSIH [ channel ]->unCTL2.stcField.CSIHnBRS    = 40U;
                    CSIH [ channel ]->unCFG0.stcField.PSCLxOBRSSx = 0U;
                    break;
                default:
                    break;
            }
        }
        else
        {
            switch ( baud )
            {
                case 1000:
                    CSIH [ channel ]->unCTL2.stcField.CSIHnPRS = 4u;
                    CSIH [ channel ]->unBRS0.stcField.CSIHnBRS = 2U;
                    break;
                case 500:
                    CSIH [ channel ]->unCTL2.stcField.CSIHnPRS = 4u;
                    CSIH [ channel ]->unBRS0.stcField.CSIHnBRS = 4U;
                    break;
                case 250:
                    CSIH [ channel ]->unCTL2.stcField.CSIHnPRS = 4u;
                    CSIH [ channel ]->unBRS0.stcField.CSIHnBRS = 8U;
                    break;
                case 100:
                    CSIH [ channel ]->unCTL2.stcField.CSIHnPRS = 4u;
                    CSIH [ channel ]->unBRS0.stcField.CSIHnBRS = 20U;
                    break;
                default:
                    break;
            }

            CSIH [ channel ]->unCFG0.stcField.PSCLxOBRSSx = 0U;
        }

        CSIH [ channel ]->unMCTL0.u16Register = 0x0100U;
        CSIH [ channel ]->unSTCR0.u16Register = 0x010BU;

        CSIH [ channel ]->unCFG0.stcField.CSIHnPSx  = 0U;
        CSIH [ channel ]->unCFG0.stcField.CSIHnDLSx = bitnum;
        CSIH [ channel ]->unCFG0.stcField.CSIHnRCBx = 0U;

        if ( dat_format == CSIH_DAT_LSbit )
        {
            CSIH [ channel ]->unCFG0.stcField.CSIHnDIRx = 1U;
        }
        else
        {
            CSIH [ channel ]->unCFG0.stcField.CSIHnDIRx = 0U;
        }

        switch ( sck_edge )
        {
            case CSIH_SCKH_Rising:
                CSIH [ channel ]->unCFG0.stcField.CSIHnCKPx = 0U;
                CSIH [ channel ]->unCFG0.stcField.CSIHnDAPx = 0U;
                break;
            case CSIH_SCKH_Falling:
                CSIH [ channel ]->unCFG0.stcField.CSIHnCKPx = 0U;
                CSIH [ channel ]->unCFG0.stcField.CSIHnDAPx = 1U;
                break;
            case CSIH_SCKL_Rising:
                CSIH [ channel ]->unCFG0.stcField.CSIHnCKPx = 1U;
                CSIH [ channel ]->unCFG0.stcField.CSIHnDAPx = 1U;
                break;
            case CSIH_SCKL_Falling:
                CSIH [ channel ]->unCFG0.stcField.CSIHnCKPx = 1U;
                CSIH [ channel ]->unCFG0.stcField.CSIHnDAPx = 0U;
                break;
            default:
                break;
        }

        CSIH [ channel ]->unCFG0.stcField.CSIHnIDLx = 0U;
        CSIH [ channel ]->unCFG0.stcField.CSIHnIDx  = 0U;
        CSIH [ channel ]->unCFG0.stcField.CSIHnHDx  = 0U;
        CSIH [ channel ]->unCFG0.stcField.CSIHnINx  = 0U;
        CSIH [ channel ]->unCFG0.stcField.CSIHnSPx  = 0U;

        CSIH [ channel ]->unCTL0.u8Register |= 0xE0U;

        switch ( channel )
        {
            case 0:
                PBGFSGD0BPROT0 = 0x07FFFFFFUL;
                INTC2EIC78     = 0x0047UL;
                INTC2EIC79     = 0x0047UL;
                break;
            case 1:
                PBGFSGD0BPROT0 = 0x07FFFFFFUL;
                INTC2EIC137    = 0x0047UL;
                INTC2EIC138    = 0x0047UL;
                break;
            default:
                break;
        }
    }
}

/*  获取发送的忙状态，即发送是忙着呢吗？  */
/*  参数 channel 为通道号：0 到 1  */
/*  返回值：MFS_SPI_OptSt_OK=发送空闲， MFS_SPI_OptSt_BUSY=发送忙中*/
static CSIH_OptSt CSIH_IsSendBusy(uint8_t channel)
{
    CSIH_OptSt re_value = CSIH_OptSt_BUSY;

    if ( channel > 1U )
    {
        re_value = CSIH_OptSt_BUSY;
    }
    else
    {
        if ( CSIH [ channel ]->unSTR0.stcField.CSIHnTSF == 1U )
        {
            re_value = CSIH_OptSt_BUSY;
        }
        else
        {
            re_value = CSIH_OptSt_OK;
        }
    }

    return re_value;
}

/*  阻塞等待发送忙完，即发送准备好了  */
/*  参数 channel 为通道号：0 到 1 */
static void CSIH_WaitForSendReady(uint8_t channel)
{
    while ( CSIH [ channel ]->unSTR0.stcField.CSIHnTSF == 1U )
    {
        CSIH_CPU_SleepIdle( ); /*  释放CPU  */
    }
}

/*  发送数据，采12bit对齐，2个数据块的方式  */
/*  参数 channel 为通道号：0 到 1  */
/*  返回值：CSIH_OptSt_OK=发送成功， CSIH_OptSt_BUSY=发送忙中*/
CSIH_OptSt CSIH_SendData_12bit8th(uint8_t channel, uint16_t *pdat)
{
    uint8_t i;

    CSIH_OptSt re_value = CSIH_OptSt_BUSY;

    if ( channel > 1U )
    {
        re_value = CSIH_OptSt_BUSY;
    }
    else
    {
        CSIH_WaitForSendReady(channel);
        CSIH [ channel ]->unMCTL2.u32Register &= 0x7FFFFFFFUL;
        CSIH [ channel ]->unMRWP0.u32Register &= 0xFFFFFF80UL;
#ifdef TLC6C5912
        CSIH [ channel ]->unMCTL2.u32Register = (0x00000010UL | (TLC6C5912_TOTAL_CHIP_NUM << 16U));
#else
        CSIH [ channel ]->unMCTL2.u32Register = 0x00080010UL;
#endif

#ifdef TLC6C5912
        for ( i = 0U; i < TLC6C5912_TOTAL_CHIP_NUM; i++ )
        {
			CSIH_DELAY();
            CSIH [ channel ]->unTX0W.u32Register = (0x00FE0000UL | pdat [ i ]);
			CSIH_DELAY();
        }
#else
        for ( i = 0U; i < 8U; i++ )
        {
            CSIH [ channel ]->unTX0W.u32Register = (0x00FE0000UL | pdat [ i ]);
        }
#endif

        CSIH [ channel ]->unMCTL2.u32Register |= 0x80000000UL;

        re_value = CSIH_OptSt_OK;
    }

    return re_value;
}

/*  发送数据，采9bit对齐，1个数据块的方式  */
/*  参数 channel 为通道号：0 到 1  */
/*  返回值：CSIH_OptSt_OK=发送成功， CSIH_OptSt_BUSY=发送忙中*/
CSIH_OptSt CSIH_SendData_9bit1th(uint8_t channel, uint16_t *pdat)
{
    uint8_t i;

    CSIH_OptSt re_value = CSIH_OptSt_BUSY;

    if ( channel > 1U )
    {
        re_value = CSIH_OptSt_BUSY;
    }
    else
    {
        CSIH_WaitForSendReady(channel);
        CSIH [ channel ]->unMCTL2.u32Register &= 0x7FFFFFFFUL;
        CSIH [ channel ]->unMRWP0.u32Register &= 0xFFFFFF80UL;
        CSIH [ channel ]->unMCTL2.u32Register = 0x00010010UL;

        for ( i = 0U; i < 1U; i++ )
        {
            CSIH [ channel ]->unTX0W.u32Register = (0x00FE0000UL | pdat [ i ]);
        }

        CSIH [ channel ]->unMCTL2.u32Register |= 0x80000000UL;

        re_value = CSIH_OptSt_OK;
    }

    return re_value;
}

void CSIH_Ch0_Rx_ISR(void) /* CSIH0 Reception Status interrupt INTCSIH0IR */
{
    uint32_t data;

    data = CSIH [ 0 ]->unRX0H.u16Register;

    PBGFSGD0BPROT0 = 0x07FFFFFFUL;
    INTC2EIC78 &= 0xEFFFU;
}

void CSIH_Ch1_Rx_ISR(void) /* CSIH1 Reception Status interrupt INTCSIH1IR */
{
    uint32_t data;

    data = CSIH [ 1 ]->unRX0H.u16Register;

    PBGFSGD0BPROT0 = 0x07FFFFFFUL;
    INTC2EIC137 &= 0xEFFFU;
}

void CSIH_Ch0_Tx_ISR(void) /* CSIH0 Communication Status interrupt INTCSIH0IC*/
{
    PBGFSGD0BPROT0 = 0x07FFFFFFUL;
    INTC2EIC79 &= 0xEFFFU;
}

void CSIH_Ch1_Tx_ISR(void) /* CSIH1 Communication Status interrupt INTCSIH1IC*/
{
    PBGFSGD0BPROT0 = 0x07FFFFFFUL;
    INTC2EIC138 &= 0xEFFFU;
    /* storage */
    // GPIO_OUT_PORT01_PIN01 = 1U;
}
