




 /**
 ******************************************************************************
 *
 * @file        MG32_ARGB_WS2812.c
 * @brief       
 
 * @par         Project
 *              MG32
 * @version     V1.03
 * @date        2022/09/26
 * @author      Megawin Software Center
 * @copyright   Copyright (c) 2017 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.
 *******************************************************************************
 *******************************************************************************
 */
 
/* Includes ------------------------------------------------------------------*/ 
#include "MG32__Common_DRV.h"
#include "MG32_GPIO_DRV.h"
#include "MG32_TM_DRV.h"
#include "MG32_URT_DRV.h"
#include "MG32_SPI_DRV.h"
#include "MG32_ARGB_API.h"


/* Wizard menu ---------------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define SMP_ARGB_PIECE           14                        /*!< Sample 14 pieces ARGB (The define can not to equal 1 )*/
#define SMP_ARGB_COLLOR_MAX      50                        /*!< The ARGB sample code max color.*/ 
                                 
                                 
#define SMP_ARGB_DATASIZE        3
#define SMP_ARGB_G               0                         /*!< ARGB green color data shift.*/
#define SMP_ARGB_R               1                         /*!< ARGB red color data shift.*/
#define SMP_ARGB_B               2                         /*!< ARGB bule color data shift.*/

#define API_ARGB_DEFAULT_COLOR   6                         /*!< Total Color setting.*/


#define ARGB_DATA_URTX                                     URT5
#define ARGB_RST_URTX                                      URT2
#define ARGB_DATA_IRQ                                      URT123_IRQn
#define ARGB_RST_IRQ                                       URT4x_IRQn

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
ARGBCTR_TypeDef          ARGB0;                            /*!< Control ARGB parameter.*/
volatile static uint8_t  ARGB_UpdateFlag;                  /*!< Calculate next data flag.*/

static uint8_t API_ARGB_UpdateBUF[SMP_ARGB_PIECE][3];      /*!< ARGB update buffer.*/                
                                             
static uint8_t API_ARGB_DramaBUF[SMP_ARGB_PIECE][3];       /*!<.The buffer is use for ARGB calculate.*/
                                              
                                              
static uint8_t API_ARGBDefault_TABLE[API_ARGB_DEFAULT_COLOR][3] = {
                                                                      { 0 ,  50 ,   0},    // ARGB0 (Input first): [G : R : B ] = [  0, 50,  0]
                                                                      {50 ,  50 ,   0},    // ARGB1              : [G : R : B ] = [ 50, 50,  0]
                                                                      {50 ,   0 ,   0},    // ARGB2              : [G : R : B ] = [ 50,  0,  0] 
                                                                      {50 ,   0 ,  50},    // ARGB3              : [G : R : B ] = [ 50,  0, 50] 
                                                                      { 0 ,   0 ,  50},    // ARGB4              : [G : R : B ] = [  0,  0, 50] 
                                                                      {50 ,  50 ,  50},    // ARGB5              : [G : R : B ] = [ 50, 50, 50]
                                                                  };

/* Private function prototypes -----------------------------------------------*/
void API_RGB_CloseAll(ARGBCTR_TypeDef* sARGB );
void TM0x_IRQHandler(void);

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

/**
 * @name	Control ARGB  Function.
 *   		
 */ 
///@{
/**
// *******************************************************************************
// * @brief       Delay us
// * @details  
// * @param[in]   DLY:
// *  @arg\b          0 ~ 255.
// * @return
// * @note
// * @par         Example
// * @code
//    Delay_us(80);
// * @endcode
// *******************************************************************************
// */
//static void ifun_Delay_us(uint8_t DLY)
//{
//    uint8_t CNT;

//    CNT = DLY;
//    do
//    {
//        __NOP();    __NOP();    __NOP();    __NOP();    __NOP();
//        __NOP();    __NOP();    __NOP();    __NOP();    __NOP();
//        __NOP();    __NOP();    __NOP();    __NOP();    __NOP();
//        __NOP();    __NOP();    __NOP();    __NOP();    __NOP();
//        __NOP();    __NOP();    __NOP();    __NOP();    __NOP();
//        __NOP();    __NOP();    __NOP();    __NOP();    __NOP();
//        __NOP();    __NOP();    __NOP();    __NOP();    __NOP();
//        __NOP();    __NOP();    __NOP();    __NOP();    __NOP();
//        __NOP();
//        CNT--;
//    }while(CNT>0);
//}

 /**
 *******************************************************************************
 * @brief	   UART use blocking mode to update ARGB  
 * @details     
 * @param      sARGB            : ARGB handle.
 * @param      UpDate_ARGBCount : Update ARGB numbers.
 * @return      
 * @note       No
 *******************************************************************************
 */
