/*!
* @file     CanHelpers.c
*
* @brief    Helper functions for testing the CAN driver.
*/

#include "CanHelpers.h"
#include "Compiler.h"
#include "Std_Types.h"
#include "Det.h"
#include "Can_Hw.h"

#include <stdio.h>
#include <string.h>

/*******************************************************************************
                            Global variables
*******************************************************************************/

/* The received CAN frames */
CanRxFrameType       g_rxBuffer[MAX_RX_FRAMES];
uint8                g_rxCount;

/* Tx confirmation state */
TxConfirmedType g_txConfirm = {.txConfirmed = 0, .pduId = 0};

/* Controller mode notification state */
uint8 g_controllerModeChanged = 0;
ControllerModeType g_controllerMode = {.controllerId = 0, .mode = CANIF_CS_UNINIT};

/* Receive flag */
volatile uint8_t g_receiveFlag = 0;
volatile uint8_t g_txFlag = 0;

/* Bus off notification state */
uint8 g_busOffEvent = 0;
uint8 g_busOffControllerId = 0;
volatile uint8 g_busOffHandlerFlg = 0;

/* Error notification state */
uint8 g_canError = 0;
uint8 g_canfdError = 0;

/* Icom state callback */
IcomStateType g_icomState = {.callback = 0};

/* Rx FIFO warning notification state */
uint8 g_fifoWarning = 0;

/* Rx FIFO overflow notification state */
uint8 g_fifoOverflow = 0;

/* The callback counter of the LPDU callout function */
uint8 g_lpduCalloutCounter = 0;

/* The return value of the LPDU callout function */
boolean g_lpduCalloutReturn = TRUE;

/* The return value of the CanIf_TriggerTransmit() function */
Std_ReturnType g_triggerTransmitReturn = E_OK;
uint8 g_triggerTransmitSdu[6] = {0x61, 0x62, 0x63, 0x64, 0x65, 0x66};

uint8 g_sdu1[1] = {0x11};
Can_PduType g_pdu1 = {.id = 0x01,
                      .swPduHandle = 0xF1,
                      .length = sizeof(g_sdu1),
                      .sdu = g_sdu1
                     };

uint8 g_sdu2[2] = {0x21, 0x22};
Can_PduType g_pdu2 = {.id = 0x02 | CAN_ID_IDE_U32,
                      .swPduHandle = 0xF2,
                      .length = sizeof(g_sdu2),
                      .sdu = g_sdu2
                     };

uint8 g_sdu3[3] = {0x31, 0x32, 0x33};
Can_PduType g_pdu3 = {.id = 0x03,
                      .swPduHandle = 0xF3,
                      .length = sizeof(g_sdu3),
                      .sdu = g_sdu3
                     };

uint8 g_sdu4[4] = {0x41, 0x42, 0x43, 0x44};
Can_PduType g_pdu4 = {.id = 0x04 | CAN_ID_IDE_U32,
                      .swPduHandle = 0xF4,
                      .length = sizeof(g_sdu4),
                      .sdu = g_sdu4
                     };

uint8 g_sdu5[5] = {0x51, 0x52, 0x53, 0x54, 0x55};
Can_PduType g_pdu5 = {.id = 0x05,
                      .swPduHandle = 0xF5,
                      .length = sizeof(g_sdu5),
                      .sdu = g_sdu5
                     };

uint8 g_sdu6[6] = {0x61, 0x62, 0x63, 0x64, 0x65, 0x66};
Can_PduType g_pdu6 = {.id = 0x06 | CAN_ID_IDE_U32,
                      .swPduHandle = 0xF6,
                      .length = sizeof(g_sdu6),
                      .sdu = g_sdu6
                     };

uint8 g_sdu7[7] = {0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77};
Can_PduType g_pdu7 = {.id = 0x07,
                      .swPduHandle = 0xF7,
                      .length = sizeof(g_sdu7),
                      .sdu = g_sdu7
                     };

uint8 g_sdu8[8] = {0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88};
Can_PduType g_pdu8 = {.id = 0x08 | CAN_ID_IDE_U32,
                      .swPduHandle = 0xF8,
                      .length = sizeof(g_sdu8),
                      .sdu = g_sdu8
                     };

