/* Copyright Statement:
 *
 * This software/firmware and related documentation ("AutoChips Software") are
 * protected under relevant copyright laws. The information contained herein is
 * confidential and proprietary to AutoChips Inc. and/or its licensors. Without
 * the prior written permission of AutoChips inc. and/or its licensors, any
 * reproduction, modification, use or disclosure of AutoChips Software, and
 * information contained herein, in whole or in part, shall be strictly
 * prohibited.
 *
 * AutoChips Inc. (C) 2023. All rights reserved.
 *
 * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
 * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("AUTOCHIPS SOFTWARE")
 * RECEIVED FROM AUTOCHIPS AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
 * ON AN "AS-IS" BASIS ONLY. AUTOCHIPS EXPRESSLY DISCLAIMS ANY AND ALL
 * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
 * NONINFRINGEMENT. NEITHER DOES AUTOCHIPS PROVIDE ANY WARRANTY WHATSOEVER WITH
 * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
 * INCORPORATED IN, OR SUPPLIED WITH THE AUTOCHIPS SOFTWARE, AND RECEIVER AGREES
 * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
 * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
 * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN AUTOCHIPS
 * SOFTWARE. AUTOCHIPS SHALL ALSO NOT BE RESPONSIBLE FOR ANY AUTOCHIPS SOFTWARE
 * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
 * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND AUTOCHIPS'S
 * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE AUTOCHIPS SOFTWARE
 * RELEASED HEREUNDER WILL BE, AT AUTOCHIPS'S OPTION, TO REVISE OR REPLACE THE
 * AUTOCHIPS SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
 * CHARGE PAID BY RECEIVER TO AUTOCHIPS FOR SUCH AUTOCHIPS SOFTWARE AT ISSUE.
 */
/******************************************************************************
 * @version: V1.0.0 demo
 ******************************************************************************/

/*!
* @file can.c
*
* @brief This file contains the user gpio function..
*
*/

/* ===========================================  Includes  =========================================== */
#include "gpio.h"
#include "can.h"
#include "ac780x_can.h"
#include "ac780x_timer.h"
#include "ac780x_can_reg.h"
#include "canbusoff.h"

/* ============================================  Define  ============================================ */
#define CAN_FILT_CNT  2  /* Number of Filter IDs */

/* ===========================================  Typedef  ============================================ */

/* ==========================================  Variables  =========================================== */
CAN_MsgInfoType g_sendCANMsgInfo; /* Used to send interrupts, transfer data */
CAN_MsgInfoType g_recvCANMsgInfo; /* Used to receive interrupts and get data */
uint32_t sendDataBuff[64/4];
uint32_t recvDataBuff[64/4];
uint8_t g_recvedCANDataRdy = 0; /* Global variable of CAN received data flag */

CAN_FilterControlType canFilterControl[CAN_FILT_CNT]=
{
    {0, ENABLE, 0x00000400, 0x00000000},    /* receive only 0x400 ID */
    {1, ENABLE, 0x00000500, 0x000000FF},    /* receive0x500~0x5FF ID */
}; 

/* ====================================  Functions declaration  ===================================== */

/* ======================================  Functions define  ======================================== */