static void ifun_API_ARGB_SendData( ARGBCTR_TypeDef* sARGB, uint32_t UpDate_ARGBCount)
{
    uint8_t  DataBitCnt;
    uint8_t  pTXData;
    uint8_t  pDataBitCmp;
    ctype    pDataBit;

    
    sARGB->State = ARGB_BUSY;
    
    //===============================================================================================
    //Set ARGB handle parameter.
    sARGB->TotalCount   = (UpDate_ARGBCount * 3);        //ARGB data byte is 3 bytes in the sample code.
    sARGB->DataCount    = 0;
    sARGB->DataBitCmp   = 0;
    pTXData             = 0;
    
    //===============================================================================================
    //Enable timeout timer & timeout timer interrupt.
    
    
    SET_BIT( *(sARGB->ARGB_REG_TMO)  , URT_TMOUT_TMO_RST_mask_w); 
    SET_BIT( *(sARGB->ARGB_rREG_STA) , sARGB->ARGB_STA_TMO); 
    SET_BIT( *(sARGB->ARGB_REG_TMO)  , sARGB->ARGB_TMO_EN);
    
    while( (READ_REG( *(sARGB->ARGB_rREG_STA)) & sARGB->ARGB_STA_TMO)==0);
    CLEAR_BIT( *(sARGB->ARGB_REG_TMO) , sARGB->ARGB_TMO_EN);
    
    SET_BIT( *(sARGB->ARGB_REG_CRX) , URT_CR4_TDAT_CLR_mask_w); 
    

    //===============================================================================================
    //Blocking mode update ARGB data
    do{
        if( sARGB->DataBitCmp == 0x00)
        {
            pTXData    = sARGB->updateBuf[ sARGB->DataCount];            
            pDataBitCmp = 0x80;
        }
        else
        {
            pDataBitCmp = sARGB->DataBitCmp; 
            sARGB->TotalCount = sARGB->TotalCount - 1;
            sARGB->DataCount  = sARGB->DataCount  + 1;
        }
        for(DataBitCnt = 0; DataBitCnt < 4; DataBitCnt++)
        {
            if((pTXData & pDataBitCmp)==0)
            {
                pDataBit.B[0] = sARGB->ARGB_LOGIC_0;
            }
            else
            {
                pDataBit.B[0] = sARGB->ARGB_LOGIC_1;
            }
            pDataBitCmp = pDataBitCmp >> 1;
            
            WRITE_REG( *(sARGB->ARGB_REG_TXData) , pDataBit.W);
            sARGB->DataBitCmp = pDataBitCmp;
            while( (READ_REG(*(sARGB->ARGB_dREG_STA)) & sARGB->ARGB_STA_TX) == 0);
        }
        
    }while(sARGB->TotalCount!=0 );
    
     //===============================================================================================
    //Wait last data for transmission end.
    while( (READ_REG(*(sARGB->ARGB_dREG_STA)) & sARGB->ARGB_STA_TC) == 0);
    
    
    sARGB->State = ARGB_READY;
}
 /**
 *******************************************************************************
 * @brief	  URT inital
 * @details    
 * @param[in] sARGB : ARGB Handle. (only need set following parameter)
 *   @arg\b   URTX :  URT register basic address.
 *   @arg\b   TRES :  ARGB reset time. ( 0 ~ 255 ARGB bit time)
 * @return       
 * @note       
 *    \n  Beacase URT one character data is ARGB one bit data , 
 *    \n  (1 / (Baudrate * 12)) have to equal (1.25us +/- 150ns if ARGB is  WS2812).       
 *******************************************************************************
 */
