/******************* include *********************/
#include "App_debug.h"
#include "Mcal.h"
#include "CddUart_Define_Types.h"
#include "CddUart_Cfg.h"
#include "CddUart.h"
#include "stdio.h"
#include "user_rtt_printf.h"

/******************* include *********************/

/******************* define *********************/

#if (UARTCONFIG)
#define CDDUART_MSG1 "Hi, Welcome to use this demo to test uart!\r\n"
#define CDDUART_MSG2 "Please input 5 data and we will send them back!\r\n"
#endif

/******************* define *********************/

/******************* structural body *********************/

#if CANCONFIG
uint8 sduData64[64];
uint8 sduDataCan0_0x110[8];
#define SetTempPdu(PduHandle, Len, Id, data) \
    do                                       \
    {                                        \
        TempPduInfo.swPduHandle = PduHandle; \
        TempPduInfo.id = Id;                 \
        TempPduInfo.length = Len;            \
        TempPduInfo.sdu = data;              \
    } while (0)

Can_PduType TempPduInfo =
    {
        .swPduHandle = 60U,
        .id = 0x000U,
        .length = 64U,
        .sdu = sduData64,
};

Can_PduType PduInfoCan = {
    .id = 0x11111111U | CAN_ID_TYPE_EXTENDED_FRAME_MASK,
    .length = 8,
    .sdu = sduDataCan0_0x110,
    .swPduHandle = 60U //
};
uint8 sduDataCan5EX[64];
Can_PduType PduInfoCanEX = {
    .id = 0x1FFC7890,
    .length = 64,
    .sdu = sduDataCan5EX,
    .swPduHandle = CanConf_CanHardwareObject_CanHardwareCan5TX //
};
#endif

canTransmitHandle canTransmit[128] = {0};

/******************* structural body *********************/

/******************* variate *********************/
#if (UARTCONFIG)
uint8 CddUart_TestedRxBuffer[10];
uint8 RxBuffIndex = 0U;
boolean RxBufferIndex_0 = FALSE;
boolean RxBufferIndex_5 = FALSE;
#endif

/******************* middle ware *********************/
/******************* middle ware *********************/

/******************* variate *********************/

/******************* function *********************/
static void RunControl(void);
void DmaConfigFun(void);
void Delay_1ms(uint32 Ms)
{
    while (Ms > 0)
    {
        --Ms;
        for (uint16 Cnt = 0; Cnt < 6660; ++Cnt)
        {
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
            __NOP();
        }
    }
}

#if (PORTCONFIG)

sint8 GetKey(void)
{
    if (STD_HIGH == Dio_ReadChannel(DioConf_DioChannel_DioKEY2))
    {
        Delay_1ms(5);
        if (STD_HIGH == Dio_ReadChannel(DioConf_DioChannel_DioKEY2))
        {
            LOGI(" Key2 press \r\n");
            return 1;
        }
    }

    if (STD_HIGH == Dio_ReadChannel(DioConf_DioChannel_DioKEY3))
    {
        Delay_1ms(5);
        if (STD_HIGH == Dio_ReadChannel(DioConf_DioChannel_DioKEY3))
        {
            LOGI(" Key3 press \r\n");
            return 1;
        }
    }
    return -1;
}

static void DioControl(void)
{
    static uint8 count = 0;
    if (0 == count)
        Dio_FlipChannel(DioConf_DioChannel_DioLED8R);
    else if (1 == count)
        Dio_FlipChannel(DioConf_DioChannel_DioLED8G);
    else if (2 == count)
    {
        Dio_FlipChannel(DioConf_DioChannel_DioLED8B);
        count = 0;
    }
    count++;
}

#endif

#if (UARTCONFIG)
/**
 * @brief 串口测试函数
 *
 */
