/**
 * @file hv_drv_Tlc5971.c
 * @brief tlc5971 led driver layer file.
 * @details This file provides the following functions: \n
 *          (1) led driver init \n
 *          (2) set global brightness control data \n
 *          (3) update led color \n
 * @author HiView SoC Software Team
 * @version 1.0.0
 * @date 2023-12-16
 * @copyright Copyright(c),2023-12, Hiview Software. All rights reserved.
 * @par History:
  */
#include "Common/Assert/hv_comm_Assert.h"
#include "hv_drv_GpioSimSWire.h"
#include "hv_drv_Tlc5971.h"

static Tlc5971Dev s_stDev = {0};
static UCHAR8 s_aucTlc5971_DataBuf[TLC5971_PACKET_LEN * HV_BOARD_CONFIG_LED_IC_NUM] = {0};
static LedColor s_stTlc5971Pixels[HV_BOARD_CONFIG_LED_IC_NUM * TLC5971_PIXELS_PER_DEVICE] = {0};
static UCHAR8 s_ucBcRatio_J = TLC5971_GLOBAL_BRIGHTNESS_CONTROL_MAX;
static UCHAR8 s_ucBcRatio_K = TLC5971_GLOBAL_BRIGHTNESS_CONTROL_MAX;
static BOOL   s_bTlc5971_Adjust_Color = HV_ENABLE;

/** Setting for TLC5971 GS Color Adjust */
#define TLC5971_GS_ADJUST_POINT_NUM      8
#define TLC5971_GS_ADJUST_INTERVAL_SIZE  ((TLC5971_GLOBAL_BRIGHTNESS_CONTROL_MAX + 1) / TLC5971_GS_ADJUST_POINT_NUM)
#define TLC5971_GS_ADJUST_DATA_SIZE      (TLC5971_GS_ADJUST_POINT_NUM * TLC5971_PIXELS_PER_DEVICE * HV_BOARD_CONFIG_LED_IC_NUM)

/* Color Offset control for Color1 */
static LedColor s_stGsAdjust[TLC5971_GS_ADJUST_DATA_SIZE] =
{
    /*device0*/
    /*ch0*/
    {255, 255, 176},/*level0*/
    {255, 255, 128},/*level1*/
    {255, 255, 128},/*level2*/
    {255, 255, 128},/*level3*/
    {255, 255, 128},/*level4*/
    {255, 255, 128},/*level5*/
    {255, 255, 128},/*level6*/
    {255, 255, 128},/*level7*/
    /*ch1*/
    {255, 255, 176},/*level0*/
    {255, 255, 128},/*level1*/
    {255, 255, 128},/*level2*/
    {255, 255, 128},/*level3*/
    {255, 255, 128},/*level4*/
    {255, 255, 128},/*level5*/
    {255, 255, 128},/*level6*/
    {255, 255, 128},/*level7*/
    /*ch2*/
    {255, 255, 176},/*level0*/
    {255, 255, 128},/*level1*/
    {255, 255, 128},/*level2*/
    {255, 255, 128},/*level3*/
    {255, 255, 128},/*level4*/
    {255, 255, 128},/*level5*/
    {255, 255, 128},/*level6*/
    {255, 255, 128},/*level7*/
    /*ch3*/
    {255, 255, 176},/*level0*/
    {255, 255, 128},/*level1*/
    {255, 255, 128},/*level2*/
    {255, 255, 128},/*level3*/
    {255, 255, 128},/*level4*/
    {255, 255, 128},/*level5*/
    {255, 255, 128},/*level6*/
    {255, 255, 128},/*level7*/
    /*device1*/
    /*ch0*/
    {255, 255, 192},/*level0*/
    {192, 255, 192},/*level1*/
    {192, 255, 128},/*level2*/
    {192, 255, 128},/*level3*/
    {192, 255, 128},/*level4*/
    {192, 255, 128},/*level5*/
    {192, 255, 128},/*level6*/
    {192, 255, 128},/*level7*/
    /*ch1*/
    {255, 255, 192},/*level0*/
    {192, 255, 176},/*level1*/
    {192, 255, 128},/*level2*/
    {192, 255, 128},/*level3*/
    {192, 255, 128},/*level4*/
    {192, 255, 128},/*level5*/
    {192, 255, 128},/*level6*/
    {192, 255, 128},/*level7*/
    /*ch2*/
    {255, 255, 192},/*level0*/
    {192, 255, 176},/*level1*/
    {192, 255, 128},/*level2*/
    {192, 255, 128},/*level3*/
    {192, 255, 128},/*level4*/
    {192, 255, 128},/*level5*/
    {192, 255, 128},/*level6*/
    {192, 255, 128},/*level7*/
    /*ch3*/
    {255, 255, 192},/*level0*/
    {192, 255, 176},/*level1*/
    {192, 255, 128},/*level2*/
    {192, 255, 128},/*level3*/
    {192, 255, 128},/*level4*/
    {192, 255, 128},/*level5*/
    {192, 255, 128},/*level6*/
    {192, 255, 128},/*level7*/
    /*device2*/
    /*ch0*/
    {255, 255, 176},/*level0*/
    {255, 255, 128},/*level1*/
    {255, 255, 128},/*level2*/
    {255, 255, 128},/*level3*/
    {255, 255, 128},/*level4*/
    {255, 255, 128},/*level5*/
    {255, 255, 128},/*level6*/
    {255, 255, 128},/*level7*/
    /*ch1*/
    {255, 255, 176},/*level0*/
    {255, 255, 128},/*level1*/
    {255, 255, 128},/*level2*/
    {255, 255, 128},/*level3*/
    {255, 255, 128},/*level4*/
    {255, 255, 128},/*level5*/
    {255, 255, 128},/*level6*/
    {255, 255, 128},/*level7*/
    /*ch2*/
    {255, 255, 176},/*level0*/
    {255, 255, 128},/*level1*/
    {255, 255, 128},/*level2*/
    {255, 255, 128},/*level3*/
    {255, 255, 128},/*level4*/
    {255, 255, 128},/*level5*/
    {255, 255, 128},/*level6*/
    {255, 255, 128},/*level7*/
    /*ch3*/
    {255, 255, 176},/*level0*/
    {255, 255, 128},/*level1*/
    {255, 255, 128},/*level2*/
    {255, 255, 128},/*level3*/
    {255, 255, 128},/*level4*/
    {255, 255, 128},/*level5*/
    {255, 255, 128},/*level6*/
    {255, 255, 128},/*level7*/
    /*device3*/
    /*ch0*/
    {255, 255, 192},/*level0*/
    {192, 255, 192},/*level1*/
    {192, 255, 128},/*level2*/
    {192, 255, 128},/*level3*/
    {192, 255, 128},/*level4*/
    {192, 255, 128},/*level5*/
    {192, 255, 128},/*level6*/
    {192, 255, 128},/*level7*/
    /*ch1*/
    {255, 255, 192},/*level0*/
    {192, 255, 176},/*level1*/
    {192, 255, 128},/*level2*/
    {192, 255, 128},/*level3*/
    {192, 255, 128},/*level4*/
    {192, 255, 128},/*level5*/
    {192, 255, 128},/*level6*/
    {192, 255, 128},/*level7*/
    /*ch2*/
    {255, 255, 192},/*level0*/
    {192, 255, 176},/*level1*/
    {192, 255, 128},/*level2*/
    {192, 255, 128},/*level3*/
    {192, 255, 128},/*level4*/
    {192, 255, 128},/*level5*/
    {192, 255, 128},/*level6*/
    {192, 255, 128},/*level7*/
    /*ch3*/
    {255, 255, 192},/*level0*/
    {192, 255, 176},/*level1*/
    {192, 255, 128},/*level2*/
    {192, 255, 128},/*level3*/
    {192, 255, 128},/*level4*/
    {192, 255, 128},/*level5*/
    {192, 255, 128},/*level6*/
    {192, 255, 128},/*level7*/
};

