 /**  
  *******************************************************************************************************
  * @file    fm33lg0xx_fl_lcd.c
  * @author  FMSH Application Team
  * @brief   Src file of LCD FL Module
  *******************************************************************************************************
  * @attention
  *  
  * Copyright (c) 2022, SHANGHAI FUDAN MICROELECTRONICS GROUP CO., LTD.(FUDAN MICROELECTRONICS./ FUDAN MICRO.)    
  * All rights reserved.    
  *    
  * Processor:                   FM33LG0xxA    
  * http:                        http://www.fmdevelopers.com.cn/    
  *    
  * Redistribution and use in source and binary forms, with or without    
  * modification, are permitted provided that the following conditions are met    
  *    
  * 1. Redistributions of source code must retain the above copyright notice,    
  *    this list of conditions and the following disclaimer.    
  *    
  * 2. Redistributions in binary form must reproduce the above copyright notice,    
  *    this list of conditions and the following disclaimer in the documentation    
  *    and/or other materials provided with the distribution.    
  *    
  * 3. Neither the name of the copyright holder nor the names of its contributors    
  *    may be used to endorse or promote products derived from this software    
  *    without specific prior written permission.    
  *    
  * 4. To provide the most up-to-date information, the revision of our documents     
  *    on the World Wide Web will be the most Current. Your printed copy may be      
  *    an earlier revision. To verify you have the latest information avaliable,    
  *    refer to: http://www.fmdevelopers.com.cn/.    
  *    
  * THIS SOFTWARE IS PROVIDED BY FUDAN MICRO "AS IS" AND ANY EXPRESSED     
  * ORIMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES     
  * OF MERCHANTABILITY NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE    
  * ARE DISCLAIMED.IN NO EVENT SHALL FUDAN MICRO OR ITS CONTRIBUTORS BE LIABLE     
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL     
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS     
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER    
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,     
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISINGIN ANY WAY OUT OF THE     
  * USE OF THIS SOFTWARE, EVEN IF ADVISED OFTHE POSSIBILITY OF SUCH DAMAGE.    
 */    
/**
  *******************************************************************************************************
  * @file    fm33lg0xx_fl_lcd.c
  * @author  FMSH Application Team
  * @brief   Src file of LCD FL Module
  *******************************************************************************************************
  * @attention
  *
  * Copyright (c) [2021] [Fudan Microelectronics]
  * THIS SOFTWARE is licensed under Mulan PSL v2.
  * You can use this software according to the terms and conditions of the Mulan PSL v2.
  * You may obtain a copy of Mulan PSL v2 at:
  *          http://license.coscl.org.cn/MulanPSL2
  * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
  * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
  * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
  * See the Mulan PSL v2 for more details.
  *
  *******************************************************************************************************
  */
/* Includes ------------------------------------------------------------------*/
#include "fm33lg0xx_fl.h"

/** @addtogroup FM33LG0XX_FL_Driver
  * @{
  */

/** @addtogroup LCD
  * @{
  */

#ifdef FL_LCD_DRIVER_ENABLED

/* Private macros ------------------------------------------------------------*/
/** @addtogroup LCD_FL_Private_Macros
  * @{
  */

#define         IS_FL_LCD_INSTANCE(INTENCE)             ((INTENCE) == LCD)

#define         IS_FL_LCD_BIASCURRENT(__VALUE__)        (((__VALUE__) == (FL_LCD_BIAS_CURRENT_VERYHIGH))||\
                                                        ((__VALUE__) == (FL_LCD_BIAS_CURRENT_HIGH))||\
                                                        ((__VALUE__) == (FL_LCD_BIAS_CURRENT_MEDIUM))||\
                                                        ((__VALUE__) == (FL_LCD_BIAS_CURRENT_LOW)))

#define         IS_FL_LCD_ENMODE(__VALUE__)             ((__VALUE__) == (FL_LCD_DRIVER_MODE_INNER_RESISTER)||\
                                                        ((__VALUE__) == (FL_LCD_DRIVER_MODE_OUTER_CAPACITY)))