/*!
* @brief  CAN1 busoff test
*
* @param[in] none
* @return none
*/
void CAN_Test(void)
{
    int32_t ret=0;
    /* Determine whether the current CAN is in a normal state */
    if(CAN_GetBusoffState() == CAN_NORMAL) 
    {
        g_sendCANMsgInfo.ID = 0x220;
        g_sendCANMsgInfo.IDE = 0;
        g_sendCANMsgInfo.DLC = 8;
        g_sendCANMsgInfo.DATA[0] = 0;
        g_sendCANMsgInfo.DATA[1] = 1;
        g_sendCANMsgInfo.DATA[2] = 2;
        g_sendCANMsgInfo.DATA[3] = 3;
        g_sendCANMsgInfo.DATA[4] = 4;
        g_sendCANMsgInfo.DATA[5] = 5;
        g_sendCANMsgInfo.DATA[6] = 6;
        g_sendCANMsgInfo.DATA[7] = 7;
        ret = CAN_TransmitMessage(CAN1, &g_sendCANMsgInfo, CAN_TRANSMIT_SECONDARY); /* send data */
        if(ret == 0)  /* Tx success */
        {
            
        }
        else
        {
            
        }
    }
    /* If a message of 0x400 is received, print out the data */
    if(g_recvedCANDataRdy)
    {
        g_recvedCANDataRdy = 0;
        printf("CAN ID = 0x%x \r\n",g_recvCANMsgInfo.ID);
        printf("CAN DLC = 0x%x \r\n",g_recvCANMsgInfo.DLC);
        printf("DATA = ");
        for(uint16_t i = 0; i < g_recvCANMsgInfo.DLC; i++)
        {
            printf("0x%x  ", g_recvCANMsgInfo.DATA[i]);
        }
    }
    /* busoff processing function */
    CAN_BusoffProcess();
}

/*!
* @brief  TIM1 module interrupt handler.
*
* @param[in] none
* @return none
*/
void TIM1_IRQnCallBack(void *device, uint32_t wpara, uint32_t lpara)
{
    /* busoff timing count */
    CAN_BusoffTimerCnt();
}


/*!
* @brief  Initalize TIM1 module.
*
* @param[in] none
* @return none
*/
void TIMER_InitHardwr(void)
{
    TIMER_ConfigType timerConfig;
    memset((void *)&timerConfig, 0, (uint32_t)sizeof(TIMER_ConfigType));   
    
    timerConfig.timeMode = TIMER_WORKMODE_TIMER;   
    timerConfig.prescaler = TIMER_PRESCALE_16_GLITCHFILTER_7;
    timerConfig.periodValue = 2000;
    timerConfig.callback = TIM1_IRQnCallBack;
    timerConfig.interruptEn = ENABLE;
    timerConfig.bypEn = DISABLE;
    
    TIMER_Init(TIMER_CLKSR_APB);        
    TIMER_InitChannel(TIMER_CHANNEL1, &timerConfig);        /* Enable TIMER_CHANNEL1, 1ms generates an interrupt */
}

/*!
* @brief  CAN1 module interrupt handler.
*
* @param[in] none
* @return none
*/
void CAN1_IRQnCallBack(void *device, uint32_t wpara, uint32_t lpara)
{
    if (wpara & CAN_CTRL1_EIF_Msk)  
    {
        /* Check whether to send busoff */
        if (CAN_IsBusoff((CAN_Type*)device) == 1)
        {
            /* Software reset CAN controller */
            CAN_SetReset((CAN_Type*)device, ENABLE);
            /* Set CAN to busoff state */
            CAN_SetBusoffState();
        }
    }
    if (wpara & CAN_CTRL1_RIF_Msk)
    {
        /* 防止接收中断未及时响应，出现接收到多帧报文才进入一次中断的情况，
        *  通过while的方式轮询完所有的缓存，若担心安全问题，可增加while计数 超时退出
        *  Prevent receiving interrupts from responding in time, and receiving multi-frame messages, 
        *  but only interrupting once。After polling all the buffers through while,
        * if you are worried about blocking, you can increase the while count and exit after timeout
        */
        //if (CAN_IsMsgInReceiveBuf((CAN_Type*)device))
        while (CAN_GetRStat((CAN_Type*)device)) 
        {
            CAN_ReceiveMessage((CAN_Type*)device, &g_recvCANMsgInfo);
            g_recvedCANDataRdy = 1;
        }
    }
    if (wpara & CAN_CTRL1_TPIF_Msk)
    {
        
    }
    if (wpara & CAN_CTRL1_TSIF_Msk)
    {
        /*STB 必须使用TSONE方式发送，发送完成后，检查STB是否还有报文缓存，有则继续触发。
        *STB can be sent in TSONE mode. After the sending is completed,
        *check whether the STB still has a message cache, and if so, continue to trigger
        */
        if (!CAN_IsTransmitIdle((CAN_Type*)device, CAN_TRANSMIT_SECONDARY))
        {
            CAN_StartTransmission((CAN_Type*)device, CAN_TRANSMIT_SECONDARY, CAN_TRANSMIT_ONE);
        }
    }
    if (wpara & CAN_CTRL1_BEIF_Msk) 
    {
        if (lpara == 3)
        {
                
        }
    }
}

