/**
  *********************************************************************************
  *
  * @file    hal_lptim.c
  * @brief   LPTIM module driver.
  *	     This is the common part of the LPTIM initialization
  *
  * @version V1.0
  * @date    09 Nov 2017
  * @author  AE Team
  * @note
  *
  * Copyright (C) Shanghai Eastsoft Microelectronics Co. Ltd. All rights reserved.
  *
  *********************************************************************************
  */

#include "hal_lptim.h"


/** @addtogroup ES32FXXX_HAL
  * @{
  */

/** @defgroup LPTIM LPTIM
  * @brief LPTIM module driver
  * @{
  */
#ifdef HAL_LPTIM

/** @defgroup LPTIM_Public_Functions LPTIM Public Functions
  * @{
  */

/** @defgroup LPTIM_Public_Functions_Group1 Initialization functions
  * @brief    Initialization and Configuration functions
  *
  * @{
  */
/**
  * @brief  Reset the LPTIM peripheral.
  * @param  hperh: Pointer to a lptim_handle_t.
  * @retval None
  */
void lptim_reset(lptim_handle_t *hperh)
{
	assert_param(IS_LPTIM(hperh->perh));

	hperh->state = LPTIM_STATE_BUSY;
	LPTIM_DISABLE(hperh);
	hperh->state = LPTIM_STATE_RESET;
	__UNLOCK(hperh);

	return;
}

/**
  * @brief  Configure the LPTIM trigger mode according to the specified parameters in
  *         the lptim_trigger_init_t.
  * @param  hperh: Pointer to a lptim_handle_t.
  * @param  config: Pointer to a lptim_trigger_init_t.
  * @retval None
  */
void lptim_trigger_config(lptim_handle_t *hperh, lptim_trigger_init_t *config)
{
	assert_param(IS_LPTIM(hperh->perh));
	assert_param(IS_LPTIM_TRIGEN(config->trig_mode));
	assert_param(IS_LPTIM_TRIGSEL(config->trig_sel));

	hperh->perh->CON0.TRIGEN  = config->trig_mode;
	hperh->perh->CON0.TRIGSEL = config->trig_sel;

	return;
}

/**
  * @brief  Configure the LPTIM clock source according to the specified parameters in
  *         the lptim_clock_source_init_t.
  * @param  hperh: Pointer to a lptim_handle_t.
  * @param  config: Pointer to a lptim_clock_source_init_t.
  * @retval None
  */
void lptim_clock_source_config(lptim_handle_t *hperh, lptim_clock_source_init_t *config)
{
	assert_param(IS_LPTIM(hperh->perh));
	assert_param(IS_LPTIM_CKSEL(config->clock_select));
	assert_param(IS_LPTIM_CKPOL(config->clock_polarity));

	hperh->perh->CON0.CKSEL = config->clock_select;
	hperh->perh->CON0.CKPOL = config->clock_polarity;

	return;
}

/**
  * @brief  Configure the LPTIM trigger filter parameter according to
  *         the specified parameters in the lptim_trgflt_t.
  * @param  hperh: Pointer to a lptim_handle_t.
  * @param  flt: Pointer to a lptim_trgflt_t.
  * @retval None
  */
void lptim_trigger_filter_config(lptim_handle_t *hperh, lptim_trgflt_t flt)
{
	assert_param(IS_LPTIM(hperh->perh));
	assert_param(IS_LPTIM_TRGFLT(flt));

	hperh->perh->CON0.TRGFLT = flt;
	return;
}

/**
  * @brief  Configure the LPTIM clock filter parameter according to
  *         the specified parameters in the lptim_ckflt_t.
  * @param  hperh: Pointer to a lptim_handle_t.
  * @param  flt: Pointer to a lptim_ckflt_t.
  * @retval None
  */
void lptim_clock_filter_config(lptim_handle_t *hperh, lptim_ckflt_t flt)
{
	assert_param(IS_LPTIM(hperh->perh));
	assert_param(IS_LPTIM_TRGFLT(flt));

	hperh->perh->CON0.CKFLT = flt;
	return;
}
/**
  * @}
  */

