/* ----------------------------------------------------------------------------
 *         SAM Software Package License 
 * ----------------------------------------------------------------------------
 * Copyright (c) 2012, Atmel Corporation
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the disclaimer below.
 *
 * Atmel's name may not be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
 * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * ----------------------------------------------------------------------------
 */

/** \file
 *  Implements functions for Controller Area Network (CAN)
 *  peripheral operations.
 */
/** \addtogroup can_module
 *@{*/

/*----------------------------------------------------------------------------
 *        Headers
 *----------------------------------------------------------------------------*/

#include "chip.h"

#include <assert.h>

#if defined(REG_CAN0_MR) || defined(REG_CAN_MR)

/* ----------- CAN_MR Operations --------------- */
/**
 * \brief Set CAN Mode Register (CAN_MR)
 * \param pCan Pointer to Can instance.
 * \param dwMr Mode register settings.
 */
void CAN_ConfigureMode(Can *pCan, uint32_t dwMr)
{
    pCan->CAN_MR = dwMr;
}

/**
 * \brief CAN Controller Enable/Disable
 * \param pCan   Pointer to Can instance.
 * \param bEnDis 1 to enable and 0 to disable.
 */
void CAN_Enable(Can *pCan, uint8_t bEnDis)
{
    if (bEnDis) pCan->CAN_MR |=  CAN_MR_CANEN;
    else        pCan->CAN_MR &= ~CAN_MR_CANEN;
}

/**
 * \brief CAN Low Power Mode Enable/Disable
 * \param pCan   Pointer to Can instance.
 * \param bEnDis 1 to enable and 0 to disable.
 */
void CAN_EnableLowPower(Can *pCan, uint8_t bEnDis)
{
    if (bEnDis) pCan->CAN_MR |=  CAN_MR_LPM;
    else        pCan->CAN_MR &= ~CAN_MR_LPM;
}

/**
 * \brief CAN Autobaud/Listen mode
 * \param pCan   Pointer to Can instance.
 * \param bEnDis 1 to enable and 0 to disable.
 */
void CAN_EnableAutobaud(Can *pCan, uint8_t bEnDis)
{
    if (bEnDis) pCan->CAN_MR |=  CAN_MR_ABM;
    else        pCan->CAN_MR &= ~CAN_MR_ABM;
}

/**
 * \brief CAN Overload Frame Enable/Disable
 * \param pCan   Pointer to Can instance.
 * \param bEnDis 1 to enable and 0 to disable.
 */
void CAN_EnableOverloadFrame(Can *pCan, uint8_t bEnDis)
{
    if (bEnDis) pCan->CAN_MR |=  CAN_MR_OVL;
    else        pCan->CAN_MR &= ~CAN_MR_OVL;
}

/**
 * \brief CAN Timestamp capture mode (@EOF/@SOF).
 * \param pCan      Pointer to Can instance.
 * \param bEofSof   1 for EOF/0 for SOF.
 */
void CAN_EnableTimeStampEof(Can *pCan, uint8_t bEofSof)
{
    if (bEofSof) pCan->CAN_MR |=  CAN_MR_TEOF;
    else         pCan->CAN_MR &= ~CAN_MR_TEOF;
}

/**
 * \brief CAN Time Triggered Mode Enable/Disable
 * \param pCan      Pointer to Can instance.
 * \param bEnDis    Enable/Disable Time Trigger Mode.
 */
void CAN_EnableTimeTriggerMode(Can *pCan, uint8_t bEnDis)
{
    if (bEnDis) pCan->CAN_MR |=  CAN_MR_TTM;
    else        pCan->CAN_MR &= ~CAN_MR_TTM;
}

/**
 * \brief CAN Timer Freeze Enable/Disable
 * \param pCan      Pointer to Can instance.
 * \param bEnDis    Enable/Disable Timer Freeze.
 */
void CAN_EnableTimerFreeze(Can *pCan, uint8_t bEnDis)
{
    if (bEnDis) pCan->CAN_MR |=  CAN_MR_TIMFRZ;
    else        pCan->CAN_MR &= ~CAN_MR_TIMFRZ;
}

