/*
 * Copyright (c) 2013, Linz Center of Mechatronics GmbH (LCM), web: www.lcm.at
 * All rights reserved.
 */
/*
 * This file is licensed according to the BSD 3-clause license as follows:
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the "Linz Center of Mechatronics GmbH" and "LCM" nor
 *       the names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL "Linz Center of Mechatronics GmbH" BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
/*
 * This file is part of X2C. web: x2c.lcm.at
 * $LastChangedRevision: 4184 $
 * $LastChangedDate:: 2026-04-09 13:05:27 +0200#$
 */
#include <stddef.h>
#include "CommonFcts.h"

/**
 * Empty Block Update function for blocks that do not have an Update function.
 * @param block Block (not used)
 */
/* RULECHECKER_comment(1:0, 1:0, check_parameter_missing_const, "see X2C MISRA Deviations, DEV0008", true_no_defect) */
void Common_Update(void* block)
{
    (void)block;
}

/**
 * Empty Block Load function for blocks that do not have a Load function.
 * The data length is always set to 0 and the function always returns no error.
 * @param[in] block Block (not used)
 * @param[out] data Load data (not used)
 * @param[out] dataLength Load data size (not used)
 * @param[in] maxSize Maximum load data size (not used)
 * @returns Always 0
 */
/* RULECHECKER_comment(1:0, 1:0, check_parameter_missing_const, "see X2C MISRA Deviations, DEV0008", true_no_defect) */
uint8 Common_Load(const void* block, uint8 data[], uint16* dataLength, uint16 maxSize)
{
    (void)block;
    (void)data;
    (void)maxSize;

    *dataLength = 0u;
    return (0u);
}

/**
 * Empty Block Save function for blocks that do not have a Save function.
 * If the data length provided is greater than 0, the function returns an error otherwise no error.
 * @param[out] block Block (not used)
 * @param[in] data Save data (not used)
 * @param[in] dataLength Save data size
 * @retval 0 if provided data size is zero
 * @retval 1 if proveded data size is greater than zero
 */
/* RULECHECKER_comment(1:0, 1:0, check_parameter_missing_const, "see X2C MISRA Deviations, DEV0008", true_no_defect) */
uint8 Common_Save(void* block, const uint8 data[], uint16 dataLength)
{
    uint8 retVal;
    (void)block;
    (void)data;

    if (dataLength > 0u)
    {
        retVal = 1u;
    }
    else
    {
        retVal = 0u;
    }
    return (retVal);
}

/**
 * Empty CoT Save Mask Parameter function for blocks that do not have a CoT Save Mask Parameter function.
 * This function is currently not used by any block.
 * @param block Block (not used)
 * @param maskParam Mask Parameters (not used)
 * @param data Mask Parameter save data (not used)
 * @param dataLength Mask parameter save data size (not used)
 * @returns Always 0
 */
/* RULECHECKER_comment(1:0, 1:0, check_parameter_missing_const, "see X2C MISRA Deviations, DEV0008", true_no_defect) */
uint8 Common_SaveMP(void* block, void* maskParam, const uint8 data[], uint16 dataLength)
{
    (void)block;
    (void)maskParam;
    (void)data;
    (void)dataLength;

    return (0u);
}

/**
 * Empty CoT Load Mask Parameter function for blocks that do not have a CoT Load Mask Parameter function.
 * The data length is always set to 0 and the function always returns no error.
 * This function is currently not used by any block.
 * @param block Block (not used)
 * @param data Mask Parameter load data (not used)
 * @param dataLength Mask Parameter load data size (not used)
 * @param maxSize Maximum Mask Parameter load data size (not used)
 * @returns Always 0
 */
/* RULECHECKER_comment(1:0, 1:0, check_parameter_missing_const, "see X2C MISRA Deviations, DEV0008", true_no_defect) */
uint8 Common_LoadMP(const void* block, uint8 data[], uint16* dataLength, uint16 maxSize)
{
    (void)block;
    (void)data;
    (void)maxSize;

    *dataLength = 0u;
    return (0u);
}

/**
 * Empty CoT Convert Mask Parameter function for blocks that do not have a CoT Convert Mask Parameter function.
 * This function is currently not used by any block.
 * @param block Block (not used)
 * @param maskParam Mask Parameters (not used)
 * @returns Always 0
 */
/* RULECHECKER_comment(1:0, 1:0, check_parameter_missing_const, "see X2C MISRA Deviations, DEV0008", true_no_defect) */
uint8 Common_ConvertMP(void* block, void* maskParam)
{
    (void)block;
    (void)maskParam;

    return (0u);
}

/**
 * Empty CoT Backup Mask Parameter function for blocks that do not have a CoT Backup Mask Parameter function.
 * This function is currently not used by any block.
 * @param maskParam Mask Parameters (not used)
 */
