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

#include "hal_acmp.h"

/** @addtogroup ES32FXXX_HAL
  * @{
  */

/** @defgroup ACMP ACMP
  * @brief ACMP module driver
  * @{
  */
#ifdef HAL_ACMP

/** @defgroup ACMP_Public_Functions ACMP Public Functions
  * @{
  */

/** @defgroup ACMP_Public_Functions_Group1 Initialization functions
  * @brief Initialization and Configuration functions
  * @{
  */

/**
  * @brief  Initializes the ACMP mode according to the specified parameters in
  *         the acmp_init_t and create the associated handle.
  * @param  hperh: Pointer to a acmp_handle_t structure that contains
  *         the configuration information for the specified ACMP module.
  * @retval Status, see @ref hal_status_t.
  */
hal_status_t acmp_init(acmp_handle_t *hperh)
{
	if (hperh == NULL)
		return ERROR;

	if (hperh->init.vdd_level > 63)
		return ERROR;

	assert_param(IS_ACMP_TYPE(hperh->perh));
	assert_param(IS_ACMP_MODE_TYPE(hperh->init.mode));
	assert_param(IS_ACMP_WARM_UP_TIME_TYPE(hperh->init.warm_time));
	assert_param(IS_ACMP_HYSTSEL_TYPE(hperh->init.hystsel));
	assert_param(IS_ACMP_WARM_FUNC_TYPE(hperh->init.warm_func));
	assert_param(IS_ACMP_POS_INPUT_TYPE(hperh->init.pos_port));
	assert_param(IS_ACMP_NEG_INPUT_TYPE(hperh->init.neg_port));
	assert_param(IS_ACMP_INACTVAL_TYPE(hperh->init.inactval));
	assert_param(IS_ACMP_EDGE_TYPE(hperh->init.edge));

	__LOCK(hperh);

	hperh->perh->CTRL.MODE         = hperh->init.mode;
	hperh->perh->CTRL.WARMTIME     = hperh->init.warm_time;
	hperh->perh->CTRL.HYSTSEL      = hperh->init.hystsel;
	hperh->perh->CTRL.INACTVAL     = hperh->init.inactval;
	hperh->perh->INPUTSEL.POSSEL   = hperh->init.pos_port;
	hperh->perh->INPUTSEL.NEGSEL   = hperh->init.neg_port;
	hperh->perh->INPUTSEL.VDDLEVEL = hperh->init.vdd_level;
	hperh->perh->IEN.WARMUP        = hperh->init.warm_func;

	switch (hperh->init.edge) {
	case ACMP_EDGE_NONE:
		hperh->perh->CTRL.IFALL = 0;
		hperh->perh->CTRL.IRISE = 0;
		break;

	case ACMP_EDGE_FALL:
		hperh->perh->CTRL.IFALL = 1;
		hperh->perh->CTRL.IRISE = 0;
		break;

	case ACMP_EDGE_RISE:
		hperh->perh->CTRL.IFALL = 0;
		hperh->perh->CTRL.IRISE = 1;
		break;

	case ACMP_EDGE_ALL:
		hperh->perh->CTRL.IFALL = 1;
		hperh->perh->CTRL.IRISE = 1;
		break;

	default:
		break;
	}

	hperh->perh->CTRL.MUXEN = 1;
	hperh->perh->CTRL.EN    = 1;

	while (hperh->perh->STATUS.ACMPACT != 1);

	__UNLOCK(hperh);
	return OK;
}
/**
  * @}
  */

/** @defgroup ACMP_Public_Functions_Group2 Interrupt operation functions
  * @brief ACMP Interrupt operation functions
  * @{
  */

/**
  * @brief  Enables or disables the specified ACMP interrupts.
  * @param  hperh: Pointer to a acmp_handle_t structure that contains
  *         the configuration information for the specified ACMP module.
  * @param  it: Specifies the ACMP interrupt sources to be enabled or disabled.
  *         This parameter can be one of the @ref acmp_it_t.
  * @param  state: New status
  *           - ENABLE
  *           - DISABLE
  * @retval Status, see @ref hal_status_t.
  */
hal_status_t acmp_interrupt_config(acmp_handle_t *hperh, acmp_it_t it, type_func_t state)
{
	assert_param(IS_ACMP_TYPE(hperh->perh));
	assert_param(IS_ACMP_IT_TYPE(it));
	assert_param(IS_FUNC_STATE(state));

	__LOCK(hperh);

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

	__UNLOCK(hperh);

	return OK;
}

/**
  * @brief  Checks whether the specified ACMP interrupt has occurred or not.
  * @param  hperh: Pointer to a acmp_handle_t structure that contains
  *         the configuration information for the specified ACMP module.
  * @param  it: Specifies the ACMP interrupt source to check.
  *         This parameter can be one of the @ref acmp_it_t.
  * @retval it_status_t
  *           - SET
  *           - RESET
  */
it_status_t acmp_get_it_status(acmp_handle_t *hperh, acmp_it_t it)
{
	assert_param(IS_ACMP_TYPE(hperh->perh));
	assert_param(IS_ACMP_IT_TYPE(it));

	if (hperh->perh->IF.Word & it) {
		__UNLOCK(hperh);
		return SET;
	}

	return RESET;
}