/**
 * \brief CAN Repeat Disable/Enable.
 * \param pCan      Pointer to Can instance.
 * \param bEnDis    Disable/Enable Repeat.
 */
void CAN_DisableRepeat(Can *pCan, uint8_t bDisEn)
{
    if (bDisEn) pCan->CAN_MR |=  CAN_MR_DRPT;
    else        pCan->CAN_MR &= ~CAN_MR_DRPT;
}

/* ---------- Interrupt settings ------------- */

/**
 * \brief CAN Interrupts Enable
 * \param pCan      Pointer to Can instance.
 * \param dwSources Interrupt sources bits.
 */
void CAN_EnableIt(Can *pCan, uint32_t dwSources)
{
    pCan->CAN_IER = dwSources;
}

/**
 * \brief CAN Interrupts Disable
 * \param pCan      Pointer to Can instance.
 * \param dwSources Interrupt sources bits.
 */
void CAN_DisableIt(Can *pCan, uint32_t dwSources)
{
    pCan->CAN_IDR = dwSources;
}

/**
 * \brief Return CAN Interrupts Masks
 * \param pCan      Pointer to Can instance.
 */
uint32_t CAN_GetItMask(Can *pCan)
{
    return pCan->CAN_IMR;
}

/**
 * \brief Return CAN Statuses
 * \param pCan      Pointer to Can instance.
 */
uint32_t CAN_GetStatus(Can *pCan)
{
    return pCan->CAN_SR;
}

/**
 * \brief Calculate and configure the baudrate
 * \param pCan       Pointer to Can instance.
 * \param dwBaudrate Baudrate value (kB/s)
 *                   allowed: 100, 800, 500, 250, 125, 50, 25, 10
 * \param dwMck      MCK.
 * \return 1 in success, otherwise return 0.
 */
uint8_t CAN_CalcBaudrate(Can *pCan, uint32_t dwBaudrate, uint32_t dwMck)
{
    uint32_t BRP, PROPAG, PHASE1, PHASE2, SJW;
    uint8_t  TQ;
    uint32_t t1t2;
    uint32_t maxClock;
    uint32_t id = ID_CAN0;

    if ((uint32_t)pCan == (uint32_t)CAN0) id = ID_CAN0;
       else if ((uint32_t)pCan == (uint32_t)CAN1) id = ID_CAN1;
    maxClock = PMC_SetPeriMaxClock(id, dwMck);

    if (dwBaudrate >= 1000) TQ = 8;
    else                    TQ = 16;
    BRP = (maxClock / (dwBaudrate * 1000 * TQ)) - 1;
    if (BRP == 0) {
        return 0;
    }

    /* Timing delay:
       Delay Bus Driver     - 50ns
       Delay Receiver       - 30ns
       Delay Bus Line (20m) - 110ns */
    if ( (TQ * dwBaudrate * 2 * (50+30+110)/1000000) >= 1 )
        PROPAG = (TQ * dwBaudrate * 2 * (50+30+110)/1000000) - 1;
    else
        PROPAG = 0;
    t1t2 = TQ - 1 - (PROPAG + 1);

    if ( (t1t2 & 0x01) == 0x01 ) {
        PHASE1 = ((t1t2 - 1) / 2) - 1;
        PHASE2 = PHASE1 + 1;
    }
    else {
        PHASE1 = ((t1t2) / 2) - 1;
        PHASE2 = PHASE1;
    }

    if ( 1 > (4/(PHASE1 + 1)) ) SJW = 3;
    else                        SJW = PHASE1;

    if ( (PROPAG + PHASE1 + PHASE2) != (uint32_t)(TQ - 4) ) {
        return 0;
    }

    pCan->CAN_BR = CAN_BR_PHASE2(PHASE2)
                 | CAN_BR_PHASE1(PHASE1)
                 | CAN_BR_PROPAG(PROPAG)
                 | CAN_BR_SJW(SJW)
                 | CAN_BR_BRP(BRP)
                 | CAN_BR_SMP_ONCE;
    return 1;
}

/**
 * \brief Set CAN baudrate register
 * \param pCan      Pointer to Can instance.
 * \param dwBr      Setting value for CAN_BR.
 */