uint8 g_sdu8_2[8] = {0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22};
Can_PduType g_pdu8_2 = {.id = 0x09 | CAN_ID_IDE_U32,
                      .swPduHandle = 0xF9,
                      .length = sizeof(g_sdu8_2),
                      .sdu = g_sdu8_2
                     };

/* CAN FD frame with 64 bytes payload */
uint8 g_sdu64[64] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,
                       0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
                       0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
                       0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40};
Can_PduType g_pdu64 = {.id = 0x34 | CAN_ID_FD_DESCRIPTOR,
                       .swPduHandle = 0x1004,
                       .length = sizeof(g_sdu64),
                       .sdu = g_sdu64
                      };

/* CAN FD frame with 64 bytes payload */
uint8 g_sdu64_2[64] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
                       0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60,
                       0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
                       0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80};
Can_PduType g_pdu64_2 = {.id = 0x35 | CAN_ID_FD_DESCRIPTOR,
                       .swPduHandle = 0x1004,
                       .length = sizeof(g_sdu64_2),
                       .sdu = g_sdu64_2
                      };

/*******************************************************************************
                Functions to reset the global variables
*******************************************************************************/

void ResetTxConfirmation()
{
    g_txConfirm.txConfirmed = 0;
    g_txConfirm.pduId = 0;
}

void ResetRxIndication()
{
    g_rxCount = 0;
}

void ResetControllerModeIndication()
{
    g_controllerModeChanged = 0;
}

void ResetBusOffIndication()
{
    g_busOffEvent = 0;
}

void ResetErrorNotification()
{
    g_canError = 0;
}

void ResetCanfdErrorNotification()
{
    g_canfdError = 0;
}

void ResetFifoWarning()
{
    g_fifoWarning = 0;
}

void ResetFifoOverflow()
{
    g_fifoOverflow = 0;
}

void ResetIcomNotification()
{
    g_icomState.callback = 0;
}

/*!
* @brief    Setup cases
* @details  This function is called before case, it will do some
*           common preparations for the case.
*/
void Setup(void)
{
    ResetTxConfirmation();
    ResetRxIndication();
    ResetControllerModeIndication();
    ResetBusOffIndication();
    ResetErrorNotification();
}

/*!
* @brief    Teardown cases
* @details  This function is called after each case, it will do some
*           common cleanups for the case.
*/
void Teardown(void)
{
}

/*!
* @brief    Delay some time
*/
void SysDelay(int Count)
{
    while(Count--);
}

/*******************************************************************************
                Callback functions called by the CAN driver
*******************************************************************************/

/*!
* @brief    Callback function called when a CAN frame has been transmitted successfully
*/
void CanIf_TxConfirmation(VAR(PduIdType, CANIF_VAR) CanTxPduId)
{
    printf("Can Tx Confirmation for PDU ID: 0x%04X\r\n", (int)CanTxPduId);

    g_txConfirm.txConfirmed += 1;
    g_txConfirm.pduId = CanTxPduId;
}