#define         IS_FL_LCD_BIASVOLTAGE(__VALUE__)        (((__VALUE__) == (FL_LCD_BIAS_VOLTAGE_LEVEL0))||\
                                                        ((__VALUE__) == (FL_LCD_BIAS_VOLTAGE_LEVEL1))||\
                                                        ((__VALUE__) == (FL_LCD_BIAS_VOLTAGE_LEVEL2))||\
                                                        ((__VALUE__) == (FL_LCD_BIAS_VOLTAGE_LEVEL3))||\
                                                        ((__VALUE__) == (FL_LCD_BIAS_VOLTAGE_LEVEL4))||\
                                                        ((__VALUE__) == (FL_LCD_BIAS_VOLTAGE_LEVEL5))||\
                                                        ((__VALUE__) == (FL_LCD_BIAS_VOLTAGE_LEVEL6))||\
                                                        ((__VALUE__) == (FL_LCD_BIAS_VOLTAGE_LEVEL7))||\
                                                        ((__VALUE__) == (FL_LCD_BIAS_VOLTAGE_LEVEL8))||\
                                                        ((__VALUE__) == (FL_LCD_BIAS_VOLTAGE_LEVEL9))||\
                                                        ((__VALUE__) == (FL_LCD_BIAS_VOLTAGE_LEVEL10))||\
                                                        ((__VALUE__) == (FL_LCD_BIAS_VOLTAGE_LEVEL11))||\
                                                        ((__VALUE__) == (FL_LCD_BIAS_VOLTAGE_LEVEL12))||\
                                                        ((__VALUE__) == (FL_LCD_BIAS_VOLTAGE_LEVEL13))||\
                                                        ((__VALUE__) == (FL_LCD_BIAS_VOLTAGE_LEVEL14))||\
                                                        ((__VALUE__) == (FL_LCD_BIAS_VOLTAGE_LEVEL15)))

#define         IS_FL_LCD_BIASMD(__VALUE__)             (((__VALUE__) == (FL_LCD_BIAS_MODE_4BIAS))||\
                                                        ((__VALUE__) == (FL_LCD_BIAS_MODE_3BIAS)))

#define         IS_FL_LCD_BWFT(__VALUE__)               (((__VALUE__) == (FL_LCD_WAVEFORM_TYPEA))||\
                                                        ((__VALUE__) == (FL_LCD_WAVEFORM_TYPEB)))

#define         IS_FL_LCD_LMUX(__VALUE__)               (((__VALUE__) == (FL_LCD_COM_NUM_4COM))||\
                                                        ((__VALUE__) == (FL_LCD_COM_NUM_6COM))||\
                                                        ((__VALUE__) == (FL_LCD_COM_NUM_8COM)))


/**
  * @}
  */

/* Exported functions --------------------------------------------------------*/
/** @addtogroup LCD_FL_EF_Init
  * @{
  */

/**
  * @brief  获取LCD工作频率寄存器.
  * @param  wavetype 波形
  * @param  freq 工作频率
  * @retval 工作频率寄存器值
  */
static uint32_t FL_LCD_DisplayFreq(uint32_t wavetype,uint32_t freq)
{
    uint32_t displayFreq = 32u;
    if((freq > 0) && (freq <= 100))
    {
      if(wavetype == FL_LCD_WAVEFORM_TYPEA)
      {
        switch(FL_LCD_GetCOMNumber(LCD))
        {
            case FL_LCD_COM_NUM_4COM:
                displayFreq = (32768 / (4 * freq * 2) );
                break;
            case FL_LCD_COM_NUM_6COM:
                displayFreq = (32768 / (6 * freq * 2) );
                break;
            case FL_LCD_COM_NUM_8COM:
                displayFreq = (32768 / (8 * freq * 2) );
                break;
            default:
                displayFreq = (32768/ (4 * freq * 2) );
                break;
        }
      }
      else
      {
        switch(FL_LCD_GetCOMNumber(LCD))
        {
            case FL_LCD_COM_NUM_4COM:
                displayFreq = (32768 / (4 * freq * 4) );
                break;
            case FL_LCD_COM_NUM_6COM:
                displayFreq = (32768 / (6 * freq * 4) );
                break;
            case FL_LCD_COM_NUM_8COM:
                displayFreq = (32768 / (8 * freq * 4) );
                break;
            default:
                displayFreq = (32768/ (4 * freq * 4) );
                break;
        }            
      }
      
    }
    displayFreq = displayFreq & 0x000000ffu;
    return displayFreq;
}

/**
  * @brief  获取LCD闪烁时间寄存器值
  * @param  timevalue 闪烁时间
  * @retval 闪烁时间寄存器
  */
