/*
  Copyright (c) 2013 Arduino.  All right reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  See the GNU Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/


#include "CAN.h"
#include "sn65hvd234.h"

/** Define the timemark mask. */
#define TIMEMARK_MASK              0x0000ffff

/* CAN timeout for synchronization. */
#define CAN_TIMEOUT                100000

/** The max value for CAN baudrate prescale. */
#define CAN_BAUDRATE_MAX_DIV       128

/** Define the scope for TQ. */
#define CAN_MIN_TQ_NUM             8
#define CAN_MAX_TQ_NUM             25

/** Define the fixed bit time value. */
#define CAN_BIT_SYNC               1
#define CAN_BIT_IPT                2

typedef struct {
	uint8_t uc_tq;      //! CAN_BIT_SYNC + uc_prog + uc_phase1 + uc_phase2 = uc_tq, 8 <= uc_tq <= 25.
	uint8_t uc_prog;    //! Propagation segment, (3-bits + 1), 1~8;
	uint8_t uc_phase1;  //! Phase segment 1, (3-bits + 1), 1~8;
	uint8_t uc_phase2;  //! Phase segment 2, (3-bits + 1), 1~8, CAN_BIT_IPT <= uc_phase2;
	uint8_t uc_sjw;     //! Resynchronization jump width, (2-bits + 1), min(uc_phase1, 4);
	uint8_t uc_sp;      //! Sample point value, 0~100 in percent.
} can_bit_timing_t;


/** Values of bit time register for different baudrates, Sample point = ((1 + uc_prog + uc_phase1) / uc_tq) * 100%. */
const can_bit_timing_t can_bit_time[] = {
	{8,   (2 + 1), (1 + 1), (1 + 1), (2 + 1), 75},
	{9,   (1 + 1), (2 + 1), (2 + 1), (1 + 1), 67},
	{10,  (2 + 1), (2 + 1), (2 + 1), (2 + 1), 70},
	{11,  (3 + 1), (2 + 1), (2 + 1), (3 + 1), 72},
	{12,  (2 + 1), (3 + 1), (3 + 1), (3 + 1), 67},
	{13,  (3 + 1), (3 + 1), (3 + 1), (3 + 1), 77},
	{14,  (3 + 1), (3 + 1), (4 + 1), (3 + 1), 64},
	{15,  (3 + 1), (4 + 1), (4 + 1), (3 + 1), 67},
	{16,  (4 + 1), (4 + 1), (4 + 1), (3 + 1), 69},
	{17,  (5 + 1), (4 + 1), (4 + 1), (3 + 1), 71},
	{18,  (4 + 1), (5 + 1), (5 + 1), (3 + 1), 67},
	{19,  (5 + 1), (5 + 1), (5 + 1), (3 + 1), 68},
	{20,  (6 + 1), (5 + 1), (5 + 1), (3 + 1), 70},
	{21,  (7 + 1), (5 + 1), (5 + 1), (3 + 1), 71},
	{22,  (6 + 1), (6 + 1), (6 + 1), (3 + 1), 68},
	{23,  (7 + 1), (7 + 1), (6 + 1), (3 + 1), 70},
	{24,  (6 + 1), (7 + 1), (7 + 1), (3 + 1), 67},
	{25,  (7 + 1), (7 + 1), (7 + 1), (3 + 1), 68}
};

/**
 * \brief Configure CAN baudrate.
 *
 * \param p_can       Pointer to a CAN peripheral instance.
 * \param ul_mck      The input main clock for the CAN module.
 * \param ul_baudrate Baudrate value (kB/s), allowed values:
 *                    1000, 800, 500, 250, 125, 50, 25, 10, 5.
 *
 * \retval Set the baudrate successfully or not.
 */
