/**
*   @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_interrupt_frequency_check.c
 *  @version    1.0
 *  @brief      This file has the implementation for the interrupt frequency check
 *              diagnostics
 *  @see        diag_interrupt.h
 *************************************************************************/
#include "diag_interrupt.h"
#include "diag_interrupt_shared.h"
#include "diag.h"

static DIAG_INTERRUPT_FREQ_RUN_STATUS intrFreqRunFlag = INTR_FREQ_DIAG_RUN_FALSE;

static DIAG_INTERRUPT_FREQ_RUN_STATUS DIAG_INTERRUPT_IsInterruptFreqTestRunning(void)
{
    return (intrFreqRunFlag);
}

/*LDRA_EXCLUDE 65 D <justification start> The function here is intended to return a void and the usage is as per the design.  65 D is therefore ignored <justification end> */
/*LDRA_EXCLUDE 3 J <justification start> it is functionally verified that the function is reached and executed. Violation is ignored <justification end> */
static void DIAG_INTERRUPT_CheckModuleInterruptCounter(uint32_t indexVal,DIAG_INTERRUPT_IRQ_MODEL *modPtr)
{
    int32_t toleranceBandHigh;
    int32_t toleranceBandLow;
    /*First get the tolerance band values for the module*/
	/*LDRA_EXCLUDE 105 D <justification start> tolernceBand is used only in the if path, hence the violation is ignored <justification end> */
    toleranceBandLow = 0 - modPtr[indexVal].moduleInterruptToleranceBand;
	/*LDRA_EXCLUDE 105 D <justification start> tolernceBand is used only in the if path, hence the violation is ignored <justification end> */
    toleranceBandHigh = 0 + modPtr[indexVal].moduleInterruptToleranceBand;
    /*If the moduleInterruptFTTICounter is 0, it means that it is time to check for the moduleInterruptCounter*/
    /*LDRA_NOANALYSIS*/
    if(modPtr[indexVal].moduleInterruptFTTICounter == (uint32_t)0U)
    { 
        /*In the following snippet moduleInterruptCounter is not getting covered for the toleranceBandLow
         *and toleranceBandHigh conditions because both cant be false simultaneously
         *Also, functionally the following code is working correctly. Hence the ldra annotation for achieving coverage.*/
        if(((modPtr[indexVal].moduleInterruptCounter) >= toleranceBandLow) &&
           ((modPtr[indexVal].moduleInterruptCounter) <= toleranceBandHigh)) 
        {
			/*LDRA_EXCLUDE 105 D <justification start> indexVal is used only in the if path, hence the violation is ignored <justification end> */
            modPtr[indexVal].moduleIntrStatus = MODULE_FREQ_TEST_PASSED;
            /*Reload the expected interrupt counter for the module for PASS condition*/
            modPtr[indexVal].moduleInterruptCounter = modPtr[indexVal].moduleExpectedInterruptCount;
        }
        else
        {
            /*In case of failure, we return the actual moduleInterruptCount in the moduleIntrStatus which 
             *indicates by how much the moduleInterruptCounter is off the actual value*/           
			 /*LDRA_EXCLUDE 105 D <justification start> indexVal is used only in the if path, hence the violation is ignored <justification end> */
            modPtr[indexVal].moduleIntrStatus = MODULE_FREQ_TEST_FAILED; 
        }
        
        /*Reload the FTTI Counter*/
        modPtr[indexVal].moduleInterruptFTTICounter = modPtr[indexVal].moduleInterruptFTTI;
    }  
    /*LDRA_ANALYSIS*/
}

