/**
 * @file hv_comm_Utilities.c
 * @brief Utilities source doe.
 * @details This file provides the following functions: \n
 *          (1) Initialization and reset functions \n
 *
 * @author HiView SoC Software Team
 * @version 1.0.0
 * @date 2022-08-23
 * @copyright Copyright(c),2022-8, Hiview Software. All rights reserved.
 * @par History:
 * <table>
 * <tr><th>Author                        <th>Date         <th>Change Description
 * <tr><td>HiView SoC Software Team      <td>2022-08-23   <td>init
 * </table>
*/


#include "hv_comm_Utilities.h"

#define HDBF_MAGIC         "HDBF"


// INT32 Hv_Common_Log2 (UINT32 uiParam) 
// {
//     static const UCHAR8 auclog2[256] = {
//     0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
//     6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
//     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
//     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
//     8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
//     8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
//     8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
//     8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
//   };
//   INT32 iL = -1;
//   while (uiParam >= 256) { iL += 8; uiParam >>= 8; }
//   return iL + auclog2[uiParam];
// }

UINT32 Hv_Common_GetEven(UINT32 uiParam)
{
  UINT32 uiEvenParam = 0;
  if (1 == (uiParam % 2))
  {
    uiEvenParam = uiParam + 1;
  }
  else
  {
    uiEvenParam = uiParam;
  }
  return uiEvenParam;
}


/**
 * @brief This function init custom bin setting  comes from PQ
 * @param *uiConfigAddr [in]    custom data setting address
 * @param uiLen [i]       total length of reg settings
 * @retval NULL
*/

VOID Hv_Common_BinConfigInit(const UINT32 *uiConfigAddr, UINT32 uiLen)
{
    PSettingData psd;

    UINT32 uiIndex = 0;
    for(uiIndex = 0; uiIndex < uiLen; uiIndex ++)
    {
        psd = (PSettingData)((UINT32)uiConfigAddr+sizeof(SettingData)*uiIndex);
        HV_W_FEILD_REG(psd->uiAddr, psd->ubStartBit, psd->ubEndBit, psd->uiVal);
    }
}

/**
 * @brief This function init custom setting by setting dataaddress, HDB init support more than one array.
 * @param *uiDBAddr [in]    custom data setting address
 * @param arrIdx    [in]    sel the idx group to init, if the arrIdx >= the expand of hdb, sel the default
 * @retval HV_FALSE            initial fail.
 * @HV_TRUE     initial success.
*/
BOOL HDB_Init(UINT32 *uiDBAddr, UINT32 arrIdx)
{
    INT32   i;
    PSettingData psd = NULL;
    PHDBF_Header pHdb = NULL;
    UINT32	uiRegCnt = 0;
    UINT32	uiExpand = 0;
    UINT32	uiArrIdx = 0;
    UINT32	uiRegVal = 0;
    UINT32	*puiRegExpandVal = NULL;

    pHdb = (PHDBF_Header)uiDBAddr;

    if (memcmp(pHdb->HDB_Magic, HDBF_MAGIC, 4) != 0) 
    {
        //LogPrintf(DBG_MSG, "[HDB] the magic is not match, magic: %s", pHdb->HDB_Magic);
        return HV_FALSE;
    }

    uiRegCnt = pHdb->HDB_RegCount;
    uiExpand = pHdb->HDB_Expand;

    if (arrIdx < uiExpand) 
    {
        uiArrIdx = arrIdx;
    }
    else 
    {
        uiArrIdx = pHdb->HDB_DefIndx;				//default index
    }

    psd = (PSettingData)((UINT32)uiDBAddr + sizeof(HDBF_Header));
    puiRegExpandVal = (UINT32*)((UINT32)uiDBAddr + sizeof(HDBF_Header) + sizeof(SettingData) * uiRegCnt);
    for (i = 0; i < uiRegCnt; i++) 
    {
        if (uiArrIdx == 0) 
        {
            uiRegVal = psd->uiVal;
        }
        else 
        {
            uiRegVal = puiRegExpandVal[i + (uiArrIdx - 1) * uiRegCnt];
        }

        HV_W_FEILD_REG(psd->uiAddr, psd->ubStartBit, psd->ubEndBit, uiRegVal);
        psd++;
    }

    return HV_TRUE;
}