static void ifun_ARGBChannel_Init(ARGBCTR_TypeDef *sARGB )
{
    URT_BRG_TypeDef  URT_BRG;
    URT_Data_TypeDef DataDef;


    sARGB->State = ARGB_BUSY;

    
    //===============================================================================================
    //Set Clock
    
    //--------------------------------------------------------
    //Set BaudRate
    URT_BRG.URT_InternalClockSource    = URT_BDClock_PROC;
    URT_BRG.URT_BaudRateMode           = URT_BDMode_Separated;
    URT_BRG.URT_PrescalerCounterReload = 0;	                        //Set PSR
    URT_BRG.URT_BaudRateCounterReload  = 0;	                        //Set RLR
    URT_BaudRateGenerator_Config(ARGB_DATA_URTX, &URT_BRG);		      //Baudrate = f(CK_URTx)/(PSR+1)/(RLR+1)/(OS_NUM+1)
    URT_BaudRateGenerator_Cmd(ARGB_DATA_URTX, ENABLE);	            //Enable BaudRateGenerator
    
    //--------------------------------------------------------
    //TX/RX Clock
    URT_TXClockSource_Select(ARGB_DATA_URTX, URT_TXClock_Internal);	//URT_TX use BaudRateGenerator
    URT_RXClockSource_Select(ARGB_DATA_URTX, URT_RXClock_Internal);	//URT_RX use BaudRateGenerator
    URT_TXOverSamplingSampleNumber_Select(ARGB_DATA_URTX, 4);	      //Set TX OS_NUM
    URT_RXOverSamplingSampleNumber_Select(ARGB_DATA_URTX, 4);	      //Set RX OS_NUM
    URT_RXOverSamplingMode_Select(ARGB_DATA_URTX, URT_RXSMP_3TIME);
    URT_TX_Cmd(ARGB_DATA_URTX, ENABLE);	                            //Enable TX
    URT_RX_Cmd(ARGB_DATA_URTX, ENABLE);	                            //Enable RX (for Timeout timer )
    //===============================================================================================
    //Set Mode
    
    //--------------------------------------------------------
    //Set Data character config
    DataDef.URT_TX_DataLength  = URT_DataLength_8;
    DataDef.URT_RX_DataLength  = URT_DataLength_8;
    DataDef.URT_TX_DataOrder   = URT_DataTyped_LSB;
    DataDef.URT_RX_DataOrder   = URT_DataTyped_LSB;
    DataDef.URT_TX_Parity      = URT_Parity_All_H;
    DataDef.URT_RX_Parity      = URT_Parity_All_H;
    DataDef.URT_TX_StopBits    = URT_StopBits_2_0;
    DataDef.URT_RX_StopBits    = URT_StopBits_2_0;
    DataDef.URT_TX_DataInverse = DISABLE;
    DataDef.URT_RX_DataInverse = DISABLE;
    URT_DataCharacter_Config(ARGB_DATA_URTX, &DataDef);
    
    //--------------------------------------------------------
    //Set Mode Select
    URT_Mode_Select(ARGB_DATA_URTX, URT_URT_mode);
    
    //--------------------------------------------------------
    //Set DataLine Select
    URT_DataLine_Select(ARGB_DATA_URTX, URT_DataLine_2);
    
    
    //===============================================================================================
    //Set Data Control
    URT_TXGuardTime_Select(ARGB_DATA_URTX, 0);    
    URT_TXInverse_Cmd( ARGB_DATA_URTX , ENABLE);                              // Data output signal invere.
    
    //===============================================================================================
    //TRst time setting. (Use timeout timer of URT )
    URT_TimeoutMode_Select(ARGB_RST_URTX , URT_TMOMDS_General);              
    URT_TimeoutTimerClockSource_Select( ARGB_RST_URTX, URT_TMOCLK_CK_URTX);
    URT_SetTimeoutTimerCompare(ARGB_RST_URTX, (sARGB->TRES *12 * 5));
    URT_TimeroutTimer_Cmd( ARGB_RST_URTX, DISABLE);
    
    //===============================================================================================
    //Enable URT Interrupt
    URT_IT_Config(ARGB_DATA_URTX, (URT_IT_TX | URT_IT_TC),  DISABLE);
	URT_IT_Config(ARGB_RST_URTX , URT_IT_TMO, DISABLE);
		
    URT_IT_Config( ARGB_RST_URTX , URT_IT_UG , ENABLE);
    URT_ITEA_Cmd(ARGB_DATA_URTX,ENABLE);
	URT_ITEA_Cmd(ARGB_RST_URTX,ENABLE);
		
    NVIC_EnableIRQ(ARGB_DATA_IRQ );
    NVIC_EnableIRQ(ARGB_RST_IRQ);
		
    //===============================================================================================
    //Enable URT
    URT_Cmd(ARGB_DATA_URTX, ENABLE);
		
    //===============================================================================================
    //Set ARGB handle state.
    sARGB->ARGB_LOGIC_0    = ARGB_LOGIC_URT_0;
    sARGB->ARGB_LOGIC_1    = ARGB_LOGIC_URT_1;
    
    sARGB->ARGB_dREG_INT   = &(ARGB_DATA_URTX->INT.W);
    sARGB->ARGB_dREG_STA   = &(ARGB_DATA_URTX->STA.W);
    sARGB->ARGB_REG_TXData = &(ARGB_DATA_URTX->TDAT.W);
	sARGB->ARGB_REG_CRX    = &(ARGB_DATA_URTX->CR4.W);
		
	sARGB->ARGB_rREG_INT   = &(ARGB_RST_URTX->INT.W);
    sARGB->ARGB_rREG_STA   = &(ARGB_RST_URTX->STA.W);
    sARGB->ARGB_REG_TMO    = &(ARGB_RST_URTX->TMOUT.W);
    
    
    sARGB->ARGB_STA_TX     = URT_STA_TXF_mask_w;
    sARGB->ARGB_STA_TC     = URT_STA_TCF_mask_w;
    sARGB->ARGB_STA_TMO    = URT_STA_TMOF_mask_w;
    sARGB->ARGB_STA_UG     = URT_STA_UGF_mask_w;
    sARGB->ARGB_TMO_EN     = URT_TMOUT_TMO_EN_mask_w;
    
    
    
    sARGB->State = ARGB_READY;
    
}
///@}


/**
 * @name    Sample code is that use blocking and interrupt mode to control ARGB.
 *   		
 */ 
///@{

/**
 *******************************************************************************
 * @brief	   To trigger change the ARGBs mode.  
 * @details     
 * @param[in]  ARGB_Mode : New ARGB mode.  
 * @note       
 *******************************************************************************
 */
void API_ARGB_UpdateTrigger(uint8_t  ARGB_Mode)
{
    ARGB0.DramaMode  = ARGB_Mode;

    ARGB0.UpdateTRG  = ARGB_UPDATE_MODE;
}
 /**
 *******************************************************************************
 * @brief	   Update ARGB status.
 * @details     
 * @param[in]  sARGB : Control ARGB data line .
 * @param[in]  UpDate_ARGBCount : Update ARGB pieces.     
 * @note       
 *******************************************************************************
 */
static void ifun_ARGB_Update(ARGBCTR_TypeDef* sARGB , uint32_t UpDate_ARGBCount )
{
    uint32_t SMP_ARGB_UpdateTmp;
    
    if( (ARGB0.UpdateTRG & ARGB_UPDATE_DATA) && ARGB0.State == ARGB_READY)
    {
        ARGB0.UpdateTRG &= (~ARGB_UPDATE_DATA);
        
        for( SMP_ARGB_UpdateTmp = 0; SMP_ARGB_UpdateTmp < (UpDate_ARGBCount * SMP_ARGB_DATASIZE); SMP_ARGB_UpdateTmp++)
        {
            sARGB->updateBuf[SMP_ARGB_UpdateTmp]= sARGB->DramaBuf[SMP_ARGB_UpdateTmp];
        }
        
        ifun_API_ARGB_SendData(&ARGB0, SMP_ARGB_PIECE);
        
    }
}
 /**
 *******************************************************************************
 * @brief	   Close the all ARGB.  
 * @details     
 * @param[in]  sARGB : Control ARGB data line .  
 * @note       Close ARGB piece according to SMP_ARGB_PIECE
 *******************************************************************************
 */
