/**************************************************************************//**
  * \file     Analog_Circuits.c
  * \brief    Analog signal processing algorithm library file
  * \details
  * \author   Zhang Xuan
  * \version  V1.0.0
  * \date     19-Sep-2018
  * \par      History:
  *           V1.0.0 Initial release
  * \par      Copyright:
  *           (c) Heilongjiang TYW Electronics co., LTD
******************************************************************************/

/* Includes ------------------------------------------------------------------*/
#include "common.h"
#include "Analog_Circuits.h"

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


uint16_t ADC_Input_Voltage_Calc(uint16_t u16ADCSample, uint16_t u16ADCRes, uint16_t u16VRef)
{
    uint32_t  u32ADCVoltage;
    uint16_t  u16Result;

    if (u16ADCRes == 0U)
    {
        u16Result = 0x0000U;
    }
    else if (u16ADCRes <= u16ADCSample)
    {
        u16Result = u16VRef;
    }
    else
    {
        u32ADCVoltage  = (uint32_t)u16ADCSample;
        u32ADCVoltage *= (uint32_t)u16VRef;
        u32ADCVoltage /= (uint32_t)u16ADCRes;

        u16Result = (uint16_t)u32ADCVoltage;
    }

    return u16Result;
}

uint16_t ADC_VRef_Calibrate(uint16_t u16ADCSample, uint16_t u16ADCRes, uint16_t u16ActVoltage)
{
    uint32_t  u32RefVoltage;
    uint16_t  u16Result;

    if ((u16ADCSample == 0U) || (u16ADCSample > u16ADCRes))
    {
        u16Result = 0x0000U;
    }
    else
    {
        u32RefVoltage  = (uint32_t)u16ActVoltage;
        u32RefVoltage *= (uint32_t)u16ADCRes;
        u32RefVoltage /= (uint32_t)u16ADCSample;

        if (u32RefVoltage & 0xFFFF0000UL)
        {
            u16Result = 0xFFFFU;
        }
        else
        {
            u16Result = (uint16_t)u32RefVoltage;
        }
    }

    return u16Result;
}

uint16_t ADC_Data_Calibrate(uint16_t u16Value, uint8_t u8CalMode, uint16_t u16CalData)
{
    uint16_t u16Result;
    
    if (u8CalMode == 1U)
    {
        if (0xFFFFU - u16CalData > u16Value)
        {
            u16Result = u16Value + u16CalData;
        }
        else
        {
            u16Result  = 0xFFFFU;
        }
    }
    else if (u8CalMode == 2U)
    {
        if (u16Value > u16CalData)
        {
            u16Result = u16Value - u16CalData;
        }
        else
        {
            u16Result  = 0x0000U;
        }
    }
    else
    {
        u16Result = u16Value;
    }
    
    return u16Result;
}



uint16_t ADC_Voltage_Calc_Circuit101(uint16_t u16ADCVoltage, 
                                     uint16_t u16Reference,
                                     uint16_t u16Resolution,
                                     const ADC_Res_List_st_t* pstResList)
{    
    return u16ADCVoltage / u16Resolution;
}

uint16_t ADC_Voltage_Calc_Circuit102(uint16_t u16ADCVoltage, 
                                     uint16_t u16Reference,
                                     uint16_t u16Resolution,
                                     const ADC_Res_List_st_t* pstResList)
{
    uint64_t  u64ActVoltage;
    uint32_t  u32ResSum;
    uint16_t  u16Result;

    if  (pstResList -> u32Res2 == 0UL)
    {
        u16Result = 0x0000U;
    }
    else
    {
        u32ResSum      = pstResList -> u32Res1 + pstResList -> u32Res2;
        u64ActVoltage  = (uint64_t)u16ADCVoltage;
        u64ActVoltage *= (uint64_t)u32ResSum;
        u64ActVoltage /= (uint64_t)(pstResList -> u32Res2);
        u64ActVoltage /= (uint64_t)u16Resolution;

        if (u64ActVoltage & 0xFFFFFFFFFFFF0000ULL)
        {
            u16Result = 0xFFFFU;
        }
        else
        {
            u16Result = (uint16_t)u64ActVoltage;
        }
    }

    return u16Result;
}