void CAN_ConfigureBaudrate(Can *pCan, uint32_t dwBr)
{
    pCan->CAN_BR = dwBr;
}

/**
 * \brief Set CAN Sampling Mode
 * \param pCan      Pointer to Can instance.
 * \param bAvg3     Sample 3 times/sample once at sample point.
 */
void CAN_SetSamplingMode(Can *pCan, uint8_t bAvg3)
{
    if (bAvg3) pCan->CAN_BR |=  CAN_BR_SMP;
    else       pCan->CAN_BR &= ~CAN_BR_SMP;
}

/**
 * \brief Return CAN Timer Register
 * \param pCan      Pointer to Can instance.
 */
uint32_t CAN_GetTimer(Can *pCan)
{
    return pCan->CAN_TIM;
}

/**
 * \brief Return CAN TimeStamp Register
 * \param pCan      Pointer to Can instance.
 */
uint32_t CAN_GetTimestamp(Can *pCan)
{
    return pCan->CAN_TIMESTP;
}

/**
 * \brief Return Error Count (TEC << 16) + REC
 * \param pCan      Pointer to Can instance.
 */
uint32_t CAN_GetErrorCount(Can *pCan)
{
    return pCan->CAN_ECR;
}

/**
 * \brief Return Receive Error Count
 * \param pCan      Pointer to Can instance.
 */
uint32_t CAN_GetRxErrorCount(Can *pCan)
{
    return (pCan->CAN_ECR & CAN_ECR_REC_Msk) >> CAN_ECR_REC_Pos;
}

/**
 * \brief Return Transmit Error Count
 * \param pCan      Pointer to Can instance.
 */
uint32_t CAN_GetTxErrorCount(Can *pCan)
{
    return (pCan->CAN_ECR & CAN_ECR_TEC_Msk) >> CAN_ECR_TEC_Pos;
}

/**
 * \brief Set Transfer Command Register to initialize transfer requests.
 * \param pCan       Pointer to Can instance.
 * \param dwRequests Transfer Command Requests.
 */
void CAN_Command(Can *pCan, uint32_t dwRequests)
{
    pCan->CAN_TCR = dwRequests;
}

/**
 * \brief Resets CAN internal timer counter.
 * \param pCan       Pointer to Can instance.
 */
void CAN_ResetTimer(Can *pCan)
{
    pCan->CAN_TCR = CAN_TCR_TIMRST;
}

/**
 * \brief Request transfer on mailbox.
 * \param pCan       Pointer to Can instance.
 * \param bMb        Mailbox number.
 */
void CAN_Tx(Can *pCan, uint8_t bMb)
{
    pCan->CAN_TCR = CAN_TCR_MB0 << bMb;
}

/**
 * \brief Abort transfer on several mailboxes.
 * \param pCan       Pointer to Can instance.
 * \param dwAborts   Abort requests.
 */
void CAN_Abort(Can *pCan, uint32_t dwAborts)
{
    pCan->CAN_ACR = dwAborts;
}

/**
 * \brief Abort transfer on single mailbox.
 * \param pCan       Pointer to Can instance.
 * \param bMb        Mailbox number.
 */
void CAN_AbortMailbox(Can *pCan, uint8_t bMb)
{
    pCan->CAN_ACR = CAN_ACR_MB0 << bMb;
}

/**
 * \brief Configure CAN Message Mode (_MMRx)
 * \param pCan       Pointer to Can instance.
 * \param bMb        Mailbox number.
 * \param dwMr       Mode settings.
 */
void CAN_ConfigureMessageMode(Can *pCan, uint8_t bMb, uint32_t dwMr)
{
    pCan->CAN_MB[bMb].CAN_MMR = dwMr;
}

/**
 * \brief Return CAN Message Mode (_MMRx)
 * \param pCan       Pointer to Can instance.
 * \param bMb        Mailbox number.
 */
uint32_t CAN_GetMessageMode(Can *pCan, uint8_t bMb)
{
    return pCan->CAN_MB[bMb].CAN_MMR;
}

/**
 * \brief Set Mailbox Timemark for Time Triggered Mode.
 * \param pCan       Pointer to Can instance.
 * \param bMb        Mailbox number.
 * \param bTimemarks Mailbox timemarks.
 */