void API_RGB_CloseAll(ARGBCTR_TypeDef* sARGB )
{
    uint32_t SMP_ARGB_CloseTmp;
    
    for( SMP_ARGB_CloseTmp = 0; SMP_ARGB_CloseTmp < (SMP_ARGB_PIECE * SMP_ARGB_DATASIZE); SMP_ARGB_CloseTmp++)
    {
        sARGB->DramaBuf[SMP_ARGB_CloseTmp]= 0x00;
    }
    
    sARGB->UpdateTRG |= ARGB_UPDATE_DATA;
    
    ifun_ARGB_Update(&ARGB0, SMP_ARGB_PIECE);
    
    while( sARGB->State != ARGB_READY);
    
    do{
        if( ARGB_UpdateFlag == 1)
        {
            ARGB_UpdateFlag = 0;
            SMP_ARGB_CloseTmp = SMP_ARGB_CloseTmp + 1;
        }
    }while(SMP_ARGB_CloseTmp<100);
}
 /**
 *******************************************************************************
 * @brief	   Update the sARGB line mode.
 * @details     
 * @param[in]  sARGB : Control ARGB data line .
 * @return      
 * @note       
 *******************************************************************************
 */
static void ifun_ARGB_UpdateDramaMode( ARGBCTR_TypeDef* sARGB )
{
    sARGB->DramaAct       = 0;  
    sARGB->DramaScene     = 0;    
    sARGB->DramaTime      = 0;    
    
    switch( sARGB->DramaMode)
    {
        case ARGB_DRAMA_STATIC:
                                    sARGB->DramaActMax    = 1;
                                    sARGB->DramaSceneMax  = 0; 
                                    sARGB->DramaTimeMax   = 0;
                                    break;
        case ARGB_DRAMA_BREATH:     
                                    sARGB->DramaActMax    = (API_ARGB_DEFAULT_COLOR - 1) * 2;
                                    sARGB->DramaSceneMax  = 100; 
                                    sARGB->DramaTimeMax   = 0;
                                    break;
        case ARGB_DRAMA_WDROP:      
                                    sARGB->DramaActMax    = 18;
                                    sARGB->DramaSceneMax  = 4;                          
                                    sARGB->DramaTimeMax   = 3;
                                    break;
        case ARGB_DRAMA_MOVING:     
                                    sARGB->DramaActMax    = ( API_ARGB_DEFAULT_COLOR * 2);
                                    sARGB->DramaSceneMax  = SMP_ARGB_PIECE;                          
                                    sARGB->DramaTimeMax   = 3;
                                    break;
        case ARGB_DRAMA_2MOVING:          
                                    sARGB->DramaActMax    = API_ARGB_DEFAULT_COLOR * 2;
                                    sARGB->DramaSceneMax  = (SMP_ARGB_PIECE - 1);            
                                    sARGB->DramaTimeMax   = 3;
                                    break;
        case ARGB_DRAMA_DISABLE:
        default:
                                    break;
    }
    
    sARGB->UpdateTRG = 0;
    
    API_RGB_CloseAll(sARGB);
    
    ARGB_UpdateFlag = 0;
    
} 

/**
 *******************************************************************************
 * @brief	   Calculate color.
 * @details     
 * @param[in]  ARGB_PEBuf  : Refer to Color.
 * @param[in]  molecular   : Calculate molecular.
 * @param[in]  Denominator : Calculate Denominator.
 * @param[in]  LoopTime    : Calculate time.  
 * @note       
 *******************************************************************************
 */
static void ifun_ARGB_PercentageTable( uint8_t* ARGB_PEBuf, uint32_t molecular ,uint32_t Denominator, uint8_t LoopTime)
{
    uint8_t  SMP_ARGB_PETmp;
    uint8_t  SMP_ARGB_PETmp2;
    uint32_t SMP_ARGB_PEDataTmp;
    
    for( SMP_ARGB_PETmp2 = 0; SMP_ARGB_PETmp2 < LoopTime ; SMP_ARGB_PETmp2++)
    {
        for(SMP_ARGB_PETmp = 0; SMP_ARGB_PETmp < 3; SMP_ARGB_PETmp++)
        {
            SMP_ARGB_PEDataTmp         = molecular * ARGB_PEBuf[SMP_ARGB_PETmp];
            ARGB_PEBuf[SMP_ARGB_PETmp] = ((uint8_t)(SMP_ARGB_PEDataTmp / Denominator));
        }
    }
}
 /**
 *******************************************************************************
 * @brief	   Calculate ARGB next data in ARGB_DRAMA_STATIC mode.
 * @details     
 * @param[in]  sARGB : Control ARGB data line .     
 * @note       
 *******************************************************************************
 */
