/**
  *******************************************************************************************************
  * @file    fm33fr0xx_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.
  * 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 "fm33fr0xx_fl.h"
/** @addtogroup FM33FR0xx_FL_Driver_LCD
  * @{
  */

/** @addtogroup 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)))


/**
  * @}
  */
/** @addtogroup LCD_FL_EF_Init
  * @{
  */

/**
  * @brief  复位对应LCD寄存器.
  * @param  LCDx
  * @retval ErrorStatus枚举值:
  *         -FL_PASS 外设寄存器值恢复复位值
  *         -FL_FAIL 未成功执行
  */
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  LCDx
  * @retval ErrorStatus枚举值:
  *         -FL_PASS 外设寄存器值恢复复位值
  *         -FL_FAIL 未成功执行
  */
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)
{
    FL_ErrorStatus status = FL_FAIL;
    if(initStruct != NULL)
    {
        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);
        /* data模式 */
        FL_LCD_SetDataMode(LCD, initStruct->datamode);
        /* 设置工作频率 */
        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);
        status = FL_PASS;
    }
    return status;
}

/**
  * @brief  设置 LCD_InitStruct 为默认配置
  * @param  LCD_InitStruct 指向需要将值设置为默认配置的结构体 @ref FL_LCD_InitTypeDef 结构体
  *
  * @retval None
  */
void FL_LCD_StructInit(FL_LCD_InitTypeDef *initStruct)
{
    if(initStruct != NULL)
    {
        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->datamode            =   FL_LCD_DATA_MODE_0;
        initStruct->displayFreq         =   42;
        initStruct->flickOnTime         =   0;
        initStruct->flickOffTime        =   0;
    }
}

/**
  * @brief  根据 LED_InitStruct 的配置信息初始化对应外设入口地址的寄存器值.
  * @param  LCDx LCDx
  * @param  LED_InitStruct 指向一个 @ref FL_LED_InitTypeDef 结构体
  *         其中包含了外设的相关配置信息.
  * @retval ErrorStatus枚举值
  *         -FL_FAIL 配置过程发生错误
  *         -FL_PASS LCD配置成功
  */
FL_ErrorStatus FL_LED_Init(LCD_Type *LCDx, FL_LED_InitTypeDef *initStruct)
{
    FL_ErrorStatus status = FL_FAIL;
    if(initStruct !=    NULL)
    {
        assert_param(IS_FL_LCD_INSTANCE(LCDx));
        assert_param(IS_FL_LCD_LMUX(initStruct->COMxNum));
        /* 外设总线始时钟 */
        FL_CMU_EnableGroup2BusClock(FL_CMU_GROUP2_BUSCLK_LCD);
        /* COMx口选择 */
        FL_LCD_SetCOMNumber(LCD, initStruct->COMxNum);
        /* seg 极性 */
        FL_LCD_SetSegPnOutputPolarity(LCD, initStruct->segPolarity);
        /* dig 极性 */
        FL_LCD_SetDigPnOutputPolarity(LCD, initStruct->digPolarity);
        /* data模式 */
        FL_LCD_SetDataMode(LCD, initStruct->datamode);
        /* 设置工作频率 */
        FL_LCD_WriteDisplayFrequency(LCD, FL_LCD_DisplayFreq(FL_LCD_WAVEFORM_TYPEA, initStruct->displayFreq));
        /* 设置闪烁频率 */
        FL_LCD_WriteDisplayOnTime(LCD, FL_LCD_FlickTime(initStruct->flickOnTime));
        FL_LCD_WriteDisplayOffTime(LCD, FL_LCD_FlickTime(initStruct->flickOffTime));
        status = FL_PASS;
    }
    return status;
}

/**
  * @brief  设置 LED_InitStruct 为默认配置
  * @param  LED_InitStruct 指向需要将值设置为默认配置的结构体 @ref FL_LED_InitTypeDef 结构体
  *
  * @retval None
  */
void FL_LED_StructInit(FL_LED_InitTypeDef *initStruct)
{
    if(initStruct != NULL)
    {
        initStruct->COMxNum             =   FL_LCD_COM_NUM_8COM;
        initStruct->displayFreq         =   50;
        initStruct->segPolarity         =   FL_LCD_SEG_OUTPUT_POLARITY_NORMAL;
        initStruct->digPolarity         =   FL_LCD_DIG_OUTPUT_POLARITY_NORMAL;
        initStruct->datamode            =   FL_LCD_DATA_MODE_0;
        initStruct->flickOnTime         =   0;
        initStruct->flickOffTime        =   0;
    }
}

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

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

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

/**
  * @}
  */
/**
  * @}
  */
/**************************Py_Code_Generator Version: 0.1-0.5-0.1 @ 2019-10-17**************************/
/*************************(C) COPYRIGHT Fudan Microelectronics **** END OF FILE*************************/