/* RULECHECKER_comment(1:0, 1:0, check_parameter_missing_const, "see X2C MISRA Deviations, DEV0008", true_no_defect) */
void Common_BackupMP(void* maskParam)
{
    (void)maskParam;
}

/**
 * Empty CoT Restore Mask Parameter function for blocks that do not have a CoT Restore Mask Parameters function.
 * This function is currently not used by any block.
 * @param maskParam Mask Parameters (not used)
 */
/* RULECHECKER_comment(1:0, 1:0, check_parameter_missing_const, "see X2C MISRA Deviations, DEV0008", true_no_defect) */
void Common_RestoreMP(void* maskParam)
{
    (void)maskParam;
}

/**
 * @brief Returns IO-Block-Parameter identifier table index for a given Parameter identifier.
 *
 * @param[in] ioParamTbl IO-Block-Parameter identifier table
 * @param[in] paramId Parameter identifier
 * @param[out] index Index
 *
 * @return Error code
 */
uint8 getIoParamIndex(const tIoParamIdEntry ioParamTbl[], uint16 paramId, uint16* index)
{
	uint16 i;
	uint8 error;

	if (ioParamTbl == NULL)
	{
		*index = 0;
		error = ERROR_TABLE_NOT_INIT;
	}
	else
	{
		i = 0;
		while ((paramId != ioParamTbl[i].id) && (ioParamTbl[i].id != 0u))
		{
			i++;
		}
		if (ioParamTbl[i].id == 0u)
		{
			*index = 0;
			error = ERROR_INVALID_ID;
		}
		else
		{
			*index = i;
			error = ERROR_SUCCESS;
		}
	}
	return (error);
}

/**
 * @brief Returns Block-Parameter identifier table index for a given Parameter identifier.
 *
 * @param[in] paramTable Block-Parameter identifier table
 * @param[in] paramId Parameter Identifier
 * @param[out] index Index
 *
 * @return Error code
 */
uint8 getBlockParamIndex(const tParameterTable* paramTable, uint16 paramId, uint16* index)
{
	uint16 i;
	uint8 error;

	/* send parameter ID error if no parameter table has been initialized */
	if (paramTable == NULL)
	{
		*index = 0;
		error = ERROR_TABLE_NOT_INIT;
	}
	else
	{
		i = 0;
		while((paramId != paramTable[i].uiParID) && (paramTable[i].uiParID != 0u))
		{
			i++;
		}
		/* check if parameter is located in parameter table */
		if (paramTable[i].uiParID == 0u)
		{
			*index = 0;
			error = ERROR_INVALID_ID;
		}
		else
		{
			*index = i;
			error = ERROR_SUCCESS;
		}
	}
	return (error);
}

/**
 * @brief Returns Mask Parameter identifier table index for a given Parameter identifier.
 *
 * @param[in] mpTable Mask Parameter identifier table
 * @param[in] paramId Parameter Identifier
 * @param[out] index Index
 *
 * @return Error code
 */
uint8 getMaskParamIndex(const tMaskParameterEntry* mpTable, uint16 paramId, uint16* index)
{
	uint16 i;
	uint8 error;

	/* send parameter ID error if no parameter table has been initialized */
	if (mpTable == NULL)
	{
		*index = 0;
		error = ERROR_TABLE_NOT_INIT;
	}
	else
	{
		i = 0;
		while((paramId != mpTable[i].id) && (mpTable[i].id != 0u))
		{
			i++;
		}
		/* check if parameter is located in parameter table */
		if (mpTable[i].id == 0u)
		{
			*index = 0;
			error = ERROR_INVALID_ID;
		}
		else
		{
			*index = i;
			error = ERROR_SUCCESS;
		}
	}
	return (error);
}

uint8 getMaskParamExtIndex(const tMaskParamExtRecord* mpTable, uint16 paramId, uint16* index)
{
    uint16 i;
    uint8 error;

    /* send parameter ID error if no parameter table has been initialized */
    if (mpTable == NULL)
    {
        *index = 0;
        error = ERROR_TABLE_NOT_INIT;
    }
    else
    {
        i = 0;
        while((paramId != mpTable[i].id) && (mpTable[i].id != 0u))
        {
            i++;
        }
        /* check if parameter is located in parameter table */
        if (mpTable[i].id == 0u)
        {
            *index = 0;
            error = ERROR_INVALID_ID;
        }
        else
        {
            *index = i;
            error = ERROR_SUCCESS;
        }
    }
    return (error);
}

/**
 * @brief Returns Block function table index for a given Block identifier.
 *
 * @param[in] fncTable Block function table
 * @param[in] blockId Block identifier
 * @param[out] index Index
 *
 * @return Error code
 */
