/**
  ******************************************************************************
  * @file    hal_dac.c
  * @brief   DAC module driver.
  *
  * @version V1.0
  * @date    15 Dec 2017
  * @author  AE Team.
  * @note
  *
  * Copyright (C) Shanghai Eastsoft Microelectronics Co. Ltd. All rights reserved.
  *
  *********************************************************************************
  */

#include "hal_dac.h"


/** @addtogroup ES32FXXX_HAL
  * @{
  */

/** @defgroup DAC DAC
  * @brief DAC module driver
  * @{
  */
#ifdef HAL_DAC

/** @defgroup DAC_Public_Functions DAC Public Functions
  * @{
  */
/**
  * @brief  Reset the dac mode.
  * @param  hperh: Pointer to a dac_handle_t structure that contains
  *         the configuration information for the specified DAC module.
  * @retval Status, see @ref hal_status_t.
  */
hal_status_t dac_reset(dac_handle_t *hperh)
{
	if (hperh == NULL)
		return ERROR;

	assert_param(IS_DAC_TYPE(hperh->perh));

	hperh->perh->CTRL.Word     = 0;
	hperh->perh->CH0CTRL.Word  = 0;
	hperh->perh->CH1CTRL.Word  = 0;
	hperh->perh->IES.Word      = 0;
	hperh->perh->IEC.Word      = 0xF;
	hperh->perh->IFM.Word      = 0;
	hperh->perh->IFC.Word      = 0xF;
	hperh->perh->CH0DATA.Word  = 0;
	hperh->perh->CH1DATA.Word  = 0;
	hperh->perh->COMBDATA.Word = 0;
	hperh->perh->CAL.Word      = 0;
	hperh->perh->BIASPROG.Word = 0;

	return OK;
}

/**
  * @brief  Initializes the DAC peripheral.
  * @param  hperh: Pointer to a dac_handle_t structure that contains
  *         the configuration information for the specified DAC module.
  * @retval Status, see @ref hal_status_t.
  */
hal_status_t dac_init(dac_handle_t *hperh)
{
	if (hperh == NULL)
		return ERROR;

	assert_param(IS_DAC_TYPE(hperh->perh));
	assert_param(IS_DAC_CONVERT_TYPE(hperh->init.convert_mode));
	assert_param(IS_DAC_OUTPUT_TYPE(hperh->init.out_mode));
	assert_param(IS_DAC_REFERENCE_TYPE(hperh->init.reference));
	assert_param(IS_DAC_REFRESH_TYPE(hperh->init.refresh));
	assert_param(IS_DAC_PRESCALE_TYPE(hperh->init.prescale));
	assert_param(IS_DAC_FUNCTION_TYPE(hperh->init.ch0reset_prs));
	assert_param(IS_DAC_FUNCTION_TYPE(hperh->init.outenable_prs));
	assert_param(IS_DAC_FUNCTION_TYPE(hperh->init.sine_enable));
	assert_param(IS_DAC_FUNCTION_TYPE(hperh->init.diff));

	__LOCK(hperh);

	DAC_CH0_DISABLE();
	DAC_CH1_DISABLE();

	hperh->perh->CTRL.REFRSEL     = hperh->init.refresh;
	hperh->perh->CTRL.PRESC       = hperh->init.prescale;
	hperh->perh->CTRL.REFSEL      = hperh->init.reference;
	hperh->perh->CTRL.CH0PRESCRST = hperh->init.ch0reset_prs;
	hperh->perh->CTRL.OUTENPRS    = hperh->init.outenable_prs;
	hperh->perh->CTRL.OUTMODE     = hperh->init.out_mode;
	hperh->perh->CTRL.CONVMODE    = hperh->init.convert_mode;
	hperh->perh->CTRL.SINEMODE    = hperh->init.sine_enable;
	hperh->perh->CTRL.DIFF        = hperh->init.diff;
	hperh->perh->CAL.SELF_CALEN   = hperh->init.self_calen;

	__UNLOCK(hperh);
	return OK;
}