static uint32_t FL_LCD_FlickTime(uint32_t timevalue)
{
    uint32_t stepTime;
    uint32_t TimeResult = 0u;
    switch(FL_LCD_GetCOMNumber(LCD))
    {
        case FL_LCD_COM_NUM_4COM:
            stepTime = (4 * FL_LCD_ReadDisplayFrequency(LCD) * 2 * 16 * 1000) / 32768;
            break;
        case FL_LCD_COM_NUM_6COM:
            stepTime = (6 * FL_LCD_ReadDisplayFrequency(LCD) * 2 * 16 * 1000) / 32768;
            break;
        case FL_LCD_COM_NUM_8COM:
            stepTime = (8 * FL_LCD_ReadDisplayFrequency(LCD) * 2 * 16 * 1000) / 32768;
            break;
        default:
            stepTime = (4 * FL_LCD_ReadDisplayFrequency(LCD) * 2 * 16 * 1000) / 32768;
            break;				
    }
    TimeResult = timevalue / stepTime;
    return TimeResult;
}

/**
  * @brief  复位对应LCD寄存器.

  * @param  LCDx
  * @retval ErrorStatus枚举值:
  *         -FL_PASS 外设寄存器值恢复复位值
  *         -FL_FAIL 未成功执行
  */
FL_ErrorStatus FL_LCD_DeInit(LCD_Type *LCDx)
{
    assert_param(IS_FL_LCD_INSTANCE(LCDx));
    /* 使能外设复位 */
    FL_RMU_EnablePeripheralReset(RMU);
    /* 复位LCD外设寄存器 */
    FL_RMU_EnableResetAPBPeripheral(RMU, FL_RMU_RSTAPB_LCD);
    FL_RMU_DisableResetAPBPeripheral(RMU, FL_RMU_RSTAPB_LCD);
    /* 关闭外设总线始时钟和工作时钟 */
    FL_CMU_DisableGroup2BusClock(FL_CMU_GROUP2_BUSCLK_LCD);
    /* 锁定外设复位 */
    FL_RMU_DisablePeripheralReset(RMU);
    return FL_PASS;
}

/**
  * @brief  根据 LCD_InitStruct 的配置信息初始化对应外设入口地址的寄存器值.
  * @param  LCDx LCDx
  * @param  LCD_InitStruct 指向一个 @ref FL_LCD_InitTypeDef 结构体
  *         其中包含了外设的相关配置信息.
  * @retval ErrorStatus枚举值
  *         -FL_FAIL 配置过程发生错误
  *         -FL_PASS LCD配置成功
  */
FL_ErrorStatus FL_LCD_Init(LCD_Type *LCDx, FL_LCD_InitTypeDef *initStruct)
{
    assert_param(IS_FL_LCD_INSTANCE(LCDx));
    assert_param(IS_FL_LCD_BIASCURRENT(initStruct->biasCurrent));
    assert_param(IS_FL_LCD_ENMODE(initStruct->mode));
    assert_param(IS_FL_LCD_BIASVOLTAGE(initStruct->biasVoltage));
    assert_param(IS_FL_LCD_BIASMD(initStruct->biasMode));
    assert_param(IS_FL_LCD_BWFT(initStruct->waveform));
    assert_param(IS_FL_LCD_LMUX(initStruct->COMxNum));
    /* 外设总线始时钟 */
    FL_CMU_EnableGroup2BusClock(FL_CMU_GROUP2_BUSCLK_LCD);
    /* 电流源电流控制 */
    FL_LCD_SetBiasCurrent(LCD, initStruct->biasCurrent);
    /* LCD驱动模式 */
    FL_LCD_SetDriverMode(LCD, initStruct->mode);
    /* 偏执电压设置 */
    FL_LCD_SetBiasVoltage(LCD, initStruct->biasVoltage);
    /* 偏执模式选择 */
    FL_LCD_SetBiasMode(LCD, initStruct->biasMode);
    /* 驱动波形设置 */
    FL_LCD_SetWaveform(LCD, initStruct->waveform);
    /* COMx口选择 */
    FL_LCD_SetCOMNumber(LCD, initStruct->COMxNum);
    /* 设置工作频率 */
    FL_LCD_WriteDisplayFrequency(LCD, FL_LCD_DisplayFreq(initStruct->waveform,initStruct->displayFreq));
    /* 设置闪烁频率 */
    FL_LCD_WriteDisplayOnTime(LCD, FL_LCD_FlickTime(initStruct->flickOnTime));
    FL_LCD_WriteDisplayOffTime(LCD, FL_LCD_FlickTime(initStruct->flickOffTime));
    /* 使能外设 */
    FL_LCD_Enable(LCD);
    return FL_PASS;
}