uint32_t CANRaw::set_baudrate(Can *p_can, uint32_t ul_mck, uint32_t ul_baudrate)
{
	uint8_t uc_tq;
	uint8_t uc_prescale;
	uint32_t ul_mod;
	uint32_t ul_cur_mod;
	can_bit_timing_t *p_bit_time;

	/* Check whether the baudrate prescale will be greater than the max divide value. */
	if (((ul_mck + (ul_baudrate * CAN_MAX_TQ_NUM * 1000 - 1)) /
		(ul_baudrate * CAN_MAX_TQ_NUM * 1000)) > CAN_BAUDRATE_MAX_DIV) {
		return 0;
	}

	/* Check whether the input MCK is too small. */
	if (ul_mck  < ul_baudrate * CAN_MIN_TQ_NUM * 1000) {
		return 0;
	}

	/* Initialize it as the minimum Time Quantum. */
	uc_tq = CAN_MIN_TQ_NUM;

	/* Initialize the remainder as the max value. When the remainder is 0, get the right TQ number. */
	ul_mod = 0xffffffff;
	/* Find out the approximate Time Quantum according to the baudrate. */
	for (uint8_t i = CAN_MIN_TQ_NUM; i <= CAN_MAX_TQ_NUM; i++) {
		if ((ul_mck / (ul_baudrate * i * 1000)) <= CAN_BAUDRATE_MAX_DIV) {
			ul_cur_mod = ul_mck % (ul_baudrate * i * 1000);
			if (ul_cur_mod < ul_mod){
				ul_mod = ul_cur_mod;
				uc_tq = i;
				if (!ul_mod) {
					break;
				}
			}
		}
	}

	/* Calculate the baudrate prescale value. */
	uc_prescale = ul_mck / (ul_baudrate * uc_tq * 1000);

	/* Get the right CAN BIT Timing group. */
	p_bit_time = (can_bit_timing_t *)&can_bit_time[uc_tq - CAN_MIN_TQ_NUM];

	/* Before modifying the CANBR register, disable the CAN controller. */
	//can_disable(p_can);
    p_can->CAN_MR &= ~CAN_MR_CANEN;

	/* Write into the CAN baudrate register. */
	p_can->CAN_BR = CAN_BR_PHASE2(p_bit_time->uc_phase2 - 1) |
					CAN_BR_PHASE1(p_bit_time->uc_phase1 - 1) |
					CAN_BR_PROPAG(p_bit_time->uc_prog - 1) |
					CAN_BR_SJW(p_bit_time->uc_sjw - 1) |
					CAN_BR_BRP(uc_prescale - 1);
	return 1;
}

/**
 * \brief Initialize CAN controller.
 *
 * \param p_can  Pointer to a CAN peripheral instance.
 * \param ul_mck CAN module input clock.
 * \param ul_baudrate CAN communication baudrate in kbs.
 *
 * \retval 0 If failed to initialize the CAN module; otherwise successful.
 *
 * \note PMC clock for CAN peripheral should be enabled before calling this function.
 */
uint32_t CANRaw::init(Can *p_can, uint32_t ul_mck, uint32_t ul_baudrate)
{
	uint32_t ul_flag;
	uint32_t ul_tick;

	/* Initialize the baudrate for CAN module. */
	ul_flag = set_baudrate(p_can, ul_mck, ul_baudrate);
	if (ul_flag == 0) {
		return 0;
	}

	/* Reset the CAN eight message mailbox. */
	can_reset_all_mailbox(p_can);

	/* Enable the CAN controller. */
	can_enable(p_can);

	/* Wait until the CAN is synchronized with the bus activity. */
	ul_flag = 0;
	ul_tick = 0;
	while (!(ul_flag & CAN_SR_WAKEUP) && (ul_tick < CAN_TIMEOUT)) {
		ul_flag = can_get_status(p_can);
		ul_tick++;
	}

	/* Timeout or the CAN module has been synchronized with the bus. */
	if (CAN_TIMEOUT == ul_tick) {
		return 0;
	} else {
		return 1;
	}
}

/**
 * \brief Enable CAN Controller.
 *
 * \param p_can  Pointer to a CAN peripheral instance.
 */