uint8 getBlockFunctionIndex(const tBlockFunctions* fncTable, uint16 blockId, uint16* index)
{
	uint16 i;
	uint8 error;

	if (fncTable == NULL)
	{
		*index = 0;
		error = ERROR_TABLE_NOT_INIT;
	}
	else
	{
		i = 0;
		while ((blockId != fncTable[i].iBlockID) && (fncTable[i].iBlockID != 0u))
		{
			i++;
		}

		if (fncTable[i].iBlockID == 0u)
		{
			*index = 0;
			error = ERROR_INVALID_ID;
		}
		else
		{
			*index = i;
			error = ERROR_SUCCESS;
		}
	}
	return (error);
}

uint8 getMaskParamDataTableIndex(const tMaskParamDataRecord* mpTable, uint16 blockParamId, uint8 maskParamId, uint16* index)
{
    uint8 error;

    /* Return error if table is not initialized */
    if (mpTable == NULL)
    {
        error = 1u;
    }
    /* Block Parameter ID and Mask Parameter ID must not be zero */
    else if ((blockParamId == 0u) || (maskParamId == 0u))
    {
        error = 1u;
    }
    else
    {
        uint16 i = 0u;
        uint8 found = 0u;

        error = 2u; /* No element found (will be updated if element found) */
        while ((mpTable[i].blockParamId != 0u) && (found == 0u))
        {
            if ((mpTable[i].blockParamId == blockParamId) && (mpTable[i].maskParamId == maskParamId))
            {
                *index = i;
                found = 1u;
                error = 0u; /* Element found */
            }
            else
            {
                i++;
            }
        }
    }

    return (error);
}

/**
 * @brief Returns Q-format for given decimal value.
 *
 * @param   decValue Decimal value (-2147483647.0 ... +2147483647.0)
 * @param   maxBits Maximum bit width (8 ... 32)
 *
 * @return  Q-Format (0 ... 31)
 */
uint8 getQFormat(float_CoT decValue, uint8 maxBits)
{
    uint8 qFormat, maxBitsLim;
    uint32 maxValue;
    float_CoT realValue, decValueLim;

    /* check and limit input arguments if necessary */
    if (maxBits > 32u)
    {
        maxBitsLim = 32;
    }
    else if (maxBits < 8u)
    {
        maxBitsLim = 8;
    }
    else
    {
        maxBitsLim = maxBits;
    }

    if (decValue > (float_CoT)INT32_MAX)
    {
        decValueLim = (float_CoT)INT32_MAX;
    }
    else if (decValue < (float_CoT)-INT32_MAX)
    {
        decValueLim = (float_CoT)-INT32_MAX;
    }
    else
    {
        decValueLim = decValue;
    }

    /* take absolute value of decValue to simplify calculation */
    if (decValueLim < (float_CoT)0)
    {
        decValueLim = -decValueLim;
    }

    /* calculate qFormat */
    /* Note: float64 has to be used rather than float_CoT, because float32 causes losses in accuracy for FiP32 CoT implementations, which lets CUnit tests fail */
    qFormat = maxBitsLim;
    maxValue = (((uint32)1) << (maxBitsLim - 1u)) - 1u;
    do {
        float64 qFormatMultiplier;

        qFormat--;
        qFormatMultiplier = (float64)(uint32)((uint32)1 << qFormat);
        realValue = (float_CoT)((float64)decValueLim * qFormatMultiplier);
    } while ((qFormat > 0u) && (realValue >= (float_CoT)maxValue));

    return (qFormat);
}


/**
 * @brief Returns integer value in Qx.8-format for given decimal value.
 *
 * @param   decValue Decimal value (-1.0 ... +1.0)
 * @param   qFormat Q-format (0 ... 7)
 *
 * @return  Q-format integer value (-127 ... +127)
 */
int8 getQx8Value(float_CoT decValue, uint8 qFormat)
{
    int16 intValue;
    float_CoT qFormatMultiplier, floatValue;

    qFormatMultiplier = (float_CoT)(uint8)((uint8)1 << qFormat);  /* 2 ^ Q-format */
    floatValue = decValue * qFormatMultiplier;                      /* Decimal value * 2 ^ Q-format */
    intValue = (int16)floatValue;
    /* Data width limitation Previous: LIMIT(intValue, INT8_MAX); */
    if (intValue > INT8_MAX)
    {
        intValue = INT8_MAX;
    }
    else if (intValue < -INT8_MAX)
    {
        intValue = -INT8_MAX;
    }
    else
    {
        /* Value within limits, no limitation required */
    }

    return (int8)intValue;
}

/**
 * @brief Returns integer value in Qx.16-format for given decimal value.
 *
 * @param   decValue Decimal value (-1.0 ... +1.0)
 * @param   qFormat Q-format (0 ... 15)
 *
 * @return  Q-format integer value (-32767 ... +32767)
 */