/*!
* @brief    Callback function called when a CAN frame has been received
*/
void CanIf_RxIndication(
    P2CONST(Can_HwType, AUTOMATIC, CANIF_APPL_CONST) Mailbox,
    P2CONST(PduInfoType, AUTOMATIC, CANIF_APPL_CONST) PduInfoPtr)
{
#if (STD_OFF == CAN_RX_INTERRUPT_HANDLE_ENABLE)
    Can_PduType g_pduTx;
    static uint16 pduHandle = 0U;
#endif

    if (PduInfoPtr->SduLength == 0)
    {
        return;
    }

    SchM_Enter_Can_CAN_CRITICAL_SECTION10();
    if (g_rxCount < MAX_RX_FRAMES)
    {
        g_rxBuffer[g_rxCount].canId = Mailbox->CanId;
        g_rxBuffer[g_rxCount].hoh = Mailbox->Hoh;
        g_rxBuffer[g_rxCount].controllerId = Mailbox->ControllerId;
        g_rxBuffer[g_rxCount].sduLength = PduInfoPtr->SduLength;
        memcpy(g_rxBuffer[g_rxCount].sduData, PduInfoPtr->SduDataPtr, PduInfoPtr->SduLength);
    #if (STD_ON == CAN_RX_INTERRUPT_HANDLE_ENABLE)
        g_receiveFlag = 1;
    #else
        g_pduTx.id = g_rxBuffer[0].canId;
        g_pduTx.swPduHandle = pduHandle;
        g_pduTx.length = g_rxBuffer[0].sduLength;
        g_pduTx.sdu = g_rxBuffer[0].sduData;

        /* Transmit CAN FD message as received */
        if(pduHandle == 0U)
        {
            g_pduTx.swPduHandle = 0x01;
            Can_Write(CAN0_TX_1, &g_pduTx);
        }
        else if(pduHandle == 1U)
        {
            g_pduTx.swPduHandle = 0x02;
            Can_Write(CAN0_TX_2, &g_pduTx);
        }
        else if(pduHandle == 2U)
        {
            g_pduTx.swPduHandle = 0x03;
            Can_Write(CAN0_TX_3, &g_pduTx);
        }
        else if(pduHandle == 3U)
        {
            g_pduTx.swPduHandle = 0x01;
            Can_Write(CAN0_TX_1, &g_pduTx);
        }
        else if(pduHandle == 4U)
        {
            g_pduTx.swPduHandle = 0x02;
            Can_Write(CAN0_TX_2, &g_pduTx);
        }
        else if(pduHandle == 5U)
        {
            g_pduTx.swPduHandle = 0x03;
            Can_Write(CAN0_TX_3, &g_pduTx);
        }
        else if(pduHandle == 6U)
        {
            g_pduTx.swPduHandle = 0x01;
            Can_Write(CAN0_TX_1, &g_pduTx);
        }
        
        if(pduHandle == 6U)
        {
            while(((REG_READ32(CAN_TXEFS_REG_ADDR(0)) & CAN_TXEFS_EFFL_MASK) >> CAN_TXEFS_EFFL_SHIFT) != 7);
            
            g_txFlag = 1;
            pduHandle = 0U;
        }
        else
        {
            pduHandle++;
        }
    #endif
    }
    SchM_Exit_Can_CAN_CRITICAL_SECTION10();
}

/*!
* @brief    Callback function called when the controller mode has changed
*/
void CanIf_ControllerModeIndication(
    VAR(uint8, CANIF_VAR) Controller,
    VAR(CanIf_ControllerModeType, CANIF_VAR) ControllerMode)
{
    g_controllerMode.controllerId = Controller;
    g_controllerMode.mode = ControllerMode;
    g_controllerModeChanged += 1;
    printf("Can Controller Mode Indication for Controller ID: %d, Mode: %d\r\n",
           Controller, ControllerMode);
}

/*!
* @brief    Callback function called when bus off event happened
*/
void CanIf_ControllerBusOff(VAR(uint8, CANIF_VAR) Controller)
{
    g_busOffEvent += 1;
    g_busOffControllerId = Controller;
    g_busOffHandlerFlg = 1;
    printf("Can Controller Bus Off for Controller ID: %d\r\n\r\n", Controller);
}

/*!
* @brief    Callback function called when the Icom state has changed
*/
void CanIf_CurrentIcomConfiguration(
    VAR(uint8, CANIF_VAR) ControllerId,
    VAR(IcomConfigIdType, CANIF_VAR) ConfigurationId,
    VAR(IcomSwitch_ErrorType, CANIF_VAR) Error)
{
    g_icomState.controllerId = ControllerId;
    g_icomState.configId = ConfigurationId;
    g_icomState.error = Error;
    g_icomState.callback = 1;
}

/*!
* @brief    Callback function called from Can_Write() in case the PDU is null
*/
Std_ReturnType CanIf_TriggerTransmit(PduIdType TxPduId, PduInfoType* PduInfoPtr)
{
    if (E_OK == g_triggerTransmitReturn)
    {
        PduLengthType sduLength = sizeof(g_triggerTransmitSdu);
        PduInfoPtr->SduLength = sduLength;
        for (uint8 i = 0; i < sduLength; i++)
        {
            /* Copy one byte of data */
            PduInfoPtr->SduDataPtr[i] = g_triggerTransmitSdu[i];
        }
    }
    return g_triggerTransmitReturn;
}

/*!
* @brief    Callback function called when CAN error happened
*/
void CanErrorControllerNotification()
{
    g_canError = 1;
}