void CANRaw::enable(Can *p_can)
{
	p_can->CAN_MR |= CAN_MR_CANEN;
}

/**
 * \brief Disable CAN Controller.
 *
 * \param p_can  Pointer to a CAN peripheral instance.
 */
void CANRaw::disable(Can *p_can)
{
	p_can->CAN_MR &= ~CAN_MR_CANEN;
}

/**
 * \brief Disable CAN Controller low power mode.
 *
 * \param p_can  Pointer to a CAN peripheral instance.
 */
void CANRaw::disable_low_power_mode(Can *p_can)
{
	p_can->CAN_MR &= ~CAN_MR_LPM;
}

/**
 * \brief Enable CAN Controller low power mode.
 *
 * \param p_can  Pointer to a CAN peripheral instance.
 */
void CANRaw::enable_low_power_mode(Can *p_can)
{
	p_can->CAN_MR |= CAN_MR_LPM;
}

/**
 * \brief Disable CAN Controller autobaud/listen mode.
 *
 * \param p_can  Pointer to a CAN peripheral instance.
 */
void CANRaw::disable_autobaud_listen_mode(Can *p_can)
{
	p_can->CAN_MR &= ~CAN_MR_ABM;
}

/**
 * \brief Enable CAN Controller autobaud/listen mode.
 *
 * \param p_can  Pointer to a CAN peripheral instance.
 */
void CANRaw::enable_autobaud_listen_mode(Can *p_can)
{
	p_can->CAN_MR |= CAN_MR_ABM;
}

/**
 * \brief CAN Controller won't generate overload frame.
 *
 * \param p_can  Pointer to a CAN peripheral instance.
 */
void CANRaw::disable_overload_frame(Can *p_can)
{
	p_can->CAN_MR &= ~CAN_MR_OVL;
}

/**
 * \brief CAN Controller will generate an overload frame after each successful
 * reception for mailboxes configured in Receive mode, Producer and Consumer.
 *
 * \param p_can  Pointer to a CAN peripheral instance.
 */
void CANRaw::enable_overload_frame(Can *p_can)
{
	p_can->CAN_MR |= CAN_MR_OVL;
}

/**
 * \brief Configure the timestamp capture point, at the start or the end of frame.
 *
 * \param p_can   Pointer to a CAN peripheral instance.
 * \param ul_flag 0: Timestamp is captured at each start of frame;
 *                1: Timestamp is captured at each end of frame.
 */
void CANRaw::set_timestamp_capture_point(Can *p_can, uint32_t ul_flag)
{
	if (ul_flag) {
		p_can->CAN_MR |= CAN_MR_TEOF;
	} else {
		p_can->CAN_MR &= ~CAN_MR_TEOF;
	}
}

/**
 * \brief Disable CAN Controller time triggered mode.
 *
 * \param p_can  Pointer to a CAN peripheral instance.
 */
void CANRaw::disable_time_triggered_mode(Can *p_can)
{
	p_can->CAN_MR &= ~CAN_MR_TTM;
}

/**
 * \brief Enable CAN Controller time triggered mode.
 *
 * \param p_can  Pointer to a CAN peripheral instance.
 */
void CANRaw::enable_time_triggered_mode(Can *p_can)
{
	p_can->CAN_MR |= CAN_MR_TTM;
}

/**
 * \brief Disable CAN Controller timer freeze.
 *
 * \param p_can  Pointer to a CAN peripheral instance.
 */
void CANRaw::disable_timer_freeze(Can *p_can)
{
	p_can->CAN_MR &= ~CAN_MR_TIMFRZ;
}

/**
 * \brief Enable CAN Controller timer freeze.
 *
 * \param p_can  Pointer to a CAN peripheral instance.
 */
void CANRaw::enable_timer_freeze(Can *p_can)
{
	p_can->CAN_MR |= CAN_MR_TIMFRZ;
}