static void UartControl(void)
{
    /*send data*/
    if (RxBufferIndex_0 == TRUE)
    {
        /* The reception is done,send the data back */
        CddUart_SyncSend(CddUartConf_UartChannel_UartChannel_0, &CddUart_TestedRxBuffer[0], 5, 0xFFFF);
        RxBufferIndex_0 = FALSE;
    }
    else if (RxBufferIndex_5 == TRUE)
    {
        CddUart_SyncSend(CddUartConf_UartChannel_UartChannel_0, &CddUart_TestedRxBuffer[5], 5, 0xFFFF);
        RxBufferIndex_5 = FALSE;
    }
    else
    {
        /* Do nothing */
    }
}
#endif

#if CANCONFIG
boolean CAN5_BusOffFlag = FALSE;
uint16 busycount;
uint16 hrh3count = 0;
uint16 CanReceiveFlag = 0;
uint16 overrunCount = 0;
volatile uint16 writeIdx = 0;
volatile uint16 readIdx = 0;
static void CanControl(void)
{
    Std_ReturnType ReturnType = 0;
    // SetTempPdu(CanConf_CanHardwareObject_CanHardwareCan5TX, 8, 0x110, sduData64);
    // Can_Write(CanConf_CanHardwareObject_CanHardwareCan5TX, &TempPduInfo);
    // SetTempPdu(CanConf_CanHardwareObject_CanHardwareCan5TX, 8, 0x10010000 | 0x80000000, sduData64);
    // Can_Write(CanConf_CanHardwareObject_CanHardwareCan5TX, &TempPduInfo);
    while (readIdx != writeIdx)
    {
        SetTempPdu(CanConf_CanHardwareObject_CanHardwareCan0TX, 8, canTransmit[readIdx].id + 0x100, canTransmit[readIdx].sdu);
        ReturnType = Can_Write(CanConf_CanHardwareObject_CanHardwareCan0TX, &TempPduInfo);
        if (ReturnType == E_OK)
        {
            readIdx = (readIdx + 1) & BUF_MASK;
        }
        else
        {
            LOGW("ReturnType: %d", ReturnType);
            LOG("ID: 0x%03x ,[%02x,%02x,%02x]", canTransmit[readIdx].id, canTransmit[readIdx].sdu[0], canTransmit[readIdx].sdu[1], canTransmit[readIdx].sdu[2]);
            busycount++;
            break;
        }
    }

    if (CAN5_BusOffFlag)
    {
        CAN5_BusOffFlag = FALSE;
        Can_SetControllerMode(CanConf_CanController_CanController_0, CAN_CS_STARTED);
    }
}

boolean CanReceiveCallOut(uint8 Hrh, Can_IdType CanId, uint8 CanDataLength, const uint8 *CanSduPtr)
{
    uint8 copyLen = (CanDataLength > 64) ? 64 : CanDataLength;
    uint16 nextWrite = (writeIdx + 1) & BUF_MASK;
    // Delay_1ms(1);

    for (uint8 i = 0; i < copyLen; i++)
    {
        canTransmit[writeIdx].sdu[i] = CanSduPtr[i];
    }
    if (CanId & 0x80000000)
    {
        // LOGI("EXTEND 29bit ID: 0x%07x", CanId & 0x1FFFFFFF);
        // SetTempPdu(CanConf_CanHardwareObject_CanHardwareCan5TX, 8, CanId | 0x80000000, (uint8 *)CanSduPtr);
        // Can_Write(CanConf_CanHardwareObject_CanHardwareCan5TX, &TempPduInfo);
    }
    else
    {
        // LOGI("st 11bit ID: 0x%03x", CanId & 0x7FF);
        if (Hrh == 5)
        {
            hrh3count++;
            if (nextWrite != readIdx)
            {
                canTransmit[writeIdx].id = CanId;
                canTransmit[writeIdx].sdu[0] = Hrh;
                canTransmit[writeIdx].sdu[1] = (uint8)hrh3count & 0x00ff;
                canTransmit[writeIdx].sdu[2] = (uint8)(hrh3count >> 8);
                writeIdx = nextWrite;
            }
            else
            {
                overrunCount++;
                LOGE("overrunCount : %d", overrunCount);
            }
        }
    }
    return TRUE;
}
void CanBusOffCan5(void)
{
    CAN5_BusOffFlag = TRUE;
    LOGW("CAN5_BusOffFlag");
}
#endif

