/**
  ******************************************************************************
  * @file    ys32md211_led.c
  * @author  YSPRING Application Team
  * @version V1.0.1
  * @date    2025.02.15
  * @brief   This file provides firmware functions to manage the following
  *          functionalities of the LED peripheral:
  *           + Initialization and Configuration functions
  *           + Flag management
  *           + LED functions Configuration
  *
  *  @verbatim
  *
  *
    ===========================================================================
                         ##### How to use this driver #####
    ===========================================================================
      [..]
      (#) Enable the LED APB2 clock using RCC_APB2PeriphClockCmd()
      (#) Configure the LED using LED_Init()
          Six possible configuration are available for LED: 
         (++) Division: System clock frequency division parameter <= 0x0f
         (++) Scan first: Configure the start line of scanning(LED[0]~LED[8]).
         (++) Array Mode: No Array or 4*4, 5*5, 6*6, 6*7, 7*7, 7*8, 8*8.
         (++) Scan Mode: Loop Scan mode or Interrupt mode.
         (++) Time: LED on-time 1 and 0 configuration.
      (#) Configuration process:
         (++) The interrupted scan mode configuration:
              (+++) Use LED_ClearITPendingBit() to clear LED interrupt.
              (+++) Using LED_Init() to Configure the clock frequency division
                    Configure the indicator status and indicator period register.
                    Set led turn-on time 0 and 1.
              (+++) Configure the driver configuration register.
              (+++) Configure the configuration register.
              (+++) Configure LED_Cmd() to start scan.
              (+++) An interrupt is generated
                   (the scan open register is configured to automatically clear),
                   and the scan is complete.
              (+++) The CPU processing is interrupted.
         (++) The Loop scan mode configuration:
              (+++) Using LED_Init() to Configure the clock frequency division
                    Configure the indicator status and indicator period register.
                    Set led turn-on time 0 and 1.
              (+++) Configure the driver configuration register.
              (+++) Configure the configuration register (start scanning).
              (+++) Configure LED_Cmd() to start scan.
              (+++) Cyclic scanning (in frames).
              (+++) Configure the configuration register (turn off scanning).
         (++) No Array:
              (+++) Using LED_Init() to Configure No array mode.
              (+++) Auto scan invalid.
              (+++) led_start set 0 by hardware.
              (+++) To light the led, the GPIO output status determines the light status.
         (++) High-current:
              (+++) Using LED_Init() and LED_SetHighCurrent() to Configure the high-current mode.
              (+++) The automatic scan is invalid.
              (+++) The led_start and LED_ArrayMode values are automatically set to 0.
              (+++) To light the led, the GPIO output status determines the light status.

    @endverbatim
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "ys32md211_led.h"

/** @addtogroup YS32MD211_StdPeriph_Driver
 * @{
 */

/** @defgroup LED
 * @brief LED driver modules
 * @{
 */

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/

/** @defgroup LED_Private_Functions
 * @{
 */

/** @defgroup LED_Group1 Initialization and Configuration
 *  @brief   Initialization and Configuration
 *
@verbatim
 ===============================================================================
                    ##### Initialization and Configuration #####
 ===============================================================================

@endverbatim
  * @{
  */

/**
 * @brief  Deinitializes LED peripheral registers to their default reset values.
 * @param  None
 * @retval None
 */
void LED_DeInit(void)
{
  /* Set ICDR register to reset value */
  LED->ICDR = 0x00000001;

  /* Set the OTCR register to the reset value*/
  LED->OTCR = 0x00000000;

  /* Reset GCR register */
  LED->GCR = 0x0000;

  /* Reset SCR1 register to reset value */
  LED->SCR1 = 0x00000000;

  /* Reset SCR2 register to reset value */
  LED->SCR2 = 0x00000000;

  /* Reset OPSR1 register to reset value */
  LED->OPSR1 = 0x00000000;

  /* Reset OPSR2 register to reset value */
  LED->OPSR2 = 0x00000000;

  /* Reset COMENR register to reset value */
  LED->COMENR = 0x00000000;
}
/**
 * @brief  Initializes the LED peripheral according to the specified
 *         parameters in the LED_InitStruct.
 * @param  LED_InitStruct: pointer to a LED_InitTypeDef structure that contains
 *         the configuration information for the specified LED peripheral.
 * @retval None
 */