/**
 * \brief Disable CAN Controller transmit repeat function.
 *
 * \param p_can  Pointer to a CAN peripheral instance.
 */
void CANRaw::disable_tx_repeat(Can *p_can)
{
	p_can->CAN_MR |= CAN_MR_DRPT;
}

/**
 * \brief Enable CAN Controller transmit repeat function.
 *
 * \param p_can  Pointer to a CAN peripheral instance.
 */
void CANRaw::enable_tx_repeat(Can *p_can)
{
	p_can->CAN_MR &= ~CAN_MR_DRPT;
}

/**
 * \brief Configure CAN Controller reception synchronization stage.
 *
 * \param p_can    Pointer to a CAN peripheral instance.
 * \param ul_stage The reception stage to be configured.
 *
 * \note This is just for debug purpose only.
 */
void CANRaw::set_rx_sync_stage(Can *p_can, uint32_t ul_stage)
{
	p_can->CAN_MR = (p_can->CAN_MR & ~CAN_MR_RXSYNC_Msk) | ul_stage;
}

/**
 * \brief Enable CAN interrupt.
 *
 * \param p_can  Pointer to a CAN peripheral instance.
 * \param dw_mask Interrupt to be enabled.
 */
void CANRaw::enable_interrupt(Can *p_can, uint32_t dw_mask)
{
	p_can->CAN_IER = dw_mask;
}

/**
 * \brief Disable CAN interrupt.
 *
 * \param p_can  Pointer to a CAN peripheral instance.
 * \param dw_mask Interrupt to be disabled.
 */
void CANRaw::disable_interrupt(Can *p_can, uint32_t dw_mask)
{
	p_can->CAN_IDR = dw_mask;
}

/**
 * \brief Get CAN Interrupt Mask.
 *
 * \param p_can Pointer to a CAN peripheral instance.
 *
 * \retval CAN interrupt mask.
 */
uint32_t CANRaw::get_interrupt_mask(Can *p_can)
{
	return (p_can->CAN_IMR);
}

/**
 * \brief Get CAN status.
 *
 * \param p_can Pointer to a CAN peripheral instance.
 *
 * \retval CAN status.
 */
uint32_t CANRaw::get_status(Can *p_can)
{
	return (p_can->CAN_SR);
}

/**
 * \brief Get the 16-bit free-running internal timer count.
 *
 * \param p_can Pointer to a CAN peripheral instance.
 *
 * \retval The internal CAN free-running timer counter.
 */
uint32_t CANRaw::get_internal_timer_value(Can *p_can)
{
	return (p_can->CAN_TIM);
}

/**
 * \brief Get CAN timestamp register value.
 *
 * \param p_can Pointer to a CAN peripheral instance.
 *
 * \retval The timestamp value.
 */
uint32_t CANRaw::get_timestamp_value(Can *p_can)
{
	return (p_can->CAN_TIMESTP);
}

/**
 * \brief Get CAN transmit error counter.
 *
 * \param p_can Pointer to a CAN peripheral instance.
 *
 * \retval Transmit error counter.
 */
uint8_t CANRaw::get_tx_error_cnt(Can *p_can)
{
	return (uint8_t) (p_can->CAN_ECR >> CAN_ECR_TEC_Pos);
}

/**
 * \brief Get CAN receive error counter.
 *
 * \param p_can Pointer to a CAN peripheral instance.
 *
 * \retval Receive error counter.
 */
uint8_t CANRaw::get_rx_error_cnt(Can *p_can)
{
	return (uint8_t) (p_can->CAN_ECR >> CAN_ECR_REC_Pos);
}

/**
 * \brief Reset the internal free-running 16-bit timer.
 *
 * \param p_can Pointer to a CAN peripheral instance.
 *
 * \note If the internal timer counter is frozen, this function automatically
 * re-enables it.
 */
void CANRaw::reset_internal_timer(Can *p_can)
{
	p_can->CAN_TCR |= CAN_TCR_TIMRST;
}

