/**
*   @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_crc_shared.c
 *  @version    1.0
 *  @brief      This file has the implementation for the CRC common 
 *		        functions. @see diag_crc_shared.h
 *
 *************************************************************************/


#include "diag_crc_shared.h"
#include "diag_crc.h"

/*Macros for TEST MODE SCENARIOS*/
#define DIAG_CRC_TEST_NORMAL                    0x91U
#define DIAG_CRC_TEST_DISABLE_MODULE            0x92U

static uint32_t testModeFunctional = DIAG_CRC_TEST_NORMAL;/*Normal Mode*/

/*
 ===============================================================================
  Static function to shift out the CRC results, is dependent on polynomial width
 ===============================================================================
 */
static void DIAG_CRC_Cleanup(uint16_t polyWidth)
{
	/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
	volatile uint32_t	*crcControlRegisterPtr;
	volatile uint32_t	*crcDataReg1;
	/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

	crcControlRegisterPtr = DIAG_CRC_CONTROL_REG;
	crcDataReg1 = DIAG_CRC_DATA;

	/* CRC calculation suspended */
	*crcControlRegisterPtr &= ~DIAG_CRC_GO_MASK;	/* disable CRCGO */
	_CRCIF = false; /* Interrupt flag disabled */

	/*
	 * Dummy data loaded onto data register to shift out the results depending on
	 * polynomial width
	 */
	if(polyWidth <= 8U)
	{
		*((uint8_t *) crcDataReg1) = 0U;
	}
	else if(polyWidth <= 16U)
	{
		/*LDRA_EXCLUDE 554 S <justification start> Variable points to known address, violation ignored <justification end> */
		*((uint16_t *) crcDataReg1) = 0U;
	}
	else
	{
		*crcDataReg1 = 0U;
	}

	/* Resume CRC calculation */
	*crcControlRegisterPtr |= DIAG_CRC_GO_MASK; /* Enable CRCGO */
}

/*
 =======================================================================================================================
    Function to compute and return the CRC results
 =======================================================================================================================
 */
uint32_t DIAG_CRC_Compute(uint8_t *data, uint32_t poly, uint16_t polyWidth)
{
	/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
	volatile uint32_t	resultCRC = 0x00000000U;
	volatile uint32_t	*crcControlRegisterPtr1;
	volatile uint32_t	*crcXorRegister1;
	volatile uint32_t	*crcDataRegister1;
	volatile uint32_t	*crcShiftRegister1;

    uint16_t			datalength = DIAG_CRC_DATALENGTH;
	uint8_t				loopCount = 0U;
    uint8_t             dataIndex = 0U;
	/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

	crcControlRegisterPtr1 = DIAG_CRC_CONTROL_REG;

	crcXorRegister1 = DIAG_CRC_POLYNOMIAL;

	crcDataRegister1 = DIAG_CRC_DATA;

	crcShiftRegister1 = DIAG_CRC_RESULT;

	*crcControlRegisterPtr1 = 0x00000000U;
	*crcControlRegisterPtr1 = (uint32_t)(DIAG_CRC_DATAWIDTH - 1U) << 24U;
	*crcControlRegisterPtr1 |= ((uint32_t)((uint32_t)polyWidth - (uint32_t)1U) << (uint32_t)16U);

	*crcControlRegisterPtr1 |= DIAG_CRC_EN_MASK;	/* Enable CRCEN */
    
    switch(testModeFunctional)
    {
        case DIAG_CRC_TEST_NORMAL:/*Normal Mode*/
                        *crcControlRegisterPtr1 |= DIAG_CRC_EN_MASK;	/* Enable CRCEN */
                        break;
        case DIAG_CRC_TEST_DISABLE_MODULE:/*Test Disable CRC Mode*/
                        *crcControlRegisterPtr1 &= ~((uint32_t)DIAG_CRC_EN_MASK);	/* Enable CRCEN */
                        break;                        
        default:// The control should not reach here.
                        break;
    }

    *crcXorRegister1 = 0x00000000U;
    *crcXorRegister1 = poly;

	*crcShiftRegister1 = 0x00000000U;

	*crcControlRegisterPtr1 |= DIAG_CRC_GO_MASK;	/* Enable CRCGO */

	while(dataIndex < datalength) /*Data moved to data register according to datalength, CRCFUL bit is not checked as data and datalength if fixed */
	{   
        /*LDRA_EXCLUDE 105 D <justification start> Variable does not need to be changed or accessed on all branches and so violation is ignored <justification end> */
		/*LDRA_EXCLUDE 151 D <justification start> Register accessed through pointer, so violation is ignored <justification end> */
		/*LDRA_EXCLUDE 436 S <justification start> Array elements accessed as indices, violation ignored <justification end> */
		*((uint8_t *) crcDataRegister1) = data[dataIndex];
        dataIndex++;
	}

	/*
	 * Call function to load dummy data and shift out the results before reading the
	 * results from the registers
	 */
	DIAG_CRC_Cleanup(polyWidth);

	/*
	 * For CRC 17 to 32 the registers have to be read in a loop to obtain the required
	 * result
	 */
	while(loopCount < (uint8_t)DIAG_CRC_RESULT_LOOP)
	{
        __builtin_repeat_nop((20U));
        
		resultCRC = *crcShiftRegister1;
		loopCount++;
	}

	return resultCRC;
}

void DIAG_CRC_SetTestModeFunctional(uint32_t setTestMode)
{
    testModeFunctional = setTestMode;
}