void LED_Init(LED_InitTypeDef *LED_InitStruct)
{
  assert_param(IS_LED_CLK_DIV(LED_InitStruct->LED_ClkDiv));
  assert_param(IS_LED_SCAN_FIRST(LED_InitStruct->LED_ScanFirst));
  assert_param(IS_LED_ARRAY_MODE(LED_InitStruct->LED_ArrayMode));
  assert_param(IS_LED_SCAN_MODE(LED_InitStruct->LED_ScanMode));
  assert_param(IS_LED_ON_TIME0_1(LED_InitStruct->LED_OnTime0));
  assert_param(IS_LED_ON_TIME0_1(LED_InitStruct->LED_OnTime1));

  LED->ICDR = LED_InitStruct->LED_ClkDiv;
  LED->OTCR = (LED_InitStruct->LED_OnTime1 << 8) | LED_InitStruct->LED_OnTime0;
  LED->GCR = LED_InitStruct->LED_ScanFirst | LED_InitStruct->LED_ArrayMode | LED_InitStruct->LED_ScanMode;
}

/**
 * @brief  Fills each LED_InitStruct member with its reset value.
 * @param  LED_InitStruct: pointer to a LED_InitTypeDef structure which will
 *         be initialized.
 * @retval None
 */
void LED_StructInit(LED_InitTypeDef *LED_InitStruct)
{
  LED_InitStruct->LED_ClkDiv = 0x01;
  LED_InitStruct->LED_OnTime0 = 0;
  LED_InitStruct->LED_OnTime1 = 0;

  LED_InitStruct->LED_ScanFirst = LED_ScanFirst_0;
  LED_InitStruct->LED_ScanMode = LED_ScanMode_INT;
  LED_InitStruct->LED_ArrayMode = LED_ArrayMode_None;
}

/**
 * @brief  Enables or disables the specified LED peripheral.
 * @param  NewState: new state of the LED peripheral.
 *         This parameter can be: ENABLE or DISABLE.
 * @retval None
 */
void LED_Cmd(FunctionalState NewState)
{
  /* Check the parameters */
  assert_param(IS_FUNCTIONAL_STATE(NewState));

  if (NewState == ENABLE)
  {
    /* Set the ENABLE bit */
    LED->GCR |= LED_GCR_STAR;
  }
  else
  {
    /* Reset the ENABLE bit */
    LED->GCR &= (~LED_GCR_STAR);
  }
}

/**
 * @brief  config Led Scan mode.
 * @note   When set to break mode(LED_ScanMode_INT), scan completion is interrupted.
 * @param  ScanMode: LED Scan mode.
 *         This parameter can be one of the following values:
 *         @arg @ref LED_ScanMode_INT  : Interrupt scan mode
 *         @arg @ref LED_ScanMode_LOOP : Cycle scan mode (no interrupted)
 * @retval None
 */
void LED_ScanModeConfig(uint32_t ScanMode)
{
  /* Check the parameters */
  assert_param(IS_LED_SCAN_MODE(ScanMode));

  /* Reset the ENABLE bit */
  LED->GCR &= (~LED_GCR_SCAN_MODE);

  LED->GCR |= ScanMode;
}

/**
 * @brief  config Led Array mode.
 * @param  ArrayMode: LED Array mode.
 *         This parameter can be one of the following Values:
 *         @arg @ref LED_ArrayMode_None : None
 *         @arg @ref LED_ArrayMode_4X4  : 4X4 Array
 *         @arg @ref LED_ArrayMode_5X5  : 5X5 Array
 *         @arg @ref LED_ArrayMode_6X6  : 6X6 Array
 *         @arg @ref LED_ArrayMode_6X7  : 6X7 Array
 *         @arg @ref LED_ArrayMode_7X7  : 7X7 Array
 *         @arg @ref LED_ArrayMode_7X8  : 7X8 Array
 *         @arg @ref LED_ArrayMode_8X8  : 8X8 Array
 * @retval None
 */
void LED_ArrayModeConfig(uint32_t ArrayMode)
{
  /* Check the parameters */
  assert_param(IS_LED_ARRAY_MODE(ArrayMode));

  /* Reset the ENABLE bit */
  LED->GCR &= (~LED_GCR_ARRAY_MODE);

  LED->GCR |= ArrayMode;
}

/**
 * @}
 */

/** @defgroup LED_Group2 LED array configuration functions
  *  @brief    LED array parameter configuration
  *
@verbatim
 ===============================================================================
                  LED array configuration functions
 ===============================================================================
  This section provides functions allowing to configure the LED array

@endverbatim
  * @{
  */