/**
 * \brief Send global transfer request.
 *
 * \param p_can   Pointer to a CAN peripheral instance.
 * \param uc_mask Mask for mailboxes that are requested to transfer.
 */
void CANRaw::global_send_transfer_cmd(Can *p_can, uint8_t uc_mask)
{
	uint32_t ul_reg;

	ul_reg = p_can->CAN_TCR & ((uint32_t)~GLOBAL_MAILBOX_MASK);
	p_can->CAN_TCR = ul_reg | uc_mask;
}

/**
 * \brief Send global abort request.
 *
 * \param p_can   Pointer to a CAN peripheral instance.
 * \param uc_mask Mask for mailboxes that are requested to abort.
 */
void CANRaw::global_send_abort_cmd(Can *p_can, uint8_t uc_mask)
{
	uint32_t ul_reg;

	ul_reg = p_can->CAN_ACR & ((uint32_t)~GLOBAL_MAILBOX_MASK);
	p_can->CAN_ACR = ul_reg | uc_mask;
}

/**
 * \brief Configure the timemark for the mailbox.
 *
 * \param p_can    Pointer to a CAN peripheral instance.
 * \param uc_index Indicate which mailbox is to be configured.
 * \param us_cnt   The timemark to be set.
 *
 * \note The timemark is active in Time Triggered mode only.
 */
void CANRaw::mailbox_set_timemark(Can *p_can, uint8_t uc_index, uint16_t us_cnt)
{
	uint32_t ul_reg;

	ul_reg = p_can->CAN_MB[uc_index].CAN_MMR & ((uint32_t)~TIMEMARK_MASK);
	p_can->CAN_MB[uc_index].CAN_MMR = ul_reg | us_cnt;
}

/**
 * \brief Get status of the mailbox.
 *
 * \param p_can    Pointer to a CAN peripheral instance.
 * \param uc_index Indicate which mailbox is to be read.
 *
 * \retval The mailbox status.
 */
uint32_t CANRaw::mailbox_get_status(Can *p_can, uint8_t uc_index)
{
	return (p_can->CAN_MB[uc_index].CAN_MSR);
}

/**
 * \brief Send single mailbox transfer request.
 *
 * \param p_can   Pointer to a CAN peripheral instance.
 * \param uc_index Indicate which mailbox is to be configured.
 */
void CANRaw::mailbox_send_transfer_cmd(Can *p_can, uint8_t uc_index)
{
	p_can->CAN_MB[uc_index].CAN_MCR |= CAN_MCR_MTCR;
}

/**
 * \brief Send single mailbox abort request.
 *
 * \param p_can    Pointer to a CAN peripheral instance.
 * \param uc_index Indicate which mailbox is to be configured.
 */
void CANRaw::mailbox_send_abort_cmd(Can *p_can, uint8_t uc_index)
{
	p_can->CAN_MB[uc_index].CAN_MCR |= CAN_MCR_MACR;
}

/**
 * \brief Initialize the mailbox in different mode and set up related configuration.
 *
 * \param p_can    Pointer to a CAN peripheral instance.
 * \param p_mailbox Pointer to a CAN mailbox instance.
 */
