

/**
 ******************************************************************************
 *
 * @file        BSP_7Segment.c
 * @brief       This is 7-seqment Display C file.
 
 * @par         Project
 *              MG32
 * @version     V1.02
 * @date        2023/12/26
 * @author      Megawin Software Center
 * @copyright   Copyright (c) 2022 MegaWin Technology Co., Ltd.
 *              All rights reserved.
 * 
 ******************************************************************************* 
 * @par Disclaimer
 * The Demo software is provided "AS IS" without any warranty, either
 * expressed or implied, including, but not limited to, the implied warranties
 * of merchantability and fitness for a particular purpose. The author will
 * not be liable for any special, incidental, consequential or indirect
 * damages due to loss of data or any other reason.
 * These statements agree with the world wide and local dictated laws about
 * authorship and violence against these laws.
 *******************************************************************************
 *******************************************************************************
 */

/*==============================================================================
                                 User Notes
How To use this function:
-----------------------
    1. Use BSP_7Segment_Init() to initial.
       (1) Default is OFF.
    2. Periodic call BSP_7Segment_main() function.
       (1) (The freq * 4 * SEG7_DramaTimeMax )is 7 segment display refresh rate. 
    3. Display unsigned value by BSP_7Segment_ShowUnsignedValue() function.
       (1) It is decimal display.
       (2) It can display 0000 ~ 9999. ( SEG7_uValueX only 0 ~ 9999)
       (3) SEG_uValue_DP parameter control DP and colon.
    4. Display signed value by BSP_7Segment_ShowSignedValue() function.
       (1) It is decimal display.
       (2) It can display -999 ~ 999. ( SEG7_uValueX only -999 ~ 999)
       (3) SEG7_iVaule_DP parameter control DP and colon.
    5. 7 segment display OFF by BSP_7Segment_Disable() function.
    6. 7 segment display customize display by :
       (1) Change BSP_7Segment_UseDefineDisplay()
       (2) Use BSP_7Segment_TriggerUserDefineDisplay() function to trigger display customize picture.
    
Driver architecture:
--------------------
    + MG32_GPIO_DRV
   
Known Limitations:
------------------

Require parameter
------------------
    Require module : CSC / GPIO
    
    GPIO pin configuration : 
        Pin / IO mode / AFS
        ---  --------  -----
        PA12/ PPO     / GPIO
        PA13/ PPO     / GPIO
        PA14/ PPO     / GPIO
        PA15/ PPO     / GPIO
        PB0 / PPO     / GPIO
        PB1 / PPO     / GPIO
        PB2 / PPO     / GPIO
        PB3 / PPO     / GPIO
        PB4 / PPO     / GPIO
        PB5 / PPO     / GPIO
        PB6 / PPO     / GPIO
        PB7 / PPO     / GPIO        
    
Example codes:
------------------
    1. BSP_7Segment_ShowSignedValue(7777,SEG7_DPMASK_NONE);
       
       >> 7 Segment display : 7777
       
    2. BSP_7Segment_ShowSignedValue(7777,SEG7_DPMASK_2ND);

       >> 7 Segment display : 77.77 
       
    3. BSP_7Segment_ShowSignedValue(7777,SEG7_DPMASK_COLON);
    
       >> 7 Segment display : 77:77 
       
    4. BSP_7Segment_ShowSignedValue(7777,(SEG7_DPMASK_2ND | SEG7_DPMASK_3RD | SEG7_DPMASK_4TH));
       
       >> 7 Segment display : 77.7.7. 

==============================================================================*/

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

/* Wizard menu ---------------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
//GPIO 
#define SEG7_COM1_PIN           PX_Pin_12
#define SEG7_COM2_PIN           PX_Pin_13
#define SEG7_COM3_PIN           PX_Pin_14
#define SEG7_COM4_PIN           PX_Pin_15
#define SEG7_COM_PIN_MODE       PINX_Mode_PushPull_O
#define SEG7_COM_PIN_AFS        0
#define SEG7_COM_IOM            IOMA
#define SEG7_COM_PORT           GPIOA

#define SEG7_A_PIN              PX_Pin_0
#define SEG7_B_PIN              PX_Pin_1
#define SEG7_C_PIN              PX_Pin_2
#define SEG7_D_PIN              PX_Pin_3
#define SEG7_E_PIN              PX_Pin_4
#define SEG7_F_PIN              PX_Pin_5
#define SEG7_G_PIN              PX_Pin_6
#define SEG7_DP_PIN             PX_Pin_7
#define SEG7_PIN_MODE           PINX_Mode_PushPull_O
#define SEG7_PIN_AFS            0
#define SEG7_IOM                IOMB
#define SEG7_PORT               GPIOB

//7-Segment Display display type
#define SEG7_TYPE_DISABLE       0         /*!< Disable.*/
#define SEG7_TYPE_SIGNED        1         /*!< Display signed mode.*/
#define SEG7_TYPE_UNSIGNED      2         /*!< Display unsigned mode.*/
#define SEG7_TYPE_USERDEFINE    3         /*!< Display user define mode.*/
    