/**
 * @brief  Select the On-period T0/T1 of the LED
 * @param  Bit0_31:   0~31 Bit.
 * @param  Bit32_63: 32~63 Bit.
 * @retval None
 */
void LED_SetOnPeriodTime(uint32_t Bit0_31, uint32_t Bit32_63)
{
  LED->OPSR1 = Bit0_31;
  LED->OPSR2 = Bit32_63;
}

/**
 * @brief  Set the state of the LED(ON/OFF)
 * @param  Bit0_31:   0~31 Bit.
 * @param  Bit32_63: 32~63 Bit.
 * @retval None
 */
void LED_SetOnArray(uint32_t Bit0_31, uint32_t Bit32_63)
{
  LED->SCR1 = Bit0_31;
  LED->SCR2 = Bit32_63;
}

/**
 * @brief  Get 64 Leds ON/OFF Status and Put the value into pBit0_31 and pBit32_63.
 * @param  pBit0_31:   0~31 Bit data pointer.
 * @param  pBit32_63: 32~63 Bit data pointer.
 * @retval None
 */
void LED_GetOnArray(uint32_t * pBit0_31, uint32_t * pBit32_63)
{
  *pBit0_31  = LED->SCR1;
  *pBit32_63 = LED->SCR2;
}

/**
 * @}
 */

/** @defgroup LED_Group3 LED specifical bit configuration functions
  *  @brief    LED bit parameter configuration
  *
@verbatim
 ===============================================================================
                  LED specifical bit configuration functions
 ===============================================================================
  This section provides functions allowing to configure the specifical LED bit

@endverbatim
  * @{
  */

/**
 * @brief  Set the bit(ON) of the LED
 * @param  LED_ID: LED_Dx (x=0..63)
 *         This parameter can be one of the following values:
 *         @arg @ref LED_D0
 *         @arg @ref LED_D1
 *         @arg @ref LED_D2
 *         @arg @ref LED_D3
 *         @arg @ref LED_D4
 *          .
 *          .
 *          .
 *         @arg @ref LED_D63
 * @param  NewState: new state of the Led On/Off Status. 
  *         This parameter can be: ENABLE or DISABLE.
 * @retval None
 */
void LED_SetOnBit(uint8_t LED_ID, FunctionalState NewState)
{
  /* Check the parameters */
  assert_param(IS_LED_BIT_ID(LED_ID));

  if (LED_ID < 32)
  {
    if (NewState != DISABLE)
    {
      LED->SCR1 |= (1 << LED_ID);
    }
    else
    {
      LED->SCR1 &= ~(1 << LED_ID);
    }
  }
  else
  {
    LED_ID -= 32;
    if (NewState != DISABLE)
    {
      LED->SCR2 |= (1 << LED_ID);
    }
    else
    {
      LED->SCR2 &= ~(1 << LED_ID);
    }
  }
}

/**
 * @brief  Checks if the LED is ON
 * @param LED_ID: LED_Dx (x=0..63)
 *         This parameter can be one of the following values:
 *         @arg @ref LED_D0
 *         @arg @ref LED_D1
 *         @arg @ref LED_D2
 *         @arg @ref LED_D3
 *         @arg @ref LED_D4
 *          .
 *          .
 *          .
 *         @arg @ref LED_D63
 * @retval State of bit (1 or 0).
 *         SET : LED ON
 *         RESET : LED OFF
 */
FlagStatus LED_GetOnBit(uint8_t LED_ID)
{
  ITStatus bitstatus;
  uint32_t Tmp;

  /* Check the parameters */
  assert_param(IS_LED_BIT_ID(LED_ID));

  if (LED_ID < 32)
  {
    Tmp = LED->SCR1;
  }
  else
  {
    LED_ID -= 32;
    Tmp = LED->SCR2;
  }
  if (Tmp & (1 << LED_ID))
    bitstatus = SET;
  else
    bitstatus = RESET;

  return bitstatus;
}

/**
 * @}
 */

/** @defgroup LED_Group4 Interrupts and flags management functions
  *  @brief    Interrupts and flags management functions
  *
@verbatim
 ===============================================================================
                  Interrupts and flags management functions
 ===============================================================================
  This section provides functions allowing to configure the LED Interrupts, get
  the status and clear flags bits.

@endverbatim
  * @{
  */