/**
  * @brief  Config dac channel.
  * @param  hperh: Pointer to a dac_handle_t structure that contains
  *         the configuration information for the specified DAC module.
  * @param  config: Pointer to a dac_channel_config_t structure that contains
  *         the configutation information for dac channel.
  * @param  ch: Specifies which dac channel to be config.
  * @retval Status, see @ref hal_status_t.
  */
hal_status_t dac_channel_config(dac_handle_t *hperh, dac_channel_config_t *config, dac_channel_t ch)
{
	if ((hperh == NULL) || (config == NULL))
		return ERROR;

	assert_param(IS_DAC_TYPE(hperh->perh));
	assert_param(IS_DAC_FUNCTION_TYPE(config->enable));
	assert_param(IS_DAC_TRIGGER_TYPE(config->trigger));
	assert_param(IS_DAC_FUNCTION_TYPE(config->refresh_enable));
	assert_param(IS_DAC_PRSSEL_CH_TYPE(config->prs_sel));

	__LOCK(hperh);

	switch (ch) {
	case DAC_CHANNEL_0:
		hperh->perh->CH0CTRL.PRSSEL = config->prs_sel;
		hperh->perh->CH0CTRL.PRSEN  = config->trigger;
		hperh->perh->CH0CTRL.REFREN = config->refresh_enable;
		hperh->perh->CH0CTRL.EN     = config->enable;
		break;

	case DAC_CHANNEL_1:
		hperh->perh->CH1CTRL.PRSSEL = config->prs_sel;
		hperh->perh->CH1CTRL.PRSEN  = config->trigger;
		hperh->perh->CH1CTRL.REFREN = config->refresh_enable;
		hperh->perh->CH1CTRL.EN     = config->enable;
		break;

	default:
		break;
	}

	__UNLOCK(hperh);
	return OK;
}

/**
  * @brief  Set dac channel output value.
  * @param  hperh: Pointer to a dac_handle_t structure that contains
  *         the configuration information for the specified DAC module.
  * @param  ch: Specifies which dac channel to be set.
  * @param  value: The value be converted,and the valid value is low 12 bit.
  * @retval Status, see @ref hal_status_t.
  */
hal_status_t dac_ch_output_set(dac_handle_t *hperh, dac_channel_t ch, uint32_t value)
{
	if (hperh == NULL)
		return ERROR;

	assert_param(IS_DAC_TYPE(hperh->perh));
	assert_param(IS_DAC_CHANNEL_TYPE(ch));

	__LOCK(hperh);

	switch (ch) {
	case DAC_CHANNEL_0:
		hperh->perh->CH0DATA.Word = value;
		break;

	case DAC_CHANNEL_1:
		hperh->perh->CH1DATA.Word = value;
		break;

	default:
		break;
	}

	__UNLOCK(hperh);
	return OK;
}

/**
 * @brief Checks whether the specified DAC flag is set or not.
 * @param hperh: Pointer to a dac_handle_t structure that contains
 *               the configuration information for the specified dac.
 * @param dac_flag: Specifies the flag to check.
 * @retval The new state of DAC_FLAG
 */
flag_status_t dac_get_status(dac_handle_t *hperh, dac_flag_t dac_flag)
{
	assert_param(IS_DAC_TYPE(hperh->perh));
	assert_param(IS_DAC_FLAG_TYPE(dac_flag));

	return hperh->perh->STATUS.Word & dac_flag ? SET : RESET;
}

/**
 * @brief Enable or disable the specified interrupt
 * @param hperh: Pointer to a dac_handle_t structure that contains
 *               the configuration information for the specified DAC.
 * @param interrupt: Specifies the interrupt type to be enabled or disabled
 *        @arg @ref DAC_IT_CH0 Channel 0 conversion complete interrupt
 *        @arg @ref DAC_IT_CH1 Channel 1 conversion complete interrupt
 *        @arg @ref DAC_IT_CH0_UF Channel 0 data underflow interrupt
 *        @arg @ref DAC_IT_CH1_UF Channel 1 data underflow interrupt
 * @param state: New state of the specified interrupt.
 *        This parameter can be: ENABLE or DISABLE
 * @retval Status, see @ref hal_status_t.
 */