/*!
* @brief  Initalize CAN pin.
*
* @param[in] none
* @return none
*/
void CAN_GPIO_Init(void)
{
    GPIO_SetFunc(GPIOC, GPIO_PIN8, GPIO_FUN4); /* CAN1_TX */
    GPIO_SetFunc(GPIOC, GPIO_PIN9, GPIO_FUN4); /* CAN1_RX */
    GPIO_SetFunc(GPIOC, GPIO_PIN0, GPIO_FUN5); /* CAN1_STB */
}

/*!
* @brief  Initalize CAN module.
*
* @param[in] none
* @return none
*/
void CAN_InitHardwr(void)
{
    CAN_ConfigType canConfig;
    CAN_BitrateConfigType canBandrateConfig; 
    memset((void *)&canConfig, 0, (uint32_t)sizeof(CAN_ConfigType));   
    memset((void *)&canBandrateConfig, 0, sizeof(CAN_BitrateConfigType));
    
    /*
    Set the baud rate to 500k,The sampling point is 81.25%.
    tSeg1 = (S_SEG_1 + 2); tSeg2 = (S_SEG_2 + 1).
    BandRate = (32M / (S_PRESC + 1) / ((S_SEG_1 + 2) + (S_SEG_2 + 1)))
    SamplePoint = (tSeg1 / (tSeg1 + tSeg2)).
    tSeg1 = 13,tSeg2 = 3.
     */
    canBandrateConfig.PRESC = 7;        /* CAN clock frequency division is 8MHz*/
    canBandrateConfig.SEG_1 = 11;
    canBandrateConfig.SEG_2 = 2;
    canBandrateConfig.SJW   = 2;        /* S_SJW <= tSeg2 */
    canConfig.interruptEn = ENABLE;     /* enable interrupt */
    canConfig.interruptMask = CAN_IRQ_ALL_ENABLE_MSK;   /* Turn on all interrupts for can */
    canConfig.canMode = CAN_MODE_NORMAL;
    canConfig.clockSrc = CAN_CLKSRC_AHB;            /* Select CAN clock source */
    canConfig.filterNum = CAN_FILT_CNT;             /* Number of filters */
    canConfig.filterList = canFilterControl;        /* Filter configuration for CAN ID */
    canConfig.callback = CAN1_IRQnCallBack;         /* Callback function of CAN1 */
    canConfig.normalBitrate = &canBandrateConfig;   /* Normal baud rate configuration */
    canConfig.tsAmount = CAN_TRANSMIT_ONE;          /* Send a message in STB */
    canConfig.tpss = DISABLE;               /* Disable PTB one-shot mode */
    canConfig.tsss = DISABLE;               /* Disable STB one-shot mode */
    canConfig.busOffRecDisable = ENABLE;    /* Disable self-recovery of BUSOFF */
    
    g_sendCANMsgInfo.DATA = (uint8_t *)sendDataBuff;
    g_recvCANMsgInfo.DATA = (uint8_t *)recvDataBuff;
    
    CAN_Init(CAN1, &canConfig); /* Initalize CAN */
    CAN_GPIO_Init();            /* Initalize CAN pin */
    CAN_BusoffInit();           /* Initalize CAN BUSOFF */
    TIMER_InitHardwr();         /* Initalize Timer1 */
}



/* =============================================  EOF  ============================================== */