/** @defgroup LPTIM_Public_Functions_Group2 LPTIM output toggle functions
  *  @brief    LPTime output toggle functions
  *
  * @verbatim
  ==============================================================================
                  ##### Time Output Compare functions #####
  ==============================================================================
  [..]
    This section provides functions allowing to:
    (+) Initialize the LPTIM Output Toggle.
    (+) Start the LPTIM Output Toggle.
    (+) Stop the LPTIM Output Toggle.
    (+) Start the LPTIM Output Toggle and enable interrupt.
    (+) Stop the LPTIM Output Toggle and disable interrupt.

    @endverbatim
  * @{
  */
/**
  * @brief  Initializes the TIM Output toggle according to the specified
  *		parameters in the tim_handle_t.
  * @param  hperh: LPTIM handle
  * @retval Status, see @ref hal_status_t.
  */
hal_status_t lptim_toggle_init(lptim_handle_t *hperh)
{
	assert_param(IS_LPTIM(hperh->perh));
	assert_param(IS_LPTIM_WAVE(hperh->init.mode));
	assert_param(IS_LPTIM_PRESC(hperh->init.psc));

	__LOCK(hperh);
	hperh->state = LPTIM_STATE_BUSY;

	cmu_lptim0_clock_select(hperh->init.clock);

	hperh->perh->CON0.WAVE  = LPTIM_WAVE_TOGGLE;
	hperh->perh->CON0.PRESC = hperh->init.psc;
	hperh->perh->ARR.ARR    = hperh->init.arr;
	hperh->perh->CMP.CMP    = hperh->init.cmp;

	while (hperh->perh->SYNCSTAT.ARRWBSY);
	hperh->state = LPTIM_STATE_READY;
	__UNLOCK(hperh);

	return OK;
}

/**
  * @brief  Starts the LPTIM Output toggle.
  * @param  hperh: LPTIM handle
  * @retval None
  */
void lptim_toggle_start(lptim_handle_t *hperh)
{
	assert_param(IS_LPTIM(hperh->perh));

	LPTIM_ENABLE(hperh);
	__delay_ms(1);

	if (hperh->init.start_mode)
		LPTIM_CNTSTART(hperh);
	else
		LPTIM_SNGSTART(hperh);

	return;
}

/**
  * @brief  Stops the LPTIM Output toggle.
  * @param  hperh: LPTIM handle
  * @retval None
  */
void lptim_toggle_stop(lptim_handle_t *hperh)
{
	assert_param(IS_LPTIM(hperh->perh));

	LPTIM_DISABLE(hperh);
	return;
}

/**
  * @brief  Starts the LPTIM Output toggle in interrupt mode.
  * @param  hperh: LPTIM handle
  * @retval None
  */
void lptim_toggle_start_by_it(lptim_handle_t *hperh)
{
	assert_param(IS_LPTIM(hperh->perh));

	lptim_interrupt_config(hperh, LPTIM_IT_ARRMAT, ENABLE);
	LPTIM_ENABLE(hperh);
	__delay_ms(1);

	if (hperh->init.start_mode)
		LPTIM_CNTSTART(hperh);
	else
		LPTIM_SNGSTART(hperh);

	return;
}

/**
  * @brief  Stops the LPTIM Output toggle in interrupt mode.
  * @param  hperh: LPTIM handle
  * @retval None
  */
void lptim_toggle_stop_by_it(lptim_handle_t *hperh)
{
	assert_param(IS_LPTIM(hperh->perh));

	lptim_interrupt_config(hperh, LPTIM_IT_ARRMAT, DISABLE);
	LPTIM_DISABLE(hperh);
	return;
}
/**
  * @}
  */

/** @defgroup LPTIM_Public_Functions_Group3 LPTIM output pulse functions
  *  @brief    LPTime output pulse functions
  *
  * @verbatim
  ==============================================================================
                  ##### Time Output Compare functions #####
  ==============================================================================
  [..]
    This section provides functions allowing to:
    (+) Initialize the LPTIM Output pulse.
    (+) Start the LPTIM Output pulse.
    (+) Stop the LPTIM Output pulse.
    (+) Start the LPTIM Output pulse and enable interrupt.
    (+) Stop the LPTIM Output pulse and disable interrupt.

    @endverbatim
  * @{
  */