HV_ATTR_ISR_SECTION VOID Hv_Common_WriteRegBytes(const UCHAR8 *pucData, UINT32 uiRegAdrr,  UINT32 uiLen)
{
    UINT32 puwSet = 0;
    UINT32 uwCnt = 0;
    UINT32 uiAlignAddr = 0;
    UINT32 uwTmp1 = 0;
    UINT32 uwTmp2 = 0;
    UINT32 uwTmp3 = 0;
    UINT32 uwTmp4 = 0;
    UCHAR8 ucSht = 0;
    UCHAR8 ucShtMv = 0;
    UCHAR8 ucFLen = 0;

    uiAlignAddr = uiRegAdrr & 0xFFFFFFFC;
    ucSht = (UCHAR8)(uiRegAdrr - uiAlignAddr);
    puwSet = uiAlignAddr;

    if (ucSht > 0)
    {
        uwTmp1 = 0;
        ucFLen = 4 - ucSht;
        if (ucFLen > uiLen)
        {
            ucFLen = uiLen;
        }

        /*Make Mask*/
        for (uwCnt=0; uwCnt<ucSht; uwCnt++)
        {
            uwTmp1 |= (0x0FF << (uwCnt << 3));
        }

        for (uwCnt = ucSht + ucFLen; uwCnt < 4; uwCnt++)
        {
            uwTmp1 |= ((UINT32) 0x0FF << (uwCnt << 3));
        }

        /*Clear the byte which will be Set*/
        uwTmp2 = HV_R32(puwSet);
        uwTmp2 &= uwTmp1;

        /*Set byte*/
        uwTmp3 = 0;
        ucShtMv = 0;

        for (uwCnt=0; uwCnt < ucFLen; uwCnt++)
        {
            uwTmp4 = pucData[uwCnt];
            uwTmp3 |= uwTmp4 << (uwCnt << 3);
        }

        uwTmp3 <<= (ucSht << 3);
        uwTmp2 |= uwTmp3;

        HV_W32(puwSet, uwTmp2);

        puwSet += 4;
    }
    else
    {
        /*Do Noting*/
    }

    while (uwCnt + 4 <= uiLen)
    {
        uwTmp1 = pucData[uwCnt+3];
        uwTmp1 <<= 8;
        uwTmp1 |= pucData[uwCnt+2];
        uwTmp1 <<= 8;
        uwTmp1 |= pucData[uwCnt+1];
        uwTmp1 <<= 8;
        uwTmp1 |= pucData[uwCnt];
        HV_W32(puwSet,uwTmp1);
        uwCnt += 4;
        puwSet += 4;
    }

    if (uwCnt < uiLen)
    {
        uwTmp1 = HV_R32(puwSet);
        uwTmp1 = (uwTmp1 >> ((uiLen - uwCnt) << 3)) << ((uiLen - uwCnt) << 3);
        ucShtMv = 0;
        while(uwCnt < uiLen)
        {
            uwTmp2 = pucData[uwCnt];
            uwTmp2 <<= (ucShtMv << 3);
            uwTmp1 |= uwTmp2;
            uwCnt++;
            ucShtMv++;
        }

        HV_W32(puwSet,uwTmp1);
    }
    else
    {
        /* Do Noting */
    }

    return;
}

/**
 * @brief Read bytes reg.
 * @param[in] uwRegAdrr Reg addr to read.
 * @param[out] pucData the data read from reg.
 * @param[in] uwLen the length of read data.
 * @return Status, 0-HV_SUCCESS, 1-HV_FAILURE.
 */
HV_ATTR_ISR_SECTION Status Hv_Common_ReadRegBytes(UCHAR8 *pucData, UINT32 uiRegAdrr, UINT32 uiLen)
{
    UINT32 puwSet = 0;
    UINT32 uwCnt = 0;
    UINT32 uiAlignAddr = 0;
    UINT32 uwTmp = 0;
    UCHAR8 ucSht = 0;
    UCHAR8 ucFLen = 0;
    UCHAR8 ucShtMv = 0;

    uiAlignAddr = uiRegAdrr & 0x0FFFFFFFC;
    ucSht = (UCHAR8)(uiRegAdrr - uiAlignAddr);
    puwSet = uiAlignAddr;

    if (ucSht > 0)
    {
        uwTmp = HV_R32(puwSet);
        ucShtMv = ucSht;
        ucFLen = 4 - ucSht;
        if (ucFLen > uiLen)
        {
            ucFLen = uiLen;
        }
        else
        {
            /* Do Noting */
        }
        while (uwCnt<ucFLen)
        {
            pucData[uwCnt] = (uwTmp & (((UINT32)0xFF) << (ucShtMv << 3))) >> (ucShtMv << 3);
            ucShtMv++;
            uwCnt++;
        }
        puwSet += 4;
    }
    else
    {
        /* Do Noting */
    }

    while (uwCnt+4 <= uiLen)
    {
        uwTmp = HV_R32(puwSet);
        pucData[uwCnt] = uwTmp & 0x0FF;
        pucData[uwCnt+1] = (uwTmp & 0x0FF00) >> 8;
        pucData[uwCnt+2] = (uwTmp & 0x0FF0000) >> 16;
        pucData[uwCnt+3] = (uwTmp & 0x0FF000000) >> 24;
        uwCnt += 4;
        puwSet += 4;
    }

    if (uwCnt < uiLen)
    {
        uwTmp = HV_R32(puwSet);
        ucShtMv = 0;
        while(uwCnt < uiLen)
        {
            pucData[uwCnt] = (uwTmp & (0x0FF << (ucShtMv << 3))) >> (ucShtMv << 3);
            ucShtMv++;
            uwCnt++;
        }
    }
    else
    {
        /* Do Noting */
    }

    return HV_SUCCESS;
}

FLOAT32 Hv_Common_Sqrt(FLOAT32 fValue)
{
    UINT32  uiLoopIndex = 0;
    FLOAT32 fSqrtRsult  = fValue;
    if(fValue <= 0)
    {
        return 0;
    }

    for(uiLoopIndex = 0; uiLoopIndex < 10; uiLoopIndex++)
    {
        fSqrtRsult = (fSqrtRsult + (fValue / fSqrtRsult)) / 2.0;
    }

    return fSqrtRsult;
}