/**
 * @brief Set serialize global brightness ratio for device daisy chain by J/K
 * @param ucJ:Numerator
 * @param ucK:Denominator
 */
VOID Hv_Drv_Led_Tlc5971_SetGlobalBrightnessRatio(UCHAR8 ucJ, UCHAR8 ucK)
{
    HV_ASSERT_TRUE_VOID(ucK > 0);
    s_ucBcRatio_J = ucJ;
    s_ucBcRatio_K = ucK;
    return;
}

/**
 * @brief Set serialize global brightness for device daisy chain
 * @param pstPixel pixel RGB data for daisy chain
 */
Status Hv_Drv_Led_Tlc5971_SetGlobalBrightness(LedGlBc *pstGbc)
{
    pstGbc->ucRedGbc   =  pstGbc->ucRedGbc * s_ucBcRatio_J / s_ucBcRatio_K;
    pstGbc->ucGreenGbc =  pstGbc->ucGreenGbc * s_ucBcRatio_J / s_ucBcRatio_K;
    pstGbc->ucBlueGbc  =  pstGbc->ucBlueGbc * s_ucBcRatio_J / s_ucBcRatio_K;
    return Hv_Cal_Led_Tlc5971_SetGlobalBrightness(&s_stDev, pstGbc);
}

/**
 * @brief Update serialize pixel data for device daisy chain
 */
Status Hv_Drv_Led_Tlc5971_UpdateColor(VOID)
{
    return Hv_Cal_Led_Tlc5971_UpdateColor(&s_stDev);
}

/**
 * @brief Fill GS Data Api for Led devices
 * @param uiDevId TLC5971 device id of daisy chain
 * @param enChId TLC5971 channel id
 * @param pstPixel pixel RGB data for daisy chain
 */