/**
  * @brief  Initializes the TIM Output pulse according to the specified
  *		parameters in the tim_handle_t.
  * @param  hperh: LPTIM handle
  * @retval Status, see @ref hal_status_t.
  */
hal_status_t lptim_pulse_init(lptim_handle_t *hperh)
{
	assert_param(IS_LPTIM(hperh->perh));
	assert_param(IS_LPTIM_WAVE(hperh->init.mode));
	assert_param(IS_LPTIM_PRESC(hperh->init.psc));

	__LOCK(hperh);
	hperh->state = LPTIM_STATE_BUSY;

	hperh->perh->CON0.WAVE  = LPTIM_WAVE_PULSE;
	hperh->perh->CON0.PRESC = hperh->init.psc;
	hperh->perh->ARR.ARR   = hperh->init.arr;
	hperh->perh->CMP.CMP   = hperh->init.cmp;

	while (hperh->perh->SYNCSTAT.ARRWBSY);
	hperh->state = LPTIM_STATE_READY;
	__UNLOCK(hperh);

	return OK;
}

/**
  * @brief  Starts the LPTIM Output pulse.
  * @param  hperh: LPTIM handle
  * @retval None
  */
void lptim_pulse_start(lptim_handle_t *hperh)
{
	assert_param(IS_LPTIM(hperh->perh));

	LPTIM_ENABLE(hperh);
	__delay_ms(1);

	if (hperh->init.start_mode)
		LPTIM_CNTSTART(hperh);
	else
		LPTIM_SNGSTART(hperh);

	return;
}

/**
  * @brief  Stops the LPTIM Output pulse.
  * @param  hperh: LPTIM handle
  * @retval None
  */
void lptim_pulse_stop(lptim_handle_t *hperh)
{
	assert_param(IS_LPTIM(hperh->perh));

	LPTIM_DISABLE(hperh);
	return;
}

/**
  * @brief  Starts the LPTIM Output pulse in interrupt mode.
  * @param  hperh: LPTIM handle
  * @retval None
  */
void lptim_pulse_start_by_it(lptim_handle_t *hperh)
{
	assert_param(IS_LPTIM(hperh->perh));

	lptim_interrupt_config(hperh, LPTIM_IT_ARRMAT, ENABLE);
	LPTIM_ENABLE(hperh);
	__delay_ms(1);

	if (hperh->init.start_mode)
		LPTIM_CNTSTART(hperh);
	else
		LPTIM_SNGSTART(hperh);

	return;
}

/**
  * @brief  Stops the LPTIM Output pulse in interrupt mode.
  * @param  hperh: LPTIM handle
  * @retval None
  */
void lptim_pulse_stop_by_it(lptim_handle_t *hperh)
{
	assert_param(IS_LPTIM(hperh->perh));

	lptim_interrupt_config(hperh, LPTIM_IT_ARRMAT, DISABLE);
	LPTIM_DISABLE(hperh);
	return;
}
/**
  * @}
  */

/** @defgroup LPTIM_Public_Functions_Group4 LPTIM output pwm functions
  *  @brief    LPTime output pwm functions
  *
  * @verbatim
  ==============================================================================
                  ##### Time Output Compare functions #####
  ==============================================================================
  [..]
    This section provides functions allowing to:
    (+) Initialize the LPTIM Output pwm.
    (+) Start the LPTIM Output pwm.
    (+) Stop the LPTIM Output pwm.
    (+) Start the LPTIM Output pwm and enable interrupt.
    (+) Stop the LPTIM Output pwm and disable interrupt.

    @endverbatim
  * @{
  */
/**
  * @brief  Initializes the TIM Output pwm according to the specified
  *		parameters in the tim_handle_t.
  * @param  hperh: LPTIM handle
  * @retval Status, see @ref hal_status_t.
  */
