 /**
   *********************************************************************************
   *
   * @file    hal_lcd.c
   * @brief   LCD module driver.
   *
   * @version V1.0
   * @date    29 Nov 2017
   * @author  AE Team
   * @note
   *
   * Copyright (C) Shanghai Eastsoft Microelectronics Co. Ltd. All rights reserved.
   *
   *********************************************************************************
   */

#include "hal_lcd.h"

/** @addtogroup ES32FXXX_HAL
  * @{
  */

/** @defgroup LCD LCD
  * @brief LCD module library
  * @{
  */
#ifdef HAL_LCD

/** @defgroup LCD_Public_Functions LCD Public Functions
  * @{
  */

/** @defgroup LCD_Public_Functions_Group1 Initialize and Enable functions
  * @brief Initialize and Enable Functions
  * @{
  */

/**
  * @brief Initializes the LCD Peripheral according to the specified parameters.
  * @note This function can be used only when the LCD is disabled.
  * @param hperh: Pointer to a lcd_handle_t structure that contains
  *               the configuration information for the specified LCD.
  * @retval Status, see @ref hal_status_t.
  */
hal_status_t lcd_init(lcd_handle_t *hperh)
{
	uint16_t delay = 0;

	assert_param(IS_LCD_PERH_TYPE(hperh->perh));
	assert_param(IS_LCD_VCHPS_TYPE(hperh->init.lcd_vchps));
	assert_param(IS_LCD_VSEL_TYPE(hperh->init.lcd_vsel));
	assert_param(IS_LCD_FUNC_TYPE(hperh->init.lcd_vbufld));
	assert_param(IS_LCD_FUNC_TYPE(hperh->init.lcd_vbufhd));
	assert_param(IS_LCD_LEVEL_TYPE(hperh->init.lcd_dsld));
	assert_param(IS_LCD_LEVEL_TYPE(hperh->init.lcd_dshd));
	assert_param(IS_LCD_RES_TYPE(hperh->init.lcd_resld));
	assert_param(IS_LCD_RES_TYPE(hperh->init.lcd_reshd));
	assert_param(IS_LCD_BIAS_TYPE(hperh->init.lcd_bias));
	assert_param(IS_LCD_DUTY_TYPE(hperh->init.lcd_duty));
	assert_param(IS_LCD_WFS_TYPE(hperh->init.lcd_wfs));
	assert_param(IS_LCD_PRS_TYPE(hperh->init.lcd_prs));
	assert_param(IS_LCD_DIV_TYPE(hperh->init.lcd_div));
	assert_param(IS_LCD_DEAD_TYPE(hperh->init.lcd_dead));
	assert_param(IS_LCD_PON_TYPE(hperh->init.lcd_pon));
	assert_param(IS_LCD_VGS_TYPE(hperh->init.lcd_vgs));

	__LOCK(hperh);

	cmu_lcd_clock_select(hperh->init.clock);

	hperh->perh->FCR.WFS = hperh->init.lcd_wfs;
	hperh->perh->FCR.PRS = hperh->init.lcd_prs;

	for (delay = 0; delay < 3000; delay++);

	hperh->perh->FCR.DIV  = hperh->init.lcd_div;
	hperh->perh->FCR.DEAD = hperh->init.lcd_dead;
	hperh->perh->FCR.PON  = hperh->init.lcd_pon;
	hperh->perh->FCR.VGS  = hperh->init.lcd_vgs;

	hperh->perh->CR.DUTY   = hperh->init.lcd_duty;
	hperh->perh->CR.BIAS   = hperh->init.lcd_bias;
	hperh->perh->CR.VBUFHD = hperh->init.lcd_vbufhd;
	hperh->perh->CR.VBUFLD = hperh->init.lcd_vbufld;
	hperh->perh->CR.DSHD   = hperh->init.lcd_dshd;
	hperh->perh->CR.DSLD   = hperh->init.lcd_dsld;
	hperh->perh->CR.RESHD  = hperh->init.lcd_reshd;
	hperh->perh->CR.RESLD  = hperh->init.lcd_resld;
	hperh->perh->CR.VSEL   = hperh->init.lcd_vsel;
	hperh->perh->CR.VCHPS  = hperh->init.lcd_vchps;
	hperh->perh->CR.VCHPS  = hperh->init.lcd_vchps;
	hperh->perh->CR.VCHPS  = hperh->init.lcd_vchps;
	hperh->perh->CR.VCHPS  = hperh->init.lcd_vchps;

	__UNLOCK(hperh);
	return OK;
}