//customize display   
#define SEG7_DramaActMax        13   
    
    
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
//7-Segment Display number 0 ~ 9 table
static uint16_t const SEG7_ON_Table[16] = 
{
    (SEG7_A_PIN | SEG7_B_PIN | SEG7_C_PIN | SEG7_D_PIN | SEG7_E_PIN | SEG7_F_PIN ),              // 0
    (SEG7_B_PIN | SEG7_C_PIN ),                                                                  // 1
    (SEG7_A_PIN | SEG7_B_PIN | SEG7_D_PIN | SEG7_E_PIN | SEG7_G_PIN ),                           // 2
    (SEG7_A_PIN | SEG7_B_PIN | SEG7_C_PIN | SEG7_D_PIN | SEG7_G_PIN ),                           // 3
    (SEG7_B_PIN | SEG7_C_PIN | SEG7_F_PIN | SEG7_G_PIN ),                                        // 4
    (SEG7_A_PIN | SEG7_C_PIN | SEG7_D_PIN | SEG7_F_PIN | SEG7_G_PIN ),                           // 5
    (SEG7_A_PIN | SEG7_C_PIN | SEG7_D_PIN | SEG7_E_PIN | SEG7_F_PIN | SEG7_G_PIN ),              // 6
    (SEG7_A_PIN | SEG7_B_PIN | SEG7_C_PIN  ),                                                    // 7
    (SEG7_A_PIN | SEG7_B_PIN | SEG7_C_PIN | SEG7_D_PIN | SEG7_E_PIN | SEG7_F_PIN | SEG7_G_PIN),  // 8
    (SEG7_A_PIN | SEG7_B_PIN | SEG7_C_PIN | SEG7_D_PIN | SEG7_F_PIN | SEG7_G_PIN),               // 9
};
//7-Segment Display COM table                                
static uint16_t const SEG7_COM_Table[4] = 
{
    SEG7_COM1_PIN,
    SEG7_COM2_PIN,
    SEG7_COM3_PIN,
    SEG7_COM4_PIN,
};    
// Calculate Decimal       
static uint16_t const SEG7_Divisor_Table[4]=
{
    1000,    
    100,
    10,
    1
};

static uint16_t const SEG7_UserDefine_Table[13]=
{
    (SEG7_A_PIN | SEG7_B_PIN | SEG7_C_PIN | SEG7_D_PIN | SEG7_E_PIN | SEG7_F_PIN | SEG7_G_PIN | SEG7_DP_PIN), /*!< 8+DP.*/
    (SEG7_A_PIN | SEG7_B_PIN | SEG7_C_PIN | SEG7_D_PIN | SEG7_E_PIN | SEG7_F_PIN | SEG7_G_PIN | SEG7_DP_PIN), /*!< 8+DP.*/
    (SEG7_A_PIN | SEG7_B_PIN | SEG7_C_PIN | SEG7_D_PIN | SEG7_E_PIN | SEG7_F_PIN | SEG7_G_PIN | SEG7_DP_PIN), /*!< 8+DP.*/
    (SEG7_A_PIN | SEG7_B_PIN | SEG7_C_PIN | SEG7_D_PIN | SEG7_E_PIN | SEG7_F_PIN | SEG7_G_PIN | SEG7_DP_PIN), /*!< 8+DP.*/
    (SEG7_A_PIN),                                                                                             /*!< A SEG.*/
    (SEG7_B_PIN),                                                                                             /*!< B SEG.*/
    (SEG7_C_PIN),                                                                                             /*!< C SEG.*/
    (SEG7_D_PIN),                                                                                             /*!< D SEG.*/
    (SEG7_E_PIN),                                                                                             /*!< E SEG.*/
    (SEG7_F_PIN),                                                                                             /*!< F SEG.*/
    (SEG7_G_PIN),                                                                                             /*!< G SEG.*/
    (SEG7_DP_PIN),                                                                                            /*!< DP point.*/
    (0),                                                                                                      
};