/**
  * @brief  设置 LCD_InitStruct 为默认配置
  * @param  LCD_InitStruct 指向需要将值设置为默认配置的结构体 @ref FL_LCD_InitTypeDef 结构体
  *
  * @retval None
  */
void FL_LCD_StructInit(FL_LCD_InitTypeDef *initStruct)
{
    initStruct->biasCurrent         =   FL_LCD_BIAS_CURRENT_HIGH;
    initStruct->mode                =   FL_LCD_DRIVER_MODE_INNER_RESISTER;
    initStruct->biasVoltage         =   FL_LCD_BIAS_VOLTAGE_LEVEL10;
    initStruct->biasMode            =   FL_LCD_BIAS_MODE_3BIAS;
    initStruct->waveform            =   FL_LCD_WAVEFORM_TYPEA;
    initStruct->COMxNum             =   FL_LCD_COM_NUM_6COM;
    initStruct->displayFreq         =   42;
    initStruct->flickOnTime         =   0;
    initStruct->flickOffTime        =   0;
}

/**
  * @brief  设置 LCD 4COM显示字端
  * @param  display 指向显示信息的缓存区域，可直接指向LCD的DATAx寄存器。
  * @param  com 待显示字段所在COM。范围0-4。
  * @param  seg 待显示字段所在SEG。范围0-43。
  * @param  state 待显示字段状态。0，熄灭；否则，点亮。
  *
  * @retval None
  */
void FL_LCD_4COMDisplay(uint32_t *display, uint8_t com, uint8_t seg, uint8_t state)
{
    uint8_t temp;
    if(state != 0)
    {
        state = 1;
    }
    if(seg > 31)
    {
        temp = (seg - 32) + com * 12;
        com = 4 + temp / 32;
        seg = temp % 32;
    }
    MODIFY_REG(display[com], (uint32_t)(0x1U << seg), (uint32_t)(state << seg));
}

/**
  * @brief  设置 LCD 6COM显示字端
  * @param  display 指向显示信息的缓存区域，可直接指向LCD的DATAx寄存器。
  * @param  com 待显示字段所在COM。范围0-6。
  * @param  seg 待显示字段所在SEG。范围0-41。
  * @param  state 待显示字段状态。0，熄灭；否则，点亮。
  *
  * @retval None
  */
void FL_LCD_6COMDisplay(uint32_t *display, uint8_t com, uint8_t seg, uint8_t state)
{
    uint8_t temp;
    if(state != 0)
    {
        state = 1;
    }
    if(seg > 31)
    {
        temp = (seg - 32) + com * 10;
        com = 6 + temp / 32;
        seg = temp % 32;
    }
    MODIFY_REG(display[com], (uint32_t)(0x1 << seg), (uint32_t)(state << seg));
}

/**
  * @brief  设置 LCD 8COM显示字端
  * @param  display 指向显示信息的缓存区域，可直接指向LCD的DATAx寄存器。
  * @param  com 待显示字段所在COM。范围0-8。
  * @param  seg 待显示字段所在SEG。范围0-39。
  * @param  state 待显示字段状态。0，熄灭；否则，点亮。
  *
  * @retval None
  */
void FL_LCD_8COMDisplay(uint32_t *display, uint8_t com, uint8_t seg, uint8_t state)
{
    uint8_t temp;
    if(state != 0)
    {
        state = 1;
    }
    if(seg > 31)
    {
        temp = (seg - 32) + com * 8;
        com = 8 + temp / 32;
        seg = temp % 32;
    }
    MODIFY_REG(display[com], (uint32_t)(0x1 << seg), (uint32_t)(state << seg));
}

/**
  * @}
  */

#endif /* FL_LCD_DRIVER_ENABLED */

/**
  * @}
  */

/**
  * @}
  */

/*************************(C) COPYRIGHT Fudan Microelectronics **** END OF FILE*************************/

