/**
*   @copyright       © 2026 Microchip Technology Inc.
    Microchip Technology Inc. and its subsidiaries. You may use this
    software and any derivatives exclusively with Microchip products.

    THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER
    EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED
    WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A
    PARTICULAR PURPOSE, OR ITS INTERACTION WITH MICROCHIP PRODUCTS, COMBINATION
    WITH ANY OTHER PRODUCTS, OR USE IN ANY APPLICATION.

    IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE,
    INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND
    WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS
    BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE
    FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN
    ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
    THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.

    MICROCHIP PROVIDES THIS SOFTWARE CONDITIONALLY UPON YOUR ACCEPTANCE OF THESE
    TERMS. 
*
*************************************************************************/

/**
 *  @file       diag_adc_linearity_monotonicity_test.c
 *  @version    1.0
 *  @brief      This file has the implementation for the ADC Linearity 
 *		        Monotonicity test diagnostics. @see diag_adc.h
 *
 *************************************************************************/

#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "diag.h"
#include "diag_adc.h"
#include "diag_adc_shared.h"
#include "diag_utility_adc.h"
#include "diag_utility_dac.h"

#define DIAG_ADC_INPUT_INCREMENT 16U
#define DIAG_ADC_BIT_STUCK_HIGH_DEFAULT_FAIL 0x0FFFU
#define DIAG_ADC_BIT_STUCK_LOW_DEFAULT_FAIL 0x0000U
#define DIAG_ADC_BIT_STUCK_HIGH_PASS 0x0000U
#define DIAG_ADC_BIT_STUCK_LOW_PASS 0x0FFFU

static DIAG_ADC_LIN_MON_RESULT resultsLinMon;
        
