/* ======================================================================
*   Copyright (C) 2022 Texas Instruments Incorporated
*
*   All rights reserved. Property of Texas Instruments Incorporated.
*   Restricted rights to use, duplicate or disclose this code are
*   granted through contract.
*
*   The program may not be used without the written permission
*   of Texas Instruments Incorporated or against the terms and conditions
*   stipulated in the agreement under which this program has been
*   supplied.
* ==================================================================== */

/* ========================================================================== */
/*                             Include Files                                  */
/* ========================================================================== */
#include "string.h"
#include "Can.h"
#include "CanIf_Cbk.h"
#include "EcuM_Cbk.h"
/* #include "Os.h" */
#include "SchM_Can.h"
#include "Can_Priv.h"

#if (CAN_DEV_ERROR_DETECT == STD_ON)
#include "Det.h"
#endif


#include "soc.h"
#define CAN_START_SEC_CODE
#include "Can_MemMap.h"
#include "hw_types.h"
#define CAN_STOP_SEC_CODE
#include "Can_MemMap.h"
#include "hw_dcan.h"

/* ========================================================================== */
/*                           Macros & Typedefs                                */
/* ========================================================================== */

/* ========================================================================== */
/*                         Structures and Enums                               */
/* ========================================================================== */

/* None */

/* ========================================================================== */
/*                          Function Declarations                             */
/* ========================================================================== */

/* ========================================================================== */
/*                          Function Definitions                              */
/* ========================================================================== */
/* Memory mapping, done via MemMap.h: Code */
#define CAN_START_SEC_CODE
#include "Can_MemMap.h"

FUNC(void, CAN_CODE) Can_hwUnitConfig(Can_ControllerObjType *canController,
                                      const Can_MailboxObjType *canMailbox,
                                      uint32 MaxMbCnt)
{

	canController->canControllerConfig.CanControllerType =
									(uint32)CAN_CONTROLLER_TYPE_INFO_MCAN;

    if ((uint32)CAN_CONTROLLER_TYPE_INFO_MCAN ==
                        canController->canControllerConfig.CanControllerType)
    {
        Can_mcanConfigController(canController,
                                 canMailbox,
                                 MaxMbCnt);
    }
}

boolean Can_mcanWkUp(Can_ControllerObjType * controllerObj)
{
    TickType    startCount = 0U, tempCount, elaspsedCount = 0U;
    boolean     timeOut = (boolean)FALSE;
    boolean toStatus = (boolean) FALSE;
    boolean status = (boolean) FALSE;
    uint32 baseAddr;

    baseAddr = controllerObj->canControllerConfig.CntrAddr;    
    /* Deactivate Local Power down */
    MCAN_addClockStopRequest(baseAddr, (uint32)FALSE);
    (void)GetCounterValue(CAN_CFG_OS_COUNTER_ID, &startCount);
         /* Below API can change start time, so use temp variable */
        tempCount = startCount;
        /* Wait for FSM to to come out of reset */
        do
        {
            toStatus = GetElapsedValue(
                         CAN_CFG_OS_COUNTER_ID,
                         &tempCount,
                         &elaspsedCount);
            if ((((StatusType) E_OK) != toStatus) ||
                (elaspsedCount >= (uint32)CAN_CFG_TIMEOUT_DURATION))
            {
                /* timeout */
                timeOut = (boolean)TRUE;
                break;
            }
        } while ((uint32)MCAN_CCCR_CSA_NO_ACK != MCAN_getClkStopAck(baseAddr));
    if (timeOut == (boolean)TRUE)
    {
        Dem_ReportErrorStatus(
            CAN_E_HARDWARE_ERROR, DEM_EVENT_STATUS_FAILED);
    }
    controllerObj->canState = CAN_CS_STOPPED;
    CanIf_ControllerModeIndication(
                            controllerObj->canControllerConfig.ControllerId,
                            CANIF_CS_STOPPED);
    status = (boolean) TRUE;
    controllerObj->canBusOffRecoveryStatus = (boolean) FALSE;

    return status;
}