/**
  * @brief Enables or disables the LCD controller.
  * @param hperh: Pointer to a lcd_handle_t structure that contains
  *               the configuration information for the specified LCD.
  * @param state: This parameter can be: ENABLE or DISABLE.
  * @retval Status, see @ref hal_status_t.
  */
hal_status_t lcd_cmd(lcd_handle_t *hperh, type_func_t state)
{
	assert_param(IS_LCD_PERH_TYPE(hperh->perh));
	assert_param(IS_FUNC_STATE(state));

	__LOCK(hperh);

	hperh->perh->CR.OE = state;
	hperh->perh->CR.EN = state;

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

/** @defgroup LCD_Public_Functions_Group2 Config output functions
  * @brief Config output and blink functions
  * @{
  */

/**
  * @brief Configures the LCD blink mode and blink frequency.
  * @param hperh: Pointer to a lcd_handle_t structure that contains
  *               the configuration information for the specified LCD.
  * @param blink_mode: Specifies the LCD blink mode.
  * @param blink_freq: Specifies the LCD blink frequency.
  * @retval Status, see @ref hal_status_t.
  */
hal_status_t lcd_blink_config(lcd_handle_t *hperh, lcd_blink_t blink_mode, lcd_blfrq_t blink_freq)
{
	uint16_t delay = 0;
	assert_param(IS_LCD_PERH_TYPE(hperh->perh));
	assert_param(IS_LCD_BLINK_MODE(blink_mode));
	assert_param(IS_LCD_BLFRQ_TYPE(blink_freq));
	__LOCK(hperh);

	hperh->perh->FCR.BLMOD = blink_mode;

	for (delay = 0; delay < 3000; delay++);

	hperh->perh->FCR.BLFRQ = blink_freq;

	__UNLOCK(hperh);
	return OK;
 }

/**
  * @brief Control segment port enable or disable
  * @param hperh: Pointer to a lcd_handle_t structure that contains
  *               the configuration information for the specified LCD.
  * @param seg: Specifies the LCD segment index
  * @param seg_data: Specifies LCD segment data to be written to control segment output enable.
  * @retval Status, see @ref hal_status_t.
  */
hal_status_t lcd_write_seg(lcd_handle_t *hperh, lcd_seg_t seg, uint32_t seg_data)
{
	assert_param(IS_LCD_PERH_TYPE(hperh->perh));
	assert_param(IS_LCD_SEG_TYPE(seg));
	__LOCK(hperh);

	if (seg == SEG_0_TO_31)
		hperh->perh->SEGCR0.Word = seg_data;
	else
		hperh->perh->SEGCR1.Word = seg_data;

	__UNLOCK(hperh);
	return OK;
}

/**
  * @brief Writes a word in the specific LCD buffer to determine display.
  * @param hperh: Pointer to a lcd_handle_t structure that contains
  *               the configuration information for the specified LCD.
  * @param buf: Specifies the LCD buffer index.
  * @param buf_data: Specifies LCD buffer data to be written to control display.
  * @retval Status, see @ref hal_status_t.
  */
hal_status_t lcd_write(lcd_handle_t *hperh, lcd_buf_t buf, uint32_t buf_data)
{
	assert_param(IS_LCD_PERH_TYPE(hperh->perh));
	assert_param(IS_LCD_BUFFER_TYPE(buf));
	__LOCK(hperh);

	hperh->perh->BUF[buf].Word = buf_data;

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

/** @defgroup LCD_Public_Functions_Group3 Peripheral State functions
  * @brief LCD State functions
  * @{
  */

/**
  * @brief Checks whether the specified LCD flag is set or not.
  * @param hperh: Pointer to a lcd_handle_t structure that contains
  *               the configuration information for the specified LCD.
  * @param lcd_flag: Specifies the flag to check.
  * @retval The new state of LCD_FLAG
  */
uint32_t lcd_get_flag_status(lcd_handle_t *hperh, lcd_flag_t lcd_flag)
{
	assert_param(IS_LCD_PERH_TYPE(hperh->perh));
	assert_param(IS_LCD_GETFLAG_TYPE(lcd_flag));

	if (lcd_flag == LCD_FLAG_ALL)
		return hperh->perh->SR.Word;
	else
		return hperh->perh->SR.Word & lcd_flag ? 1 : 0;
}
/**
  * @}
  */

/** @defgroup LCD_Public_Functions_Group4 Interrupt functions
  * @brief LCD Interrupt functions
  * @{
  */

/**
  * @brief Enable or disable the specified interrupt
  * @param hperh: Pointer to a lcd_handle_t structure that contains
  *               the configuration information for the specified LCD.
  * @param interrupt: Specifies the interrupt type to be enabled or disabled
  *        @arg @ref LCD_IT_SOF Start of frame interrupt enable
  *        @arg @ref LCD_IT_UDD Update display done 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 lcd_interrupt_config(lcd_handle_t *hperh, lcd_it_t interrupt, type_func_t state)
{
	assert_param(IS_LCD_PERH_TYPE(hperh->perh));
	assert_param(IS_LCD_IT_TYPE(interrupt));
	assert_param(IS_FUNC_STATE(state));
	__LOCK(hperh);

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

	__UNLOCK(hperh);
	return OK;
}

/**
  * @brief Checks whether the specified interrupt has occurred or not.
  * @param hperh: Pointer to a lcd_handle_t structure that contains
  *               the configuration information for the specified LCD.
  * @param interrupt: Specifies the interrupt type to check
  *        This parameter can be one of the following values:
  *        @arg @ref LCD_IT_SOF Start of frame interrupt enable
  *        @arg @ref LCD_IT_UDD Update display done interrupt
  * @retval The new state of the LCD_IT
  */
it_status_t lcd_get_it_status(lcd_handle_t *hperh, lcd_it_t interrupt)
{
	assert_param(IS_LCD_PERH_TYPE(hperh->perh));
	assert_param(IS_LCD_IT_TYPE(interrupt));

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

/**
  * @brief Clear interrupt state flag
  * @param hperh: Pointer to a lcd_handle_t structure that contains
  *               the configuration information for the specified LCD.
  * @param interrupt: Specifies the interrupt type to clear
  *        This parameter can be one of the following values:
  *        @arg @ref LCD_IT_SOF Start of frame interrupt enable
  *        @arg @ref LCD_IT_UDD Update display done interrupt
  * @retval Status, see @ref hal_status_t.
  */
hal_status_t lcd_clear_it_status(lcd_handle_t *hperh, lcd_it_t interrupt)
{
	assert_param(IS_LCD_PERH_TYPE(hperh->perh));
	assert_param(IS_LCD_IT_TYPE(interrupt));
	__LOCK(hperh);

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

	__UNLOCK(hperh);
	return OK;
}

/**
  * @brief  This function handles LCD event interrupt request.
  * @param hperh: Pointer to a lcd_handle_t structure that contains
  *               the configuration information for the specified LCD.
  * @retval None
  */
void lcd_irq_handler(lcd_handle_t *hperh)
{
	if (lcd_get_it_status(hperh,LCD_IT_UDD)) {
		lcd_clear_it_status(hperh, LCD_IT_UDD);

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

	if (lcd_get_it_status(hperh,LCD_IT_SOF)) {
		lcd_clear_it_status(hperh, LCD_IT_SOF);

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

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