hal_status_t lptim_pwm_init(lptim_handle_t *hperh)
{
	assert_param(IS_LPTIM(hperh->perh));
	assert_param(IS_LPTIM_WAVE(hperh->init.mode));
	assert_param(IS_LPTIM_PRESC(hperh->init.psc));

	__LOCK(hperh);
	hperh->state = LPTIM_STATE_BUSY;

	hperh->perh->CON0.WAVE    = LPTIM_WAVE_PWM;
//	hperh->perh->CON0.WAVEPOL = ENABLE;
	hperh->perh->CON0.PRESC   = hperh->init.psc;
	hperh->perh->ARR.ARR      = hperh->init.arr;
	hperh->perh->CMP.CMP      = hperh->init.cmp;

	while (hperh->perh->SYNCSTAT.ARRWBSY);
	while (hperh->perh->SYNCSTAT.CMPWBSY);
	hperh->state = LPTIM_STATE_READY;
	__UNLOCK(hperh);

	return OK;
}

/**
  * @brief  Starts the LPTIM Output pwm.
  * @param  hperh: LPTIM handle
  * @retval None
  */
void lptim_pwm_start(lptim_handle_t *hperh)
{
	assert_param(IS_LPTIM(hperh->perh));

	LPTIM_ENABLE(hperh);
	__delay_ms(1);

	if (hperh->init.start_mode)
		LPTIM_CNTSTART(hperh);
	else
		LPTIM_SNGSTART(hperh);

	return;
}

/**
  * @brief  Stops the LPTIM Output pwm.
  * @param  hperh: LPTIM handle
  * @retval None
  */
void lptim_pwm_stop(lptim_handle_t *hperh)
{
	assert_param(IS_LPTIM(hperh->perh));

	LPTIM_DISABLE(hperh);
	return;
}

/**
  * @brief  Starts the LPTIM Output pwm in interrupt mode.
  * @param  hperh: LPTIM handle
  * @retval None
  */
void lptim_pwm_start_by_it(lptim_handle_t *hperh)
{
	assert_param(IS_LPTIM(hperh->perh));

	lptim_interrupt_config(hperh, LPTIM_IT_CMPMAT, ENABLE);
	LPTIM_ENABLE(hperh);
	__delay_ms(1);

	if (hperh->init.start_mode)
		LPTIM_CNTSTART(hperh);
	else
		LPTIM_SNGSTART(hperh);

	return;
}

/**
  * @brief  Stops the LPTIM Output pwm in interrupt mode.
  * @param  hperh: LPTIM handle
  * @retval None
  */
void lptim_pwm_stop_by_it(lptim_handle_t *hperh)
{
	assert_param(IS_LPTIM(hperh->perh));

	lptim_interrupt_config(hperh, LPTIM_IT_CMPMAT, DISABLE);
	LPTIM_DISABLE(hperh);
	return;
}
/**
  * @}
  */


/** @defgroup LPTIM_Public_Functions_Group5 Control functions
  * @brief LPTIM Control functions
  *
  * @{
  */
/**
  * @brief  This function handles LPTIM interrupts requests.
  * @param  hperh: LPTIM  handle
  * @retval None
  */