uint16_t ADC_Res_Calc_Circuit101(uint16_t u16ADCVoltage, 
                                 uint16_t u16Reference,
                                 uint16_t u16Resolution,
                                 const ADC_Res_List_st_t* pstResList)
{
    uint64_t  u64CalcRes;
    uint32_t  u32ActRes;
    uint16_t  u16VDiff;
    uint16_t  u16Result;

    if ((u16ADCVoltage >= u16Reference) || (pstResList -> u32Res4 == 0U))
    {
        u16Result = 0xFFFFU;
    }
    else
    {
        u16VDiff    = u16Reference - u16ADCVoltage;
        u64CalcRes  = (uint64_t)u16ADCVoltage;
        u64CalcRes *= (uint64_t)(pstResList -> u32Res4);
        u64CalcRes /= (uint64_t)u16VDiff;

        if (u64CalcRes & 0xFFFFFFFF00000000ULL)
        {
            u16Result = 0xFFFFU;
        }
        else
        {
            u32ActRes = (uint32_t)u64CalcRes;
            if (u32ActRes <= pstResList -> u32Res5)
            {
                u16Result = 0x0000U;
            }
            else
            {
                u32ActRes -= pstResList -> u32Res5;
                u32ActRes /= (uint32_t)u16Resolution;
                if (u32ActRes & 0xFFFF0000UL)
                {
                    u16Result = 0xFFFFU;
                }
                else
                {
                    u16Result = (uint16_t)u32ActRes;
                }
            }
        }
    }
    return u16Result;
}

uint16_t ADC_Res_Calc_Circuit102(uint16_t u16ADCVoltage, 
                                 uint16_t u16Reference,
                                 uint16_t u16Resolution,
                                 const ADC_Res_List_st_t* pstResList)
{
    uint64_t  u64TempValM;
    uint64_t  u64TempValN;
    uint64_t  u64CalcRes;
    uint32_t  u32ActRes;
    uint16_t  u16VDiff;
    uint16_t  u16Result;

    if ((u16ADCVoltage >= u16Reference) || (pstResList -> u32Res2 == 0U) || (pstResList -> u32Res4 == 0U))
    {
        u16Result = 0xFFFFU;
    }
    else
    {
        u16VDiff     = u16Reference - u16ADCVoltage;
        u64TempValM  = (uint64_t)(pstResList -> u32Res2);
        u64TempValM *= (uint64_t)u16VDiff;

        u64TempValN  = (uint64_t)(pstResList -> u32Res4);
        u64TempValN *= (uint64_t)u16ADCVoltage;

        if (u64TempValM <= u64TempValN)
        {
            u16Result = 0xFFFFU;
        }
        else
        {
            u64CalcRes  = (uint64_t)u16ADCVoltage;
            u64CalcRes *= (uint64_t)(pstResList -> u32Res2);
            u64CalcRes *= (uint64_t)(pstResList -> u32Res4);
            u64CalcRes /= u64TempValM - u64TempValN;

            if (u64CalcRes & 0xFFFFFFFF00000000ULL)
            {
                u16Result = 0xFFFFU;
            }
            else
            {
                u32ActRes = (uint32_t)u64CalcRes;
                if (u32ActRes <= pstResList -> u32Res5)
                {
                    u16Result = 0x0000U;
                }
                else
                {
                    u32ActRes -= pstResList -> u32Res5;
                    u32ActRes /= (uint32_t)u16Resolution;
                    if (u32ActRes & 0xFFFF0000UL)
                    {
                        u16Result = 0xFFFFU;
                    }
                    else
                    {
                        u16Result = (uint16_t)u32ActRes;
                    }
                }
            }
        }
    }
    return u16Result;
}