void CAN_SetTimemark(Can *pCan, uint8_t bMb, uint8_t bTimemarks)
{
    uint32_t dwMmr = (pCan->CAN_MB[bMb].CAN_MMR) & (~0xFFu);
    pCan->CAN_MB[bMb].CAN_MMR = dwMmr | ((bTimemarks << 0) & 0xFF);
}

/**
 * \brief Set Mailbox Priority.
 * \param pCan       Pointer to Can instance.
 * \param bMb        Mailbox number.
 * \param bPriority  Mailbox Priority.
 */
void CAN_SetPriority(Can *pCan, uint8_t bMb, uint8_t bPriority)
{
    uint32_t dwMmr = (pCan->CAN_MB[bMb].CAN_MMR & ~CAN_MMR_PRIOR_Msk);
    pCan->CAN_MB[bMb].CAN_MMR = dwMmr | CAN_MMR_PRIOR(bPriority);
}

/**
 * \brief Set Mailbox Object Type.
 * \param pCan       Pointer to Can instance.
 * \param bMb        Mailbox number.
 * \param bType      Mailbox Object Type.
 */
void CAN_SetObjectType(Can *pCan, uint8_t bMb, uint8_t bType)
{
    uint32_t dwMr = (pCan->CAN_MB[bMb].CAN_MMR & CAN_MMR_MOT_Msk) >> CAN_MMR_MOT_Pos;
    pCan->CAN_MB[bMb].CAN_MMR |= dwMr | ((bType << CAN_MMR_MOT_Pos) & CAN_MMR_MOT_Msk);
}

/**
 * \brief Configure CAN Message Acceptance Mask (_MAMx)
 * \param pCan       Pointer to Can instance.
 * \param bMb        Mailbox number.
 * \param dwMam      The setting value for _MAMx.
 */
void CAN_ConfigureMessageAcceptanceMask(Can *pCan, uint8_t bMb, uint32_t dwMAM)
{
    pCan->CAN_MB[bMb].CAN_MAM = dwMAM;
}

/**
 * \brief Return CAN Message Acceptance Mask (_MAMx)
 * \param pCan       Pointer to Can instance.
 * \param bMb        Mailbox number.
 */
uint32_t CAN_GetMessageAcceptanceMask(Can *pCan, uint8_t bMb)
{
    return pCan->CAN_MB[bMb].CAN_MAM;
}

/**
 * \brief Configure Identifier Version in CAN Message Acceptance Mask (_MAMx)
 * \param pCan       Pointer to Can instance.
 * \param bMb        Mailbox number.
 * \param bIdCfg     IDvA and IDvB/IDvA only Identify.
 */
void CAN_ConfigureIdentifierMask(Can *pCan, uint8_t bMb, uint8_t bIdCfg)
{
    if (bIdCfg) pCan->CAN_MB[bMb].CAN_MAM |=  CAN_MAM_MIDE;
    else        pCan->CAN_MB[bMb].CAN_MAM &= ~CAN_MAM_MIDE;
}

/**
 * \brief Set Identifier for standard frame mode (MIDvA) mask
 * \param pCan       Pointer to Can instance.
 * \param bMb        Mailbox number.
 * \param dwMIDvA    Identifier for standard frame mode.
 */
void CAN_SetMIDvAMask(Can *pCan, uint8_t bMb, uint32_t dwIDvA)
{
    uint32_t dwMam = pCan->CAN_MB[bMb].CAN_MAM & CAN_MAM_MIDvA_Msk;
    pCan->CAN_MB[bMb].CAN_MAM = dwMam | CAN_MAM_MIDvA(dwIDvA);
}

/**
 * \brief Set Complementary bits for identifier in extended frame mode (MIDvB) mask
 * \param pCan       Pointer to Can instance.
 * \param bMb        Mailbox number.
 * \param dwMIDvB    Identifier for extended frame mode.
 */
void CAN_SetMIDvBMask(Can *pCan, uint8_t bMb, uint32_t dwIDvA)
{
    uint32_t dwMam = pCan->CAN_MB[bMb].CAN_MAM & CAN_MAM_MIDvB_Msk;
    pCan->CAN_MB[bMb].CAN_MAM = dwMam | CAN_MAM_MIDvB(dwIDvA);
}

