/* * @Author : stark1898y 1658608470@qq.com * @Date : 2024-06-14 13:25:23 * @LastEditors : stark1898y 1658608470@qq.com * @LastEditTime : 2024-06-14 13:25:40 * @FilePath : \wuxi_alarm_ch32v303rct6_rtt\common\LwUtil\lwutil.h * @Description : * * Copyright (c) 2024 by yzy, All Rights Reserved. */ /** * \file lwutil.h * \brief Lightweight utility library */ /* * Copyright (c) 2024 Tilen MAJERLE * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * This file is part of LwUTIL - Lightweight utility library. * * Author: Tilen MAJERLE * Version: v1.3.0 */ #ifndef LWUTIL_HDR_H #define LWUTIL_HDR_H #include #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /** * \defgroup LWUTIL Lightweight utility * \brief Lightweight utility * \{ */ /** * \brief Get size of statically allocated array * Array must be declared in a form of `type var_name[element_count]` * * \param[in] x: Object to get array size of * \return Number of elements in array (`element_count`) */ #define LWUTIL_ARRAYSIZE(x) (sizeof(x) / sizeof((x)[0])) /** * \brief Get size of statically allocated array * Array must be declared in a form of `type var_name[element_count]` * * \note This is an alias of \ref LWUTIL_ARRAYSIZE * * \param[in] x: Object to get array size of * \return Number of elements in array (`element_count`) */ #define LWUTIL_ASZ(x) LWUTIL_ARRAYSIZE(x) /** * \brief Get larger value out of 2 different inputs * \param[in] x: First input * \param[in] y: Second input * \return Larger of both inputs */ #define LWUTIL_MAX(x, y) ((x) > (y) ? (x) : (y)) /** * \brief Get smaller value out of 2 different inputs * \param[in] x: First input * \param[in] y: Second input * \return Smaller of both inputs */ #define LWUTIL_MIN(x, y) ((x) < (y) ? (x) : (y)) /** * \brief Constrains an input number within a range * \param[in] x: Number to constrain * \param[in] a: Minimum allowed number * \param[in] b: Maximum allowed number * * \return `x` if `a < x < b` * \return `a` if `x <= a` * \return `b` if `x >= b` * * \note Function does not check if `a < b`. This must be handled by the user. * \note This is implemented as macro and return data type depends on the input number types. */ #define LWUTIL_CONSTRAIN(x, a, b) LWUTIL_MIN(LWUTIL_MAX((x), (a)), (b)) /** * \brief Maps the input number with the min and max range to the map of the output min and max range * * Mathematical calculation is: * * (x - in_min) * (out_max - out_min) * y = ------------------------------------ + out_min * (in_max - in_min) * * \note Data types depend on the user inputs. If high precision is required, * user can cast the input variables to appropriate type (double or float), * or use integer types if decimal precision is not required. * * \note Input data is not constrained between out min and out max values. * This may sometimes be useful for the application. * Use \ref LWUTIL_CONSTRAIN macro to constrain the value * * \param[in] x: Input value to map * \param[in] in_min: Minimum value to map from (input boundary) * \param[in] in_max: Maximum value to map from (input boundary) * \param[in] out_min: Minimum value to map to (output boundary) * \param[in] out_max: Maximum value to map to (output boundary) * \return Mapped value */ #define LWUTIL_MAP(x, in_min, in_max, out_min, out_max) \ (((x) - (in_min)) * ((out_max) - (out_min)) / ((in_max) - (in_min)) + (out_min)) /** * \brief Get absolute value of the input * Returns always-positive value of the input. * * \note Special care must be taken when input variable holds * minimum value available for given signed integer type (char, int, long, ...). * * Making absolute value of such input means longer output data type requirement. * * Consider writing result of this function to unsigned type of same integer width. * For example, minimum `signed char` value is `-128` while its absolute value (`128`) * requires variable type of either `unsigned char` or minimum signed 16-bit (or more). * * \param[in] x: Input value * \return Absolute value of the input value */ #define LWUTIL_ABS(x) ((x) < 0 ? -(x) : (x)) /** * \brief Unused variable to avoid compilation warning if declared but not used * \param[in] x: Input variable to declare unused */ #define LWUTIL_UNUSED(x) (void)(x) /** * \brief Dereference the pointer and assign the value to it, * but only if ptr is not NULL. * * \note It is fully up to user to handle to correct variable and data types * * \param[in] ptr: Pointer to check and assign to * \param[in] value: Value to assign */ #define LWUTIL_SET_VALUE_IF_PTR_NOT_NULL(ptr, value) \ do { \ if ((ptr) != NULL) { \ *(ptr) = (value); \ } \ } while (0) #define LWUTIL_CONCAT_BASE(x, y) x##y #define LWUTIL_CONCAT(s0, s1) LWUTIL_CONCAT_BASE(s0, s1) /** * \brief Compile time assert to validate specific expression. * Compilation will fail if expression evaluated to zero * \note Can only be used with the integer types * * \param[in] exp: Expression to test. It must be compile-time evaluation * \param[in] random_variable_name: Meaningful variable name to be used. * Can be whatever until it is valid variable name */ #define LWUTIL_COMPILE_TIME_ASSERT(exp, random_variable_name) \ typedef char LWUTIL_CONCAT2(random_variable_name, __LINE__)[!(exp) ? -1 : 1]; /** * \brief Check if all bits in the `bit_mask` are set in the input value * \note Can only be used with the integer types * * \param[in] val: Value to check for bits in * \param[in] bit_mask: Bit mask to check in value * \return `1` if all bits are set, `0` otherwise */ #define lwutil_bits_is_set_all(val, bit_mask) (((val) & (bit_mask)) == (bit_mask)) /** * \brief Check if any of the `bit_mask` bits is set in the input value * \note Can only be used with the integer types * * \param[in] val: Value to check for bits in * \param[in] bit_mask: Bit mask to check in value * \return `1` if any bit is set, `0` otherwise */ #define lwutil_bits_is_set_any(val, bit_mask) (((val) & (bit_mask)) != 0) /** * \brief Set bit mask in the input value * \note Can only be used with the integer types * * \param[in] val: Value to set bits in. * Original input is not modified. It is pass-by-value. * \param[in] bit_mask: Bit mask indicating which bits to set * \return New value with bitwise OR between input value and bit mask */ #define lwutil_bits_set(val, bit_mask) ((val) | (bit_mask)) /** * \brief Clear bit mask in the input value * \note Can only be used with the integer types * * \param[in] val: Value to clear bits in. * Original input is not modified. It is pass-by-value. * \param[in] bit_mask: Bit mask indicating which bits to clear * \return New value with bitwise AND and negated bit_mask between input value and bit mask * Value has bits cleared in the bit_mask set */ #define lwutil_bits_clear(val, bit_mask) ((val) & ~(bit_mask)) /** * \brief Toggle bit mask in the input value * \note Can only be used with the integer types * * \param[in] val: Value to toggle bits in. * Original input is not modified. It is pass-by-value. * \param[in] bit_mask: Bit mask indicating which bits to toggle * \return New value with bitwise AND and negated bit_mask between input value and bit mask * Value has bits cleared in the bit_mask set */ #define lwutil_bits_toggle(val, bit_mask) ((val) ^ (bit_mask)) /** * \brief Store `16-bit` value to bytes array in little-endian format * \param[in] val: Value to write to output array * \param[out] ptr: Minimum `2-bytes` long output array to write value to */ static inline void lwutil_st_u16_le(uint16_t val, void* ptr) { uint8_t* p = (uint8_t*)ptr; p[0] = (uint8_t)((val >> 0) & 0xFF); p[1] = (uint8_t)((val >> 8) & 0xFF); } /** * \brief Store `32-bit` value to bytes array in little-endian format * \param[in] val: Value to write to output array * \param[out] ptr: Minimum `4-bytes` long output array to write value to */ static inline void lwutil_st_u32_le(uint32_t val, void* ptr) { uint8_t* p = (uint8_t*)ptr; p[0] = (uint8_t)((val >> 0) & 0xFF); p[1] = (uint8_t)((val >> 8) & 0xFF); p[2] = (uint8_t)((val >> 16) & 0xFF); p[3] = (uint8_t)((val >> 24) & 0xFF); } /** * \brief Load `16-bit` value from bytes array in little-endian format * \param[in] ptr: Minimum `2-bytes` long input array to extract bytes from * \return `16-bit` value extracted from input array */ static inline uint16_t lwutil_ld_u16_le(const void* ptr) { const uint8_t* p = (const uint8_t*)ptr; return p[1] << 8 | p[0]; } /** * \brief Load `32-bit` value from bytes array in little-endian format * \param[in] ptr: Minimum `2-bytes` long input array to extract bytes from * \return `32-bit` value extracted from input array */ static inline uint32_t lwutil_ld_u32_le(const void* ptr) { const uint8_t* p = (const uint8_t*)ptr; return p[3] << 24 | p[2] << 16 | p[1] << 8 | p[0]; } /** * \brief Store `16-bit` value to bytes array in big-endian format * \param[in] val: Value to write to output array * \param[out] ptr: Minimum `2-bytes` long output array to write value to */ static inline void lwutil_st_u16_be(uint16_t val, void* ptr) { uint8_t* p = (uint8_t*)ptr; p[0] = (uint8_t)((val >> 8) & 0xFF); p[1] = (uint8_t)((val >> 0) & 0xFF); } /** * \brief Store `32-bit` value to bytes array in big-endian format * \param[in] val: Value to write to output array * \param[out] ptr: Minimum `4-bytes` long output array to write value to */ static inline void lwutil_st_u32_be(uint32_t val, void* ptr) { uint8_t* p = (uint8_t*)ptr; p[0] = (uint8_t)((val >> 24) & 0xFF); p[1] = (uint8_t)((val >> 16) & 0xFF); p[2] = (uint8_t)((val >> 8) & 0xFF); p[3] = (uint8_t)((val >> 0) & 0xFF); } /** * \brief Load `16-bit` value from bytes array in big-endian format * \param[in] ptr: Minimum `2-bytes` long input array to extract bytes from * \return `16-bit` value extracted from input array */ static inline uint16_t lwutil_ld_u16_be(const void* ptr) { const uint8_t* p = (const uint8_t*)ptr; return p[0] << 8 | p[1]; } /** * \brief Load `32-bit` value from bytes array in big-endian format * \param[in] ptr: Minimum `4-bytes` long input array to extract bytes from * \return `32-bit` value extracted from input array */ static inline uint32_t lwutil_ld_u32_be(const void* ptr) { const uint8_t* p = (const uint8_t*)ptr; return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; } void lwutil_u8_to_2asciis(uint8_t hex, char* ascii); void lwutil_u16_to_4asciis(uint16_t hex, char* ascii); void lwutil_u32_to_8asciis(uint32_t hex, char* ascii); uint8_t lwutil_ld_u32_varint(const void* ptr, size_t ptr_len, uint32_t* val_out); uint8_t lwutil_st_u32_varint(uint32_t val, void* ptr, size_t ptr_len); /** * \} */ #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* LWUTIL_HDR_H */