uint16_t ADC_Res_Calc_Circuit103(uint16_t u16ADCVoltage, 
                                 uint16_t u16Reference,
                                 uint16_t u16Resolution,
                                 const ADC_Res_List_st_t* pstResList)
{
    uint64_t  u64TempValM;
    uint64_t  u64TempValN;
    uint64_t  u64ActVoltage;
    uint64_t  u64CalcRes;
    uint32_t  u32ActRes;
    uint32_t  u32ResSum;
    uint16_t  u16Result;

    if ((pstResList -> u32Res2 == 0U) || (pstResList -> u32Res4 == 0U))
    {
        u16Result = 0xFFFFU;
    }
    else
    {
        u32ResSum      = pstResList -> u32Res1 + pstResList -> u32Res2;
        u64ActVoltage  = (uint64_t)u16ADCVoltage;
        u64ActVoltage *= (uint64_t)u32ResSum;
        u64ActVoltage /= (uint64_t)(pstResList -> u32Res2);

        if (u64ActVoltage >= (uint64_t)u16Reference)
        {
            u16Result = 0xFFFFU;
        }
        else
        {
            u64TempValM  = (uint64_t)u32ResSum;
            u64TempValM *= (uint64_t)u16Reference - u64ActVoltage;

            u64TempValN  = (uint64_t)(pstResList -> u32Res4);
            u64TempValN *= u64ActVoltage;

            if (u64TempValM <= u64TempValN)
            {
                u16Result = 0xFFFFU;
            }
            else
            {
                u64CalcRes  = u64ActVoltage;
                u64CalcRes *= (uint64_t)u32ResSum;
                u64CalcRes *= (uint64_t)(pstResList -> u32Res4);
                u64CalcRes /= u64TempValM - u64TempValN;

                if (u64CalcRes & 0xFFFFFFFF00000000ULL)
                {
                    u16Result = 0xFFFFU;
                }
                else
                {
                    u32ActRes = (uint32_t)u64CalcRes;
                    if (u32ActRes <= pstResList -> u32Res5)
                    {
                        u16Result = 0x0000U;
                    }
                    else
                    {
                        u32ActRes -= pstResList -> u32Res5;
                        u32ActRes /= (uint32_t)u16Resolution;
                        if (u32ActRes & 0xFFFF0000UL)
                        {
                            u16Result = 0xFFFFU;
                        }
                        else
                        {
                            u16Result = (uint16_t)u32ActRes;
                        }
                    }
                }
            }
        }
    }
    return u16Result;
}

uint16_t ADC_Res_Calc_Circuit201(uint16_t u16ADCVoltage, 
                                 uint16_t u16Reference,
                                 uint16_t u16Resolution,
                                 const ADC_Res_List_st_t* pstResList)
{
    uint64_t  u64CalcRes;
    uint32_t  u32ActRes;
    uint16_t  u16VDiff;
    uint16_t  u16Result;

    if ((u16ADCVoltage >= u16Reference) || (u16ADCVoltage == 0U) ||\
        (pstResList -> u32Res4 == 0U)   || (u16Resolution == 0U))
    {
        u16Result = 0xFFFFU;
    }
    else
    {
        u16VDiff    = u16Reference - u16ADCVoltage;
        u64CalcRes  = (uint64_t)u16VDiff;
        u64CalcRes *= (uint64_t)(pstResList -> u32Res4);
        u64CalcRes /= (uint64_t)u16ADCVoltage;

        if (u64CalcRes & 0xFFFFFFFF00000000ULL)
        {
            u16Result = 0xFFFFU;
        }
        else
        {
            u32ActRes = (uint32_t)u64CalcRes;
            if (u32ActRes <= pstResList -> u32Res5)
            {
                u16Result = 0x0000U;
            }
            else
            {
                u32ActRes -= pstResList -> u32Res5;
                u32ActRes /= (uint32_t)u16Resolution;
                if (u32ActRes & 0xFFFF0000UL)
                {
                    u16Result = 0xFFFFU;
                }
                else
                {
                    u16Result = (uint16_t)u32ActRes;
                }
            }
        }
    }
    return u16Result;
}