/**
 * \brief Configure CAN Message ID (_MIDx)
 * \param pCan       Pointer to Can instance.
 * \param bMb        Mailbox number.
 * \param dwMID      The setting value for _MIDx.
 */
void CAN_ConfigureMessageID(Can *pCan, uint8_t bMb, uint32_t dwMID)
{
    pCan->CAN_MB[bMb].CAN_MID = dwMID;
}

/**
 * \brief Return CAN Message ID (_MIDx)
 * \param pCan       Pointer to Can instance.
 * \param bMb        Mailbox number.
 */
uint32_t CAN_GetMessageID(Can *pCan, uint8_t bMb)
{
    return pCan->CAN_MB[bMb].CAN_MID;
}

/**
 * \brief Configure Identifier Version in CAN Message ID register (_MIDx)
 * \param pCan       Pointer to Can instance.
 * \param bMb        Mailbox number.
 * \param bIdVer     2.0 Part B/2.0 Part A.
 */
void CAN_ConfigureIdVer(Can *pCan, uint8_t bMb, uint8_t bIdVer)
{
    uint32_t dwMid = pCan->CAN_MB[bMb].CAN_MID & CAN_MID_MIDE;
    pCan->CAN_MB[bMb].CAN_MID = dwMid | (bIdVer ? CAN_MID_MIDE : 0);
}

/**
 * \brief Set Identifier for standard frame mode (MIDvA) value
 * \param pCan       Pointer to Can instance.
 * \param bMb        Mailbox number.
 * \param dwMIDvA    Identifier for standard frame mode.
 */
void CAN_SetMIDvA(Can *pCan, uint8_t bMb, uint32_t dwIDvA)
{
    uint32_t dwMam = pCan->CAN_MB[bMb].CAN_MID & CAN_MID_MIDvA_Msk;
    pCan->CAN_MB[bMb].CAN_MID = dwMam | CAN_MID_MIDvA(dwIDvA);
}

/**
 * \brief Set Complementary bits for identifier in extended frame mode (MIDvB) value
 * \param pCan       Pointer to Can instance.
 * \param bMb        Mailbox number.
 * \param dwMIDvB    Identifier for extended frame mode.
 */
void CAN_SetMIDvB(Can *pCan, uint8_t bMb, uint32_t dwIDvA)
{
    uint32_t dwMam = pCan->CAN_MB[bMb].CAN_MID & CAN_MID_MIDvB_Msk;
    pCan->CAN_MB[bMb].CAN_MID = dwMam | CAN_MID_MIDvB(dwIDvA);
}

/**
 * \brief Return CAN Message Family ID (Masked ID)
 * \param pCan       Pointer to Can instance.
 * \param bMb        Mailbox number.
 */
uint32_t CAN_GetFamilyID(Can *pCan, uint8_t bMb)
{
    return pCan->CAN_MB[bMb].CAN_MFID;
}

/**
 * \brief Return CAN Message Status
 * \param pCan       Pointer to Can instance.
 * \param bMb        Mailbox number.
 */
uint32_t CAN_GetMessageStatus(Can *pCan, uint8_t bMb)
{
    return pCan->CAN_MB[bMb].CAN_MSR;
}

/**
 * \brief Return CAN Message Data Low
 * \param pCan       Pointer to Can instance.
 * \param bMb        Mailbox number.
 */
uint32_t CAN_GetMessageDataL(Can *pCan, uint8_t bMb)
{
    return pCan->CAN_MB[bMb].CAN_MDL;
}

/**
 * \brief Set CAN Message Data Low
 * \param pCan       Pointer to Can instance.
 * \param bMb        Mailbox number.
 * \param dwL        Data Low Value.
 */
void CAN_SetMessageDataL(Can *pCan, uint8_t bMb, uint32_t dwL)
{
    pCan->CAN_MB[bMb].CAN_MDL = dwL;
}

/**
 * \brief Set CAN Message Data High
 * \param pCan       Pointer to Can instance.
 * \param bMb        Mailbox number.
 * \param dwH        Data High Value.
 */