static Status Hv_Drv_Led_Tlc5971_AdjustColor(LedDeviceId enDevId, LedChannelId enChId, LedColor *pstPixel)
{
    UCHAR8 ucGbc = s_stDev.stData.ucGbcColor2;
    UCHAR8 ucPhase = ucGbc/TLC5971_GS_ADJUST_INTERVAL_SIZE;
    USHORT16 usIndex = enDevId * TLC5971_GS_ADJUST_POINT_NUM * TLC5971_PIXELS_PER_DEVICE
                        + enChId * TLC5971_GS_ADJUST_POINT_NUM + ucPhase;
    HV_ASSERT_TRUE(usIndex < TLC5971_GS_ADJUST_DATA_SIZE);
    LedColor *pstGsAdjust = &s_stGsAdjust[usIndex];
    pstPixel->ucRed   = pstPixel->ucRed * pstGsAdjust->ucRed / 255;
    pstPixel->ucGreen = pstPixel->ucGreen * pstGsAdjust->ucGreen / 255;
    pstPixel->ucBlue  = pstPixel->ucBlue * pstGsAdjust->ucBlue / 255;
    return HV_SUCCESS;
}

/**
 * @brief Enable/Disable Color Adjust for Led devices
 * @param bEnable enable/disable
 */
VOID Hv_Drv_Led_Tlc5971_AdjustColorEnable(BOOL bEnable)
{
    s_bTlc5971_Adjust_Color = bEnable;
    return;
}

/**
 * @brief Fill GS Data Api for Led devices
 * @param uiDevId TLC5971 device id of daisy chain
 * @param enChId TLC5971 channel id
 * @param pstPixel pixel RGB data for daisy chain
 */
Status Hv_Drv_Led_Tlc5971_FillColorData(LedDeviceId enDevId, LedChannelId enChId, LedColor *pstPixel)
{
    if (s_bTlc5971_Adjust_Color)
    {
        Hv_Drv_Led_Tlc5971_AdjustColor(enDevId, enChId, pstPixel);
    }

    return Hv_Cal_Led_Tlc5971_FillGsPixels(&s_stDev, enDevId, enChId, pstPixel);
}

/**
 * @brief Clear GS Data Api for Led devices
 */
Status Hv_Drv_Led_Tlc5971_ClearColorData(VOID)
{
    return Hv_Cal_Led_Tlc5971_ClearAllGsPixels(&s_stDev);
}

/**
 * @brief Dump Data Api for Led devices
 */
Status Hv_Drv_Led_Tlc5971_DumpDataBuffer(VOID)
{
    Hv_Cal_Led_Tlc5971_Dump_Data_Buffer(&s_stDev);
    return HV_SUCCESS;
}

/**
 * @brief Send Data Api for TLC5971
 * @param pucData data
 * @param uiDatasize data length
 */
static Status Hv_Drv_Led_Tlc5971_SendData(UCHAR8 *pucData, UINT32 uiDatasize)
{
    return Hv_Drv_GpioSimSWire_SendData(SIMSWIRE_ID_0, pucData, uiDatasize);
}

/**
 * @brief Initial TLC5971
 * @return Status
 */
Status Hv_Drv_Led_Tlc5971_init(VOID)
{
    if (s_stDev.stConfig.ucInitFlag)
    {
        return HV_SUCCESS;
    }
    GpioSimSWire stGpioSimSwire = {0};
    stGpioSimSwire.enBus = SIMSWIRE_ID_0;
    stGpioSimSwire.ucSckPin = HV_BOARD_CONFIG_GPIO_SCKI;
    stGpioSimSwire.ucSdtPin = HV_BOARD_CONFIG_GPIO_SDTI;
    stGpioSimSwire.ucTWHL = 1;
    stGpioSimSwire.ucTSU =  1;
    stGpioSimSwire.ucTHL =  1;
    Hv_Drv_GpioSimSWire_Init(&stGpioSimSwire);

    s_stDev.stConfig.aucColorMapping[0] = LED_COLOR_ID_BLUE;
    s_stDev.stConfig.aucColorMapping[1] = LED_COLOR_ID_GREEN;
    s_stDev.stConfig.aucColorMapping[2] = LED_COLOR_ID_RED;
    s_stDev.stConfig.ucColorNum = TLC5971_NUMBER_OF_COLORS;
    s_stDev.stConfig.ucPixelsNum = TLC5971_PIXELS_PER_DEVICE * HV_BOARD_CONFIG_LED_IC_NUM;
    s_stDev.stConfig.pfSendData = Hv_Drv_Led_Tlc5971_SendData;
    Hv_Vos_Memset(s_aucTlc5971_DataBuf, 0, sizeof(s_aucTlc5971_DataBuf));
    s_stDev.stData.pucDataBuffer = s_aucTlc5971_DataBuf;
    Hv_Vos_Memset(s_stTlc5971Pixels, 0, sizeof(s_stTlc5971Pixels));
    s_stDev.stData.pstPixels = s_stTlc5971Pixels;
    Hv_Cal_Led_Tlc5971_Init(&s_stDev, NULL);
    s_stDev.stConfig.ucInitFlag = 1;
    return HV_SUCCESS;
}