/*!
* @brief    Callback function called when CAN FD error happened
*/
void CanErrorFDControllerNotification()
{
    g_canfdError = 1;
}

/*!
* @brief    Callback function called when FIFO warning happened
*/
void Can0RxFifoWarning(void)
{
    g_fifoWarning = 1;
}

/*!
* @brief    Callback function called when FIFO overflow happened
*/
void Can0RxFifoOverflow(void)
{
    g_fifoOverflow = 1;
}

/*!
* @brief    Callback function called when a LPDU is received
*/
boolean LPduReceived(uint8 Hrh, Can_IdType CanId, uint8 CanDlc, const uint8* CanSduPtr)
{
    g_lpduCalloutCounter++;
    return g_lpduCalloutReturn;
}

/* @brief    Print an array of bytes
*/
void PrintBytes(const char* Message, const uint8* Buf, uint32 BufSize)
{
    printf("%s:", Message);
    for (uint32 i = 0; i < BufSize; i++)
    {
        printf(" %02X", Buf[i]);
    }
    printf("\r\n");
}

/*******************************************************************************
                        Verification functions
*******************************************************************************/

/*!
* @brief    Verify if an byte array matches expected value
*/
boolean VerifyBuffer(const uint8* Buf,
                     uint32 BufSize,
                     const uint8* ExpectedBuf,
                     uint32 ExpectedBufSize,
                     const char* Name)
{
    PrintBytes(Name, Buf, BufSize);
    PrintBytes("Expected", ExpectedBuf, ExpectedBufSize);

    if (BufSize != ExpectedBufSize)
    {
        printf("Size = %d (Expected: %d)\r\n", (int)BufSize, (int)ExpectedBufSize);
        return FALSE;
    }

    for (uint32 i = 0; i < BufSize; i++)
    {
        if (Buf[i] != ExpectedBuf[i])
        {
            return FALSE;
        }
    }
    return TRUE;
}

boolean VerifyRxBuffer(const uint8* Buf,
                     uint32 BufSize,
                     const uint8* ExpectedBuf,
                     uint32 ExpectedBufSize,
                     const char* Name)
{
    boolean result = TRUE;
    if (BufSize != ExpectedBufSize)
    {
        printf("Size = %d (Expected: %d)\r\n", (int)BufSize, (int)ExpectedBufSize);
        result = FALSE;
    }

    for (uint32 i = 0; i < BufSize; i++)
    {
        if (Buf[i] != ExpectedBuf[i])
        {
            result =  FALSE;
        }
    }
    if(FALSE == result)
    {
        PrintBytes(Name, Buf, BufSize);
        PrintBytes("Expected", ExpectedBuf, ExpectedBufSize);   
    }
    return result;
}

/*!
* @brief    Verify if the version info is correct
*/
boolean VerifyVersionInfo(Std_VersionInfoType VersionInfo)
{
    printf("vendorID = %d (Expected: %d)\r\n", VersionInfo.vendorID, CAN_H_VENDOR_ID);
    printf("moduleID = %d (Expected: %d)\r\n", VersionInfo.moduleID, CAN_H_MODULE_ID);
    printf("sw_major_version = %d (Expected: %d)\r\n",
           VersionInfo.sw_major_version, CAN_H_SW_MAJOR_VERSION);
    printf("sw_minor_version = %d (Expected: %d)\r\n",
           VersionInfo.sw_minor_version, CAN_H_SW_MINOR_VERSION);
    printf("sw_patch_version = %d (Expected: %d)\r\n",
           VersionInfo.sw_patch_version, CAN_H_SW_PATCH_VERSION);

    if ((CAN_H_VENDOR_ID == VersionInfo.vendorID)
        && (CAN_H_MODULE_ID == VersionInfo.moduleID)
        && (CAN_H_SW_MAJOR_VERSION == VersionInfo.sw_major_version)
        && (CAN_H_SW_MINOR_VERSION == VersionInfo.sw_minor_version)
        && (CAN_H_SW_PATCH_VERSION == VersionInfo.sw_patch_version))
    {
        return TRUE;
    }
    return FALSE;
}