int16 getQx16Value(float_CoT decValue, uint8 qFormat)
{
    int32 intValue;
    float_CoT qFormatMultiplier, floatValue;

    qFormatMultiplier = (float_CoT)(uint16)((uint16)1 << qFormat);  /* 2 ^ Q-format */
    floatValue = decValue * qFormatMultiplier;                      /* Decimal value * 2 ^ Q-format */
    intValue = (int32)floatValue;
    /* Data width limitation Previous: LIMIT(intValue, INT16_MAX); */
    if (intValue > INT16_MAX)
    {
        intValue = INT16_MAX;
    }
    else if (intValue < -INT16_MAX)
    {
        intValue = -INT16_MAX;
    }
    else
    {
        /* Value within limits, no limitation required */
    }

    return (int16)intValue;
}

/**
 * @brief Returns integer value in Qx.32-format for given decimal value.
 *
 * @param   decValue Decimal value (-1.0 ... +1.0)
 * @param   qFormat Q-format (0 ... 31)
 *
 * @return  Q-format integer value (-2147483647 ... +2147483647)
 */
int32 getQx32Value(float_CoT decValue, uint8 qFormat)
{
    int64 intValue;
    float_CoT qFormatMultiplier, floatValue;

    qFormatMultiplier = (float_CoT)(uint32)((uint32)1 << qFormat);  /* 2 ^ Q-format */
    floatValue = decValue * qFormatMultiplier;                      /* Decimal value * 2 ^ Q-format */
    intValue = (int64)floatValue;
    /* Data width limitation Previous: LIMIT(intValue, INT32_MAX); */
    if (intValue > INT32_MAX)
    {
        intValue = INT32_MAX;
    }
    else if (intValue < -INT32_MAX)
    {
        intValue = -INT32_MAX;
    }
    else
    {
        /* Value within limits, no limitation required */
    }

    return (int32)intValue;
}

/**
 * @brief Returns asymmetric integer value (for angular signals) in Qx.8-format for given decimal value.
 *
 * @param   decValue Decimal value (-1.0 ... +1.0)
 * @param   qFormat Q-format (0 ... 7)
 *
 * @return  Q-format integer value (-128 ... +127)
 */
int8 getAQx8Value(float_CoT decValue, uint8 qFormat)
{
    int16 intValue;
    float_CoT qFormatMultiplier, floatValue;

    qFormatMultiplier = (float_CoT)(uint8)((uint8)1 << qFormat);  /* 2 ^ Q-format */
    floatValue = decValue * qFormatMultiplier;                      /* Decimal value * 2 ^ Q-format */
    intValue = (int16)floatValue;
    if (intValue > INT8_MAX)
    {
        intValue = INT8_MAX;
    }
    else if (intValue < INT8_MIN)
    {
        intValue = INT8_MIN;
    }
    else
    {
        /* Value within limits, no limitation required */
    }

    return (int8)intValue;
}

/**
 * @brief Returns asymmetric integer value (for angular signals) in Qx.16-format for given decimal value.
 *
 * @param   decValue Decimal value (-1.0 ... +1.0)
 * @param   qFormat Q-format (0 ... 15)
 *
 * @return  Q-format integer value (-32768 ... +32767)
 */
int16 getAQx16Value(float_CoT decValue, uint8 qFormat)
{
    int32 intValue;
    float_CoT qFormatMultiplier, floatValue;

    qFormatMultiplier = (float_CoT)(uint16)((uint16)1 << qFormat);  /* 2 ^ Q-format */
    floatValue = decValue * qFormatMultiplier;                      /* Decimal value * 2 ^ Q-format */
    intValue = (int32)floatValue;
    if (intValue > INT16_MAX)
    {
        intValue = INT16_MAX;
    }
    else if (intValue < INT16_MIN)
    {
        intValue = INT16_MIN;
    }
    else
    {
        /* Value within limits, no limitation required */
    }

    return (int16)intValue;
}

/**
 * @brief Returns asymmetric integer value (for angular signals) in Qx.32-format for given decimal value.
 *
 * @param   decValue Decimal value (-1.0 ... +1.0)
 * @param   qFormat Q-format (0 ... 31)
 *
 * @return  Q-format integer value (-2147483648 ... +2147483647)
 */
int32 getAQx32Value(float_CoT decValue, uint8 qFormat)
{
    int64 intValue;
    float_CoT qFormatMultiplier, floatValue;

    qFormatMultiplier = (float_CoT)(uint32)((uint32)1 << qFormat);  /* 2 ^ Q-format */
    floatValue = decValue * qFormatMultiplier;                      /* Decimal value * 2 ^ Q-format */
    intValue = (int64)floatValue;
    if (intValue > INT32_MAX)
    {
        intValue = INT32_MAX;
    }
    else if (intValue < INT32_MIN)
    {
        intValue = INT32_MIN;
    }
    else
    {
        /* Value within limits, no limitation required */
    }

    return (int32)intValue;
}