void lptim_irq_handle(lptim_handle_t *hperh)
{
	assert_param(IS_LPTIM(hperh->perh));

	/* Output compare event */
	if (((lptim_get_it_status(hperh, LPTIM_IT_CMPMAT)) != RESET) &&
                           ((lptim_get_flag_status(hperh, LPTIM_FLAG_CMPMAT)) != RESET)) {
		lptim_clear_flag_status(hperh, LPTIM_FLAG_CMPMAT);

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

	/* Output update event */
	if (((lptim_get_it_status(hperh, LPTIM_IT_ARRMAT)) != RESET) &&
                           ((lptim_get_flag_status(hperh, LPTIM_FLAG_ARRMAT)) != RESET)) {
		lptim_clear_flag_status(hperh, LPTIM_FLAG_ARRMAT);

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

	/* Trigger event */
	if (((lptim_get_it_status(hperh, LPTIM_IT_EXTTRIG)) != RESET) &&
                           ((lptim_get_flag_status(hperh, LPTIM_FLAG_EXTTRIG)) != RESET)) {
		lptim_clear_flag_status(hperh, LPTIM_FLAG_EXTTRIG);

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

	return;
}

/**
  * @brief  Enables or disables the specified LPTIM interrupts.
  * @param  hperh: Pointer to a lptim_handle_t structure that contains
  *         the configuration information for the specified LPTIM module.
  * @param  it: Specifies the SPI interrupt sources to be enabled or disabled.
  *         This parameter can be one of the @ref lptim_it_t.
  * @param  state: New status
  *           - ENABLE
  *           - DISABLE
  * @retval None
  */
void lptim_interrupt_config(lptim_handle_t *hperh, lptim_it_t it, type_func_t state)
{
	assert_param(IS_LPTIM(hperh->perh));
	assert_param(IS_LPTIM_IT(it));
	assert_param(IS_FUNC_STATE(state));

	if (state == ENABLE)
		hperh->perh->IER.Word |= (uint32_t)it;
	else
		hperh->perh->IER.Word &= ~((uint32_t)it);
	return;
}

/**
  * @brief  Checks whether the specified LPTIM interrupt has occurred or not.
  * @param  hperh: Pointer to a lptim_handle_t structure that contains
  *         the configuration information for the specified LPTIM module.
  * @param  it: Specifies the LPTIM interrupt source to check.
  *         This parameter can be one of the @ref lptim_it_t.
  * @retval Status
  *           - SET
  *           - RESET
  */
it_status_t lptim_get_it_status(lptim_handle_t *hperh, lptim_it_t it)
{
	assert_param(IS_LPTIM(hperh->perh));
	assert_param(IS_LPTIM_IT(it));

	if(hperh->perh->IER.Word & it)
		return SET;

	return RESET;
}

/** @brief  Check whether the specified LPTIM flag is set or not.
  * @param  hperh: Pointer to a lptim_handle_t structure that contains
  *         the configuration information for the specified LPTIM module.
  * @param  flag: specifies the flag to check.
  *         This parameter can be one of the @ref lptim_flag_t.
  * @retval Status
  *           - SET
  *           - RESET
  */
flag_status_t lptim_get_flag_status(lptim_handle_t *hperh, lptim_flag_t flag)
{
	assert_param(IS_LPTIM(hperh->perh));
	assert_param(IS_LPTIM_FLAG(flag));

	if(hperh->perh->ISR.Word & flag)
		return SET;

	return RESET;
}

/** @brief  Clear the specified LPTIM pending flags.
  * @param  hperh: Pointer to a lptim_handle_t structure that contains
  *         the configuration information for the specified LPTIM module.
  * @param  flag: specifies the flag to check.
  *         This parameter can be one of the @ref lptim_flag_t.
  * @retval None
  */
void lptim_clear_flag_status(lptim_handle_t *hperh, lptim_flag_t flag)
{
	assert_param(IS_LPTIM(hperh->perh));
	assert_param(IS_LPTIM_FLAG(flag));

	hperh->perh->IFC.Word = (uint32_t)flag;
	return;
}
/**
  * @}
  */

/** @defgroup LPTIM_Public_Functions_Group6 Peripheral State functions
 *  @brief   Peripheral State functions
 *
 * @verbatim
  ==============================================================================
                        ##### Peripheral State functions #####
  ==============================================================================
    [..]
    This subsection permit to get in run-time the status of the peripheral.

    @endverbatim
  * @{
  */

/**
  * @brief  Return the LPTIM state
  * @param  hperh: LPTIM handle
  * @retval LPTIM peripheral state
  */
lptim_state_t lptim_get_state(lptim_handle_t *hperh)
{
	return hperh->state;
}
/**
  * @}
  */
/**
  * @}
  */
#endif /* HAL_LPTIM */
/**
  * @}
  */
/**
  * @}
  */