hal_status_t dac_interrupt_config(dac_handle_t *hperh, dac_it_t interrupt, type_func_t state)
{
	if (hperh == NULL)
		return ERROR;

	assert_param(IS_DAC_TYPE(hperh->perh));
	assert_param(IS_DAC_INTERRUPT_TYPE(interrupt));
	assert_param(IS_FUNC_STATE(state));
	__LOCK(hperh);

	if (state)
		hperh->perh->IES.Word |= interrupt;
	else
		hperh->perh->IES.Word &= ~interrupt;

	__UNLOCK(hperh);
	return OK;
}

/**
 * @brief Checks whether the specified interrupt has occurred or not.
 * @param hperh: Pointer to a dac_handle_t structure that contains
 *               the configuration information for the specified DAC.
 * @param interrupt: Specifies the interrupt type to check
 *        This parameter can be one of the following values:
 *        @arg @ref DAC_IT_CH0 Channel 0 conversion complete interrupt
 *        @arg @ref DAC_IT_CH1 Channel 1 conversion complete interrupt
 *        @arg @ref DAC_IT_CH0_UF Channel 0 data underflow interrupt
 *        @arg @ref DAC_IT_CH1_UF Channel 1 data underflow interrupt
 * @retval The new state of the DAC_IT
 */
it_status_t dac_get_it_status(dac_handle_t *hperh, dac_it_t interrupt)
{
	assert_param(IS_DAC_TYPE(hperh->perh));
	assert_param(IS_DAC_INTERRUPT_TYPE(interrupt));

	return hperh->perh->RIF.Word & interrupt ? SET : RESET;
}

/**
 * @brief Clear interrupt state flag
 * @param hperh: Pointer to a dac_handle_t structure that contains
 *               the configuration information for the specified DAC.
 * @param interrupt: Specifies the interrupt type to clear
 *        This parameter can be one of the following values:
 *        @arg @ref DAC_IT_CH0 Channel 0 conversion complete interrupt
 *        @arg @ref DAC_IT_CH1 Channel 1 conversion complete interrupt
 *        @arg @ref DAC_IT_CH0_UF Channel 0 data underflow interrupt
 *        @arg @ref DAC_IT_CH1_UF Channel 1 data underflow interrupt
 * @retval Status, see @ref hal_status_t.
 */
hal_status_t dac_clear_it_status(dac_handle_t *hperh, dac_it_t interrupt)
{
	if (hperh == NULL)
		return ERROR;

	assert_param(IS_DAC_TYPE(hperh->perh));
	assert_param(IS_DAC_INTERRUPT_TYPE(interrupt));
	__LOCK(hperh);

	hperh->perh->IFC.Word |= interrupt;

	__UNLOCK(hperh);
	return OK;
}

/**
  * @brief  This function handles DAC event interrupt request.
  * @param hperh: Pointer to a dac_handle_t structure that contains
  *               the configuration information for the specified DAC.
  * @retval None
  */
void dac_irq_handler(dac_handle_t *hperh)
{
	if (dac_get_it_status(hperh, DAC_IT_CH0)) {
		dac_clear_it_status(hperh, DAC_IT_CH0);

		if (hperh->ch0_cplt_cbk)
			hperh->ch0_cplt_cbk(hperh);
	}

	if (dac_get_it_status(hperh, DAC_IT_CH1)) {
		dac_clear_it_status(hperh, DAC_IT_CH1);

		if (hperh->ch1_cplt_cbk)
			hperh->ch1_cplt_cbk(hperh);
	}

	if (dac_get_it_status(hperh, DAC_IT_CH0_UF)) {
		dac_clear_it_status(hperh, DAC_IT_CH0_UF);

		if (hperh->ch0_underflow_cbk)
			hperh->ch0_underflow_cbk(hperh);
	}

	if (dac_get_it_status(hperh, DAC_IT_CH1_UF)) {
		dac_clear_it_status(hperh, DAC_IT_CH1_UF);

		if (hperh->ch1_underflow_cbk)
			hperh->ch1_underflow_cbk(hperh);
	}

	return;
}
/**
  *@}
  */
#endif /* HAL_DAC */
/**
  *@}
  */
/**
  *@}
  */