static void ifun_ARGB_SignalColorDrama(ARGBCTR_TypeDef* sARGB)
{
    uint32_t SMP_ARGB_SIGDTmp;
    uint32_t SMP_ARGB_SIGDAdr;
    
    if( sARGB->DramaActMax !=0)
    {
        sARGB->DramaActMax = 0;
        
        for( SMP_ARGB_SIGDTmp = 0; SMP_ARGB_SIGDTmp < SMP_ARGB_PIECE ; SMP_ARGB_SIGDTmp++)
        {
            SMP_ARGB_SIGDAdr = (SMP_ARGB_SIGDTmp * 3);
            
            sARGB->DramaBuf[ SMP_ARGB_SIGDAdr + SMP_ARGB_G] = API_ARGBDefault_TABLE[0][ SMP_ARGB_G];
            sARGB->DramaBuf[ SMP_ARGB_SIGDAdr + SMP_ARGB_R] = API_ARGBDefault_TABLE[0][ SMP_ARGB_R];
            sARGB->DramaBuf[ SMP_ARGB_SIGDAdr + SMP_ARGB_B] = API_ARGBDefault_TABLE[0][ SMP_ARGB_B];
        }
        
        sARGB->UpdateTRG |= ARGB_UPDATE_DATA;
    }
}
/**
 *******************************************************************************
 * @brief	   Calculate ARGB next data in ARGB_DRAMA_BREATH mode.
 * @details     
 * @param[in]  sARGB : Control ARGB data line .   
 * @note       
 *******************************************************************************
 */
static void ifun_ARGB_BreathDrama(ARGBCTR_TypeDef* sARGB)
{
    uint32_t SMP_ARGB_BRDTmp;

    
    sARGB->DramaTmp[SMP_ARGB_G] = API_ARGBDefault_TABLE[(sARGB->DramaAct >> 1)][SMP_ARGB_G];
    sARGB->DramaTmp[SMP_ARGB_R] = API_ARGBDefault_TABLE[(sARGB->DramaAct >> 1)][SMP_ARGB_R];
    sARGB->DramaTmp[SMP_ARGB_B] = API_ARGBDefault_TABLE[(sARGB->DramaAct >> 1)][SMP_ARGB_B];
    
    if( sARGB->DramaAct & 0x01)
    {
        ifun_ARGB_PercentageTable( &sARGB->DramaTmp[0] , ( sARGB->DramaSceneMax -  sARGB->DramaScene ) , sARGB->DramaSceneMax ,2);
    }
    else
    {
        ifun_ARGB_PercentageTable( &sARGB->DramaTmp[0] , sARGB->DramaScene, sARGB->DramaSceneMax , 2);
    }
    
    
    if( sARGB->DramaScene == sARGB->DramaSceneMax)
    {
        if( sARGB->DramaAct > sARGB->DramaActMax)
        {
            sARGB->DramaAct = 0;
        }
        else
        {
            sARGB->DramaAct = sARGB->DramaAct + 1;
        }
        sARGB->DramaScene = 0;        
    }
    else
    {
        sARGB->DramaScene = sARGB->DramaScene + 1;
    }
    
    for( SMP_ARGB_BRDTmp = 0; SMP_ARGB_BRDTmp < SMP_ARGB_PIECE ; SMP_ARGB_BRDTmp++)
    {
        sARGB->DramaBuf[ (SMP_ARGB_BRDTmp * 3) + SMP_ARGB_G] = sARGB->DramaTmp[ SMP_ARGB_G];
        sARGB->DramaBuf[ (SMP_ARGB_BRDTmp * 3) + SMP_ARGB_R] = sARGB->DramaTmp[ SMP_ARGB_R];
        sARGB->DramaBuf[ (SMP_ARGB_BRDTmp * 3) + SMP_ARGB_B] = sARGB->DramaTmp[ SMP_ARGB_B];
    }
    
    sARGB->UpdateTRG |= ARGB_UPDATE_DATA;
}

/**
 *******************************************************************************
 * @brief	   Calculate ARGB next data in ARGB_DRAMA_WDROP mode.
 * @details     
 * @param[in]  sARGB : Control ARGB data line .     
 * @note       
 *******************************************************************************
 */