static uint16_t const SEG7_UserDefineCOM_Table[13]= 
{
    (SEG7_COM1_PIN),                                                  
    (SEG7_COM2_PIN),                                                  
    (SEG7_COM3_PIN),                                                  
    (SEG7_COM4_PIN),                                                  
    (SEG7_COM1_PIN | SEG7_COM2_PIN | SEG7_COM3_PIN | SEG7_COM4_PIN),  
    (SEG7_COM1_PIN | SEG7_COM2_PIN | SEG7_COM3_PIN | SEG7_COM4_PIN),  
    (SEG7_COM1_PIN | SEG7_COM2_PIN | SEG7_COM3_PIN | SEG7_COM4_PIN),  
    (SEG7_COM1_PIN | SEG7_COM2_PIN | SEG7_COM3_PIN | SEG7_COM4_PIN),  
    (SEG7_COM1_PIN | SEG7_COM2_PIN | SEG7_COM3_PIN | SEG7_COM4_PIN),  
    (SEG7_COM1_PIN | SEG7_COM2_PIN | SEG7_COM3_PIN | SEG7_COM4_PIN),  
    (SEG7_COM1_PIN | SEG7_COM2_PIN | SEG7_COM3_PIN | SEG7_COM4_PIN),  
    (SEG7_COM1_PIN | SEG7_COM2_PIN | SEG7_COM3_PIN | SEG7_COM4_PIN),  
    (0)
};

static uint8_t  SEG7_Type;
static uint16_t SEG7_uValue;
static int16_t  SEG7_iValue;
static uint8_t  SEG7_DpMask;    

static uint16_t SEG7_ValueTmp;  
static uint8_t  SEG7_DpMaskTmp;
static uint8_t  SEG7_DramaAct;
static uint8_t  SEG7_DramaTime;
static uint8_t  SEG7_DramaTimeMax;   

/* Private function prototypes -----------------------------------------------*/
static void BSP_7Segment_NormalDisplay(void);
static void BSP_7Segment_UseDefineDisplay(void);

/* Exported variables --------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/* External variables --------------------------------------------------------*/

/**
 *******************************************************************************
 * @brief	  7-segment Display initial
 * @details    
 * @return     
 * @exception No 
 * @note      No
 *******************************************************************************
 */
void BSP_7Segment_Init(void)
{
    PIN_InitTypeDef  SEG7_Pin;
    
    /*GPIO initial.*/
    GPIO_SetPortBit(SEG7_COM_PORT, (SEG7_COM1_PIN | SEG7_COM2_PIN | SEG7_COM3_PIN | SEG7_COM4_PIN )); 
    GPIO_SetPortBit(SEG7_PORT, (SEG7_A_PIN | SEG7_B_PIN | SEG7_C_PIN | SEG7_D_PIN | SEG7_E_PIN | SEG7_F_PIN | SEG7_G_PIN | SEG7_DP_PIN)); 
    
    SEG7_Pin.PINX_PUResistant        = PINX_PUResistant_Disable;
    SEG7_Pin.PINX_Speed              = PINX_Speed_Low;
    SEG7_Pin.PINX_Inverse            = PINX_Inverse_Disable;
    SEG7_Pin.PINX_OUTDrive           = PINX_OUTDrive_Level0;
    SEG7_Pin.PINX_FilterDivider      = PINX_FilterDivider_Bypass;

    SEG7_Pin.PINX_Pin                = (SEG7_A_PIN | SEG7_B_PIN | SEG7_C_PIN | SEG7_D_PIN | SEG7_E_PIN | SEG7_F_PIN | SEG7_G_PIN | SEG7_DP_PIN);
    SEG7_Pin.PINX_Alternate_Function = SEG7_PIN_AFS;
    SEG7_Pin.PINX_Mode               = SEG7_PIN_MODE;
    GPIO_PortMode_Config( SEG7_IOM ,&SEG7_Pin);

    SEG7_Pin.PINX_Pin                = (SEG7_COM1_PIN | SEG7_COM2_PIN | SEG7_COM3_PIN | SEG7_COM4_PIN);
    SEG7_Pin.PINX_Alternate_Function = SEG7_COM_PIN_AFS;
    SEG7_Pin.PINX_Mode               = SEG7_COM_PIN_MODE;
    GPIO_PortMode_Config( SEG7_COM_IOM ,&SEG7_Pin);

    /*Parameter initial.*/
    BSP_7Segment_Disable();
}
/**
 *******************************************************************************
 * @brief	  7-segment Display OFF
 * @details   Disable display & clear Drama
 * @return     
 * @exception No 
 * @note      No
 *******************************************************************************
 */