/*******************************************************************************
 * Can_hwUnitStart
 ******************************************************************************/
/*! \brief      This function will start the CAN node.
 *
 ******************************************************************************/
/*Requirements: SWS_Can_00409,  */
 boolean Can_hwUnitStart(Can_ControllerObjType *controllerObj)
{

    boolean status = (boolean) FALSE;

#if (CAN_DEV_ERROR_DETECT == STD_ON)
    if (controllerObj->canState != CAN_CS_STOPPED)
    {
        status = (boolean) FALSE;
        (void) Det_ReportError((uint16) CAN_MODULE_ID,
                               (uint8) CAN_INSTANCE_ID,
                               (uint8) CAN_SETCTR_ID,
                               (uint8) CAN_E_TRANSITION);
    }
    else
#endif

    {     
        /* Need to call MCAN wake up before the START to take care if there 
           was a SLEEP state before*/  
       status = Can_mcanWkUp(controllerObj);
       if(status == (boolean) TRUE)
       {
         status = Can_mcanStart(controllerObj);
       }
    }
    return status;
}

/*******************************************************************************
 * Can_hwUnitStop
 ******************************************************************************/
/*! \brief      This function will stop the CAN node.
 *
 ******************************************************************************/
/*Requirements: SWS_Can_00263, SWS_Can_00410, SWS_Can_00264*/
boolean Can_hwUnitStop(Can_ControllerObjType * controllerObj)
{
    boolean status = (boolean) FALSE;

if (controllerObj->canState == CAN_CS_STOPPED)
    {
        CanIf_ControllerModeIndication(
                            controllerObj->canControllerConfig.ControllerId,
                            CANIF_CS_STOPPED);
        status = (boolean) TRUE;
    }
    else
    {  
#if (CAN_DEV_ERROR_DETECT == STD_ON)
        if ((controllerObj->canState == CAN_CS_STARTED)||
            (controllerObj->canState == CAN_CS_SLEEP))
        {
          status = Can_mcanStop(controllerObj);
        }
        else
        {
          status = (boolean)FALSE;
          (void)Det_ReportError((uint16)CAN_MODULE_ID,
            (uint8)CAN_INSTANCE_ID,
            (uint8)CAN_SETCTR_ID,
            (uint8)CAN_E_TRANSITION);
        }
#else
        {

          status = Can_mcanStop(controllerObj);

        }
#endif
    }

    return status;
}

/*******************************************************************************
 * Can_hwUnitSleep
 ******************************************************************************/
/*! \brief      This function will sleep the CAN node.
 *
 ******************************************************************************/
/*Requirements: SWS_Can_00258, SWS_Can_00404, SWS_Can_00266, SWS_Can_00411*/
boolean Can_hwUnitSleep(Can_ControllerObjType *controllerObj)
{
    boolean status = (boolean) FALSE;

    if (controllerObj->canState == CAN_CS_SLEEP)
    {
        CanIf_ControllerModeIndication(
                            controllerObj->canControllerConfig.ControllerId,
                            CANIF_CS_SLEEP);
        status = (boolean) TRUE;
    }
    else
    {
#if (CAN_DEV_ERROR_DETECT == STD_ON)
        if (controllerObj->canState != CAN_CS_STOPPED)
        {
            status = (boolean) FALSE;
            (void) Det_ReportError((uint16) CAN_MODULE_ID,
                                   (uint8) CAN_INSTANCE_ID,
                                   (uint8) CAN_SETCTR_ID,
                                   (uint8) CAN_E_TRANSITION);
        }
        else
#endif
        {
            status = Can_mcanSleep(controllerObj);

        }
    }

    return status;
}

void Can_writeTxMailbox(const Can_MailboxType *mailboxCfg,
                        Can_ControllerObjType *controllerObj,
                        uint32 Hth,
                        uint32 messageBox,
                        const Can_PduType *PduInfo)
{
        Can_mcanWriteTxMailbox(mailboxCfg,
                               controllerObj,
                               messageBox,
                               PduInfo,
                               Hth);
}