static void ifun_ARGB_WDropDrama( ARGBCTR_TypeDef* sARGB )
{
    uint32_t SMP_ARGB_WVDTmp;

    if( sARGB->DramaTime < ( sARGB->DramaTimeMax - 1))
    {
        sARGB->DramaTime = sARGB->DramaTime + 1;
    }
    else
    {
        sARGB->DramaTime = 0;
        
        for( SMP_ARGB_WVDTmp = 0; SMP_ARGB_WVDTmp < (SMP_ARGB_PIECE - 1); SMP_ARGB_WVDTmp++)
        {
            sARGB->DramaBuf[ (SMP_ARGB_WVDTmp * 3) + SMP_ARGB_G] = sARGB->DramaBuf[ ((SMP_ARGB_WVDTmp + 1)* 3) + SMP_ARGB_G];
            sARGB->DramaBuf[ (SMP_ARGB_WVDTmp * 3) + SMP_ARGB_R] = sARGB->DramaBuf[ ((SMP_ARGB_WVDTmp + 1)* 3) + SMP_ARGB_R];
            sARGB->DramaBuf[ (SMP_ARGB_WVDTmp * 3) + SMP_ARGB_B] = sARGB->DramaBuf[ ((SMP_ARGB_WVDTmp + 1)* 3) + SMP_ARGB_B];
        }
        
        
        if( sARGB->DramaScene < sARGB->DramaSceneMax)
        {
            sARGB->DramaScene = sARGB->DramaScene +  1;
            
            sARGB->DramaBuf[ (( SMP_ARGB_PIECE - 1)* 3) + SMP_ARGB_G ] = 0;
            sARGB->DramaBuf[ (( SMP_ARGB_PIECE - 1)* 3) + SMP_ARGB_R ] = 0;    
            sARGB->DramaBuf[ (( SMP_ARGB_PIECE - 1)* 3) + SMP_ARGB_B ] = 0;
        }        
        else
        {
            sARGB->DramaTmp[SMP_ARGB_G] = API_ARGBDefault_TABLE[ 0 ][SMP_ARGB_G];
            sARGB->DramaTmp[SMP_ARGB_R] = API_ARGBDefault_TABLE[ 0 ][SMP_ARGB_R];
            sARGB->DramaTmp[SMP_ARGB_B] = API_ARGBDefault_TABLE[ 0 ][SMP_ARGB_B];
            
            
            ifun_ARGB_PercentageTable( &sARGB->DramaTmp[0] , ( sARGB->DramaActMax -  sARGB->DramaAct ) , sARGB->DramaActMax ,4);
            
            
            sARGB->DramaBuf[ (( SMP_ARGB_PIECE - 1)* 3) + SMP_ARGB_G ] = sARGB->DramaTmp[ SMP_ARGB_G ];
            sARGB->DramaBuf[ (( SMP_ARGB_PIECE - 1)* 3) + SMP_ARGB_R ] = sARGB->DramaTmp[ SMP_ARGB_R ];    
            sARGB->DramaBuf[ (( SMP_ARGB_PIECE - 1)* 3) + SMP_ARGB_B ] = sARGB->DramaTmp[ SMP_ARGB_B ];
            
            
            if( sARGB->DramaAct < sARGB->DramaActMax)
            {
                sARGB->DramaAct = sARGB->DramaAct + 1;
            }
            else
            {
                sARGB->DramaAct = 0;
                sARGB->DramaScene  = 0;
            }
            
            
        }
        sARGB->UpdateTRG |= ARGB_UPDATE_DATA;
    }
}
 /**
 *******************************************************************************
 * @brief	   Calculate ARGB next data in ARGB_DRAMA_MOVING mode.
 * @details     
 * @param[in]  sARGB : Control ARGB data line .      
 * @note       
 *******************************************************************************
 */
static void ifun_ARGB_MovingDrama( ARGBCTR_TypeDef* sARGB )
{
    uint8_t    SMP_ARGB_MOVDColor;
    uint32_t   SMP_ARGB_MOVDUpdate;
    
    if( sARGB->DramaTime < sARGB->DramaTimeMax)
    {
        sARGB->DramaTime = sARGB->DramaTime + 1;
    }
    else
    {
        sARGB->DramaTime = 0;
        
        if( sARGB->DramaAct & 0x01)
        {
            SMP_ARGB_MOVDUpdate = (sARGB->DramaScene* 3);
            
            sARGB->DramaBuf[ SMP_ARGB_MOVDUpdate + SMP_ARGB_G ] = 0;
            sARGB->DramaBuf[ SMP_ARGB_MOVDUpdate + SMP_ARGB_R ] = 0;    
            sARGB->DramaBuf[ SMP_ARGB_MOVDUpdate + SMP_ARGB_B ] = 0;
        }
        else
        {
            SMP_ARGB_MOVDColor = sARGB->DramaAct >> 1;
            SMP_ARGB_MOVDUpdate = ((( sARGB->DramaSceneMax - 1) - sARGB->DramaScene )* 3);
            
            sARGB->DramaBuf[ SMP_ARGB_MOVDUpdate + SMP_ARGB_G ] = API_ARGBDefault_TABLE[ SMP_ARGB_MOVDColor ][ SMP_ARGB_G ];
            sARGB->DramaBuf[ SMP_ARGB_MOVDUpdate + SMP_ARGB_R ] = API_ARGBDefault_TABLE[ SMP_ARGB_MOVDColor ][ SMP_ARGB_R ];    
            sARGB->DramaBuf[ SMP_ARGB_MOVDUpdate + SMP_ARGB_B ] = API_ARGBDefault_TABLE[ SMP_ARGB_MOVDColor ][ SMP_ARGB_B ];
            
        }
        
        if( sARGB->DramaScene < (sARGB->DramaSceneMax - 1))
        {
            sARGB->DramaScene = sARGB->DramaScene + 1;
        }
        else
        {
            sARGB->DramaScene = 0;
            
            if( sARGB->DramaAct < (sARGB->DramaActMax - 1))
            {
                sARGB->DramaAct = sARGB->DramaAct + 1;
            }
            else
            {
                sARGB->DramaAct = 0;
            }
            
        }
        
        sARGB->UpdateTRG |= ARGB_UPDATE_DATA;
    }
}

 /**
 *******************************************************************************
 * @brief	   Calculate ARGB next data in ARGB_DRAMA_2MOVING mode.
 * @details     
 * @param[in]  sARGB : Control ARGB data line .     
 * @note       
 *******************************************************************************
 */