void BSP_7Segment_Disable(void)
{
    SEG7_Type = SEG7_TYPE_DISABLE;
    
    SEG7_DramaAct     = 0;
    SEG7_DramaTime    = 0;
    SEG7_DramaTimeMax = 0;
}
/**
 *******************************************************************************
 * @brief	  7-segment Display displays signed value (decimal)
 * @details    
 * @param[in] SEG7_iVaule: ( 999 ~ -999)
 * @param[in] SEG7_iVaule_DP : Control DP whether ON or not.
 *   \n       - (SEG7_DPMASK_2ND ~ SEG7_DPMASK_4TH) It can multiple choice.
 * @return    Return if the input parameter is correct or not.
 * @exception No 
 * @note      No
 * @par       Example
 * @code
    BSP_7Segment_ShowSignedValue( -123, SEG7_DPMASK_NONE);                        // Display -123 and all DP no ON.

    or

    BSP_7Segment_ShowSignedValue( 456, (SEG7_DPMASK_2ND | SEG7_DPMASK_COLON));    // Display 456 , 2ND DP and Colon ON.

  * @endcode
 *******************************************************************************
 */
uint8_t BSP_7Segment_ShowSignedValue( int16_t SEG7_iValueX, uint8_t SEG7_iVaule_DP)
{
    if( SEG7_iValueX > 999 || SEG7_iValueX < -999)
    {
        return(SEG7_DISPLAY_FAILURE);  
    }
    
    SEG7_iValue = SEG7_iValueX;
    SEG7_DpMask = SEG7_iVaule_DP;
    SEG7_Type   = SEG7_TYPE_SIGNED;
    
    SEG7_DramaAct     = 0;
    SEG7_DramaTime    = 0;
    SEG7_DramaTimeMax = 0;
    
    return(SEG7_DISPLAY_SUCCESS);
}
/**
 *******************************************************************************
 * @brief	  7-segment Display displays unsigned value (decimal)
 * @details    
 * @param[in] SEG7_uValue: ( 9999 ~ 0)
 * @param[in] SEG7_uVaule_DP : Control DP whether ON or not.
 *   \n       - (SEG7_DPMASK_2ND ~ SEG7_DPMASK_4TH) It can multiple choice.
 * @return    Return if the input parameter is correct or not.
 * @exception No 
 * @note      No
 * @par       Example
 * @code
    BSP_7Segment_ShowUnsignedValue( 1234, SEG7_DPMASK_NONE);                        // Display 1234 and all DP no ON.

    or

    BSP_7Segment_ShowUnsignedValue( 5678, (SEG7_DPMASK_2ND | SEG7_DPMASK_COLON));   // Display 5678 , 2ND DP and Colon ON.

  * @endcode
 *******************************************************************************
 */
uint8_t BSP_7Segment_ShowUnsignedValue( uint16_t SEG7_uValueX, uint8_t SEG7_uVaule_DP )
{
    if( SEG7_uValueX > 9999)
    {
        return(SEG7_DISPLAY_FAILURE);  
    }
    SEG7_uValue = SEG7_uValueX;
    SEG7_DpMask = SEG7_uVaule_DP;
    SEG7_Type   = SEG7_TYPE_UNSIGNED;
    
    SEG7_DramaAct     = 0;
    SEG7_DramaTime    = 0;
    SEG7_DramaTimeMax = 0;
    
    return(SEG7_DISPLAY_SUCCESS);
}
/**
 *******************************************************************************
 * @brief	  Trigger 7-segment Display to display "User define ".
 * @details    
 * @return     
 * @exception No 
 * @note      No
 *******************************************************************************
 */
void BSP_7Segment_TriggerUserDefineDisplay(void)
{
    SEG7_Type = SEG7_TYPE_USERDEFINE;
    
    SEG7_DramaAct     = 0;
    SEG7_DramaTime    = 0;
    SEG7_DramaTimeMax = 40;
}
/**
 *******************************************************************************
 * @brief	  7-Segment Display main function.
 * @details   According visiting function frequency to control 7 segment 
              refresh frequency. 
 * @return     
 * @exception No 
 * @note      No
 *******************************************************************************
 */