/**
 * @brief  Check whether the specified LED interrupt has occurred or not.
 * @param  LED_IT: specifies the LPTIM interrupt source to check.
 *            @arg LED_IT_INT: LED interrupts flag
 * @retval The new state of LED_IT (SET or RESET).
 */
ITStatus LED_GetITStatus(uint32_t LED_IT)
{
  ITStatus bitstatus = RESET;
  uint32_t enablestatus = 0;

  /* Check the parameters */
  assert_param(IS_LED_IT_CONFIG(LED_IT));

  if ((LED_IT == LED_IT_INT) && ((LED->GCR & LED_GCR_SCAN_MODE) == 0))
    enablestatus = 1;

  if ((LED->ICDR & LED_IT) && (enablestatus != 0))
    bitstatus = SET;
  else
    bitstatus = RESET;

  return bitstatus;
}

/**
 * @brief  Clear the specified LED interrupt flag.
 * @param  LED_IT: specifies the pending bit to clear.
 *            @arg LED_IT_INT: LED interrupts flag
 * @retval None
 */
void LED_ClearITPendingBit(uint32_t LED_IT)
{
  /* Check the parameters */
  assert_param(IS_LED_IT_CONFIG(LED_IT));

  /* Clear the IT pending Bit */
  LED->ICDR &= (~LED_IT);
}

/**
 * @}
 */

/** @defgroup LED_Group5 Current management functions
  *  @brief    Current management functions
  *
@verbatim
 ===============================================================================
                  Current management functions
 ===============================================================================
  This section provides functions allowing to configure the LED current management.

@endverbatim
  * @{
  */

/**
 * @brief  Configures LED High current mode.
 * @param  COMENx: This parameter can be one of the following values:
 *         @arg LED_HIGH_CURRENT_BIT0
 *         @arg LED_HIGH_CURRENT_BIT1
 *         @arg LED_HIGH_CURRENT_BIT2
 *         @arg LED_HIGH_CURRENT_BIT3
 *         @arg LED_HIGH_CURRENT_BIT4
 *         @arg LED_HIGH_CURRENT_BIT5
 *         @arg LED_HIGH_CURRENT_BIT6
 *         @arg LED_HIGH_CURRENT_BIT7
 *         @arg LED_HIGH_CURRENT_BIT8
 * @param  LED_Mode: LED current mode configuration
 *          This parameter can be one of the following values:
 *         @arg LED_NormalCurrent
 *         @arg LED_HighCurrent
 * @note   Only apply for one bit, Config invalid if over one bit
 *         When in cyclic scan mode or interrupt scan mode,
 *         COMENx is configured by hardware
 * @retval None
 */
void LED_SetHighCurrent(uint16_t COMENx, uint16_t LED_Mode)
{
  /* Check the parameters */
  assert_param(IS_LED_HIGH_CURRENT(COMENx));
  assert_param(IS_LED_MODE(LED_Mode));

  if((LED->GCR & LED_GCR_ARRAY_MODE) == 0)
  {
    /* Write to LED COMENR register */
    LED->COMENR = (LED_Mode << COMENx);
  }
}

/**
 * @brief  Gets the LED COMENR value.
 * @param  None
 * @note   When in cyclic scan mode or interrupt scan mode,
 *         COMENx is configured by hardware
 * @retval This parameter can be one of the following Values:
 * @note   In Matrix mode (LED_ARRAY_MODE != 0), Configured by hardware.
 * 
 *         0x01F : 4*4 array
 *         0x03F : 5*5 array
 *         0x07F : 6*6 array
 *         0x07F : 6*7 array
 *         0x0FF : 7*7 array
 *         0x0FF : 7*8 array
 *         0x1FF : 8*8 array
 * 
 * @note   Non-matrix mode (LED_ARRAY_MODE == 0), Configured by LED_SetHighCurrent(), 
 *         Only one can be enabled at the same time.
 * 
 *         0x001 : LED0 High Current
 *         0x002 : LED1 High Current
 *         0x004 : LED2 High Current
 *         0x008 : LED3 High Current
 *         0x010 : LED4 High Current
 *         0x020 : LED5 High Current
 *         0x040 : LED6 High Current
 *         0x080 : LED7 High Current
 *         0x100 : LED8 High Current
 * 
 */
uint32_t LED_GetHighCurrent(void)
{
  /* Get the COMENR Register value */
  return LED->COMENR;
}

/**
 * @}
 */

/**
 * @}
 */

/**
 * @}
 */

/**
 * @}
 */