/*!
* @brief    Verify if the CAN ID matches expected value
*/
boolean VerifyCanId(Can_IdType CanId, Can_IdType ExpectedCanId)
{
    printf("CAN ID = 0x%08X (Expected: 0x%08X)\r\n", (int)CanId, (int)ExpectedCanId);
    return CanId == ExpectedCanId ? TRUE : FALSE;
}

boolean VerifyRxCanId(Can_IdType CanId, Can_IdType ExpectedCanId)
{
    boolean result = TRUE;
    if(CanId != ExpectedCanId)
    {
       result = FALSE;
       printf("CAN ID = 0x%08X (Expected: 0x%08X)\r\n", (int)CanId, (int)ExpectedCanId);
    }
    
    return result;
}

/*!
* @brief    Verify if the CAN driver status matches expected value
*/
boolean VerifyDriverStatus(Can_DriverStatusType ExpectedState)
{
    printf("CAN driver status = %d (Expected: %d)\r\n",
           g_canDriverStatus, ExpectedState);
    return ExpectedState == g_canDriverStatus ? TRUE : FALSE;
}

/*!
* @brief    Verify if the CAN controller state matches expected value
*/
boolean VerifyControllerState(Can_ControllerStateType State, Can_ControllerStateType ExpectedState)
{
    printf("CAN controller state = %d (Expected: %d)\r\n", State, ExpectedState);
    return State == ExpectedState ? TRUE : FALSE;
}

/*!
* @brief    Verify if the CAN controller error state matches expected value
*/
boolean VerifyControllerErrorState(Can_ErrorStateType State, Can_ErrorStateType ExpectedState)
{
    printf("CAN controller error state = %d (Expected: %d)\r\n", State, ExpectedState);
    return State == ExpectedState ? TRUE : FALSE;
}

/*!
* @brief    Verify if the register value matches expected value
*/
boolean VerifyRegister(const char* Name, uint32 Value, uint32 ExpectedValue)
{
    printf("Register %s = 0x%08X (Expected: 0x%08X)\r\n", Name, (int)Value, (int)ExpectedValue);
    return Value == ExpectedValue ? TRUE : FALSE;
}

/*!
* @brief    Verify if the interrupt disable level matches expected value
*/
boolean VerifyInterruptDisableLevel(uint8 ControllerId, sint8 ExpectedValue)
{
    extern VAR(Can_ControllerStatusType, CAN_VAR) g_canControllerStatus[CAN_MAXCTRL_NUMBER_CFG];

    printf("Interrupt Disable Level = %d (Expected: %d)\r\n",
           g_canControllerStatus[ControllerId].disableIntrpCount, ExpectedValue);
    return g_canControllerStatus[ControllerId].disableIntrpCount == ExpectedValue ? TRUE : FALSE;
}

/*!
* @brief    Verify if the callback function CanIf_TxConfirmation() has been called
*/
boolean VerifyTxConfirmation(PduIdType PduId)
{
    printf("CanIf_TxConfirmation() was called %d times (Expected: %d times)\r\n",
           g_txConfirm.txConfirmed, 1);

    if (1 == g_txConfirm.txConfirmed)
    {
        g_txConfirm.txConfirmed = 0;

        printf("PDU ID = 0x%04X (Expected: 0x%04X)\r\n",
               g_txConfirm.pduId, PduId);
        return PduId == g_txConfirm.pduId ? TRUE : FALSE;
    }
    return FALSE;
}

/*!
* @brief    Verify that the callback function CanIf_TxConfirmation() was not called
*/
boolean VerifyNoTxConfirmation()
{
    printf("CanIf_TxConfirmation() was called %d times (Expected: %d times)\r\n",
           g_txConfirm.txConfirmed, 0);
    return 0 == g_txConfirm.txConfirmed ? TRUE : FALSE;
}