uint16_t ADC_Res_Calc_Circuit202(uint16_t u16ADCVoltage, 
                                 uint16_t u16Reference,
                                 uint16_t u16Resolution,
                                 const ADC_Res_List_st_t* pstResList)
{
    uint64_t  u64CalcRes;
    uint64_t  u64ParallelRes;
    uint32_t  u32ActRes;
    uint16_t  u16VDiff;
    uint16_t  u16Result;

    if ((u16ADCVoltage >= u16Reference) || (u16ADCVoltage == 0U) || (pstResList -> u32Res2 == 0U) || \
        (pstResList -> u32Res4 == 0U)   || (u16Resolution == 0U))
    {
        u16Result = 0xFFFFU;
    }
    else
    {
        u64ParallelRes  = (uint64_t)(pstResList -> u32Res2);
        u64ParallelRes *= (uint64_t)(pstResList -> u32Res4);
        u64ParallelRes /= (uint64_t)(pstResList -> u32Res2) + (uint64_t)(pstResList -> u32Res4);
        
        u16VDiff    = u16Reference - u16ADCVoltage;
        u64CalcRes  = (uint64_t)u16VDiff;
        u64CalcRes *= u64ParallelRes;
        u64CalcRes /= (uint64_t)u16ADCVoltage;

        if (u64CalcRes & 0xFFFFFFFF00000000ULL)
        {
            u16Result = 0xFFFFU;
        }
        else
        {
            u32ActRes = (uint32_t)u64CalcRes;
            if (u32ActRes <= pstResList -> u32Res5)
            {
                u16Result = 0x0000U;
            }
            else
            {
                u32ActRes -= pstResList -> u32Res5;
                u32ActRes /= (uint32_t)u16Resolution;
                if (u32ActRes & 0xFFFF0000UL)
                {
                    u16Result = 0xFFFFU;
                }
                else
                {
                    u16Result = (uint16_t)u32ActRes;
                }
            }
        }
    }
    return u16Result;
}

uint16_t ADC_Res_Calc_Circuit203(uint16_t u16ADCVoltage, 
                                 uint16_t u16Reference,
                                 uint16_t u16Resolution,
                                 const ADC_Res_List_st_t* pstResList)
{
    uint64_t  u64ActVoltage;
    uint64_t  u64ParallelRes;
    uint64_t  u64CalcRes;
    uint32_t  u32ActRes;
    uint32_t  u32ResSum;
    uint16_t  u16Result;
    
    if ((u16ADCVoltage >= u16Reference) || (u16ADCVoltage == 0U) || (pstResList -> u32Res2 == 0U) || \
        (pstResList -> u32Res4 == 0U)   || (u16Resolution == 0U))
    {
        u16Result = 0xFFFFU;
    }
    else
    {
        u32ResSum      = pstResList -> u32Res1 + pstResList -> u32Res2;
        u64ActVoltage  = (uint64_t)u16ADCVoltage;
        u64ActVoltage *= (uint64_t)u32ResSum;
        u64ActVoltage /= (uint64_t)(pstResList -> u32Res2);

        if (u64ActVoltage >= (uint64_t)u16Reference)
        {
            u16Result = 0xFFFFU;
        }
        else
        {
            u64ParallelRes  = (uint64_t)u32ResSum;
            u64ParallelRes *= (uint64_t)(pstResList -> u32Res4);
            u64ParallelRes /= (uint64_t)u32ResSum + (uint64_t)(pstResList -> u32Res4);
            
            u64CalcRes  = (uint64_t)u16Reference - u64ActVoltage;
            u64CalcRes *= u64ParallelRes;
            u64CalcRes /= u64ActVoltage;
            
            if (u64CalcRes & 0xFFFFFFFF00000000ULL)
            {
                u16Result = 0xFFFFU;
            }
            else
            {
                u32ActRes = (uint32_t)u64CalcRes;
                if (u32ActRes <= pstResList -> u32Res5)
                {
                    u16Result = 0x0000U;
                }
                else
                {
                    u32ActRes -= pstResList -> u32Res5;
                    u32ActRes /= (uint32_t)u16Resolution;
                    if (u32ActRes & 0xFFFF0000UL)
                    {
                        u16Result = 0xFFFFU;
                    }
                    else
                    {
                        u16Result = (uint16_t)u32ActRes;
                    }
                }
            }
        }
    }
    return u16Result;
}