void CANRaw::mailbox_init(Can *p_can, can_mb_conf_t *p_mailbox)
{
	uint8_t uc_index;

	uc_index = (uint8_t)p_mailbox->ul_mb_idx;
	/* Check the object type of the mailbox. If it's used to disable the mailbox, reset the whole mailbox. */
	if (!p_mailbox->uc_obj_type) {
		p_can->CAN_MB[uc_index].CAN_MMR = 0;
		p_can->CAN_MB[uc_index].CAN_MAM = 0;
		p_can->CAN_MB[uc_index].CAN_MID = 0;
		p_can->CAN_MB[uc_index].CAN_MDL = 0;
		p_can->CAN_MB[uc_index].CAN_MDH = 0;
		p_can->CAN_MB[uc_index].CAN_MCR = 0;
		return;
	}

	/* Set the priority in Transmit mode. */
	p_can->CAN_MB[uc_index].CAN_MMR = (p_can->CAN_MB[uc_index].CAN_MMR &
		~CAN_MMR_PRIOR_Msk) | (p_mailbox-> uc_tx_prio << CAN_MMR_PRIOR_Pos);

	/* Set the message ID and message acceptance mask for the mailbox in other modes. */
	if (p_mailbox->uc_id_ver) {
		p_can->CAN_MB[uc_index].CAN_MAM = p_mailbox->ul_id_msk | CAN_MAM_MIDE;
		p_can->CAN_MB[uc_index].CAN_MID = p_mailbox->ul_id | CAN_MAM_MIDE;
	} else {
		p_can->CAN_MB[uc_index].CAN_MAM = p_mailbox->ul_id_msk;
		p_can->CAN_MB[uc_index].CAN_MID = p_mailbox->ul_id;
	}

	/* Set up mailbox in one of the five different modes. */
	p_can->CAN_MB[uc_index].CAN_MMR = (p_can->CAN_MB[uc_index].CAN_MMR &
		~CAN_MMR_MOT_Msk) | (p_mailbox-> uc_obj_type << CAN_MMR_MOT_Pos);
}

/**
 * \brief Read receive information for the mailbox.
 *
 * \param p_can     Pointer to a CAN peripheral instance.
 * \param p_mailbox Pointer to a CAN mailbox instance.
 *
 * \retval Different CAN mailbox transfer status.
 *
 * \note Read the mailbox status before calling this function.
 */
uint32_t CANRaw::mailbox_read(Can *p_can, can_mb_conf_t *p_mailbox)
{
	uint32_t ul_status;
	uint8_t uc_index;
	uint32_t ul_retval;

	ul_retval = 0;
	uc_index = (uint8_t)p_mailbox->ul_mb_idx;
	ul_status = p_mailbox->ul_status;

	/* Check whether there is overwriting happening in Receive with Overwrite mode,
	   or there're messages lost in Receive mode. */
	if ((ul_status & CAN_MSR_MRDY) && (ul_status & CAN_MSR_MMI)) {
		ul_retval = CAN_MAILBOX_RX_OVER;
	}

	/* Read the message family ID. */
	p_mailbox->ul_fid = p_can->CAN_MB[uc_index].CAN_MFID & CAN_MFID_MFID_Msk;

	/* Read received data length. */
	p_mailbox->uc_length = (ul_status & CAN_MSR_MDLC_Msk) >> CAN_MSR_MDLC_Pos;

	/* Read received data. */
	p_mailbox->ul_datal = p_can->CAN_MB[uc_index].CAN_MDL;
	if (p_mailbox->uc_length > 4) {
		p_mailbox->ul_datah = p_can->CAN_MB[uc_index].CAN_MDH;
	}

	/* Read the mailbox status again to check whether the software needs to re-read mailbox data register. */
	p_mailbox->ul_status = p_can->CAN_MB[uc_index].CAN_MSR;
	ul_status = p_mailbox->ul_status;
	if (ul_status & CAN_MSR_MMI) {
		ul_retval |= CAN_MAILBOX_RX_NEED_RD_AGAIN;
	} else {
		ul_retval |= CAN_MAILBOX_TRANSFER_OK;
	}

	/* Enable next receive process. */
	can_mailbox_send_transfer_cmd(p_can, uc_index);

	return ul_retval;
}

/**
 * \brief Prepare transmit information and write them into the mailbox.
 *
 * \param p_can     Pointer to a CAN peripheral instance.
 * \param p_mailbox Pointer to a CAN mailbox instance.
 *
 * \retval CAN_MAILBOX_NOT_READY: Failed because mailbox isn't ready.
 *       CAN_MAILBOX_TRANSFER_OK: Successfully write message into mailbox.
 *
 * \note After calling this function, the mailbox message won't be sent out until
 * can_mailbox_send_transfer_cmd() is called.
 */