/*!
* @brief    Verify if the callback function CanIf_RxIndication() has been called
*/
boolean VerifyRxIndication(uint8 ControllerId, Can_HwHandleType Hoh, const Can_PduType* PduPtr)
{
    printf("CanIf_RxIndication() was called %d times (Expected: %d times)\r\n", g_rxCount, 1);
    if (1 == g_rxCount)
    {
        g_rxCount = 0;

        printf("Controller ID = %d (Expected: %d)\r\n", g_rxBuffer[0].controllerId, ControllerId);
        printf("Hoh = %d (Expected: %d)\r\n", g_rxBuffer[0].hoh, Hoh);
        printf("CAN ID = 0x%08X (Expected: 0x%08X)\r\n", (int)g_rxBuffer[0].canId, (int)PduPtr->id);
        printf("Length = %d (Expected: %d)\r\n", (int)g_rxBuffer[0].sduLength, PduPtr->length);

        if ((ControllerId == g_rxBuffer[0].controllerId)
            && (Hoh == g_rxBuffer[0].hoh)
            && (PduPtr->id == g_rxBuffer[0].canId)
            && (PduPtr->length == g_rxBuffer[0].sduLength)
            && VerifyBuffer(PduPtr->sdu, PduPtr->length,
                            g_rxBuffer[0].sduData, g_rxBuffer[0].sduLength, "Rx"))
        {
            return TRUE;
        }
    }
    return FALSE;
}

/*!
* @brief    Verify a CAN frame
*/
boolean VerifyCanFrame(
    Can_IdType CanId,
    Can_IdType ExpectedCanId,
    uint8 Length,
    uint8 Expectedength,
    const uint8* Data,
    const uint8* ExpectedData)
{
    printf("CAN ID = 0x%08X (Expected: 0x%08X)\r\n", (int)CanId, (int)ExpectedCanId);
    printf("Length = %d (Expected: %d)\r\n", Length, Expectedength);

    if (   (CanId == ExpectedCanId)
        && (Length == Expectedength)
        && VerifyBuffer(Data, Length, ExpectedData, Expectedength, "Rx"))
    {
        return TRUE;
    }
    return FALSE;
}

/*!
* @brief    Verify if multiple CAN frames in the receive buffer matches the expected buffer
*/
boolean VerifyRxCanFrames(Can_PduType** ExpectedPduBuffer, uint8 ExpectedPduCount)
{
    boolean result = TRUE;
    for (uint8 i = 0; i < ExpectedPduCount; i++)
    {
        if (VerifyCanFrame(g_rxBuffer[i].canId, ExpectedPduBuffer[i]->id,
                           g_rxBuffer[i].sduLength, ExpectedPduBuffer[i]->length,
                           g_rxBuffer[i].sduData, ExpectedPduBuffer[i]->sdu) == FALSE)
        {
            result = FALSE;
        }
    }
    return result;
}

/*!
* @brief    Verify the number of received CAN frames
*/
boolean VerifyRxCount(uint8 ExpectedRxCount)
{
    printf("%d CAN frames received (Expected: %d)\r\n", g_rxCount, ExpectedRxCount);
    return g_rxCount == ExpectedRxCount ? TRUE : FALSE;
}

/*!
* @brief    Verify that the callback function CanIf_RxIndication() was not called
*/
boolean VerifyNoRxIndication()
{
    printf("CanIf_RxIndication() was called %d times (Expected: %d times)\r\n",
           g_rxCount, 0);
    return 0 == g_rxCount ? TRUE : FALSE;
}

/*!
* @brief    Verify if the bus off event happened
*/
boolean VerifyBusOffEvent(uint8 ControllerId)
{
    printf("CanIf_ControllerBusOff() was called = %d times (Expected: %d times)\r\n", g_busOffEvent, 1);
    if (1 == g_busOffEvent)
    {
        g_busOffEvent = 0;

        printf("Controller ID = %d (Expected: %d)\r\n", g_busOffControllerId, ControllerId);
        return ControllerId == g_busOffControllerId ? TRUE : FALSE;
    }
    return FALSE;
}

/*!
* @brief    Verify that there was no bus off event
*/
boolean VerifyNoBusOffEvent()
{
    printf("CanIf_ControllerBusOff() was called %d times (Expected: %d times)\r\n",
           g_busOffEvent, 0);
    return 0 == g_busOffEvent ? TRUE : FALSE;
}

/*!
* @brief    Verify the error notification callback was called
*/
boolean VerifyErrorNotification()
{
    printf("CAN Error Notification was called %d times (Expected: %d times)\r\n",
           g_canError, 1);
    if (1 == g_canError)
    {
        g_canError = 0;
        return TRUE;
    }
    return FALSE;
}

