/**
 * @file
 * @copyright    InSolem SARL reserves all rights even in the event of industrial
 *               property rights. We reserve all rights of disposal such as
 *               copying and passing on to third parties.
 *
 * @version      $Revision: #1 $
 * @change       $Change: 17569 $
 * @date         $Date: 2022/06/08 $
 * @authors      $Author: qbourdon $
 *
 * @brief        Utility functions for Insolem's projects.
 */

#ifndef INCLUDED_INS_UTILS_H
#define INCLUDED_INS_UTILS_H
/******************************************************************************
 * Include-Files
 ******************************************************************************/
#include "nms_types.h"

/******************************************************************************
 * Constants and Macros
 ******************************************************************************/
#define NMS_MIN(a,b) ((a >= b) ? b : a)
#define NMS_MAX(a,b) ((a >= b) ? a : b)

/******************************************************************************
 * Type Declarations
 ******************************************************************************/

/******************************************************************************
 * Global Variable Declarations
 ******************************************************************************/

/******************************************************************************
 * Function Declarations
 ******************************************************************************/
/**
 * @brief    This function sets data bytes to memory block.
 *
 * @param[out]    dest_pv    Pointer to the block of memory to fill.
 * @param         val_u8     Byte to be set for initialization.
 * @param         len_u32    Length (in bytes !).
 *
 * @note    This function fulfills the same task as the library function
 *          memset(). This function should be used because at some libraries and
 *          compilers the behavior is partly unpredictable.
 */
void NmsMemSet(void * dest_pv, uint8 val_u8, uint32 len_u32);


/**
 * @brief    This function copies data bytes from memory block to another.
 *
 * @param[out]    dest_pv    Pointer to the block of memory to fill.
 * @param[in]     src_pv     Pointer to the source of data to be copied.
 * @param         len_u32    Length (in bytes !).
 *
 * @note    This function fulfills the same task as the library function
 *          memcpy(). This function should be used because at some libraries and
 *          compilers the behavior is partly unpredictable.
 */
void NmsMemCpy(void * dest_pv, const void * src_pv, uint32 len_u32);


/**
 * @brief     This function compares data bytes from memory blocks.
 *
 * @param[in]    src1_pv    Pointer to first memory block to compare.
 * @param[in]    src2_pv    Pointer to second memory block to compare.
 * @param        len_u32    Length (in bytes !).
 *
 * @return    True if the buffers are identical. False if not.
 *
 * @note    This function fulfills the same task as the library function
 *          memcmp(). This function should be used because at some libraries and
 *          compilers the behavior is partly unpredictable.
 */
bool NmsMemCmp(const void * src1_pv, const void * src2_pv, uint32 len_u32);


/**
 * @brief    This function reverses data bytes from memory block to another.
 *
 * @param[out]    dest_pv    Pointer to the block of memory to fill.
 * @param[in]     src_pv     Pointer to the source of data to be reversed.
 * @param         len_u32    Length in bytes .
 */
void NmsMemRvs(void * dest_pv, const void * src_pv, uint32 len_u32);


/**
 * @brief       This function returns the bit at the position "pos_u8" from the
 *              value "value_u64".
 *
 * @param       value_u64   Value where bits are stored.
 * @param       pos_u8      Position of the bit to return (0 to 63 --> first bit = index 0).
 *
 * @return      True: bit set (1), False: bit reset (0).
 *
 * @note        uint64 is used to make this function work with all integer types
 *              (from uint8 to uint64). A void* could have been used but that
 *              requires to transmit the variable type as argument.
 *
 * @note        If called to read a bit out of range (e.g. 10th bit of an uint8,
 *              or 65th bit of an uint64), the function will return "false".
 */
bool NmsMemGetBit(uint64 value_u64, uint8 pos_u8);


/**
 * @brief       This function sets or resets the bit at the position "pos_u8" in
 *              the value "value_u64".
 *
 * @param       value_u64      Value where bits are stored.
 * @param       bit_b          Value of the bit to set. 1 or 0.
 * @param       pos_u8         Position of the bit to write (0 to 63 --> first bit = index 0).
 *
 * @return      Updated value.
 *
 * @note        uint64 is used to make this function work with all integer types
 *              (from uint8 to uint64). A void* could have been used but that
 *              requires to transmit the variable type as argument.
 *
 * @note        If called to set or reset a bit out of range (e.g. 10th bit of an uint8,
 *              or 65th bit of an uint64), the function will return a copy of value_u64.
 */
uint64 NmsMemSetBit(uint64 value_u64, bool bit_b, uint8 pos_u8);


/**
 * @brief       Helper function to convert an array of bytes to a unsigned int value.
 *              Byte at index in the array [0] is the most significant byte (big-endian).
 *              This function is independant from the target's memory endianness.
 *
 * @param       bytes_tu8   Array of bytes.
 * @param       nb_u8       Nb of bytes to consider or length of the array, max 8 bytes.
 *
 * @return      The unsigned integer represented by the bytes array.
 */
uint64 NmsBytesToUint(const uint8 bytes_tu8[], uint8 nb_u8);


 /**
 * @brief       Helper function to convert an integer value into an array of bytes representing it.
 *              Byte at index [0] in the array is the most significant byte (big-endian).
 *              This function is independant from the target's memory endianness.
 *
 * @param       value_u64   Integer value for which to get the byte representation.
 * @param       bytes_tu8   Array of bytes, must be long enougth to store the number of bytes specified.
 * @param       nb_u8       Nb of bytes in the number, max 8 bytes.
 */
void NmsUintToBytes(uint64 value_u64, uint8 bytes_tu8[], uint8 nb_u8);


/**
 * @brief     This function converts integer to ascii string.
 *
 * @param     num_i64    Number to be converted to a string.
 *            str_tc     Array in memory where to store the resulting
 *                       null-terminated string. Pointer full of null-terminated
 *                       string in case of overflow.
 *            base_u8    Numerical base used to represent the value as a string,
 *                       between 2 and 36, where 10 means decimal base,
 *                       16 hexadecimal, 8 octal, and 2 binary.
 *            len_u32    Size of the destination string to prevent overflow.
 *
 * @return    Size of the final converted string, including the null-terminated
 *            string, limited by the length. Value is 0 in case of overflow.
 *
 * @note      itoa() is a non-standard function. Negative value are only handled
 *            for base 10.
 */
uint32 NmsItoa(sint64 num_i64, char str_tc[], uint8 base_u8, uint32 len_u32);

#endif /* INCLUDED_INS_UTILS_H */