uint32_t DIAG_INTERRUPT_FrequencyCheck(DIAG_INTERRUPT_IRQ_MODEL *modulePtr,uint32_t modulesForFreqCheck)
{
    uint32_t retVal;
    uint32_t modIrqIndex = 0U;
    /*Loop through the module irq structure to check for the interrupt counter status of every module
       for which the interrupt frequency test is performed.*/
    while(modIrqIndex < modulesForFreqCheck)
    {
        /*If modules are removed from the module structure, then skip those modules.*/
        if(modulePtr[modIrqIndex].moduleIrq != DIAG_INVALID_MODULE_ID)
        {
             /*Decrement the individual moduleInterruptFTTICounter */
            modulePtr[modIrqIndex].moduleInterruptFTTICounter -= 1U;
/*LDRA_EXCLUDE 1 J <justification start> it is functionally verified that the function is reached and executed. Violation is ignored <justification end> */			
            DIAG_INTERRUPT_CheckModuleInterruptCounter(modIrqIndex,modulePtr);
        }
        else
        {
            modulePtr[modIrqIndex].moduleIntrStatus = MODULE_FREQ_TEST_FAILED; 
        }             
        /*Go to the next module*/
        modIrqIndex += 1U;
    }
    /*Reset the modIrqIndex, and check if the API has to return pass or fail*/
    modIrqIndex = 0U;
    while(modIrqIndex < modulesForFreqCheck)
    {
        if(modulePtr[modIrqIndex].moduleIntrStatus == MODULE_FREQ_TEST_FAILED)
        {
            DIAG_INTERRUPT_SetRetValue(DIAG_FAIL);
            break;
        }
        else
        {
            DIAG_INTERRUPT_SetRetValue(DIAG_PASS);
        }
        modIrqIndex += 1U;
    }
    retVal = DIAG_INTERRUPT_GetRetValue();
    return(retVal);
}

void DIAG_INTERRUPT_GetFreqTestResults(uint32_t *failCount, DIAG_INTERRUPT_MODULE_STATUS *IrqDataTable,DIAG_INTERRUPT_IRQ_MODEL *modulePtr,uint32_t size)
{
    uint32_t index = 0U;
    while(index < size)
    {
        /*Update the result of only the modules that being currently monitored*/
        if(modulePtr[index].moduleIrq != DIAG_INVALID_MODULE_ID)
        {
            
            IrqDataTable[index].interruptStatus = modulePtr[index].moduleIntrStatus;
            IrqDataTable[index].IrqNumber = modulePtr[index].moduleIrq;
            IrqDataTable[index].intrCounter = modulePtr[index].moduleInterruptCounter;
        }
        /*Update the failcount as well*/
        if(modulePtr[index].moduleIntrStatus == MODULE_FREQ_TEST_FAILED)  
        {
            *failCount += 1U;
        }
        index += 1U;
    }
}

void DIAG_INTERRUPT_StartFrequencyTest(void)
{
    intrFreqRunFlag = INTR_FREQ_DIAG_RUN_TRUE;
}

void DIAG_INTERRUPT_StopFrequencyTest(void)
{
    intrFreqRunFlag = INTR_FREQ_DIAG_RUN_FALSE;
}

/*LDRA_EXCLUDE 65 D <justification start> The function here is intended to return a void and the usage is as per the design.  65 D is therefore ignored <justification end> */
void DIAG_INTERRUPT_UpdateISRNotifications(uint32_t irqNum,DIAG_INTERRUPT_IRQ_MODEL *modulePtr, uint32_t modsize)
{
    DIAG_INTERRUPT_FREQ_RUN_STATUS curDiag;
    uint32_t index = 0U;
    curDiag = DIAG_INTERRUPT_IsInterruptFreqTestRunning();
    
    if(curDiag == INTR_FREQ_DIAG_RUN_TRUE)
    {
/*LDRA_EXCLUDE 28 D <justification start> The function is verified to be working correctly for all conditions. 28 D is therefore ignored <justification end> */		
        while(index < modsize)
        {
			/*Scan through the interrupt module structure to get the moduleIndex*/
			/*LDRA_EXCLUDE 105 D <justification start> Variable does not need to be changed or accessed on all branches and so 105 D is ignored <justification end> */
			if (modulePtr[index].moduleIrq == irqNum)
            {
                break; 
            }
            index += 1U;            
        }
        /*LDRA_NOANALYSIS*/
        if(index == modsize)
        {
            /*LDRA_EXCLUDE 105 D <justification start> index is used only in the if path, hence the violation is ignored <justification end> */
            index = DIAG_INVALID_MODULE_INDEX;
        }
        /*the ModuleInterruptModel structure should be updated only if the moduleIntrStatus is 
        MODULE_FREQ_TEST_PASSED or MODULE_FREQ_TEST_IN_PROGRESS. In case of failure, the 
        moduleIntrStatus will have the moduleInterruptCounter value which is outside the tolerance band*/
		else if(modulePtr[index].moduleIntrStatus != MODULE_FREQ_TEST_FAILED)
        {
            modulePtr[index].moduleInterruptCounter -= 1;
        }
        /*LDRA_ANALYSIS*/
    }
}