/** @brief  Clear the specified ACMP it flags.
  * @param  hperh: Pointer to a acmp_handle_t structure that contains
  *         the configuration information for the specified ACMP module.
  * @param  it: specifies the  it flag.
  *         This parameter can be one of the @ref acmp_it_t.
  * @retval Status, see @ref hal_status_t.
  */
hal_status_t acmp_clear_it_status(acmp_handle_t *hperh, acmp_it_t it)
{
	assert_param(IS_ACMP_TYPE(hperh->perh));
	assert_param(IS_ACMP_IT_TYPE(it));

	__LOCK(hperh);
	hperh->perh->IFC.Word |= it;
	__UNLOCK(hperh);

	return OK;
}

/** @brief  Set the specified acmp it flags.
  * @param  hperh: Pointer to a acmp_handle_t structure that contains
  *         the configuration information for the specified acmp module.
  * @param  it: specifies the  it flag.
  *         This parameter can be one of the @ref acmp_it_t.
  * @retval Status, see @ref hal_status_t.
  */
hal_status_t acmp_set_it_status(acmp_handle_t *hperh, acmp_it_t it)
{
	assert_param(IS_ACMP_TYPE(hperh->perh));
	assert_param(IS_ACMP_IT_TYPE(it));

	__LOCK(hperh);
	hperh->perh->IFS.Word |= it;
	__UNLOCK(hperh);

	return OK;
}

/** @brief  Check whether the specified ACMP flag is set or not.
  * @param  hperh: Pointer to a acmp_handle_t structure that contains
  *         the configuration information for the specified ACMP module.
  * @param  flag: specifies the flag to check.
  *         This parameter can be one of the @ref acmp_flag_t.
  * @retval flag_status_t
  *           - SET
  *           - RESET
  */
flag_status_t acmp_get_flag_status(acmp_handle_t *hperh, acmp_flag_t flag)
{
	assert_param(IS_ACMP_TYPE(hperh->perh));
	assert_param(IS_ACMP_FLAG_TYPE(flag));

	if (hperh->perh->STATUS.Word & flag) {
		__UNLOCK(hperh);
		return SET;
	}

	return RESET;
}
/**
  * @}
  */

/** @defgroup ACMP_Public_Functions_Group3 Output value functions
  * @brief ACMP Output value functions
  * @{
  */

/**
  * @brief  This function handles ACMP interrupt request.
  * @param  hperh: Pointer to a acmp_handle_t structure that contains
  *         the configuration information for the specified ACMP module.
  * @retval None
  */
void acmp_irq_handle(acmp_handle_t *hperh)
{
	if (acmp_get_it_status(hperh, ACMP_IT_WARMUP) == SET) {
		if (hperh->acmp_warmup_cplt_cbk)
			hperh->acmp_warmup_cplt_cbk(hperh);
		acmp_clear_it_status(hperh, ACMP_IT_WARMUP);
	}

	if (acmp_get_it_status(hperh, ACMP_IT_EDGE) == SET) {
		if (hperh->acmp_edge_cplt_cbk)
			hperh->acmp_edge_cplt_cbk(hperh);
		acmp_clear_it_status(hperh, ACMP_IT_EDGE);
	}

	return;
}

/**
  * @brief  This function config acmp output.
  * @param  hperh: Pointer to a acmp_handle_t structure that contains
  *         the configuration information for the specified ACMP module.
  * @param  config: Pointer to a acmp_output_config_t structure that contains
  *         the configutation information for acmp output.
  * @retval Status, see @ref hal_status_t.
  */
hal_status_t acmp_out_config(acmp_handle_t *hperh, acmp_output_config_t *config)
{
	if (hperh == NULL)
		return ERROR;

	if (config == NULL)
		return ERROR;

	assert_param(IS_ACMP_TYPE(hperh->perh));
	assert_param(IS_ACMP_INVERT_TYPE(config->gpioinv));
	assert_param(IS_ACMP_LOCATION_TYPE(config->location));
	assert_param(IS_ACMP_OUT_FUNC_TYPE(config->out_func));

	__LOCK(hperh);
	hperh->perh->ROUTE.LOCATION = config->location;
	hperh->perh->CTRL.GPIOINV   = config->gpioinv;
	hperh->perh->ROUTE.ACMPPEN  = config->out_func;
	__UNLOCK(hperh);

	return OK;
}

/**
  * @brief  This function output acmp result.
  * @param  hperh: Pointer to a acmp_handle_t structure that contains
  *         the configuration information for the specified ACMP module.
  * @retval output value.
  */
uint8_t acmp_out_result(acmp_handle_t *hperh)
{
	assert_param(IS_ACMP_TYPE(hperh->perh));

	return hperh->perh->STATUS.ACMPOUT;
}
/**
  * @}
  */

/**
  * @}
  */
#endif /* HAL_ACMP */
/**
  * @}
  */

/**
  * @}
  */