uint32_t CANRaw::mailbox_write(Can *p_can, can_mb_conf_t *p_mailbox)
{
	uint32_t ul_status;
	uint8_t uc_index;

	uc_index = (uint8_t)p_mailbox->ul_mb_idx;
	/* Read the mailbox status firstly to check whether the mailbox is ready or not. */
	p_mailbox->ul_status = can_mailbox_get_status(p_can, uc_index);
	ul_status = p_mailbox->ul_status;
	if (!(ul_status & CAN_MSR_MRDY)) {
		return CAN_MAILBOX_NOT_READY;
	}

	/* Write transmit identifier. */
	if (p_mailbox->uc_id_ver) {
		p_can->CAN_MB[uc_index].CAN_MID = p_mailbox->ul_id | CAN_MAM_MIDE;
	} else {
		p_can->CAN_MB[uc_index].CAN_MID = p_mailbox->ul_id;
	}

	/* Write transmit data into mailbox data register. */
	p_can->CAN_MB[uc_index].CAN_MDL = p_mailbox->ul_datal;
	if (p_mailbox->uc_length > 4) {
		p_can->CAN_MB[uc_index].CAN_MDH = p_mailbox->ul_datah;
	}

	/* Write transmit data length into mailbox control register. */
	p_can->CAN_MB[uc_index].CAN_MCR = (p_can->CAN_MB[uc_index].CAN_MCR &
			~CAN_MCR_MDLC_Msk) | CAN_MCR_MDLC(p_mailbox->uc_length);

	return CAN_MAILBOX_TRANSFER_OK;
}

/**
 * \brief Require to send out a remote frame.
 *
 * \param p_can    Pointer to a CAN peripheral instance.
 * \param p_mailbox Pointer to a CAN mailbox instance.
 *
 * \retval CAN_MAILBOX_NOT_READY: Failed because mailbox isn't ready for transmitting message.
 *       CAN_MAILBOX_TRANSFER_OK: Successfully send out a remote frame.
 */
uint32_t CANRaw::mailbox_tx_remote_frame(Can *p_can, can_mb_conf_t *p_mailbox)
{
	uint32_t ul_status;
	uint8_t uc_index;

	uc_index = (uint8_t)p_mailbox->ul_mb_idx;
	/* Read the mailbox status firstly to check whether the mailbox is ready or not. */
	p_mailbox->ul_status = p_can->CAN_MB[uc_index].CAN_MSR;
	ul_status = p_mailbox->ul_status;
	if (!(ul_status & CAN_MSR_MRDY)) {
		return CAN_MAILBOX_NOT_READY;
	}

	/* Write transmit identifier. */
	if (p_mailbox->uc_id_ver) {
		p_can->CAN_MB[uc_index].CAN_MID = p_mailbox->ul_id | CAN_MAM_MIDE;
	} else {
		p_can->CAN_MB[uc_index].CAN_MID = p_mailbox->ul_id;
	}

	/* Set the RTR bit in the sent frame. */
	p_can->CAN_MB[uc_index].CAN_MCR |= CAN_MCR_MRTR;

	/* Set the MBx bit in the Transfer Command Register to send out the remote frame. */
	can_global_send_transfer_cmd(p_can, (1 << uc_index));

	return CAN_MAILBOX_TRANSFER_OK;
}

/**
 * \brief Reset the eight mailboxes.
 *
 * \param p_can Pointer to a CAN peripheral instance.
 */
void CANRaw::reset_all_mailbox(Can *p_can)
{
	can_mb_conf_t mb_config_t;

	/* Set the mailbox object type parameter to disable the mailbox. */
	mb_config_t.uc_obj_type = CAN_MB_DISABLE_MODE;

	for (uint8_t i = 0; i < CANMB_NUMBER; i++) {
		mb_config_t.ul_mb_idx = i;
		can_mailbox_init(p_can, &mb_config_t);
	}
}