/*!
* @brief    Verify the CAN FD error notification callback was called
*/
boolean VerifyCanfdErrorNotification()
{
    printf("CAN FD Error Notification was called %d times (Expected: %d times)\r\n",
           g_canfdError, 1);
    if (1 == g_canfdError)
    {
        g_canfdError = 0;
        return TRUE;
    }
    return FALSE;
}

/*!
* @brief    Verify the error notification callback was not called
*/
boolean VerifyNoErrorNotification()
{
    printf("CAN Error Notification was called %d times (Expected: %d times)\r\n",
           g_canError, 0);
    return 0 == g_canError ? TRUE : FALSE;
}

/*!
* @brief    Verify if the callback function CanIf_ControllerModeIndication() has been called
*/
boolean VerifyControllerModeIndication(uint8 ControllerId, CanIf_ControllerModeType ControllerMode)
{
    printf("CanIf_ControllerModeIndication() was called %d times (Expected: %d times)\r\n",
           g_controllerModeChanged, 1);
    if (1 == g_controllerModeChanged)
    {
        g_controllerModeChanged = 0;

        printf("Controller ID = %d (Expected: %d)\r\n", g_controllerMode.controllerId, ControllerId);
        printf("Controller Mode = %d (Expected: %d)\r\n", g_controllerMode.mode, ControllerMode);
        if ((ControllerId == g_controllerMode.controllerId)
            && (ControllerMode == g_controllerMode.mode))
        {
            return TRUE;
        }
    }
    return FALSE;
}

/*!
* @brief    Verify if the FIFO warning event happened
*/
boolean VerifyFifoWarning()
{
    printf("FIFO Warning = %d (Expected: %d times)\r\n", g_fifoWarning, 1);
    return 1 == g_fifoWarning ? TRUE : FALSE;
}

/*!
* @brief    Verify if the FIFO overflow event happened
*/
boolean VerifyFifoOverflow()
{
    printf("FIFO Overflow = %d (Expected: %d times)\r\n", g_fifoOverflow, 1);
    return 1 == g_fifoOverflow ? TRUE : FALSE;
}

/*!
* @brief    Verify if the callback function CanIf_CurrentIcomConfiguration() has been called
*/
boolean VerifyIcomNotification(
    uint8 ControllerId,
    IcomConfigIdType ConfigurationId,
    IcomSwitch_ErrorType Error)
{
    printf("CanIf_CurrentIcomConfiguration() was called %d times (Expected: %d times)\r\n",
           g_icomState.callback, 1);

    if (1 == g_icomState.callback)
    {
        g_icomState.callback = 0;

        printf("Icom Controller ID = %d (Expected: %d)\r\n", g_icomState.controllerId, ControllerId);
        printf("Icom Configuration ID = %d (Expected: %d)\r\n", g_icomState.configId, ConfigurationId);
        printf("Icom Error = %d (Expected: %d)\r\n", g_icomState.error, Error);

        if (   (ControllerId == g_icomState.controllerId)
            && (ConfigurationId == g_icomState.configId)
            && (Error == g_icomState.error))
        {
            return TRUE;
        }
    }
    return FALSE;
}

/*!
* @brief    Verify if the LPDU callout function has been called
*/
boolean VerifyLPduCallout()
{
    printf("LPDU callout function was called %d times (Expected: %d times)\r\n", g_lpduCalloutCounter, 1);
    if (1 == g_lpduCalloutCounter)
    {
        g_lpduCalloutCounter = 0;
        return TRUE;
    }
    return FALSE;
}

/*******************************************************************************
                        Other helper functions
*******************************************************************************/

/*!
* @brief    Print a CAN frame
*/
void PrintCanFrame(const char* Message, const Can_PduType* PduPtr)
{
    char buf[64] = {0};
    sprintf(buf, "%s[CAN ID = 0x%08X]", Message, (int)PduPtr->id);
    PrintBytes(buf, PduPtr->sdu, PduPtr->length);
}

/*!
* @brief    Put the MCU to sleep mode
* @details  This function will return until the MCU is waken up by a specific
*           CAN frame from the bus.
*/
void GoToSleep()
{
    printf("Going to STOP mode\r\n");
    __asm volatile("WFI");
    printf("Wake up, now in RUN mode\r\n");
}
