/**
*   @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_clock_fscmtest.c
 *  @version    1.0
 *  @brief      This file has the implementation for the Fail Safe Clock Monitor
 *              diagnostics
 *              
 *************************************************************************/

#include "diag_clock.h"

#define CLKMON_SFR_ADDRESS_SPACE 10U

typedef volatile uint32_t (*clkMonRegAddr_t)[CLKMON_SFR_ADDRESS_SPACE];

#define CLOCKMON1_BASE_ADDRESS  (uint32_t)0x3200
#define CLOCKMON2_BASE_ADDRESS  (uint32_t)0x3230 
#define CLOCKMON3_BASE_ADDRESS  (uint32_t)0x3260
#define CLOCKMON4_BASE_ADDRESS  (uint32_t)0x3290

#define CLOCKMON_FAILSAFE_VALUE 0xFF4240U

#define CLK_MON_CONTROL_REG_INDEX 0U
#define CLK_MON_STATUS_REG_INDEX 1U
#define CLK_MON_WIN_PRESCALER_REG_INDEX 2U
#define CLK_MON_INPUT_SEL_REG_INDEX 3U
#define CLK_MON_BUF_REG_INDEX 4U
#define CLK_MON_BUF_SAT_REG_INDEX 5U
#define CLK_MON_HTF_REG_INDEX 6U
#define CLK_MON_LTF_REG_INDEX 7U
#define CLK_MON_HTW_REG_INDEX 8U
#define CLK_MON_LTW_REG_INDEX 9U

#define CLK_MON_CONTROL_REG_ON_BIT      0x00008000U
#define CLK_MON_STATUS_REG_BUFV_VALID   0x00000001U

static uint32_t clockMonitorInstAddrMap[DIAG_CLOCK_MONITOR_MAX_INSTANCE] = {CLOCKMON1_BASE_ADDRESS,
                                                                CLOCKMON2_BASE_ADDRESS,
                                                                CLOCKMON3_BASE_ADDRESS,
                                                                CLOCKMON4_BASE_ADDRESS};

static volatile uint32_t clockFaultInjectStatus;

void DIAG_CLOCK_SetClockMonFaultStatus(uint32_t status)
{
    clockFaultInjectStatus = status;
}

uint32_t DIAG_CLOCK_FscmTest(DIAG_CLOCK_MON_INST clkMonInstance,
                            DIAG_CLOCK_MON_REF_CLK monClkSrc, 
                            DIAG_CLOCK_MON_REF_CLK refClkSrc,
                            DIAG_CLOCK_FLTINJ_TYPE fltinjType)
{
    uint32_t status = 0;
    uint32_t timeOut;
	/* LDRA_EXCLUDE 606 S <justification start>Wrong Violation reported by the tool. Violation Ignored.<justification end> */
    /* LDRA_EXCLUDE 440 S <justification start>Wrong violation reported by the tool. Violation Ignored.<justification end> */
	clkMonRegAddr_t clkMonRegArrPtr = (clkMonRegAddr_t)clockMonitorInstAddrMap[clkMonInstance];
    DIAG_CLOCK_SetClockMonFaultStatus(DIAG_CLOCKMON_FAULT_UNDETECTED);
    (*clkMonRegArrPtr)[CLK_MON_CONTROL_REG_INDEX] &= ~CLK_MON_CONTROL_REG_ON_BIT;
    (*clkMonRegArrPtr)[CLK_MON_INPUT_SEL_REG_INDEX] |= ((uint32_t)monClkSrc << 4U);
    (*clkMonRegArrPtr)[CLK_MON_INPUT_SEL_REG_INDEX] |= ((uint32_t)refClkSrc);
    //Now switch ON clock monitor
    (*clkMonRegArrPtr)[CLK_MON_CONTROL_REG_INDEX] |= CLK_MON_CONTROL_REG_ON_BIT;
    //Now wait till a valid Buffer value is available
	/*LDRA_EXCLUDE 105 D <justification start> The timeout value is restored for the next loop. Violation ignored<justification end>*/
    /*LDRA_EXCLUDE 151 D <justification start> The timeout value is restored for the next loop. Violation ignored<justification end>*/
	timeOut = CLOCKMON_FAILSAFE_VALUE;
    while((((*clkMonRegArrPtr)[CLK_MON_STATUS_REG_INDEX] & CLK_MON_STATUS_REG_BUFV_VALID) == 0U)&&(timeOut != 0U))
	{
		/*LDRA_EXCLUDE 151 D <justification start> The timeout value is restored for the next loop. Violation ignored<justification end>*/
		timeOut -= 1U;
	}
    //Now introduce the fault 
	/*LDRA_EXCLUDE 151 D <justification start> The timeout value is restored for the next loop. Violation ignored<justification end>*/
	timeOut = CLOCKMON_FAILSAFE_VALUE;	
    (*clkMonRegArrPtr)[CLK_MON_CONTROL_REG_INDEX] |= (uint32_t)fltinjType; 
    /*This entire block is testing of fault injection. So the condition which has
     to be satisfied is failure to introduce fault injection, which is completely
     dependent on hardware. Hence this whole block is under no analysis annotation*/
    /*LDRA_NOANALYSIS*/
    while((clockFaultInjectStatus == DIAG_CLOCKMON_FAULT_UNDETECTED)&&(timeOut != 0U))
    {
		/*LDRA_EXCLUDE 151 D <justification start> The timeout value is restored for the next loop. Violation ignored<justification end>*/
		timeOut -= 1U;
    }
    if(clockFaultInjectStatus == DIAG_CLOCKMON_FAULT_DETECTED)
    {
        status = DIAG_PASS;
    }
    else
    {
        status = DIAG_FAIL;
    }
    /*LDRA_ANALYSIS*/
    return(status);
} 