uint32_t DIAG_ADC_LinearityMonotonicityTest(DIAG_ADC_CHANNELS adcChannelNumber, 
                                        uint8_t tolerance)
{
    volatile uint16_t input, failCount, bitStuckLow, bitStuckHigh;
    int16_t minRange, maxRange;
    volatile int16_t deviation;
	volatile uint16_t resultPrevious, result;
    uint32_t status = DIAG_PASS;
    
    bitStuckHigh = DIAG_ADC_BIT_STUCK_HIGH_DEFAULT_FAIL;
    bitStuckLow = DIAG_ADC_BIT_STUCK_LOW_DEFAULT_FAIL;
    failCount = 0U;
    /*LDRA_EXCLUDE 151 D: <justification start> This variable is set with a known value before test, violation ignored <justification end> */
    resultsLinMon.lastTestFailCurrentResult = 0x0000U;
    /*LDRA_EXCLUDE 151 D: <justification start> This variable is set with a known value before test, violation ignored <justification end> */
    resultsLinMon.lastTestFailPreviousResult = 0x0000U;   
        
	if(DIAG_ADC_IsChannelValid(adcChannelNumber) == DIAG_ADC_VALID_CHANNEL)
	{   
        /*LDRA_EXCLUDE 151 D: <justification start> This variable is set with a known value before test, violation ignored <justification end> */
        resultsLinMon.resultLinMon = DIAG_PASS;
        /*LDRA_EXCLUDE 151 D: <justification start> This variable is set with a known value before test, violation ignored <justification end> */
        resultsLinMon.stuckAtHighValue = DIAG_ADC_BIT_STUCK_HIGH_PASS;
        /*LDRA_EXCLUDE 151 D: <justification start> This variable is set with a known value before test, violation ignored <justification end> */
        resultsLinMon.stuckAtLowValue = DIAG_ADC_BIT_STUCK_LOW_PASS;
                
        //Store the values before executing the diagnostics
        DIAG_ADC_StoreRegisters(adcChannelNumber);
           
        //Calculate the range
        minRange = (int16_t)((int16_t)(DIAG_ADC_INPUT_INCREMENT) - (int16_t)(tolerance));
        maxRange = (int16_t)((int16_t)(DIAG_ADC_INPUT_INCREMENT) + (int16_t)(tolerance));
        
        //The starting range of DAC is the initial input value
        input = DIAG_ADC_LIN_INPUT_START_RANGE;
        DIAG_UTIL_DAC_GenerateDC(input);
        /*LDRA_EXCLUDE 91 D : <justification start> The value is used to calculate deviations, violation ignored <justification end> */
        resultPrevious = (uint16_t)DIAG_ADC_TriggerConversionAndGetResult(adcChannelNumber);
        
        /*LDRA_EXCLUDE 270 S : <justification start> The loop initialization is as per design, violation ignored <justification end> */
        /*LDRA_EXCLUDE 271 S : <justification start> The loop increment is as per design, violation ignored <justification end> */
        for(input = (input + DIAG_ADC_INPUT_INCREMENT); input <= DIAG_ADC_LIN_INPUT_END_RANGE;input = (input + DIAG_ADC_INPUT_INCREMENT))
        {
            DIAG_UTIL_DAC_GenerateDC(input);
            result = (uint16_t)DIAG_ADC_TriggerConversionAndGetResult(adcChannelNumber);            

            /*LDRA_EXCLUDE 134 S : <justification start> The below calculations are needed for deviation calculation, violation ignored <justification end> */
            deviation = (int16_t)((int16_t)(result) - (int16_t)(resultPrevious));

            /*LDRA_EXCLUDE 134 S : <justification start> The volatile variable is only compared with known values, violation ignored <justification end> */
            /*LDRA_EXCLUDE 408 S : <justification start> The volatile variable is only compared with known values, violation ignored <justification end> */
            if((deviation < minRange) || (deviation > maxRange))
            {
                /*LDRA_EXCLUDE 151 D: <justification start> This variable is being set with result based on the test results, violation ignored <justification end> */
                resultsLinMon.lastTestFailCurrentResult = result;
                /*LDRA_EXCLUDE 151 D: <justification start> This variable is being set with result based on the test results, violation ignored <justification end> */
                resultsLinMon.lastTestFailPreviousResult = resultPrevious;
                /*LDRA_EXCLUDE 151 D: <justification start> This variable is being set with result based on the test results, violation ignored <justification end> */
                status = DIAG_FAIL;
                failCount++;
            }
            else
            {
                //The deviation is within the range.
            }
            /*LDRA_EXCLUDE 134 S : <justification start> The volatile variable value doesn't change outside the software scope, violation ignored <justification end> */
            bitStuckHigh = bitStuckHigh & result;
            /*LDRA_EXCLUDE 134 S : <justification start> The volatile variable value doesn't change outside the software scope, violation ignored <justification end> */            
            bitStuckLow = bitStuckLow | result;
            resultPrevious = result; 
        }
        
		/*LDRA_NOANALYSIS*/
        /*LDRA_EXCLUDE 134 S : <justification start> The volatile variable value doesn't change outside the software scope and is only compared with known values, violation ignored <justification end> */
        /*LDRA_EXCLUDE 408 S : <justification start> The volatile variable value doesn't change outside the software scope and is only compared with known values, violation ignored <justification end> */
        if((bitStuckHigh != 0x0000U)||(bitStuckLow != 0x0FFFU))
        {
            /*LDRA_EXCLUDE 151 D: <justification start> This variable is set with result based on the test, violation ignored <justification end> */
            status = DIAG_FAIL;
        }
        else
        {
            //Bit are not stuck at high or low
        }
		/*LDRA_ANALYSIS*/
        
        //Restore the values after the diagnostics is executed
        DIAG_ADC_RestoreRegisters(adcChannelNumber);
    }
    else
    {
        status = DIAG_INVALID_PARAM;
    }
    
    /*LDRA_EXCLUDE 151 D: <justification start> This variable is set with result value after test, violation ignored <justification end> */
    resultsLinMon.resultLinMon = status;
    resultsLinMon.failCount = failCount;
    /*LDRA_EXCLUDE 151 D: <justification start> This variable is set with result value after test, violation ignored <justification end> */
    resultsLinMon.stuckAtHighValue = bitStuckHigh;
    /*LDRA_EXCLUDE 151 D: <justification start> This variable is set with result value after test, violation ignored <justification end> */
    resultsLinMon.stuckAtLowValue = bitStuckLow;
    
    return status;
}

DIAG_ADC_LIN_MON_RESULT DIAG_ADC_GetLinearityMonotonicityResult(void)
{
    return resultsLinMon;
}