static void ifun_ARGB_TwoMovingDrama( ARGBCTR_TypeDef* sARGB )
{
    uint8_t SMP_ARGB_TMDTmp;
    uint8_t SMP_ARGB_TMDMode;
    
    if( sARGB->DramaTime < sARGB->DramaTimeMax)
    {
        sARGB->DramaTime = sARGB->DramaTime + 1;
    }
    else
    {
        sARGB->DramaTime = 0;
        
        SMP_ARGB_TMDTmp   = sARGB->DramaAct & 0x7F;
        SMP_ARGB_TMDMode  = sARGB->DramaAct & 0x80;
        
        if( SMP_ARGB_TMDMode == 0)
        {
            if( sARGB->DramaScene != 0)
            {
                sARGB->DramaBuf[ ((sARGB->DramaScene - 1) * 3) + SMP_ARGB_G ]    = 0;
                sARGB->DramaBuf[ ((sARGB->DramaScene - 1) * 3) + SMP_ARGB_R ]    = 0;    
                sARGB->DramaBuf[ ((sARGB->DramaScene - 1) * 3) + SMP_ARGB_B ]    = 0;
            }
            if( sARGB->DramaSceneMax != (SMP_ARGB_PIECE-1))
            {
                sARGB->DramaBuf[ ((sARGB->DramaSceneMax + 1) * 3) + SMP_ARGB_G ] = 0;
                sARGB->DramaBuf[ ((sARGB->DramaSceneMax + 1) * 3) + SMP_ARGB_R ] = 0;    
                sARGB->DramaBuf[ ((sARGB->DramaSceneMax + 1) * 3) + SMP_ARGB_B ] = 0;
            }
        }
        else
        {
            sARGB->DramaBuf[ ((sARGB->DramaScene + 1) * 3) + SMP_ARGB_G ]       = 0;
            sARGB->DramaBuf[ ((sARGB->DramaScene + 1) * 3) + SMP_ARGB_R ]       = 0;    
            sARGB->DramaBuf[ ((sARGB->DramaScene + 1) * 3) + SMP_ARGB_B ]       = 0;
            
            sARGB->DramaBuf[ ((sARGB->DramaSceneMax - 1) * 3) + SMP_ARGB_G ]    = 0;
            sARGB->DramaBuf[ ((sARGB->DramaSceneMax - 1) * 3) + SMP_ARGB_R ]    = 0;    
            sARGB->DramaBuf[ ((sARGB->DramaSceneMax - 1) * 3) + SMP_ARGB_B ]    = 0;
        }
        
        sARGB->DramaBuf[ (sARGB->DramaScene * 3) + SMP_ARGB_G ]    = API_ARGBDefault_TABLE[ SMP_ARGB_TMDTmp ][ SMP_ARGB_G ];
        sARGB->DramaBuf[ (sARGB->DramaScene * 3) + SMP_ARGB_R ]    = API_ARGBDefault_TABLE[ SMP_ARGB_TMDTmp ][ SMP_ARGB_R ];    
        sARGB->DramaBuf[ (sARGB->DramaScene * 3) + SMP_ARGB_B ]    = API_ARGBDefault_TABLE[ SMP_ARGB_TMDTmp ][ SMP_ARGB_B ];
        
        sARGB->DramaBuf[ (sARGB->DramaSceneMax * 3) + SMP_ARGB_G ] = API_ARGBDefault_TABLE[ SMP_ARGB_TMDTmp ][ SMP_ARGB_G ];
        sARGB->DramaBuf[ (sARGB->DramaSceneMax * 3) + SMP_ARGB_R ] = API_ARGBDefault_TABLE[ SMP_ARGB_TMDTmp ][ SMP_ARGB_R ];    
        sARGB->DramaBuf[ (sARGB->DramaSceneMax * 3) + SMP_ARGB_B ] = API_ARGBDefault_TABLE[ SMP_ARGB_TMDTmp ][ SMP_ARGB_B ];
        
        if( SMP_ARGB_TMDMode == 0)
        {
            if( (sARGB->DramaScene + 1) < sARGB->DramaSceneMax)
            {
                sARGB->DramaScene    = sARGB->DramaScene + 1;
                sARGB->DramaSceneMax = sARGB->DramaSceneMax - 1;
            }                
            else
            {
                sARGB->DramaAct = sARGB->DramaAct | 0x80;
                
                if( ( (sARGB->DramaAct & 0x7F) == ( API_ARGB_DEFAULT_COLOR - 1)))
                {
                    sARGB->DramaAct = sARGB->DramaAct & (~0x7F);
                }
                else
                {
                    sARGB->DramaAct = sARGB->DramaAct + 1;
                }
            }
        }
        else
        {
            if(sARGB->DramaScene == 0) 
            {
                sARGB->DramaAct = sARGB->DramaAct & (~0x80);
            }
            else
            {
                sARGB->DramaScene    = sARGB->DramaScene    - 1;
                sARGB->DramaSceneMax = sARGB->DramaSceneMax + 1;
            }
        }
        
        sARGB->UpdateTRG |= ARGB_UPDATE_DATA;
    }
}
 /**
 *******************************************************************************
 * @brief	   Calculate ARGB next data according to ARGB mode.
 * @details     
 * @param[in]  sARGB : Control ARGB data line .
 * @note       
 *******************************************************************************
 */