#if GPTCONFIG
volatile uint32 timeTick = 0;

void GptControl(void)
{
    static uint32 CurrentTime = 0;
    if (timeTick >= CurrentTime)
    {
        if (timeTick - CurrentTime >= TIMERS)
        {
            CurrentTime = timeTick;
            RunControl();
        }
    }
    else
    {
        if (0xFFFFFFFF - CurrentTime + timeTick >= TIMERS)
        {
            CurrentTime = timeTick;
            RunControl();
        }
    }
}
#endif

void PTB2CallBack(void)
{
    static int cmtkey = 0;
    cmtkey++;
}

int fputc(int ch, FILE *f)
{
    CddUart_SyncSend(CddUartConf_UartChannel_UartChannel_0, (uint8 *)&ch, 1, 0xFFFF);
    return (ch);
}

void Uart2CallBack(uint8 Channel, CddUart_General_EventType Event)
{
#if (UARTCONFIG)
    if (UART_EVENT_RX_FULL == Event)
    {
        RxBuffIndex += 5U;
        if (RxBuffIndex >= 10U)
        {
            RxBuffIndex = 0U;
        }
        if (RxBuffIndex == 5U)
        {
            RxBufferIndex_0 = TRUE;
        }
        else
        {
            RxBufferIndex_5 = TRUE;
        }
        /* Set the buffer to receive data */
        CddUart_SetBuffer(CddUartConf_UartChannel_UartChannel_0, &CddUart_TestedRxBuffer[RxBuffIndex], 5, CDDUART_RECEIVE);
    }
#endif
}

void Gpt_Lptmr0Callback(void)
{
#if GPTCONFIG
    timeTick++;
#endif
}
static void RunControl(void)
{
#if (PORTCONFIG && DIOCONFIG)
    DioControl();
#endif
#if (UARTCONFIG)
    printf("hello cool \r\n");
    UartControl();
#endif
#if CANCONFIG
    // CanControl();
#endif

#if DMACONFIG
    // DmaConfigFun();
#endif

    if (GetKey())
    {
    }
    else
    {
    }
    LOGW("busycount : %d", busycount);
    LOGI("hrh3count : %d", hrh3count);
}
void CoolDome(void)
{
    LOGI("I ok \r\n");
    LOGW("W ok \r\n");
    LOGE("E ok \r\n");

#if (PORTCONFIG && DIOCONFIG)
    Dio_WriteChannel(DioConf_DioChannel_DioLED8G, STD_LOW);
    Dio_WriteChannel(DioConf_DioChannel_DioLED8R, STD_LOW);
    Dio_WriteChannel(DioConf_DioChannel_DioLED8B, STD_LOW);
    Dio_WriteChannel(DioConf_DioChannel_DioCAN0_STB, STD_LOW);
    Dio_WriteChannel(DioConf_DioChannel_DioCAN5_STB, STD_LOW);
#endif
#if (UARTCONFIG)
    CddUart_SyncSend(CddUartConf_UartChannel_UartChannel_0, (uint8 *)CDDUART_MSG1, sizeof(CDDUART_MSG1), 0xFFFF);
    CddUart_AsyncSend(CddUartConf_UartChannel_UartChannel_0, (uint8 *)CDDUART_MSG2, sizeof(CDDUART_MSG2));
    CddUart_AsyncReceive(CddUartConf_UartChannel_UartChannel_0, CddUart_TestedRxBuffer, 5);
#endif
#if CANCONFIG
    Can_SetControllerMode(CanConf_CanController_CanController_0, CAN_CS_STARTED);
    Can_SetControllerMode(CanConf_CanController_CanController_1, CAN_CS_STARTED);
#endif
    while (1)
    {
        // RunControl();
        CanControl();
        GptControl();
    }
}

/******************* function *********************/