void BSP_7Segment_main(void)
{
    if( SEG7_DramaTime < (SEG7_DramaTimeMax+1))
    {
        SEG7_DramaTime = 0;
        
        /*Turn off 4x7-SEG display*/
        GPIO_SetPortBit(SEG7_PORT, (SEG7_A_PIN | SEG7_B_PIN | SEG7_C_PIN | SEG7_D_PIN | SEG7_E_PIN | SEG7_F_PIN | SEG7_G_PIN | SEG7_DP_PIN));
        GPIO_SetPortBit(SEG7_COM_PORT, SEG7_COM1_PIN | SEG7_COM2_PIN | SEG7_COM3_PIN | SEG7_COM4_PIN);
        
        /*Display depend on SEG7_Type*/
        switch( SEG7_Type)
        {
            case SEG7_TYPE_DISABLE:
                                    break;
            case SEG7_TYPE_SIGNED:
            case SEG7_TYPE_UNSIGNED:
                                    BSP_7Segment_NormalDisplay();
                                    if( SEG7_DramaAct == 3)
                                    {
                                        SEG7_DramaAct = 0;
                                    }
                                    else
                                    {
                                        SEG7_DramaAct = SEG7_DramaAct + 1;
                                    }
                                    break;
            default:
                                    BSP_7Segment_UseDefineDisplay();
                                    break;
        }
    }
    else
    {
        SEG7_DramaTime  = SEG7_DramaTime  + 1;
    }
}
/**
 *******************************************************************************
 * @brief	  7-segment Display normal display.
 * @details   Display signal value (999 ~ -999) or unsigned value( 9999 ~ 0) 
 * @return     
 * @exception No 
 * @note      No
 *******************************************************************************
 */
static void BSP_7Segment_NormalDisplay(void)
{
    uint32_t SEG7_NRLTmp;

    /* 7 segment COM 0 handler*/
    if( SEG7_DramaAct == 0)
    {
        SEG7_DpMaskTmp = SEG7_DPMASK_2ND;
        
        if( SEG7_DpMask & SEG7_DpMaskTmp)
        {
            GPIO_ClearPortBit( SEG7_PORT,SEG7_DP_PIN);
        }
        
        if( SEG7_Type == SEG7_TYPE_UNSIGNED)
        {
            SEG7_ValueTmp = SEG7_uValue;
        }
        else if( SEG7_iValue & 0x8000)
        {
            GPIO_ClearPortBit( SEG7_PORT,SEG7_G_PIN);
            GPIO_ClearPortBit( SEG7_COM_PORT,SEG7_COM_Table[0]);

            SEG7_ValueTmp = (uint16_t)(~( SEG7_iValue - 1));
            return;
        }
        else
        {
            SEG7_ValueTmp = (uint16_t)SEG7_iValue;
            return;
        }
    }
    /* 7 segment COM 1 ~ 3 handler*/
    else
    {
        SEG7_DpMaskTmp = (uint8_t)(SEG7_DpMaskTmp << 1);
        
        if( SEG7_DpMask & SEG7_DpMaskTmp)
        {
            GPIO_ClearPortBit( SEG7_PORT,SEG7_DP_PIN);
        }
    }
    
    GPL->DIVD.W   = (uint32_t)SEG7_ValueTmp;
    GPL->DIVS.W   = (uint32_t)SEG7_Divisor_Table[SEG7_DramaAct];  
    GPL->CR1.W   |= GPL_CR1_DIV_START_mask_w;
    while(GPL->CR1.W & GPL_CR1_DIV_START_mask_w);
    SEG7_ValueTmp = (uint16_t)GPL->REM.W;              /*!<Get remainer.*/
    SEG7_NRLTmp = GPL->QUT.W;                          /*!<Get quotient.*/

    GPIO_ClearPortBit( SEG7_PORT,SEG7_ON_Table[SEG7_NRLTmp]);
    GPIO_ClearPortBit( SEG7_COM_PORT,SEG7_COM_Table[SEG7_DramaAct]);
}

/**
 *******************************************************************************
 * @brief	  7 segment initial
 * @details   User can modify "SEG7_UserDefine_Table" and  "SEG7_UserDefineCOM_Table"
              to own display.
 * @return     
 * @exception No 
 * @note      No
 *******************************************************************************
 */
static void BSP_7Segment_UseDefineDisplay(void)
{
    GPIO_ClearPortBit( SEG7_PORT,SEG7_UserDefine_Table[SEG7_DramaAct]);
    GPIO_ClearPortBit( SEG7_COM_PORT,SEG7_UserDefineCOM_Table[SEG7_DramaAct]);
    
    if( SEG7_DramaAct == (SEG7_DramaActMax-1))
    {
        SEG7_DramaAct = 0;
    }
    else
    {
        SEG7_DramaAct = SEG7_DramaAct + 1;
    }
}