void CAN_SetMessageDataH(Can *pCan, uint8_t bMb, uint32_t dwH)
{
    pCan->CAN_MB[bMb].CAN_MDH = dwH;
}

/**
 * \brief Return CAN Message Data High
 * \param pCan       Pointer to Can instance.
 * \param bMb        Mailbox number.
 */
uint32_t CAN_GetMessageDataH(Can *pCan, uint8_t bMb)
{
    return pCan->CAN_MB[bMb].CAN_MDH;
}

/**
 * \brief Copy DW array to CAN Message Data.
 * \param pCan       Pointer to Can instance.
 * \param bMb        Mailbox number.
 * \param pDwData    Pointer to a buffer for data.
 */
void CAN_SetMessage(Can *pCan, uint8_t bMb, uint32_t *pDwData)
{
    pCan->CAN_MB[bMb].CAN_MDL = pDwData[0];
    pCan->CAN_MB[bMb].CAN_MDH = pDwData[1];
}

/**
 * \brief Copy CAN Message Data to DW array.
 * \param pCan       Pointer to Can instance.
 * \param bMb        Mailbox number.
 * \param pDwData    Pointer to a buffer for data.
 */
void CAN_GetMessage(Can *pCan, uint8_t bMb, uint32_t *pDwData)
{
    pDwData[0] = pCan->CAN_MB[bMb].CAN_MDL;
    pDwData[1] = pCan->CAN_MB[bMb].CAN_MDH;
}

/**
 * \brief Set CAN Message Data in u64
 * \param pCan       Pointer to Can instance.
 * \param bMb        Mailbox number.
 */
void CAN_SetMessageData64(Can *pCan, uint8_t bMb, uint64_t u64)
{
    pCan->CAN_MB[bMb].CAN_MDL = (uint32_t)u64;
    pCan->CAN_MB[bMb].CAN_MDH = (u64 >> 32);
}

/**
 * \brief Return CAN Message Data in u64
 * \param pCan       Pointer to Can instance.
 * \param bMb        Mailbox number.
 */
uint64_t CAN_GetMessageData64(Can *pCan, uint8_t bMb)
{
    uint64_t ddwMd = (uint64_t)pCan->CAN_MB[bMb].CAN_MDH << 32;
    ddwMd += pCan->CAN_MB[bMb].CAN_MDL;
    return ddwMd;
}

/**
 * \brief Set CAN Message Control Register (_MCRx).
 * \param pCan       Pointer to Can instance.
 * \param bMb        Mailbox number.
 * \param dwCtrl     Control value.
 */
void CAN_MessageControl(Can *pCan, uint8_t bMb, uint32_t dwCtrl)
{
    pCan->CAN_MB[bMb].CAN_MCR = dwCtrl;
}

/**
 * \brief Start remote frame.
 * \param pCan       Pointer to Can instance.
 * \param bMb        Mailbox number.
 */
void CAN_MessageRemote(Can *pCan, uint8_t bMb)
{
    pCan->CAN_MB[bMb].CAN_MCR = CAN_MCR_MRTR;
}

/**
 * \brief Abort transmission.
 * \param pCan       Pointer to Can instance.
 * \param bMb        Mailbox number.
 */
void CAN_MessageAbort(Can *pCan, uint8_t bMb)
{
    pCan->CAN_MB[bMb].CAN_MCR = CAN_MCR_MACR;
}

/**
 * \brief Start transmission.
 * \param pCan       Pointer to Can instance.
 * \param bMb        Mailbox number.
 * \param bLen       Message length.
 */
void CAN_MessageTx(Can *pCan, uint8_t bMb, uint8_t bLen)
{
    pCan->CAN_MB[bMb].CAN_MCR = CAN_MCR_MTCR | CAN_MCR_MDLC(bLen);
}

/**
 * \brief Start reception.
 * \param pCan       Pointer to Can instance.
 * \param bMb        Mailbox number.
 */
void CAN_MessageRx(Can *pCan, uint8_t bMb)
{
    pCan->CAN_MB[bMb].CAN_MCR = CAN_MCR_MTCR;
}

#endif
/**@}*/