static void ifun_ARGB_UpdateDrama( ARGBCTR_TypeDef* sARGB )
{   
    if( sARGB->UpdateTRG & ARGB_UPDATE_DATA)
    {
        return;
    }
    else
    {
        switch( sARGB->DramaMode)
        {
            case ARGB_DRAMA_STATIC:
                                       ifun_ARGB_SignalColorDrama(sARGB);
                                       break;
            case ARGB_DRAMA_BREATH:    
                                       ifun_ARGB_BreathDrama( sARGB);
                                       break;
            case ARGB_DRAMA_WDROP:     
                                       ifun_ARGB_WDropDrama(sARGB);
                                       break;
            case ARGB_DRAMA_MOVING:    
                                       ifun_ARGB_MovingDrama(sARGB);
                                       break;
            case ARGB_DRAMA_2MOVING:   
                                       ifun_ARGB_TwoMovingDrama(sARGB);
                                       break;
            case ARGB_DRAMA_DISABLE:
            default: 
                                       break;
        }
    } 
}

 /**
 *******************************************************************************
 * @brief	   The sample code is that UART use blocking mode to update ARGB
 * @details     
 * @return      
 * @note       No
 *******************************************************************************
 */
void API_ARGB_Init(void)
{
    PIN_InitTypeDef  PINX_InitStruct;

    //================================================================================================
    //*. CSC Inital :
    //    *. The URT sample need URT clock source is 48MHz.
    //    *. CSC Inital :
    //        1. Checked CSC checkbox of MG32_ChipInit in Manage Run-Time Environment.
    //        2. In MG32_ChipInit_Wizard of Project window use MG32_CSC_Init.h file
    //           to select that you want CSC environment ( APB = 48MHz , and AHB <= 24MHz).
    //
    //================================================================================================
    //*. GPIO Inital can :
    //    1. Checked GPIO checkbox of MG32_ChipInit in Manage Run-Time Environment.
    //       In MG32_ChipInit_Wizard of Project window use MG32_GPIO_Init.h file
    //       to select that you want GPIO environment.
    //    or
    //    2. Use GPIO_PinMode_Config to setting GPIO mode.
    PINX_InitStruct.PINX_Mode               = PINX_Mode_PushPull_O;
    PINX_InitStruct.PINX_PUResistant        = PINX_PUResistant_Disable;
    PINX_InitStruct.PINX_Speed              = PINX_Speed_Low;
    PINX_InitStruct.PINX_OUTDrive           = PINX_OUTDrive_Level0;
    PINX_InitStruct.PINX_FilterDivider      = PINX_FilterDivider_Bypass;
    PINX_InitStruct.PINX_Inverse            = PINX_Inverse_Disable;

    PINX_InitStruct.PINX_Alternate_Function = 11;
    GPIO_PinMode_Config(PINA(11),&PINX_InitStruct);                                          

    //================================================================================================
    //4. Set Timer to count interval of ARGB update drama 
    //   (1). Here use TM00.
    //   (2). TM00 clock source from LS and divider 1.
    //   (3). TM00 is full counter mode.
    //   (4). TM00 overflow time is about 10 ms. ( 320 / 32KHz)
    //   (5). Enable TM00 interrupt.
    TM_InternalClockSource_Select( TM00 , TM_CK_LS);
    TM_SetInternalClockDivider(TM00, TM_IntDIV1);
    TM_CounterClock_Select(  TM00, TM_CK_INT);
    TM_PrescalerClock_Select(TM00, TM_CK_INT);

    TM_TimerMode_Select(TM00, Full_Counter);
    
    TM_Prescaler_Config( TM00 , 0x3F , 0x3F);
    TM_Counter_Config( TM00 , 0x01, 0x01);

    TM_IT_Config( TM00 , TMx_TIE_IE , ENABLE);
    TM_ITEA_Cmd( TM00 , ENABLE);
    NVIC_EnableIRQ(TM0x_IRQn);

    TM_Timer_Cmd( TM00 , ENABLE);

    //================================================================================================
    //5. ARGB Inital.
    //----------------------------------------------------------------------
    //Peripheral option ( confirm the device whether support the peripheral or not.) 
    ARGB0.TRES                  = 50;                                                               // Set Reset time ( min time).
    ARGB0.updateBuf             = &API_ARGB_UpdateBUF[0][0];                                        // Control ARGB update data buffer pointer.
    ARGB0.DramaBuf              = &API_ARGB_DramaBUF[0][0];                                         // Control ARGB calculation buffer pointer.

    ifun_ARGBChannel_Init(&ARGB0);                                                               // ARGB Inital.
    URT_RxTxSwap_Cmd(URT5, ENABLE);
}

/**
 *******************************************************************************
 * @brief       
 * @details     
 * @return      
 * @note       No
 *******************************************************************************
 */
void API_ARGB_main(void)
{
    PE0 = ~PE0;
    
    //-----------------------------------------------------------------
    //Update ARGB Disaplay Mode.
    if( ARGB0.UpdateTRG & ARGB_UPDATE_MODE)                                              // To detect whether ARG mode be changed or not.
    {
        ifun_ARGB_UpdateDramaMode(&ARGB0);
    }
    else
    {
        //------------------------------------------------------------------
        //Update Data To ARGB 
        
        ifun_ARGB_Update(&ARGB0, SMP_ARGB_PIECE);
    }
    //-----------------------------------------------------------------
    //Calculate ARGB next data.
    if( ARGB_UpdateFlag == 1)                                          
    {
        ARGB_UpdateFlag = 0;
        ifun_ARGB_UpdateDrama(&ARGB0);
        
    }
}

/**
 *******************************************************************************
 * @brief       TM0x IRQHandle function.
 * @details     
 * @return      
 * @note       No
 *******************************************************************************
 */
void TM0x_IRQHandler(void)
{
    ARGB_UpdateFlag = 1;                       // Set ARGB update software flag.
    
    TM_ClearFlag( TM00 , TMx_TOF);
    
    
    
}


///@}