Can_ReturnType Can_writeGetFreeMsgObj(const Can_MailboxType *mailboxCfg,
                                     const Can_ControllerObjType *controllerObj,
                                     uint32 *msgObj,
                                     uint32 htrh)
{
    Can_ReturnType status = CAN_OK;
        status = Can_mcanWriteGetFreeMsgObj(mailboxCfg,
                                            controllerObj,
                                            msgObj,
                                            htrh);

    return status;
}

void Can_hwUnitDisableInterrupts(Can_ControllerObjType *controllerObj)
{
      Can_mcanDisableInterrupts(controllerObj);
}

void Can_hwUnitEnableInterrupts(Can_ControllerObjType *controllerObj)
{
      Can_mcanEnableInterrupts(controllerObj);

}

void Can_hwUnitTxDonePolling(Can_ControllerObjType *canController,
                             const Can_MailboxObjType *canMailbox,
                             uint8 htrh)
{
      Can_mcanTxDonePolling(canController, canMailbox, htrh);

}

Can_ReturnType Can_hwUnitCheckWakeup(uint32 baseAddr)
{
    Can_ReturnType status = CAN_NOT_OK;
    status = Can_mcanCheckWakeup(baseAddr);
    return status;
}

void Can_hwUnitChangeBaudrate(uint32 baseAddr,
                              uint32 brp)
{

    Can_mcanChangeBaudrate(baseAddr, brp);

}

void Can_hwUnitSetBaudrate(uint32 baseAddr,
                           const Can_BaudConfigType *setBaud)
{

        Can_mcanSetBaudrate(baseAddr, setBaud);
}

#if  (CAN_WAKEUP_POLLING == STD_ON)
void Can_MainFunction_WakeupProcess(Can_ControllerObjType *canController)
{
      Can_mcan_WakeupProcess(canController);
}
#endif

void Can_MainFunction_BusOffProcess(Can_ControllerObjType *canController)
{
    Can_mcan_BusOffProcess(canController);
}

void Can_MainFunction_ModeProcess(Can_ControllerObjType *canController)
{
        Can_mcan_ModeProcess(canController);
}

#if (CAN_RX_POLLING == STD_ON)
void Can_MainFunction_ReadProcess(Can_DriverObjType *can_DriverObj)
{
    uint32 loopCnt;
    Can_ControllerObjType *controllerObj;

    for (loopCnt = 0U ;
        loopCnt <  can_DriverObj->canMaxControllerCount;
        loopCnt++)
    {
        if (can_DriverObj->canController[loopCnt].
                    canControllerConfig.CntrActive == (boolean) TRUE)
        {
                controllerObj = &can_DriverObj->canController[loopCnt];
                Can_mcan_ReadProcess(controllerObj,
                        (Can_MailboxObjType *)&can_DriverObj->canMailbox[0U],
                         can_DriverObj->maxMbCnt);
        }
    }
}
#endif

Std_ReturnType Can_hwUnitTestLoopBackModeEnable(uint32 baseAddr,
                                                uint8 mode)
{
    VAR(Std_ReturnType, AUTOMATIC) retVal;
    retVal = Can_mcanTestLoopBackModeEnable(baseAddr, mode);
    return retVal;
}

Std_ReturnType Can_hwUnitTestLoopBackModeDisable(uint32 baseAddr,
                                                 uint8 mode)
{
    VAR(Std_ReturnType, AUTOMATIC) retVal;

    retVal = Can_mcanTestLoopBackModeDisable(baseAddr, mode);
    return retVal;
}



#if (CAN_CFG_DEINIT_API == STD_ON)
void Can_hwDeInit(const Can_ControllerObjType *canController)
{
      Can_mcanHwDeInit(canController);
}
#endif

/* Memory mapping, done via MemMap.h: Code */
#define CAN_STOP_SEC_CODE
#include "Can_MemMap.h"
/*******************************************************************************
 *  End of File: Can_priv.c
 ******************************************************************************/