uint16_t ADC_Res_Calc_Circuit301(uint16_t u16ADCVoltage, 
                                 uint16_t u16Reference,
                                 uint16_t u16Resolution,
                                 const ADC_Res_List_st_t* pstResList)
{
    uint32_t  u32ActRes;
    uint16_t  u16Result;

    if ((u16Reference  == 0U) || (u16Resolution == 0U))
    {
        u16Result = 0xFFFFU;
    }
    else
    {
        u32ActRes   = (uint32_t)u16ADCVoltage;
        u32ActRes  *= 10000UL;
        u32ActRes  /= (uint32_t)u16Reference;
        
        if (u32ActRes <= pstResList -> u32Res5)
        {
            u16Result = 0x0000U;
        }
        else
        {
            u32ActRes -= pstResList -> u32Res5;
            u32ActRes /= (uint32_t)u16Resolution;
            if (u32ActRes & 0xFFFF0000UL)
            {
                u16Result = 0xFFFFU;
            }
            else
            {
                u16Result = (uint16_t)u32ActRes;
            }
        }

    }
    return u16Result;
}

uint16_t ADC_Res_Calc_Circuit302(uint16_t u16ADCVoltage, 
                                 uint16_t u16Reference,
                                 uint16_t u16Resolution,
                                 const ADC_Res_List_st_t* pstResList)
{
    uint32_t  u32ActRes;
    uint32_t  u32Bypass;
    uint16_t  u16Result;

    if ((u16Reference  == 0U) || (u16Resolution == 0U) || (pstResList -> u32Res2 == 0U))
    {
        u16Result = 0xFFFFU;
    }
    else
    {
        u32Bypass   = (uint32_t)u16ADCVoltage;
        u32Bypass  *= 10000UL;
        u32Bypass  /= pstResList -> u32Res2;        
        
        if (u32Bypass >= (uint32_t)u16Reference)
        {
            u16Result = 0xFFFFU;
        }
        else
        {
            u32ActRes   = (uint32_t)u16ADCVoltage;
            u32ActRes  *= 10000UL;
            u32ActRes  /= (uint32_t)u16Reference - u32Bypass;
            
            if (u32ActRes <= pstResList -> u32Res5)
            {
                u16Result = 0x0000U;
            }
            else
            {
                u32ActRes -= pstResList -> u32Res5;
                u32ActRes /= (uint32_t)u16Resolution;
                if (u32ActRes & 0xFFFF0000UL)
                {
                    u16Result = 0xFFFFU;
                }
                else
                {
                    u16Result = (uint16_t)u32ActRes;
                }
            }
        }
    }
    return u16Result;
}

uint16_t ADC_Res_Calc_Circuit303(uint16_t u16ADCVoltage, 
                                 uint16_t u16Reference,
                                 uint16_t u16Resolution,
                                 const ADC_Res_List_st_t* pstResList)
{
    uint64_t  u64ActVoltage;
    uint32_t  u32ActRes;
    uint32_t  u32ResSum;
    uint32_t  u32Bypass;
    uint16_t  u16Result;

    if ((u16Reference  == 0U) || (u16Resolution == 0U) || (pstResList -> u32Res2 == 0U))
    {
        u16Result = 0xFFFFU;
    }
    else
    {
        u32ResSum      = pstResList -> u32Res1 + pstResList -> u32Res2;
        u64ActVoltage  = (uint64_t)u16ADCVoltage;
        u64ActVoltage *= (uint64_t)u32ResSum;
        u64ActVoltage /= (uint64_t)(pstResList -> u32Res2);
        
        u64ActVoltage *= 10000ULL;
        if (u64ActVoltage & 0x00000000FFFFFFFFULL)
        {
            u16Result = 0xFFFFU;
        }
        else
        {
            u32Bypass   = (uint32_t)u64ActVoltage;
            u32Bypass  /= u32ResSum;        
        
            if (u32Bypass >= (uint32_t)u16Reference)
            {
                u16Result = 0xFFFFU;
            }
            else
            {
                u32ActRes   = (uint32_t)u64ActVoltage;
                u32ActRes  /= (uint32_t)u16Reference - u32Bypass;
                
                if (u32ActRes <= pstResList -> u32Res5)
                {
                    u16Result = 0x0000U;
                }
                else
                {
                    u32ActRes -= pstResList -> u32Res5;
                    u32ActRes /= (uint32_t)u16Resolution;
                    if (u32ActRes & 0xFFFF0000UL)
                    {
                        u16Result = 0xFFFFU;
                    }
                    else
                    {
                        u16Result = (uint16_t)u32ActRes;
                    }
                }
            }
        }
    }
    return u16Result;
}