From dbb35e8c0116e232aac1f3c83be1ddaa772ec2de Mon Sep 17 00:00:00 2001 From: Dorijan Di Zepp Date: Wed, 29 Oct 2025 10:24:38 +0100 Subject: [PATCH 1/8] feat: add common functions #1 --- include/common-api.h | 92 ++++++++++++++++++++++++++++++++++++++++++++ include/common.h | 29 ++++++++++++++ library.json | 21 ++++++---- src/common-api.c | 50 ++++++++++++++++++++++++ 4 files changed, 184 insertions(+), 8 deletions(-) create mode 100644 include/common-api.h create mode 100644 include/common.h create mode 100644 src/common-api.c diff --git a/include/common-api.h b/include/common-api.h new file mode 100644 index 0000000..3dff3ba --- /dev/null +++ b/include/common-api.h @@ -0,0 +1,92 @@ +/*! + * \file common-api.h + * \date 2025-10-27 + * \authors Dorijan Di Zepp [dorijan.dizepp@eagletrt.it] + * + * \brief A simple library providing a set of common utilities for all embedded projects. + * + * \details This library provides a set of functions that are often needed in most embedded proejects. + * This helps in reducing developing time and maintain consistency across multiple projects. + */ + +#ifndef COMMON_API_H +#define COMMON_API_H + +#include +#include "common.h" + +/*! + * \brief Return the smaller of two values. + * + * \param[in] a: First value to compare. + * \param[in] b: Second value to compare. + * \return The smaller of the two input values. + */ +#define common_api_min(a, b) MIN(a, b) + +/*! + * \brief Return the larger of two values. + * + * \param[in] a: First value to compare. + * \param[in] b: Second value to compare. + * \return The larger of the two input values. + */ +#define common_api_max(a, b) MAX(a, b) + +/*! + * \brief Clamp a value between a lower and upper limit. + * + * \param[in] x: Value to clamp. + * \param[in] low: Minimum allowable value. + * \param[in] high: Maximum allowable value. + * \return The clamped value, within the [low, high] range. + */ +#define common_api_clamp(x, low, high) CLAMP(x, low, high) + +/*! + * \brief Map a value from one range to another. + * + * \param[in] x: Input value. + * \param[in] in_min: Lower bound of input range. + * \param[in] in_max: Upper bound of input range. + * \param[in] out_min: Lower bound of output range. + * \param[in] out_max: Upper bound of output range. + * \return Mapped value corresponding to x in the output range. + */ +float common_api_mapf(float x, float in_min, float in_max, float out_min, float out_max); + +/*! + * \brief Normalize a value within a given range to [0, 1]. + * + * \param[in] x: Input value. + * \param[in] in_min: Lower bound of the input range. + * \param[in] in_max: Upper bound of the input range. + * \return Normalized value between 0.0 and 1.0. + */ +float common_api_normalize(float x, float in_min, float in_max); + +/*! + * \brief pply a deadband to a value. + * + * \param[in] x: Input value. + * \param[in] deadband: Deadband threshold (values within ±deadband become 0). + * \return 0 if |x| < deadband, otherwise x. + */ +float common_api_constrain_deadband(float x, float deadband); + +/*! + * \brief Constrain a value based on a threshold condition. + * + * \param[in] x: Input value. + * \param[in] threshold: Threshold limit to be enforced. + * \param[in] mode: + * - COMMON_THRESHOLD_ABOVE, x must be above threshold, otherwise return sub_threshold_value. + * - COMMON_THRESHOLD_BELOW, x must be below threshold, otherwise return sup_threshold_value. + * \param[in] sub_threshold_value: Value returned if x is below threshold when isOverThreshold = true. + * \param[in] sup_threshold_value: Value returned if x is above threshold when isOverThreshold = false. + * + * \return The constrained or fallback value, depending on the condition. + */ +float common_api_constrain_threshold(float x, float threshold, enum common_threshold_mode mode, float sub_threshold_value, float sup_threshold_value); + +#endif /*! COMMON_API_H */ \ No newline at end of file diff --git a/include/common.h b/include/common.h new file mode 100644 index 0000000..d635e40 --- /dev/null +++ b/include/common.h @@ -0,0 +1,29 @@ +/*! + * \file common.h + * \date 2025-10-27 + * \authors Dorijan Di Zepp [dorijan.dizepp@eagletrt.it] + * + * \brief A simple library providing a set of common utilities for all embedded projects. + * + * \details This library provides a set of functions that are often needed in most embedded proejects. + * This helps in reducing developing time and maintain consistency across multiple projects. + */ + +#ifndef COMMON_H +#define COMMON_H + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define CLAMP(x, l, h) (MAX(MIN((x), (h)), (l))) + +/*! + * \brief Threshold mode for common_api_constrain_threshold function. + * + * These modes indicate if the input value must be above or below the threshold + */ +enum common_threshold_mode { + COMMON_THRESHOLD_ABOVE, + COMMON_THRESHOLD_BELOW +}; + +#endif /*! COMMON_H */ \ No newline at end of file diff --git a/library.json b/library.json index c040765..8ba32fa 100644 --- a/library.json +++ b/library.json @@ -1,26 +1,31 @@ { "$schema": "https://raw.githubusercontent.com/platformio/platformio-core/develop/platformio/assets/schema/library.json", - "name": "LibraryTemplate", - "version": "1.0.0", - "description": "Templates for libraries compatible with the PlatformIO ecosystem", + "name": "Common", + "version": "0.1.0", + "description": "A simple library providing a set of common utilities for all embedded projects.", "keywords": [ - "template" + "embedded", + "common-utils", + "math" ], "repository": { "type": "git", - "url": "" + "url": "https://github.com/eagletrt/libcommon-sw.git" }, "authors": [ { - "name": "Antonio Gelain", - "email": "antonio.gelain2@gmail.com", + "name": "Dorijan Di Zepp", + "email": "dorijan.dizeep@eagletrt.it", "maintainer": true } ], "license": "AGPL-3.0-only", "frameworks": "*", "platforms": "*", - "headers": [], + "headers": [ + "common.h", + "common-api.h" + ], "examples": [], "export": { "include": [ diff --git a/src/common-api.c b/src/common-api.c new file mode 100644 index 0000000..2820066 --- /dev/null +++ b/src/common-api.c @@ -0,0 +1,50 @@ +/*! + * \file common-api.c + * \date 2025-10-27 + * \authors Dorijan Di Zepp [dorijan.dizepp@eagletrt.it] + * + * \brief A simple library providing a set of common utilities for all embedded projects. + * + * \details This library provides a set of functions that are often needed in most embedded proejects. + * This helps in reducing developing time and maintain consistency across multiple projects. + */ + +//TODO: add git workflow and hooks (already done but check once more) +#include "common-api.h" + +float common_api_mapf(float x, float in_min, float in_max, float out_min, float out_max) { + if (in_max == in_min) { + return out_min; + } + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; +} + +float common_api_normalize(float x, float in_min, float in_max) { + if (in_max == in_min) { + return 0.0f; + } + return (x - in_min) / (in_max - in_min); +} + +float common_api_constrain_deadband(float x, float deadband) { + if (x > deadband) { + return x - deadband; + } else if (x < -deadband) { + return x + deadband; + } else { + return 0.0f; + } +} + +float common_api_constrain_threshold(float x, float threshold, enum common_threshold_mode mode, float sub_threshold_value, float sup_threshold_value) { + switch (mode) { + case COMMON_THRESHOLD_ABOVE: + return (x >= threshold) ? x : sub_threshold_value; + + case COMMON_THRESHOLD_BELOW: + return (x <= threshold) ? x : sup_threshold_value; + + default: + return x; // should never happen, fallback return + } +} \ No newline at end of file From 5640514368fa82cde53462b262cb6dfa7ccb7d45 Mon Sep 17 00:00:00 2001 From: Dorijan Di Zepp Date: Sun, 2 Nov 2025 18:35:59 +0100 Subject: [PATCH 2/8] feat: add unity test, example, documentation #1 --- .github/workflows/platformio.yml | 114 ++++++++++ README.md | 78 ++++--- examples/README.md | 7 - examples/example.c | 55 +++++ include/README.md | 10 - include/common-api.h | 18 +- library.json | 10 +- src/README.md | 4 - src/common-api.c | 11 +- test/README.md | 11 - test/test-common.c | 372 +++++++++++++++++++++++++++++++ 11 files changed, 608 insertions(+), 82 deletions(-) create mode 100644 .github/workflows/platformio.yml delete mode 100644 examples/README.md create mode 100644 examples/example.c delete mode 100644 include/README.md delete mode 100644 src/README.md delete mode 100644 test/README.md create mode 100644 test/test-common.c diff --git a/.github/workflows/platformio.yml b/.github/workflows/platformio.yml new file mode 100644 index 0000000..b8783be --- /dev/null +++ b/.github/workflows/platformio.yml @@ -0,0 +1,114 @@ +name: PlatformIO Library CI + +on: + push: + branches: + - '**' + pull_request: + branches: + - master + - dev + +jobs: + test: + name: Unit Tests + runs-on: ubuntu-latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Cache PlatformIO + pip + uses: actions/cache@v4 + with: + path: | + ~/.cache/pip + ~/.platformio/.cache + key: ${{ runner.os }}-pio-${{ hashFiles('**/platformio.ini') }} + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install PlatformIO Core + run: pip install --upgrade platformio + + - name: Run Unit Tests + run: | + if [ ! -f "platformio.ini" ]; then + echo "[env:native]" > platformio.ini + echo "platform = native" >> platformio.ini + echo "lib_deps = Unity" >> platformio.ini + fi + pio test -e native + + build: + name: Example Build + runs-on: ubuntu-latest + needs: test + continue-on-error: true # we don't want the build to block PRs if an example fails + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Cache PlatformIO + pip + uses: actions/cache@v4 + with: + path: | + ~/.cache/pip + ~/.platformio/.cache + key: ${{ runner.os }}-pio-${{ hashFiles('**/platformio.ini') }} + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install PlatformIO Core + run: pip install --upgrade platformio + + - name: Compile Example + run: | + if [ ! -f "platformio.ini" ]; then + echo "[env:native]" > platformio.ini + echo "platform = native" >> platformio.ini + echo "test_build_src = false" >> platformio.ini + fi + pio ci examples/example.c -l . --board=native + + check: + name: Static Code Analysis + runs-on: ubuntu-latest + if: > + (github.event_name == 'push' && (github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/master')) || + (github.event_name == 'pull_request' && github.event.pull_request.merged == true) + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Cache PlatformIO + pip + uses: actions/cache@v4 + with: + path: | + ~/.cache/pip + ~/.platformio/.cache + key: ${{ runner.os }}-pio-${{ hashFiles('**/platformio.ini') }} + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install PlatformIO Core + run: pip install --upgrade platformio + + - name: Run Static Analysis + run: | + if [ ! -f "platformio.ini" ]; then + echo "[env:native]" > platformio.ini + echo "platform = native" >> platformio.ini + fi + pio check \ No newline at end of file diff --git a/README.md b/README.md index 4a029e3..11f0880 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,43 @@ -# LIBSTM32-SW-TEMPLATE - -This repository serves as a template for libraries compatible with the -[PlatformIO ecosystem](https://docs.platformio.org/en/latest/librarymanager/creating.html). +# LIBCOMMON +This library provides a set of general purpose utility functions commonly used across embedded software projects. ## Usage - -Before starting to develop the library, a couple of things need to be done: -1. Change this README explaining the library and the functionalities that it offers -2. Modify the `library.json` including: - - The **name** of the library - - The library **version** - - The **description** explaining what the library does and for which devices - - The list of **keywords** - - The repository **url** (and type if necessary) - - The list of **authors** - - The supported **frameworks** and **platforms** (if needed) - - The list of **header files** of the library - - The list of **examples** - - The file of the library to **export** (if needed) - -## Structure - -The code of the library should be splitted in sources which must be placed inside -the `src` folder and headers which must be placed inside the `include` folder. - -Inside the `example` folder multiple source files should be placed to further -explain how to use the library and how it works in different scenario. - -The library must be tested with the maximum possible code coverage, the source -code used to run the unit tests should be put inside the `test` folder. - -If scripts or other tools are needed for the library they must be put inside -the `tools` folder. - -No other folders should be created besides the ones described before if not -necessary, to handle complex file structures nested folders can be used. - -For more info check the READMEs inside the corresponding folders. +To use the library, simply include the main header file: +```c +#include "common-api.h" +``` +>[!NOTE] +> No other dependencies are required in order to work with this library. + +The functions provided are: +- min & max +- clamp +- map +- deadband constraint +- threshold constraint + +>[!NOTE] +> This library is intentionally minimal.\ +> Its purpose is to provide only the most common and essential utilities shared across all embedded projects.\ +> Adding project specific or rarely used functions would defeat the purpose of keeping this library lightweight and universally applicable. + +## Example +A complete usage can be found in this [example](./examples/example.c). + +Example snippet: + +```c +#include "common-api.h" +#include + +int main(void) { + printf("max(5, -1) = %d\n", common_api_max(5, -1)); + // will print 5 + + printf("normalize(25.0, 0.0–100.0) = %.2f\n", + common_api_normalize(25.0f, 0.0f, 100.0f)); + //will print 0.25 + + return 0; +} +``` \ No newline at end of file diff --git a/examples/README.md b/examples/README.md deleted file mode 100644 index d2c0511..0000000 --- a/examples/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Examples - -Inside this folder several code examples should be given to demonstrate how the -library should be used in different context. - -The examples should cover all the available functionalities of the library. - diff --git a/examples/example.c b/examples/example.c new file mode 100644 index 0000000..dfc87a0 --- /dev/null +++ b/examples/example.c @@ -0,0 +1,55 @@ +/*! + * \file example.c + * \brief Example usage of the Common library. + * \author Dorijan Di Zepp [dorijan.dizepp@eagletrt.it] + * \date 2025-11-02 + */ + +#include +#include +#include "common-api.h" + +int main(void) { + + /* min / max / clamp */ + int a = 5, b = -1; + printf("min(%d, %d) = %d\n", a, b, common_api_min(a, b)); + printf("max(%d, %d) = %d\n", a, b, common_api_max(a, b)); + + int value = 15; + printf("clamp(%d, 0, 10) = %d\n", value, common_api_clamp(value, 0, 10)); + + /* mapf */ + float x = 5.0f; + float in_min = 0.0f, in_max = 10.0f; + float out_min = 0.0f, out_max = 100.0f; + float mapped = common_api_mapf(x, in_min, in_max, out_min, out_max); + printf("mapf(%.2f, %.2f-%.2f > %.2f-%.2f) = %.2f\n", x, in_min, in_max, out_min, out_max, mapped); + + /* normalize */ + float normalized = common_api_normalize(25.0f, 0.0f, 100.0f); + printf("normalize(25.0, 0.0-100.0) = %.2f\n", normalized); + + /* constrain deadband */ + float val = 0.05f; + float deadband = 0.1f; + float adjusted = common_api_constrain_deadband(val, deadband); + printf("constrain_deadband(%.2f, %.2f) = %.2f\n", val, deadband, adjusted); + + val = 0.25f; + adjusted = common_api_constrain_deadband(val, deadband); + printf("constrain_deadband(%.2f, %.2f) = %.2f\n", val, deadband, adjusted); + + /* constrain threshold */ + float threshold = 5.0f; + float sub_threshold_value = -1.0f; + float sup_threshold_value = 99.0f; + + float t1 = common_api_constrain_threshold(3.0f, threshold, COMMON_THRESHOLD_ABOVE, sub_threshold_value, sup_threshold_value); + float t2 = common_api_constrain_threshold(8.0f, threshold, COMMON_THRESHOLD_BELOW, sub_threshold_value, sup_threshold_value); + + printf("constrain_threshold(3.0, ABOVE, thr=%.1f) = %.2f\n", threshold, t1); + printf("constrain_threshold(8.0, BELOW, thr=%.1f) = %.2f\n", threshold, t2); + + return 0; +} \ No newline at end of file diff --git a/include/README.md b/include/README.md deleted file mode 100644 index f347d47..0000000 --- a/include/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# Headers - -Library headers should be placed within this folder adding nested folders when -necessary to better organize the file structure. - -It is advised to separate the function declarations from other definitions (such -as macros, types, constant, etc...) into two different files, respectively: -- `-api.h` -- `.h` - diff --git a/include/common-api.h b/include/common-api.h index 3dff3ba..d88bd46 100644 --- a/include/common-api.h +++ b/include/common-api.h @@ -52,6 +52,12 @@ * \param[in] out_min: Lower bound of output range. * \param[in] out_max: Upper bound of output range. * \return Mapped value corresponding to x in the output range. + * + * \note If in_min equals in_max, the result is inf due to division by zero. + * + * \warning The function does not perform automatic clamping. + * Ensure that x lies within [in_min, in_max] to avoid + * output values falling outside [out_min, out_max]. */ float common_api_mapf(float x, float in_min, float in_max, float out_min, float out_max); @@ -62,11 +68,17 @@ float common_api_mapf(float x, float in_min, float in_max, float out_min, float * \param[in] in_min: Lower bound of the input range. * \param[in] in_max: Upper bound of the input range. * \return Normalized value between 0.0 and 1.0. + * + * \note If in_max equals in_min, the function returns 0.0f to avoid division by zero. + * + * \warning This function does not clamp the input value automatically. + * The caller must ensure that x lies within [in_min, in_max], + * otherwise the returned normalized value may be outside the [0.0f, 1.0f] range. */ float common_api_normalize(float x, float in_min, float in_max); /*! - * \brief pply a deadband to a value. + * \brief Apply a deadband to a value. * * \param[in] x: Input value. * \param[in] deadband: Deadband threshold (values within ±deadband become 0). @@ -82,8 +94,8 @@ float common_api_constrain_deadband(float x, float deadband); * \param[in] mode: * - COMMON_THRESHOLD_ABOVE, x must be above threshold, otherwise return sub_threshold_value. * - COMMON_THRESHOLD_BELOW, x must be below threshold, otherwise return sup_threshold_value. - * \param[in] sub_threshold_value: Value returned if x is below threshold when isOverThreshold = true. - * \param[in] sup_threshold_value: Value returned if x is above threshold when isOverThreshold = false. + * \param[in] sub_threshold_value: Value returned if x is below threshold when COMMON_THRESHOLD_ABOVE. + * \param[in] sup_threshold_value: Value returned if x is above threshold when COMMON_THRESHOLD_BELOW. * * \return The constrained or fallback value, depending on the condition. */ diff --git a/library.json b/library.json index 8ba32fa..3b14e84 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/platformio/platformio-core/develop/platformio/assets/schema/library.json", - "name": "Common", + "name": "LibCommon", "version": "0.1.0", "description": "A simple library providing a set of common utilities for all embedded projects.", "keywords": [ @@ -26,7 +26,13 @@ "common.h", "common-api.h" ], - "examples": [], + "examples": [ + { + "name": "Example", + "base": "examples", + "files": [ "example.c" ] + } + ], "export": { "include": [ "src/**", diff --git a/src/README.md b/src/README.md deleted file mode 100644 index 77c50ae..0000000 --- a/src/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Sources - -Library sources should be placed within this folder adding nested folders when -necessary to better organize the file structure. diff --git a/src/common-api.c b/src/common-api.c index 2820066..d7cc7e2 100644 --- a/src/common-api.c +++ b/src/common-api.c @@ -9,13 +9,10 @@ * This helps in reducing developing time and maintain consistency across multiple projects. */ -//TODO: add git workflow and hooks (already done but check once more) #include "common-api.h" +#include float common_api_mapf(float x, float in_min, float in_max, float out_min, float out_max) { - if (in_max == in_min) { - return out_min; - } return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } @@ -27,10 +24,8 @@ float common_api_normalize(float x, float in_min, float in_max) { } float common_api_constrain_deadband(float x, float deadband) { - if (x > deadband) { - return x - deadband; - } else if (x < -deadband) { - return x + deadband; + if (fabs(x) >= deadband) { + return x; } else { return 0.0f; } diff --git a/test/README.md b/test/README.md deleted file mode 100644 index e53c05e..0000000 --- a/test/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# Unit tests - -To test the library one test file for each source file should be created with -the `test-` prefix. -The file structure may be kept the same as the one in the `src` folder to keep -the structure consistent. - -To run the unit tests it is needed to create a separate project including the -library as a dependency, and copy or link the test files inside the project -`test` folder. - diff --git a/test/test-common.c b/test/test-common.c new file mode 100644 index 0000000..7ebdfb5 --- /dev/null +++ b/test/test-common.c @@ -0,0 +1,372 @@ +/** + * @file test-common.c + * @brief Test suite for common-api.c file + * + * @author Dorijan Di Zepp [dorijan.dizepp@eagletrt.it] + * @date 2025-11-02 + */ + +#include "unity.h" +#include "common-api.h" +#include + +void test_common_api_min() { + float a, b; + + /* test with both values positives */ + a = 1; + b = 10; + TEST_ASSERT_EQUAL_MESSAGE(a, common_api_min(a, b), "Failed with both values positive"); + + a = 10; + b = 7; + TEST_ASSERT_EQUAL_MESSAGE(b, common_api_min(a, b), "Failed with both values positive"); + + /* test with both values negatives */ + a = -10; + b = -7; + TEST_ASSERT_EQUAL_MESSAGE(a, common_api_min(a, b), "Failed with both values negative"); + + a = -0.5f; + b = -3.14f; + TEST_ASSERT_EQUAL_MESSAGE(b, common_api_min(a, b), "Failed with both values negative"); + + /* test with one positive and one negative */ + a = -0.75f; + b = sqrt(2); + TEST_ASSERT_EQUAL_MESSAGE(a, common_api_min(a, b), "Failed with a positive and negative value"); + + a = 12.75f; + b = -sqrt(2); + TEST_ASSERT_EQUAL_MESSAGE(b, common_api_min(a, b), "Failed with a positive and negative value"); + + /* test with same value*/ + a = b = 3; + TEST_ASSERT_EQUAL_MESSAGE(b, common_api_min(a, b), "Failed with same positive value"); + + a = b = -cos(12); + TEST_ASSERT_EQUAL_MESSAGE(b, common_api_min(a, b), "Failed with same negative value"); +} + +void test_common_api_max() { + float a, b; + + /* test with both values positives */ + a = 10; + b = 1; + TEST_ASSERT_EQUAL_MESSAGE(a, common_api_max(a, b), "Failed with both values positive"); + + a = 5.34f; + b = 10; + TEST_ASSERT_EQUAL_MESSAGE(b, common_api_max(a, b), "Failed with both values positive"); + + /* test with both values negatives */ + a = -7; + b = -10; + TEST_ASSERT_EQUAL_MESSAGE(a, common_api_max(a, b), "Failed with both values negative"); + + a = -3.14f; + b = -0.15f; + TEST_ASSERT_EQUAL_MESSAGE(b, common_api_max(a, b), "Failed with both values negative"); + + /* test with one positive and one negative */ + a = sqrt(2); + b = -0.75f; + TEST_ASSERT_EQUAL_MESSAGE(a, common_api_max(a, b), "Failed with a positive and negative value"); + + a = -sqrt(2); + b = 12.75f; + TEST_ASSERT_EQUAL_MESSAGE(b, common_api_max(a, b), "Failed with a positive and negative value"); + + /* test with same value*/ + a = b = 3; + TEST_ASSERT_EQUAL_MESSAGE(b, common_api_max(a, b), "Failed with same positive value"); + + a = b = -cos(12); + TEST_ASSERT_EQUAL_MESSAGE(b, common_api_max(a, b), "Failed with same negative value"); +} + +void test_common_api_clamp() { + float x, low, high; + + /* test with x in a positive range */ + x = 5; + low = 0; + high = 10; + TEST_ASSERT_EQUAL_MESSAGE(x, common_api_clamp(x, low, high), "Failed with positive range"); + + /* test with x in a negative range */ + x = -5; + low = -10; + high = 0; + TEST_ASSERT_EQUAL_MESSAGE(x, common_api_clamp(x, low, high), "Failed with negative range"); + + /* test with x in a negative/positive range */ + x = 5; + low = -3.15f; + high = 5.14f; + TEST_ASSERT_EQUAL_MESSAGE(x, common_api_clamp(x, low, high), "Failed with negative/positive range"); + + /* test with x not in range */ + x = 5; + low = 0; + high = 4; + TEST_ASSERT_EQUAL_MESSAGE(high, common_api_clamp(x, low, high), "Failed to clamp on higher range"); + + x = -2; + low = 0.3f; + high = 4; + TEST_ASSERT_EQUAL_MESSAGE(low, common_api_clamp(x, low, high), "Failed to clamp on lower range"); + + /* test with x on range limit*/ + x = 0.3f; + low = 0.3f; + high = 4; + TEST_ASSERT_EQUAL_MESSAGE(x, common_api_clamp(x, low, high), "Failed with x equal to lower range limit"); + + x = 4; + low = 0.3f; + high = 4; + TEST_ASSERT_EQUAL_MESSAGE(x, common_api_clamp(x, low, high), "Failed with x equal to higher range limit"); +} + +void test_common_api_mapf() { + float x, in_min, in_max, out_min, out_max; + + /* test with positive range */ + x = 5.0f; + in_min = 0.0f, in_max = 10.0f; + out_min = 0.0f, out_max = 100.0f; + float result = common_api_mapf(x, in_min, in_max, out_min, out_max); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 50.0f, result, "Failed with positive range"); + + /* test with negative input range */ + x = -5.0f; + in_min = -10.0f; + in_max = 0.0f; + out_min = 0.0f; + out_max = 100.0f; + result = common_api_mapf(x, in_min, in_max, out_min, out_max); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 50.0f, result, "Failed with negative input range"); + + /* test with reversed output range */ + x = 2.5f; + in_min = 0.0f; + in_max = 5.0f; + out_min = 100.0f; + out_max = 0.0f; + result = common_api_mapf(x, in_min, in_max, out_min, out_max); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 50.0f, result, "Failed with reversed output range"); + + /* test with input value outside range (no clamping) */ + x = 15.0f; + in_min = 0.0f; + in_max = 10.0f; + out_min = 0.0f; + out_max = 100.0f; + result = common_api_mapf(x, in_min, in_max, out_min, out_max); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 150.0f, result, "Failed with value above input range"); + + /* test with identical input and output ranges (identity mapping) */ + x = 3.5f; + in_min = 0.0f; + in_max = 10.0f; + out_min = 0.0f; + out_max = 10.0f; + result = common_api_mapf(x, in_min, in_max, out_min, out_max); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 3.5f, result, "Failed with identical ranges"); + + /* test with zero-length input range (division by zero case) */ + x = 5.0f; + in_min = 1.0f; + in_max = 1.0f; + out_min = 0.0f; + out_max = 10.0f; + result = common_api_mapf(x, in_min, in_max, out_min, out_max); + TEST_ASSERT_TRUE_MESSAGE(isinf(result), "Failed to handle zero input range correctly"); +} + +void test_common_api_normalize() { + float x, in_min, in_max, result; + + /* test with positive range */ + x = 5.0f; + in_min = 0.0f; + in_max = 10.0f; + result = common_api_normalize(x, in_min, in_max); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 0.5f, result, "Failed with positive range"); + + /* test with negative range */ + x = -5.0f; + in_min = -10.0f; + in_max = 0.0f; + result = common_api_normalize(x, in_min, in_max); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 0.5f, result, "Failed with negative input range"); + + /* test with reversed input range */ + x = 2.5f; + in_min = 5.0f; + in_max = 0.0f; + result = common_api_normalize(x, in_min, in_max); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 0.5f, result, "Failed with reversed input range"); + + /* test with input value below range */ + x = -5.0f; + in_min = 0.0f; + in_max = 10.0f; + result = common_api_normalize(x, in_min, in_max); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, -0.5f, result, "Failed with value below input range"); + + /* test with input value above range */ + x = 15.0f; + in_min = 0.0f; + in_max = 10.0f; + result = common_api_normalize(x, in_min, in_max); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 1.5f, result, "Failed with value above input range"); + + /* test with identical input bounds (zero-length range) */ + x = 5.0f; + in_min = 1.0f; + in_max = 1.0f; + result = common_api_normalize(x, in_min, in_max); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 0.0f, result, "Failed to handle zero input range correctly"); + + /* test with input at minimum boundary */ + x = 0.0f; + in_min = 0.0f; + in_max = 10.0f; + result = common_api_normalize(x, in_min, in_max); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 0.0f, result, "Failed with input at minimum boundary"); + + /* test with input at maximum boundary */ + x = 10.0f; + in_min = 0.0f; + in_max = 10.0f; + result = common_api_normalize(x, in_min, in_max); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 1.0f, result, "Failed with input at maximum boundary"); +} + +void test_common_api_constrain_deadband() { + float x, deadband, result; + + /* test with value within positive deadband range */ + x = 0.05f; + deadband = 0.1f; + result = common_api_constrain_deadband(x, deadband); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, 0.0f, result, "Failed when value within positive deadband"); + + /* test with value within negative deadband range */ + x = -0.05f; + deadband = 0.1f; + result = common_api_constrain_deadband(x, deadband); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, 0.0f, result, "Failed when value within negative deadband"); + + /* test with value above deadband */ + x = 0.2f; + deadband = 0.1f; + result = common_api_constrain_deadband(x, deadband); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, 0.2f, result, "Failed when value above positive deadband"); + + /* test with value below negative deadband */ + x = -0.2f; + deadband = 0.1f; + result = common_api_constrain_deadband(x, deadband); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, -0.2f, result, "Failed when value below negative deadband"); + + /* test with value exactly equal to positive deadband */ + x = 0.1f; + deadband = 0.1f; + result = common_api_constrain_deadband(x, deadband); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, 0.1f, result, "Failed when value equals positive deadband"); + + /* test with value exactly equal to negative deadband */ + x = -0.1f; + deadband = 0.1f; + result = common_api_constrain_deadband(x, deadband); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, -0.1f, result, "Failed when value equals negative deadband"); + + /* test with zero input */ + x = 0.0f; + deadband = 0.1f; + result = common_api_constrain_deadband(x, deadband); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, 0.0f, result, "Failed when x equals 0"); + + /* test with zero deadband (function acts as pass-through) */ + x = 0.25f; + deadband = 0.0f; + result = common_api_constrain_deadband(x, deadband); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, 0.25f, result, "Failed when deadband equals 0 (positive)"); + + x = -0.25f; + result = common_api_constrain_deadband(x, deadband); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, -0.25f, result, "Failed when deadband equals 0 (negative)"); +} + +void test_common_api_constrain_threshold() { + float x, threshold, sub_val, sup_val, result; + + /* test that enum values are defined correctly*/ + TEST_ASSERT_EQUAL_INT_MESSAGE(0, COMMON_THRESHOLD_ABOVE, "COMMON_THRESHOLD_ABOVE has different value than expected"); + TEST_ASSERT_EQUAL_INT_MESSAGE(1, COMMON_THRESHOLD_BELOW, "COMMON_THRESHOLD_BELOW has different value than expected"); + + /* test COMMON_THRESHOLD_ABOVE - x above threshold */ + x = 10.0f; + threshold = 5.0f; + sub_val = -1.0f; + sup_val = 99.0f; + result = common_api_constrain_threshold(x, threshold, COMMON_THRESHOLD_ABOVE, sub_val, sup_val); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, 10.0f, result, "Failed when x > threshold (ABOVE mode)"); + + /* test COMMON_THRESHOLD_ABOVE - x below threshold */ + x = 3.0f; + threshold = 5.0f; + sub_val = -1.0f; + result = common_api_constrain_threshold(x, threshold, COMMON_THRESHOLD_ABOVE, sub_val, sup_val); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, -1.0f, result, "Failed when x < threshold (ABOVE mode)"); + + /* test COMMON_THRESHOLD_ABOVE - x exactly equal to threshold */ + x = 5.0f; + threshold = 5.0f; + result = common_api_constrain_threshold(x, threshold, COMMON_THRESHOLD_ABOVE, sub_val, sup_val); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, 5.0f, result, "Failed when x == threshold (ABOVE mode)"); + + /* test COMMON_THRESHOLD_BELOW - x below threshold */ + x = 3.0f; + threshold = 5.0f; + sup_val = 99.0f; + result = common_api_constrain_threshold(x, threshold, COMMON_THRESHOLD_BELOW, sub_val, sup_val); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, 3.0f, result, "Failed when x < threshold (BELOW mode)"); + + /* test COMMON_THRESHOLD_BELOW - x above threshold */ + x = 8.0f; + threshold = 5.0f; + sup_val = 99.0f; + result = common_api_constrain_threshold(x, threshold, COMMON_THRESHOLD_BELOW, sub_val, sup_val); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, 99.0f, result, "Failed when x > threshold (BELOW mode)"); + + /* test COMMON_THRESHOLD_BELOW - x exactly equal to threshold */ + x = 5.0f; + threshold = 5.0f; + result = common_api_constrain_threshold(x, threshold, COMMON_THRESHOLD_BELOW, sub_val, sup_val); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, 5.0f, result, "Failed when x == threshold (BELOW mode)"); + + /* test invalid mode fallback */ + x = 7.0f; + threshold = 5.0f; + result = common_api_constrain_threshold(x, threshold, (enum common_threshold_mode)999, sub_val, sup_val); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, 7.0f, result, "Failed invalid mode fallback"); +} + +int main() { + UNITY_BEGIN(); + + RUN_TEST(test_common_api_min); + RUN_TEST(test_common_api_max); + RUN_TEST(test_common_api_clamp); + RUN_TEST(test_common_api_mapf); + RUN_TEST(test_common_api_normalize); + RUN_TEST(test_common_api_constrain_deadband); + RUN_TEST(test_common_api_constrain_threshold); + + UNITY_END(); +} \ No newline at end of file From 62e45755d14fc44e0a884dc0ba1b2837240b0b6d Mon Sep 17 00:00:00 2001 From: Dorijan Di Zepp Date: Sun, 2 Nov 2025 18:43:54 +0100 Subject: [PATCH 3/8] fix: git action for unity test #1 --- .github/workflows/platformio.yml | 51 ++++++++------------------------ 1 file changed, 12 insertions(+), 39 deletions(-) diff --git a/.github/workflows/platformio.yml b/.github/workflows/platformio.yml index b8783be..de7ee79 100644 --- a/.github/workflows/platformio.yml +++ b/.github/workflows/platformio.yml @@ -37,46 +37,19 @@ jobs: - name: Run Unit Tests run: | if [ ! -f "platformio.ini" ]; then - echo "[env:native]" > platformio.ini - echo "platform = native" >> platformio.ini - echo "lib_deps = Unity" >> platformio.ini + printf "[env:native]\nplatform = native\nlib_deps = Unity, ./\n" > platformio.ini + echo "Created platformio.ini" fi pio test -e native - build: - name: Example Build - runs-on: ubuntu-latest - needs: test - continue-on-error: true # we don't want the build to block PRs if an example fails - - steps: - - name: Checkout Repository - uses: actions/checkout@v4 - - - name: Cache PlatformIO + pip - uses: actions/cache@v4 - with: - path: | - ~/.cache/pip - ~/.platformio/.cache - key: ${{ runner.os }}-pio-${{ hashFiles('**/platformio.ini') }} - - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: '3.11' - - - name: Install PlatformIO Core - run: pip install --upgrade platformio - - - name: Compile Example + - name: Compile Examples run: | - if [ ! -f "platformio.ini" ]; then - echo "[env:native]" > platformio.ini - echo "platform = native" >> platformio.ini - echo "test_build_src = false" >> platformio.ini - fi - pio ci examples/example.c -l . --board=native + for example in examples/*/; do + if [ -d "$example" ]; then + echo "Building $example" + pio ci "$example" --board native || true + fi + done check: name: Static Code Analysis @@ -105,10 +78,10 @@ jobs: - name: Install PlatformIO Core run: pip install --upgrade platformio - - name: Run Static Analysis + - name: Run Static Code Analysis run: | if [ ! -f "platformio.ini" ]; then - echo "[env:native]" > platformio.ini - echo "platform = native" >> platformio.ini + printf "[env:native]\nplatform = native\nlib_deps = Unity, ./\n" > platformio.ini + echo "Created platformio.ini" fi pio check \ No newline at end of file From 6de2a23b8714a4734be2eae2b0240a0b8c11c0c1 Mon Sep 17 00:00:00 2001 From: Dorijan Di Zepp Date: Mon, 3 Nov 2025 17:22:56 +0100 Subject: [PATCH 4/8] feat: change library name and api signatures, moved macros in api header --- README.md | 10 +- examples/example.c | 20 +-- include/{common-api.h => eagle-eco-api.h} | 44 +++---- include/{common.h => eagle-eco.h} | 20 ++- library.json | 12 +- src/{common-api.c => eagle-eco-api.c} | 16 +-- test/{test-common.c => test-eagle-eco.c} | 144 +++++++++++----------- 7 files changed, 132 insertions(+), 134 deletions(-) rename include/{common-api.h => eagle-eco-api.h} (69%) rename include/{common.h => eagle-eco.h} (57%) rename src/{common-api.c => eagle-eco-api.c} (63%) rename test/{test-common.c => test-eagle-eco.c} (59%) diff --git a/README.md b/README.md index 11f0880..f981948 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -# LIBCOMMON +# LibEagleECO This library provides a set of general purpose utility functions commonly used across embedded software projects. ## Usage To use the library, simply include the main header file: ```c -#include "common-api.h" +#include "eagle-eco-api.h" ``` >[!NOTE] > No other dependencies are required in order to work with this library. @@ -27,15 +27,15 @@ A complete usage can be found in this [example](./examples/example.c). Example snippet: ```c -#include "common-api.h" +#include "eagle-eco-api.h" #include int main(void) { - printf("max(5, -1) = %d\n", common_api_max(5, -1)); + printf("max(5, -1) = %d\n", eagle_eco_api_max(5, -1)); // will print 5 printf("normalize(25.0, 0.0–100.0) = %.2f\n", - common_api_normalize(25.0f, 0.0f, 100.0f)); + eagle_eco_api_normalize(25.0f, 0.0f, 100.0f)); //will print 0.25 return 0; diff --git a/examples/example.c b/examples/example.c index dfc87a0..766d484 100644 --- a/examples/example.c +++ b/examples/example.c @@ -7,37 +7,37 @@ #include #include -#include "common-api.h" +#include "eagle-eco-api.h" int main(void) { /* min / max / clamp */ int a = 5, b = -1; - printf("min(%d, %d) = %d\n", a, b, common_api_min(a, b)); - printf("max(%d, %d) = %d\n", a, b, common_api_max(a, b)); + printf("min(%d, %d) = %d\n", a, b, EAGLE_ECO_API_MIN(a, b)); + printf("max(%d, %d) = %d\n", a, b, EAGLE_ECO_API_MAX(a, b)); int value = 15; - printf("clamp(%d, 0, 10) = %d\n", value, common_api_clamp(value, 0, 10)); + printf("clamp(%d, 0, 10) = %d\n", value, EAGLE_ECO_API_CLAMP(value, 0, 10)); /* mapf */ float x = 5.0f; float in_min = 0.0f, in_max = 10.0f; float out_min = 0.0f, out_max = 100.0f; - float mapped = common_api_mapf(x, in_min, in_max, out_min, out_max); + float mapped = eagle_eco_api_mapf(x, in_min, in_max, out_min, out_max); printf("mapf(%.2f, %.2f-%.2f > %.2f-%.2f) = %.2f\n", x, in_min, in_max, out_min, out_max, mapped); /* normalize */ - float normalized = common_api_normalize(25.0f, 0.0f, 100.0f); + float normalized = eagle_eco_api_normalize(25.0f, 0.0f, 100.0f); printf("normalize(25.0, 0.0-100.0) = %.2f\n", normalized); /* constrain deadband */ float val = 0.05f; float deadband = 0.1f; - float adjusted = common_api_constrain_deadband(val, deadband); + float adjusted = eagle_eco_api_constrain_deadband(val, deadband); printf("constrain_deadband(%.2f, %.2f) = %.2f\n", val, deadband, adjusted); val = 0.25f; - adjusted = common_api_constrain_deadband(val, deadband); + adjusted = eagle_eco_api_constrain_deadband(val, deadband); printf("constrain_deadband(%.2f, %.2f) = %.2f\n", val, deadband, adjusted); /* constrain threshold */ @@ -45,8 +45,8 @@ int main(void) { float sub_threshold_value = -1.0f; float sup_threshold_value = 99.0f; - float t1 = common_api_constrain_threshold(3.0f, threshold, COMMON_THRESHOLD_ABOVE, sub_threshold_value, sup_threshold_value); - float t2 = common_api_constrain_threshold(8.0f, threshold, COMMON_THRESHOLD_BELOW, sub_threshold_value, sup_threshold_value); + float t1 = eagle_eco_api_constrain_threshold(3.0f, threshold, EAGLE_ECO_THRESHOLD_MODE_ABOVE, sub_threshold_value, sup_threshold_value); + float t2 = eagle_eco_api_constrain_threshold(8.0f, threshold, EAGLE_ECO_THRESHOLD_MODE_BELOW, sub_threshold_value, sup_threshold_value); printf("constrain_threshold(3.0, ABOVE, thr=%.1f) = %.2f\n", threshold, t1); printf("constrain_threshold(8.0, BELOW, thr=%.1f) = %.2f\n", threshold, t2); diff --git a/include/common-api.h b/include/eagle-eco-api.h similarity index 69% rename from include/common-api.h rename to include/eagle-eco-api.h index d88bd46..9e69508 100644 --- a/include/common-api.h +++ b/include/eagle-eco-api.h @@ -1,5 +1,5 @@ /*! - * \file common-api.h + * \file eagle-eco-api.h * \date 2025-10-27 * \authors Dorijan Di Zepp [dorijan.dizepp@eagletrt.it] * @@ -9,11 +9,11 @@ * This helps in reducing developing time and maintain consistency across multiple projects. */ -#ifndef COMMON_API_H -#define COMMON_API_H +#ifndef EAGLE_ECO_API_H +#define EAGLE_ECO_API_H #include -#include "common.h" +#include "eagle-eco.h" /*! * \brief Return the smaller of two values. @@ -22,16 +22,16 @@ * \param[in] b: Second value to compare. * \return The smaller of the two input values. */ -#define common_api_min(a, b) MIN(a, b) +#define EAGLE_ECO_API_MIN(a, b) ((a) < (b) ? (a) : (b)) /*! - * \brief Return the larger of two values. - * - * \param[in] a: First value to compare. - * \param[in] b: Second value to compare. - * \return The larger of the two input values. - */ -#define common_api_max(a, b) MAX(a, b) +* \brief Return the larger of two values. +* +* \param[in] a: First value to compare. +* \param[in] b: Second value to compare. +* \return The larger of the two input values. +*/ +#define EAGLE_ECO_API_MAX(a, b) ((a) > (b) ? (a) : (b)) /*! * \brief Clamp a value between a lower and upper limit. @@ -41,7 +41,7 @@ * \param[in] high: Maximum allowable value. * \return The clamped value, within the [low, high] range. */ -#define common_api_clamp(x, low, high) CLAMP(x, low, high) +#define EAGLE_ECO_API_CLAMP(x, l, h) (EAGLE_ECO_API_MAX(EAGLE_ECO_API_MIN((x), (h)), (l))) /*! * \brief Map a value from one range to another. @@ -59,7 +59,7 @@ * Ensure that x lies within [in_min, in_max] to avoid * output values falling outside [out_min, out_max]. */ -float common_api_mapf(float x, float in_min, float in_max, float out_min, float out_max); +float eagle_eco_api_mapf(float x, float in_min, float in_max, float out_min, float out_max); /*! * \brief Normalize a value within a given range to [0, 1]. @@ -75,7 +75,7 @@ float common_api_mapf(float x, float in_min, float in_max, float out_min, float * The caller must ensure that x lies within [in_min, in_max], * otherwise the returned normalized value may be outside the [0.0f, 1.0f] range. */ -float common_api_normalize(float x, float in_min, float in_max); +float eagle_eco_api_normalize(float x, float in_min, float in_max); /*! * \brief Apply a deadband to a value. @@ -84,7 +84,7 @@ float common_api_normalize(float x, float in_min, float in_max); * \param[in] deadband: Deadband threshold (values within ±deadband become 0). * \return 0 if |x| < deadband, otherwise x. */ -float common_api_constrain_deadband(float x, float deadband); +float eagle_eco_api_constrain_deadband(float x, float deadband); /*! * \brief Constrain a value based on a threshold condition. @@ -92,13 +92,13 @@ float common_api_constrain_deadband(float x, float deadband); * \param[in] x: Input value. * \param[in] threshold: Threshold limit to be enforced. * \param[in] mode: - * - COMMON_THRESHOLD_ABOVE, x must be above threshold, otherwise return sub_threshold_value. - * - COMMON_THRESHOLD_BELOW, x must be below threshold, otherwise return sup_threshold_value. - * \param[in] sub_threshold_value: Value returned if x is below threshold when COMMON_THRESHOLD_ABOVE. - * \param[in] sup_threshold_value: Value returned if x is above threshold when COMMON_THRESHOLD_BELOW. + * - EAGLE_ECO_THRESHOLD_ABOVE, x must be above threshold, otherwise return sub_threshold_value. + * - EAGLE_ECO_THRESHOLD_BELOW, x must be below threshold, otherwise return sup_threshold_value. + * \param[in] sub_threshold_value: Value returned if x is below threshold when EAGLE_ECO_THRESHOLD_ABOVE. + * \param[in] sup_threshold_value: Value returned if x is above threshold when EAGLE_ECO_THRESHOLD_BELOW. * * \return The constrained or fallback value, depending on the condition. */ -float common_api_constrain_threshold(float x, float threshold, enum common_threshold_mode mode, float sub_threshold_value, float sup_threshold_value); +float eagle_eco_api_constrain_threshold(float x, float threshold, enum eagle_eco_threshold_mode mode, float sub_threshold_value, float sup_threshold_value); -#endif /*! COMMON_API_H */ \ No newline at end of file +#endif /*! EAGLE_ECO_API_H */ \ No newline at end of file diff --git a/include/common.h b/include/eagle-eco.h similarity index 57% rename from include/common.h rename to include/eagle-eco.h index d635e40..1eca85e 100644 --- a/include/common.h +++ b/include/eagle-eco.h @@ -1,5 +1,5 @@ /*! - * \file common.h + * \file eagle-eco.h * \date 2025-10-27 * \authors Dorijan Di Zepp [dorijan.dizepp@eagletrt.it] * @@ -9,21 +9,17 @@ * This helps in reducing developing time and maintain consistency across multiple projects. */ -#ifndef COMMON_H -#define COMMON_H - -#define MIN(a, b) ((a) < (b) ? (a) : (b)) -#define MAX(a, b) ((a) > (b) ? (a) : (b)) -#define CLAMP(x, l, h) (MAX(MIN((x), (h)), (l))) +#ifndef EAGLE_ECO_H +#define EAGLE_ECO_H /*! - * \brief Threshold mode for common_api_constrain_threshold function. + * \brief Threshold mode for eagle_eco_api_constrain_threshold function. * * These modes indicate if the input value must be above or below the threshold */ -enum common_threshold_mode { - COMMON_THRESHOLD_ABOVE, - COMMON_THRESHOLD_BELOW +enum eagle_eco_threshold_mode { + EAGLE_ECO_THRESHOLD_MODE_ABOVE, + EAGLE_ECO_THRESHOLD_MODE_BELOW }; -#endif /*! COMMON_H */ \ No newline at end of file +#endif /*! EAGLE_ECO_H */ \ No newline at end of file diff --git a/library.json b/library.json index 3b14e84..6bc2310 100644 --- a/library.json +++ b/library.json @@ -1,16 +1,18 @@ { "$schema": "https://raw.githubusercontent.com/platformio/platformio-core/develop/platformio/assets/schema/library.json", - "name": "LibCommon", + "name": "LibEagleECO", "version": "0.1.0", - "description": "A simple library providing a set of common utilities for all embedded projects.", + "description": "ECO [Embedded Common Objects], a simple library providing a set of common utilities for all embedded projects.", "keywords": [ "embedded", + "common", + "minimal", "common-utils", "math" ], "repository": { "type": "git", - "url": "https://github.com/eagletrt/libcommon-sw.git" + "url": "https://github.com/eagletrt/libeagleeco-sw.git" }, "authors": [ { @@ -23,8 +25,8 @@ "frameworks": "*", "platforms": "*", "headers": [ - "common.h", - "common-api.h" + "eagle-eco.h", + "eagle-eco-api.h" ], "examples": [ { diff --git a/src/common-api.c b/src/eagle-eco-api.c similarity index 63% rename from src/common-api.c rename to src/eagle-eco-api.c index d7cc7e2..ae16b46 100644 --- a/src/common-api.c +++ b/src/eagle-eco-api.c @@ -1,5 +1,5 @@ /*! - * \file common-api.c + * \file eagle-eco-api.c * \date 2025-10-27 * \authors Dorijan Di Zepp [dorijan.dizepp@eagletrt.it] * @@ -9,21 +9,21 @@ * This helps in reducing developing time and maintain consistency across multiple projects. */ -#include "common-api.h" +#include "eagle-eco-api.h" #include -float common_api_mapf(float x, float in_min, float in_max, float out_min, float out_max) { +float eagle_eco_api_mapf(float x, float in_min, float in_max, float out_min, float out_max) { return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } -float common_api_normalize(float x, float in_min, float in_max) { +float eagle_eco_api_normalize(float x, float in_min, float in_max) { if (in_max == in_min) { return 0.0f; } return (x - in_min) / (in_max - in_min); } -float common_api_constrain_deadband(float x, float deadband) { +float eagle_eco_api_constrain_deadband(float x, float deadband) { if (fabs(x) >= deadband) { return x; } else { @@ -31,12 +31,12 @@ float common_api_constrain_deadband(float x, float deadband) { } } -float common_api_constrain_threshold(float x, float threshold, enum common_threshold_mode mode, float sub_threshold_value, float sup_threshold_value) { +float eagle_eco_api_constrain_threshold(float x, float threshold, enum eagle_eco_threshold_mode mode, float sub_threshold_value, float sup_threshold_value) { switch (mode) { - case COMMON_THRESHOLD_ABOVE: + case EAGLE_ECO_THRESHOLD_MODE_ABOVE: return (x >= threshold) ? x : sub_threshold_value; - case COMMON_THRESHOLD_BELOW: + case EAGLE_ECO_THRESHOLD_MODE_BELOW: return (x <= threshold) ? x : sup_threshold_value; default: diff --git a/test/test-common.c b/test/test-eagle-eco.c similarity index 59% rename from test/test-common.c rename to test/test-eagle-eco.c index 7ebdfb5..f349ed2 100644 --- a/test/test-common.c +++ b/test/test-eagle-eco.c @@ -1,143 +1,143 @@ /** - * @file test-common.c - * @brief Test suite for common-api.c file + * @file test-eagle-eco.c + * @brief Test suite for eagle-eco-api.c file * * @author Dorijan Di Zepp [dorijan.dizepp@eagletrt.it] * @date 2025-11-02 */ #include "unity.h" -#include "common-api.h" +#include "eagle-eco-api.h" #include -void test_common_api_min() { +void test_eagle_eco_api_min() { float a, b; /* test with both values positives */ a = 1; b = 10; - TEST_ASSERT_EQUAL_MESSAGE(a, common_api_min(a, b), "Failed with both values positive"); + TEST_ASSERT_EQUAL_MESSAGE(a, EAGLE_ECO_API_MIN(a, b), "Failed with both values positive"); a = 10; b = 7; - TEST_ASSERT_EQUAL_MESSAGE(b, common_api_min(a, b), "Failed with both values positive"); + TEST_ASSERT_EQUAL_MESSAGE(b, EAGLE_ECO_API_MIN(a, b), "Failed with both values positive"); /* test with both values negatives */ a = -10; b = -7; - TEST_ASSERT_EQUAL_MESSAGE(a, common_api_min(a, b), "Failed with both values negative"); + TEST_ASSERT_EQUAL_MESSAGE(a, EAGLE_ECO_API_MIN(a, b), "Failed with both values negative"); a = -0.5f; b = -3.14f; - TEST_ASSERT_EQUAL_MESSAGE(b, common_api_min(a, b), "Failed with both values negative"); + TEST_ASSERT_EQUAL_MESSAGE(b, EAGLE_ECO_API_MIN(a, b), "Failed with both values negative"); /* test with one positive and one negative */ a = -0.75f; b = sqrt(2); - TEST_ASSERT_EQUAL_MESSAGE(a, common_api_min(a, b), "Failed with a positive and negative value"); + TEST_ASSERT_EQUAL_MESSAGE(a, EAGLE_ECO_API_MIN(a, b), "Failed with a positive and negative value"); a = 12.75f; b = -sqrt(2); - TEST_ASSERT_EQUAL_MESSAGE(b, common_api_min(a, b), "Failed with a positive and negative value"); + TEST_ASSERT_EQUAL_MESSAGE(b, EAGLE_ECO_API_MIN(a, b), "Failed with a positive and negative value"); /* test with same value*/ a = b = 3; - TEST_ASSERT_EQUAL_MESSAGE(b, common_api_min(a, b), "Failed with same positive value"); + TEST_ASSERT_EQUAL_MESSAGE(b, EAGLE_ECO_API_MIN(a, b), "Failed with same positive value"); a = b = -cos(12); - TEST_ASSERT_EQUAL_MESSAGE(b, common_api_min(a, b), "Failed with same negative value"); + TEST_ASSERT_EQUAL_MESSAGE(b, EAGLE_ECO_API_MIN(a, b), "Failed with same negative value"); } -void test_common_api_max() { +void test_eagle_eco_api_max() { float a, b; /* test with both values positives */ a = 10; b = 1; - TEST_ASSERT_EQUAL_MESSAGE(a, common_api_max(a, b), "Failed with both values positive"); + TEST_ASSERT_EQUAL_MESSAGE(a, EAGLE_ECO_API_MAX(a, b), "Failed with both values positive"); a = 5.34f; b = 10; - TEST_ASSERT_EQUAL_MESSAGE(b, common_api_max(a, b), "Failed with both values positive"); + TEST_ASSERT_EQUAL_MESSAGE(b, EAGLE_ECO_API_MAX(a, b), "Failed with both values positive"); /* test with both values negatives */ a = -7; b = -10; - TEST_ASSERT_EQUAL_MESSAGE(a, common_api_max(a, b), "Failed with both values negative"); + TEST_ASSERT_EQUAL_MESSAGE(a, EAGLE_ECO_API_MAX(a, b), "Failed with both values negative"); a = -3.14f; b = -0.15f; - TEST_ASSERT_EQUAL_MESSAGE(b, common_api_max(a, b), "Failed with both values negative"); + TEST_ASSERT_EQUAL_MESSAGE(b, EAGLE_ECO_API_MAX(a, b), "Failed with both values negative"); /* test with one positive and one negative */ a = sqrt(2); b = -0.75f; - TEST_ASSERT_EQUAL_MESSAGE(a, common_api_max(a, b), "Failed with a positive and negative value"); + TEST_ASSERT_EQUAL_MESSAGE(a, EAGLE_ECO_API_MAX(a, b), "Failed with a positive and negative value"); a = -sqrt(2); b = 12.75f; - TEST_ASSERT_EQUAL_MESSAGE(b, common_api_max(a, b), "Failed with a positive and negative value"); + TEST_ASSERT_EQUAL_MESSAGE(b, EAGLE_ECO_API_MAX(a, b), "Failed with a positive and negative value"); /* test with same value*/ a = b = 3; - TEST_ASSERT_EQUAL_MESSAGE(b, common_api_max(a, b), "Failed with same positive value"); + TEST_ASSERT_EQUAL_MESSAGE(b, EAGLE_ECO_API_MAX(a, b), "Failed with same positive value"); a = b = -cos(12); - TEST_ASSERT_EQUAL_MESSAGE(b, common_api_max(a, b), "Failed with same negative value"); + TEST_ASSERT_EQUAL_MESSAGE(b, EAGLE_ECO_API_MAX(a, b), "Failed with same negative value"); } -void test_common_api_clamp() { +void test_eagle_eco_api_clamp() { float x, low, high; /* test with x in a positive range */ x = 5; low = 0; high = 10; - TEST_ASSERT_EQUAL_MESSAGE(x, common_api_clamp(x, low, high), "Failed with positive range"); + TEST_ASSERT_EQUAL_MESSAGE(x, EAGLE_ECO_API_CLAMP(x, low, high), "Failed with positive range"); /* test with x in a negative range */ x = -5; low = -10; high = 0; - TEST_ASSERT_EQUAL_MESSAGE(x, common_api_clamp(x, low, high), "Failed with negative range"); + TEST_ASSERT_EQUAL_MESSAGE(x, EAGLE_ECO_API_CLAMP(x, low, high), "Failed with negative range"); /* test with x in a negative/positive range */ x = 5; low = -3.15f; high = 5.14f; - TEST_ASSERT_EQUAL_MESSAGE(x, common_api_clamp(x, low, high), "Failed with negative/positive range"); + TEST_ASSERT_EQUAL_MESSAGE(x, EAGLE_ECO_API_CLAMP(x, low, high), "Failed with negative/positive range"); /* test with x not in range */ x = 5; low = 0; high = 4; - TEST_ASSERT_EQUAL_MESSAGE(high, common_api_clamp(x, low, high), "Failed to clamp on higher range"); + TEST_ASSERT_EQUAL_MESSAGE(high, EAGLE_ECO_API_CLAMP(x, low, high), "Failed to clamp on higher range"); x = -2; low = 0.3f; high = 4; - TEST_ASSERT_EQUAL_MESSAGE(low, common_api_clamp(x, low, high), "Failed to clamp on lower range"); + TEST_ASSERT_EQUAL_MESSAGE(low, EAGLE_ECO_API_CLAMP(x, low, high), "Failed to clamp on lower range"); /* test with x on range limit*/ x = 0.3f; low = 0.3f; high = 4; - TEST_ASSERT_EQUAL_MESSAGE(x, common_api_clamp(x, low, high), "Failed with x equal to lower range limit"); + TEST_ASSERT_EQUAL_MESSAGE(x, EAGLE_ECO_API_CLAMP(x, low, high), "Failed with x equal to lower range limit"); x = 4; low = 0.3f; high = 4; - TEST_ASSERT_EQUAL_MESSAGE(x, common_api_clamp(x, low, high), "Failed with x equal to higher range limit"); + TEST_ASSERT_EQUAL_MESSAGE(x, EAGLE_ECO_API_CLAMP(x, low, high), "Failed with x equal to higher range limit"); } -void test_common_api_mapf() { +void test_eagle_eco_api_mapf() { float x, in_min, in_max, out_min, out_max; /* test with positive range */ x = 5.0f; in_min = 0.0f, in_max = 10.0f; out_min = 0.0f, out_max = 100.0f; - float result = common_api_mapf(x, in_min, in_max, out_min, out_max); + float result = eagle_eco_api_mapf(x, in_min, in_max, out_min, out_max); TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 50.0f, result, "Failed with positive range"); /* test with negative input range */ @@ -146,7 +146,7 @@ void test_common_api_mapf() { in_max = 0.0f; out_min = 0.0f; out_max = 100.0f; - result = common_api_mapf(x, in_min, in_max, out_min, out_max); + result = eagle_eco_api_mapf(x, in_min, in_max, out_min, out_max); TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 50.0f, result, "Failed with negative input range"); /* test with reversed output range */ @@ -155,7 +155,7 @@ void test_common_api_mapf() { in_max = 5.0f; out_min = 100.0f; out_max = 0.0f; - result = common_api_mapf(x, in_min, in_max, out_min, out_max); + result = eagle_eco_api_mapf(x, in_min, in_max, out_min, out_max); TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 50.0f, result, "Failed with reversed output range"); /* test with input value outside range (no clamping) */ @@ -164,7 +164,7 @@ void test_common_api_mapf() { in_max = 10.0f; out_min = 0.0f; out_max = 100.0f; - result = common_api_mapf(x, in_min, in_max, out_min, out_max); + result = eagle_eco_api_mapf(x, in_min, in_max, out_min, out_max); TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 150.0f, result, "Failed with value above input range"); /* test with identical input and output ranges (identity mapping) */ @@ -173,7 +173,7 @@ void test_common_api_mapf() { in_max = 10.0f; out_min = 0.0f; out_max = 10.0f; - result = common_api_mapf(x, in_min, in_max, out_min, out_max); + result = eagle_eco_api_mapf(x, in_min, in_max, out_min, out_max); TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 3.5f, result, "Failed with identical ranges"); /* test with zero-length input range (division by zero case) */ @@ -182,191 +182,191 @@ void test_common_api_mapf() { in_max = 1.0f; out_min = 0.0f; out_max = 10.0f; - result = common_api_mapf(x, in_min, in_max, out_min, out_max); + result = eagle_eco_api_mapf(x, in_min, in_max, out_min, out_max); TEST_ASSERT_TRUE_MESSAGE(isinf(result), "Failed to handle zero input range correctly"); } -void test_common_api_normalize() { +void test_eagle_eco_api_normalize() { float x, in_min, in_max, result; /* test with positive range */ x = 5.0f; in_min = 0.0f; in_max = 10.0f; - result = common_api_normalize(x, in_min, in_max); + result = eagle_eco_api_normalize(x, in_min, in_max); TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 0.5f, result, "Failed with positive range"); /* test with negative range */ x = -5.0f; in_min = -10.0f; in_max = 0.0f; - result = common_api_normalize(x, in_min, in_max); + result = eagle_eco_api_normalize(x, in_min, in_max); TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 0.5f, result, "Failed with negative input range"); /* test with reversed input range */ x = 2.5f; in_min = 5.0f; in_max = 0.0f; - result = common_api_normalize(x, in_min, in_max); + result = eagle_eco_api_normalize(x, in_min, in_max); TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 0.5f, result, "Failed with reversed input range"); /* test with input value below range */ x = -5.0f; in_min = 0.0f; in_max = 10.0f; - result = common_api_normalize(x, in_min, in_max); + result = eagle_eco_api_normalize(x, in_min, in_max); TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, -0.5f, result, "Failed with value below input range"); /* test with input value above range */ x = 15.0f; in_min = 0.0f; in_max = 10.0f; - result = common_api_normalize(x, in_min, in_max); + result = eagle_eco_api_normalize(x, in_min, in_max); TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 1.5f, result, "Failed with value above input range"); /* test with identical input bounds (zero-length range) */ x = 5.0f; in_min = 1.0f; in_max = 1.0f; - result = common_api_normalize(x, in_min, in_max); + result = eagle_eco_api_normalize(x, in_min, in_max); TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 0.0f, result, "Failed to handle zero input range correctly"); /* test with input at minimum boundary */ x = 0.0f; in_min = 0.0f; in_max = 10.0f; - result = common_api_normalize(x, in_min, in_max); + result = eagle_eco_api_normalize(x, in_min, in_max); TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 0.0f, result, "Failed with input at minimum boundary"); /* test with input at maximum boundary */ x = 10.0f; in_min = 0.0f; in_max = 10.0f; - result = common_api_normalize(x, in_min, in_max); + result = eagle_eco_api_normalize(x, in_min, in_max); TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 1.0f, result, "Failed with input at maximum boundary"); } -void test_common_api_constrain_deadband() { +void test_eagle_eco_api_constrain_deadband() { float x, deadband, result; /* test with value within positive deadband range */ x = 0.05f; deadband = 0.1f; - result = common_api_constrain_deadband(x, deadband); + result = eagle_eco_api_constrain_deadband(x, deadband); TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, 0.0f, result, "Failed when value within positive deadband"); /* test with value within negative deadband range */ x = -0.05f; deadband = 0.1f; - result = common_api_constrain_deadband(x, deadband); + result = eagle_eco_api_constrain_deadband(x, deadband); TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, 0.0f, result, "Failed when value within negative deadband"); /* test with value above deadband */ x = 0.2f; deadband = 0.1f; - result = common_api_constrain_deadband(x, deadband); + result = eagle_eco_api_constrain_deadband(x, deadband); TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, 0.2f, result, "Failed when value above positive deadband"); /* test with value below negative deadband */ x = -0.2f; deadband = 0.1f; - result = common_api_constrain_deadband(x, deadband); + result = eagle_eco_api_constrain_deadband(x, deadband); TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, -0.2f, result, "Failed when value below negative deadband"); /* test with value exactly equal to positive deadband */ x = 0.1f; deadband = 0.1f; - result = common_api_constrain_deadband(x, deadband); + result = eagle_eco_api_constrain_deadband(x, deadband); TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, 0.1f, result, "Failed when value equals positive deadband"); /* test with value exactly equal to negative deadband */ x = -0.1f; deadband = 0.1f; - result = common_api_constrain_deadband(x, deadband); + result = eagle_eco_api_constrain_deadband(x, deadband); TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, -0.1f, result, "Failed when value equals negative deadband"); /* test with zero input */ x = 0.0f; deadband = 0.1f; - result = common_api_constrain_deadband(x, deadband); + result = eagle_eco_api_constrain_deadband(x, deadband); TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, 0.0f, result, "Failed when x equals 0"); /* test with zero deadband (function acts as pass-through) */ x = 0.25f; deadband = 0.0f; - result = common_api_constrain_deadband(x, deadband); + result = eagle_eco_api_constrain_deadband(x, deadband); TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, 0.25f, result, "Failed when deadband equals 0 (positive)"); x = -0.25f; - result = common_api_constrain_deadband(x, deadband); + result = eagle_eco_api_constrain_deadband(x, deadband); TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, -0.25f, result, "Failed when deadband equals 0 (negative)"); } -void test_common_api_constrain_threshold() { +void test_eagle_eco_api_constrain_threshold() { float x, threshold, sub_val, sup_val, result; /* test that enum values are defined correctly*/ - TEST_ASSERT_EQUAL_INT_MESSAGE(0, COMMON_THRESHOLD_ABOVE, "COMMON_THRESHOLD_ABOVE has different value than expected"); - TEST_ASSERT_EQUAL_INT_MESSAGE(1, COMMON_THRESHOLD_BELOW, "COMMON_THRESHOLD_BELOW has different value than expected"); + TEST_ASSERT_EQUAL_INT_MESSAGE(0, EAGLE_ECO_THRESHOLD_MODE_ABOVE, "COMMON_THRESHOLD_ABOVE has different value than expected"); + TEST_ASSERT_EQUAL_INT_MESSAGE(1, EAGLE_ECO_THRESHOLD_MODE_BELOW, "COMMON_THRESHOLD_BELOW has different value than expected"); /* test COMMON_THRESHOLD_ABOVE - x above threshold */ x = 10.0f; threshold = 5.0f; sub_val = -1.0f; sup_val = 99.0f; - result = common_api_constrain_threshold(x, threshold, COMMON_THRESHOLD_ABOVE, sub_val, sup_val); + result = eagle_eco_api_constrain_threshold(x, threshold, EAGLE_ECO_THRESHOLD_MODE_ABOVE, sub_val, sup_val); TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, 10.0f, result, "Failed when x > threshold (ABOVE mode)"); /* test COMMON_THRESHOLD_ABOVE - x below threshold */ x = 3.0f; threshold = 5.0f; sub_val = -1.0f; - result = common_api_constrain_threshold(x, threshold, COMMON_THRESHOLD_ABOVE, sub_val, sup_val); + result = eagle_eco_api_constrain_threshold(x, threshold, EAGLE_ECO_THRESHOLD_MODE_ABOVE, sub_val, sup_val); TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, -1.0f, result, "Failed when x < threshold (ABOVE mode)"); /* test COMMON_THRESHOLD_ABOVE - x exactly equal to threshold */ x = 5.0f; threshold = 5.0f; - result = common_api_constrain_threshold(x, threshold, COMMON_THRESHOLD_ABOVE, sub_val, sup_val); + result = eagle_eco_api_constrain_threshold(x, threshold, EAGLE_ECO_THRESHOLD_MODE_ABOVE, sub_val, sup_val); TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, 5.0f, result, "Failed when x == threshold (ABOVE mode)"); /* test COMMON_THRESHOLD_BELOW - x below threshold */ x = 3.0f; threshold = 5.0f; sup_val = 99.0f; - result = common_api_constrain_threshold(x, threshold, COMMON_THRESHOLD_BELOW, sub_val, sup_val); + result = eagle_eco_api_constrain_threshold(x, threshold, EAGLE_ECO_THRESHOLD_MODE_BELOW, sub_val, sup_val); TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, 3.0f, result, "Failed when x < threshold (BELOW mode)"); /* test COMMON_THRESHOLD_BELOW - x above threshold */ x = 8.0f; threshold = 5.0f; sup_val = 99.0f; - result = common_api_constrain_threshold(x, threshold, COMMON_THRESHOLD_BELOW, sub_val, sup_val); + result = eagle_eco_api_constrain_threshold(x, threshold, EAGLE_ECO_THRESHOLD_MODE_BELOW, sub_val, sup_val); TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, 99.0f, result, "Failed when x > threshold (BELOW mode)"); /* test COMMON_THRESHOLD_BELOW - x exactly equal to threshold */ x = 5.0f; threshold = 5.0f; - result = common_api_constrain_threshold(x, threshold, COMMON_THRESHOLD_BELOW, sub_val, sup_val); + result = eagle_eco_api_constrain_threshold(x, threshold, EAGLE_ECO_THRESHOLD_MODE_BELOW, sub_val, sup_val); TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, 5.0f, result, "Failed when x == threshold (BELOW mode)"); /* test invalid mode fallback */ x = 7.0f; threshold = 5.0f; - result = common_api_constrain_threshold(x, threshold, (enum common_threshold_mode)999, sub_val, sup_val); + result = eagle_eco_api_constrain_threshold(x, threshold, (enum eagle_eco_threshold_mode)999, sub_val, sup_val); TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, 7.0f, result, "Failed invalid mode fallback"); } int main() { UNITY_BEGIN(); - RUN_TEST(test_common_api_min); - RUN_TEST(test_common_api_max); - RUN_TEST(test_common_api_clamp); - RUN_TEST(test_common_api_mapf); - RUN_TEST(test_common_api_normalize); - RUN_TEST(test_common_api_constrain_deadband); - RUN_TEST(test_common_api_constrain_threshold); + RUN_TEST(test_eagle_eco_api_min); + RUN_TEST(test_eagle_eco_api_max); + RUN_TEST(test_eagle_eco_api_clamp); + RUN_TEST(test_eagle_eco_api_mapf); + RUN_TEST(test_eagle_eco_api_normalize); + RUN_TEST(test_eagle_eco_api_constrain_deadband); + RUN_TEST(test_eagle_eco_api_constrain_threshold); UNITY_END(); } \ No newline at end of file From 2c993c5f278132bb8f61afe40dd6c2033fb42a54 Mon Sep 17 00:00:00 2001 From: Dorijan Di Zepp Date: Thu, 6 Nov 2025 23:30:38 +0100 Subject: [PATCH 5/8] feat: add bit operation, new unit test #1 --- README.md | 19 +- examples/example.c | 101 +++-- include/eagle-eco.h | 25 -- include/{eagle-eco-api.h => eagletrt-api.h} | 73 ++-- include/eagletrt.h | 38 ++ library.json | 10 +- src/eagle-eco-api.c | 45 -- src/eagletrt-api.c | 67 +++ test/test-eagle-eco.c | 372 ---------------- test/test-eagletrt.c | 444 ++++++++++++++++++++ 10 files changed, 668 insertions(+), 526 deletions(-) delete mode 100644 include/eagle-eco.h rename include/{eagle-eco-api.h => eagletrt-api.h} (57%) create mode 100644 include/eagletrt.h delete mode 100644 src/eagle-eco-api.c create mode 100644 src/eagletrt-api.c delete mode 100644 test/test-eagle-eco.c create mode 100644 test/test-eagletrt.c diff --git a/README.md b/README.md index f981948..c807486 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,14 @@ -# LibEagleECO +# LIBEAGLETRT This library provides a set of general purpose utility functions commonly used across embedded software projects. ## Usage To use the library, simply include the main header file: ```c -#include "eagle-eco-api.h" +#include "eagletrt-api.h" ``` >[!NOTE] > No other dependencies are required in order to work with this library. -The functions provided are: -- min & max -- clamp -- map -- deadband constraint -- threshold constraint - >[!NOTE] > This library is intentionally minimal.\ > Its purpose is to provide only the most common and essential utilities shared across all embedded projects.\ @@ -27,16 +20,16 @@ A complete usage can be found in this [example](./examples/example.c). Example snippet: ```c -#include "eagle-eco-api.h" +#include "eagletrt-api.h" #include int main(void) { - printf("max(5, -1) = %d\n", eagle_eco_api_max(5, -1)); + printf("max(5, -1) = %d\n", EAGLETRT_API_MAX(5, -1)); // will print 5 printf("normalize(25.0, 0.0–100.0) = %.2f\n", - eagle_eco_api_normalize(25.0f, 0.0f, 100.0f)); - //will print 0.25 + eagletrt_api_normalize(25.0f, 0.0f, 100.0f)); + // will print 0.25 return 0; } diff --git a/examples/example.c b/examples/example.c index 766d484..4cad783 100644 --- a/examples/example.c +++ b/examples/example.c @@ -2,54 +2,93 @@ * \file example.c * \brief Example usage of the Common library. * \author Dorijan Di Zepp [dorijan.dizepp@eagletrt.it] - * \date 2025-11-02 + * \date 2025-11-06 */ #include +#include #include -#include "eagle-eco-api.h" +#include +#include "eagletrt-api.h" + +/* Example condition function for bit operation */ +static bool example_condition_true(const void *ctx) { + EAGLETRT_UNUSED(ctx); + return true; +} + +static bool example_condition_threshold(const void *ctx) { + const float *value = (const float *)ctx; + return (*value > 0.5f); /* toggle only if above 0.5 */ +} int main(void) { + /* NOP / UNUSED */ + int z = 5, w = 7, unused = 1; + EAGLETRT_UNUSED(unused); + if (z > w) { + EAGLETRT_NOP(); + } else { + EAGLETRT_NOP(); + } - /* min / max / clamp */ + /* MIN / MAX / CLAMP */ int a = 5, b = -1; - printf("min(%d, %d) = %d\n", a, b, EAGLE_ECO_API_MIN(a, b)); - printf("max(%d, %d) = %d\n", a, b, EAGLE_ECO_API_MAX(a, b)); + printf("[MIN/MAX/CLAMP]\n"); + printf(" min(%d, %d) = %d\n", a, b, EAGLETRT_API_MIN(a, b)); + printf(" max(%d, %d) = %d\n", a, b, EAGLETRT_API_MAX(a, b)); int value = 15; - printf("clamp(%d, 0, 10) = %d\n", value, EAGLE_ECO_API_CLAMP(value, 0, 10)); + printf(" clamp(%d, 0, 10) = %d\n\n", value, EAGLETRT_API_CLAMP(value, 0, 10)); - /* mapf */ - float x = 5.0f; - float in_min = 0.0f, in_max = 10.0f; - float out_min = 0.0f, out_max = 100.0f; - float mapped = eagle_eco_api_mapf(x, in_min, in_max, out_min, out_max); - printf("mapf(%.2f, %.2f-%.2f > %.2f-%.2f) = %.2f\n", x, in_min, in_max, out_min, out_max, mapped); + /* BIT OPERATION */ + printf("[BIT OPERATION]\n"); + uint8_t reg = 0b00001010; /* initial value = 10 (bit3=1, bit1=1) */ + printf(" Initial value: 0x%02X\n", reg); - /* normalize */ - float normalized = eagle_eco_api_normalize(25.0f, 0.0f, 100.0f); - printf("normalize(25.0, 0.0-100.0) = %.2f\n", normalized); + /* SET bit 0 */ + eagletrt_api_bit_operation(®, sizeof(reg), 0, EAGLETRT_BIT_OPERATION_SET, NULL, NULL); + printf(" After SET bit 0 -> 0x%02X\n", reg); - /* constrain deadband */ - float val = 0.05f; - float deadband = 0.1f; - float adjusted = eagle_eco_api_constrain_deadband(val, deadband); - printf("constrain_deadband(%.2f, %.2f) = %.2f\n", val, deadband, adjusted); + /* RESET bit 3 */ + eagletrt_api_bit_operation(®, sizeof(reg), 3, EAGLETRT_BIT_OPERATION_RESET, NULL, NULL); + printf(" After RESET bit 3 -> 0x%02X\n", reg); - val = 0.25f; - adjusted = eagle_eco_api_constrain_deadband(val, deadband); - printf("constrain_deadband(%.2f, %.2f) = %.2f\n", val, deadband, adjusted); + /* TOGGLE bit 1 */ + eagletrt_api_bit_operation(®, sizeof(reg), 1, EAGLETRT_BIT_OPERATION_TOGGLE, NULL, NULL); + printf(" After TOGGLE bit 1 -> 0x%02X\n", reg); - /* constrain threshold */ - float threshold = 5.0f; - float sub_threshold_value = -1.0f; - float sup_threshold_value = 99.0f; + /* TOGGLE_IF using a true condition */ + eagletrt_api_bit_operation(®, sizeof(reg), 2, EAGLETRT_BIT_OPERATION_TOGGLE_IF, example_condition_true, NULL); + printf(" After TOGGLE_IF (always true) bit 2 -> 0x%02X\n", reg); - float t1 = eagle_eco_api_constrain_threshold(3.0f, threshold, EAGLE_ECO_THRESHOLD_MODE_ABOVE, sub_threshold_value, sup_threshold_value); - float t2 = eagle_eco_api_constrain_threshold(8.0f, threshold, EAGLE_ECO_THRESHOLD_MODE_BELOW, sub_threshold_value, sup_threshold_value); + /* TOGGLE_IF using a contextual condition */ + float threshold_value = 0.3f; + eagletrt_api_bit_operation(®, sizeof(reg), 7, EAGLETRT_BIT_OPERATION_TOGGLE_IF, example_condition_threshold, &threshold_value); + printf(" After TOGGLE_IF (threshold=0.3f) bit 7 -> 0x%02X\n", reg); + + threshold_value = 0.8f; + eagletrt_api_bit_operation(®, sizeof(reg), 7, EAGLETRT_BIT_OPERATION_TOGGLE_IF, example_condition_threshold, &threshold_value); + printf(" After TOGGLE_IF (threshold=0.8f) bit 7 -> 0x%02X\n\n", reg); + + /* MAPF */ + printf("[MAPF]\n"); + float x = 5.0f; + float in_min = 0.0f, in_max = 10.0f; + float out_min = 0.0f, out_max = 100.0f; + float mapped = eagletrt_api_mapf(x, in_min, in_max, out_min, out_max); + printf(" mapf(%.2f, %.2f-%.2f -> %.2f-%.2f) = %.2f\n\n", + x, + in_min, + in_max, + out_min, + out_max, + mapped); - printf("constrain_threshold(3.0, ABOVE, thr=%.1f) = %.2f\n", threshold, t1); - printf("constrain_threshold(8.0, BELOW, thr=%.1f) = %.2f\n", threshold, t2); + /* NORMALIZE */ + printf("[NORMALIZE]\n"); + float normalized = eagletrt_api_normalize(25.0f, 0.0f, 100.0f); + printf(" normalize(25.0, 0.0-100.0) = %.2f\n\n", normalized); return 0; } \ No newline at end of file diff --git a/include/eagle-eco.h b/include/eagle-eco.h deleted file mode 100644 index 1eca85e..0000000 --- a/include/eagle-eco.h +++ /dev/null @@ -1,25 +0,0 @@ -/*! - * \file eagle-eco.h - * \date 2025-10-27 - * \authors Dorijan Di Zepp [dorijan.dizepp@eagletrt.it] - * - * \brief A simple library providing a set of common utilities for all embedded projects. - * - * \details This library provides a set of functions that are often needed in most embedded proejects. - * This helps in reducing developing time and maintain consistency across multiple projects. - */ - -#ifndef EAGLE_ECO_H -#define EAGLE_ECO_H - -/*! - * \brief Threshold mode for eagle_eco_api_constrain_threshold function. - * - * These modes indicate if the input value must be above or below the threshold - */ -enum eagle_eco_threshold_mode { - EAGLE_ECO_THRESHOLD_MODE_ABOVE, - EAGLE_ECO_THRESHOLD_MODE_BELOW -}; - -#endif /*! EAGLE_ECO_H */ \ No newline at end of file diff --git a/include/eagle-eco-api.h b/include/eagletrt-api.h similarity index 57% rename from include/eagle-eco-api.h rename to include/eagletrt-api.h index 9e69508..0ffb3fe 100644 --- a/include/eagle-eco-api.h +++ b/include/eagletrt-api.h @@ -1,6 +1,6 @@ /*! - * \file eagle-eco-api.h - * \date 2025-10-27 + * \file eagletrt-api.h + * \date 2025-11-06 * \authors Dorijan Di Zepp [dorijan.dizepp@eagletrt.it] * * \brief A simple library providing a set of common utilities for all embedded projects. @@ -9,11 +9,25 @@ * This helps in reducing developing time and maintain consistency across multiple projects. */ -#ifndef EAGLE_ECO_API_H -#define EAGLE_ECO_API_H +#ifndef EAGLETRT_API_H +#define EAGLETRT_API_H #include -#include "eagle-eco.h" +#include +#include +#include "eagletrt.h" + +/*! + * \brief A placeholder that has no side effects but is valid + * wherever a statement is expected. + */ +#define EAGLETRT_NOP() ((void)(0U)) + +/*! + * \brief Marks a variable or parameter as intentionally + * unused, to silence compiler warnings + */ +#define EAGLETRT_UNUSED(_) ((void)(_)) /*! * \brief Return the smaller of two values. @@ -22,7 +36,7 @@ * \param[in] b: Second value to compare. * \return The smaller of the two input values. */ -#define EAGLE_ECO_API_MIN(a, b) ((a) < (b) ? (a) : (b)) +#define EAGLETRT_API_MIN(a, b) ((a) < (b) ? (a) : (b)) /*! * \brief Return the larger of two values. @@ -31,7 +45,7 @@ * \param[in] b: Second value to compare. * \return The larger of the two input values. */ -#define EAGLE_ECO_API_MAX(a, b) ((a) > (b) ? (a) : (b)) +#define EAGLETRT_API_MAX(a, b) ((a) > (b) ? (a) : (b)) /*! * \brief Clamp a value between a lower and upper limit. @@ -41,7 +55,20 @@ * \param[in] high: Maximum allowable value. * \return The clamped value, within the [low, high] range. */ -#define EAGLE_ECO_API_CLAMP(x, l, h) (EAGLE_ECO_API_MAX(EAGLE_ECO_API_MIN((x), (h)), (l))) +#define EAGLETRT_API_CLAMP(x, l, h) (EAGLETRT_API_MAX(EAGLETRT_API_MIN((x), (h)), (l))) + +/*! + * \brief Operate on a specified bit of a value passed based on the operation to complete + * + * \param[in] val: The value to be read + * \param[in] val_size: Size of the pointed value in bytes + * \param[in] bit: The bit position to be modified + * \param[in] operation: Which operation has to be performed in the indicated bit (set, reset, toggle, ...) + * \param[in] condition: If an operation requires it, a condition has to be specified whether a bit has to be modified or not + * \param[in] context: Optional user context passed to the condition function. + * \return A boolean value indicating whether the operation has been completed successfully or not. + */ +bool eagletrt_api_bit_operation(void * val, size_t val_size, uint64_t bit, enum EagleTrtBitOperation operation, bool (*condition)(const void *context), const void *context); /*! * \brief Map a value from one range to another. @@ -59,7 +86,7 @@ * Ensure that x lies within [in_min, in_max] to avoid * output values falling outside [out_min, out_max]. */ -float eagle_eco_api_mapf(float x, float in_min, float in_max, float out_min, float out_max); +float eagletrt_api_mapf(float x, float in_min, float in_max, float out_min, float out_max); /*! * \brief Normalize a value within a given range to [0, 1]. @@ -75,30 +102,6 @@ float eagle_eco_api_mapf(float x, float in_min, float in_max, float out_min, flo * The caller must ensure that x lies within [in_min, in_max], * otherwise the returned normalized value may be outside the [0.0f, 1.0f] range. */ -float eagle_eco_api_normalize(float x, float in_min, float in_max); - -/*! - * \brief Apply a deadband to a value. - * - * \param[in] x: Input value. - * \param[in] deadband: Deadband threshold (values within ±deadband become 0). - * \return 0 if |x| < deadband, otherwise x. - */ -float eagle_eco_api_constrain_deadband(float x, float deadband); - -/*! - * \brief Constrain a value based on a threshold condition. - * - * \param[in] x: Input value. - * \param[in] threshold: Threshold limit to be enforced. - * \param[in] mode: - * - EAGLE_ECO_THRESHOLD_ABOVE, x must be above threshold, otherwise return sub_threshold_value. - * - EAGLE_ECO_THRESHOLD_BELOW, x must be below threshold, otherwise return sup_threshold_value. - * \param[in] sub_threshold_value: Value returned if x is below threshold when EAGLE_ECO_THRESHOLD_ABOVE. - * \param[in] sup_threshold_value: Value returned if x is above threshold when EAGLE_ECO_THRESHOLD_BELOW. - * - * \return The constrained or fallback value, depending on the condition. - */ -float eagle_eco_api_constrain_threshold(float x, float threshold, enum eagle_eco_threshold_mode mode, float sub_threshold_value, float sup_threshold_value); +float eagletrt_api_normalize(float x, float in_min, float in_max); -#endif /*! EAGLE_ECO_API_H */ \ No newline at end of file +#endif /*! EAGLETRT_API_H */ \ No newline at end of file diff --git a/include/eagletrt.h b/include/eagletrt.h new file mode 100644 index 0000000..4e8915b --- /dev/null +++ b/include/eagletrt.h @@ -0,0 +1,38 @@ +/*! + * \file eagletrt.h + * \date 2025-11-06 + * \authors Dorijan Di Zepp [dorijan.dizepp@eagletrt.it] + * + * \brief A simple library providing a set of common utilities for all embedded projects. + * + * \details This library provides a set of functions that are often needed in most embedded proejects. + * This helps in reducing developing time and maintain consistency across multiple projects. + */ + +#ifndef EAGLETRT_H +#define EAGLETRT_H + +#ifndef EAGLETRT_STATIC +#define EAGLETRT_STATIC static +#endif /* EAGLETRT_STATIC */ + +#ifndef EAGLETRT_STATIC_INLINE +#define EAGLETRT_STATIC_INLINE +#endif /* EAGLETRT_STATIC_INLINE */ + +#ifndef EAGLETRT_VOLATILE +#define EAGLETRT_VOLATILE +#endif /* EAGLETRT_VOLATILE */ + +/*! + * \brief The operation to be executed on a specified bit + */ +enum EagleTrtBitOperation { + EAGLETRT_BIT_OPERATION_GET, + EAGLETRT_BIT_OPERATION_SET, + EAGLETRT_BIT_OPERATION_RESET, + EAGLETRT_BIT_OPERATION_TOGGLE, + EAGLETRT_BIT_OPERATION_TOGGLE_IF, +}; + +#endif /*! EAGLETRT_H */ \ No newline at end of file diff --git a/library.json b/library.json index 6bc2310..b722582 100644 --- a/library.json +++ b/library.json @@ -1,8 +1,8 @@ { "$schema": "https://raw.githubusercontent.com/platformio/platformio-core/develop/platformio/assets/schema/library.json", - "name": "LibEagleECO", + "name": "LibEagleTrt", "version": "0.1.0", - "description": "ECO [Embedded Common Objects], a simple library providing a set of common utilities for all embedded projects.", + "description": "A simple library providing a set of common utilities for all embedded projects.", "keywords": [ "embedded", "common", @@ -12,7 +12,7 @@ ], "repository": { "type": "git", - "url": "https://github.com/eagletrt/libeagleeco-sw.git" + "url": "https://github.com/eagletrt/libeagletrt-sw.git" }, "authors": [ { @@ -25,8 +25,8 @@ "frameworks": "*", "platforms": "*", "headers": [ - "eagle-eco.h", - "eagle-eco-api.h" + "eagletrt.h", + "eagletrt-api.h" ], "examples": [ { diff --git a/src/eagle-eco-api.c b/src/eagle-eco-api.c deleted file mode 100644 index ae16b46..0000000 --- a/src/eagle-eco-api.c +++ /dev/null @@ -1,45 +0,0 @@ -/*! - * \file eagle-eco-api.c - * \date 2025-10-27 - * \authors Dorijan Di Zepp [dorijan.dizepp@eagletrt.it] - * - * \brief A simple library providing a set of common utilities for all embedded projects. - * - * \details This library provides a set of functions that are often needed in most embedded proejects. - * This helps in reducing developing time and maintain consistency across multiple projects. - */ - -#include "eagle-eco-api.h" -#include - -float eagle_eco_api_mapf(float x, float in_min, float in_max, float out_min, float out_max) { - return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; -} - -float eagle_eco_api_normalize(float x, float in_min, float in_max) { - if (in_max == in_min) { - return 0.0f; - } - return (x - in_min) / (in_max - in_min); -} - -float eagle_eco_api_constrain_deadband(float x, float deadband) { - if (fabs(x) >= deadband) { - return x; - } else { - return 0.0f; - } -} - -float eagle_eco_api_constrain_threshold(float x, float threshold, enum eagle_eco_threshold_mode mode, float sub_threshold_value, float sup_threshold_value) { - switch (mode) { - case EAGLE_ECO_THRESHOLD_MODE_ABOVE: - return (x >= threshold) ? x : sub_threshold_value; - - case EAGLE_ECO_THRESHOLD_MODE_BELOW: - return (x <= threshold) ? x : sup_threshold_value; - - default: - return x; // should never happen, fallback return - } -} \ No newline at end of file diff --git a/src/eagletrt-api.c b/src/eagletrt-api.c new file mode 100644 index 0000000..b0f4baf --- /dev/null +++ b/src/eagletrt-api.c @@ -0,0 +1,67 @@ +/*! + * \file eagletrt-api.c + * \date 2025-11-06 + * \authors Dorijan Di Zepp [dorijan.dizepp@eagletrt.it] + * + * \brief A simple library providing a set of common utilities for all embedded projects. + * + * \details This library provides a set of functions that are often needed in most embedded proejects. + * This helps in reducing developing time and maintain consistency across multiple projects. + */ + +#include +#include "eagletrt-api.h" + +bool eagletrt_api_bit_operation(void *val, size_t val_size, uint64_t bit, enum EagleTrtBitOperation operation, bool (*condition)(const void *context), const void *context) { + if (!val || val_size == 0) + return false; // invalid input + + uint64_t max_bits = val_size * 8ULL; + if (bit >= max_bits) + return false; // invalid bit index + + if (operation == EAGLETRT_BIT_OPERATION_TOGGLE_IF && !condition) + return false; // the condition function is not defined + + uint8_t *bytes = (uint8_t *)val; + size_t byte_index = bit / 8; + uint8_t bit_mask = (1U << (bit % 8)); + + switch (operation) { + case EAGLETRT_BIT_OPERATION_GET: + return (bytes[byte_index] & bit_mask) != 0; + + case EAGLETRT_BIT_OPERATION_SET: + bytes[byte_index] |= bit_mask; + break; + + case EAGLETRT_BIT_OPERATION_RESET: + bytes[byte_index] &= ~bit_mask; + break; + + case EAGLETRT_BIT_OPERATION_TOGGLE: + bytes[byte_index] ^= bit_mask; + break; + + case EAGLETRT_BIT_OPERATION_TOGGLE_IF: + if (condition(context)) + bytes[byte_index] ^= bit_mask; + break; + + default: + return false; + } + + return true; +} + +float eagletrt_api_mapf(float x, float in_min, float in_max, float out_min, float out_max) { + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; +} + +float eagletrt_api_normalize(float x, float in_min, float in_max) { + if (in_max == in_min) { + return 0.0f; + } + return (x - in_min) / (in_max - in_min); +} \ No newline at end of file diff --git a/test/test-eagle-eco.c b/test/test-eagle-eco.c deleted file mode 100644 index f349ed2..0000000 --- a/test/test-eagle-eco.c +++ /dev/null @@ -1,372 +0,0 @@ -/** - * @file test-eagle-eco.c - * @brief Test suite for eagle-eco-api.c file - * - * @author Dorijan Di Zepp [dorijan.dizepp@eagletrt.it] - * @date 2025-11-02 - */ - -#include "unity.h" -#include "eagle-eco-api.h" -#include - -void test_eagle_eco_api_min() { - float a, b; - - /* test with both values positives */ - a = 1; - b = 10; - TEST_ASSERT_EQUAL_MESSAGE(a, EAGLE_ECO_API_MIN(a, b), "Failed with both values positive"); - - a = 10; - b = 7; - TEST_ASSERT_EQUAL_MESSAGE(b, EAGLE_ECO_API_MIN(a, b), "Failed with both values positive"); - - /* test with both values negatives */ - a = -10; - b = -7; - TEST_ASSERT_EQUAL_MESSAGE(a, EAGLE_ECO_API_MIN(a, b), "Failed with both values negative"); - - a = -0.5f; - b = -3.14f; - TEST_ASSERT_EQUAL_MESSAGE(b, EAGLE_ECO_API_MIN(a, b), "Failed with both values negative"); - - /* test with one positive and one negative */ - a = -0.75f; - b = sqrt(2); - TEST_ASSERT_EQUAL_MESSAGE(a, EAGLE_ECO_API_MIN(a, b), "Failed with a positive and negative value"); - - a = 12.75f; - b = -sqrt(2); - TEST_ASSERT_EQUAL_MESSAGE(b, EAGLE_ECO_API_MIN(a, b), "Failed with a positive and negative value"); - - /* test with same value*/ - a = b = 3; - TEST_ASSERT_EQUAL_MESSAGE(b, EAGLE_ECO_API_MIN(a, b), "Failed with same positive value"); - - a = b = -cos(12); - TEST_ASSERT_EQUAL_MESSAGE(b, EAGLE_ECO_API_MIN(a, b), "Failed with same negative value"); -} - -void test_eagle_eco_api_max() { - float a, b; - - /* test with both values positives */ - a = 10; - b = 1; - TEST_ASSERT_EQUAL_MESSAGE(a, EAGLE_ECO_API_MAX(a, b), "Failed with both values positive"); - - a = 5.34f; - b = 10; - TEST_ASSERT_EQUAL_MESSAGE(b, EAGLE_ECO_API_MAX(a, b), "Failed with both values positive"); - - /* test with both values negatives */ - a = -7; - b = -10; - TEST_ASSERT_EQUAL_MESSAGE(a, EAGLE_ECO_API_MAX(a, b), "Failed with both values negative"); - - a = -3.14f; - b = -0.15f; - TEST_ASSERT_EQUAL_MESSAGE(b, EAGLE_ECO_API_MAX(a, b), "Failed with both values negative"); - - /* test with one positive and one negative */ - a = sqrt(2); - b = -0.75f; - TEST_ASSERT_EQUAL_MESSAGE(a, EAGLE_ECO_API_MAX(a, b), "Failed with a positive and negative value"); - - a = -sqrt(2); - b = 12.75f; - TEST_ASSERT_EQUAL_MESSAGE(b, EAGLE_ECO_API_MAX(a, b), "Failed with a positive and negative value"); - - /* test with same value*/ - a = b = 3; - TEST_ASSERT_EQUAL_MESSAGE(b, EAGLE_ECO_API_MAX(a, b), "Failed with same positive value"); - - a = b = -cos(12); - TEST_ASSERT_EQUAL_MESSAGE(b, EAGLE_ECO_API_MAX(a, b), "Failed with same negative value"); -} - -void test_eagle_eco_api_clamp() { - float x, low, high; - - /* test with x in a positive range */ - x = 5; - low = 0; - high = 10; - TEST_ASSERT_EQUAL_MESSAGE(x, EAGLE_ECO_API_CLAMP(x, low, high), "Failed with positive range"); - - /* test with x in a negative range */ - x = -5; - low = -10; - high = 0; - TEST_ASSERT_EQUAL_MESSAGE(x, EAGLE_ECO_API_CLAMP(x, low, high), "Failed with negative range"); - - /* test with x in a negative/positive range */ - x = 5; - low = -3.15f; - high = 5.14f; - TEST_ASSERT_EQUAL_MESSAGE(x, EAGLE_ECO_API_CLAMP(x, low, high), "Failed with negative/positive range"); - - /* test with x not in range */ - x = 5; - low = 0; - high = 4; - TEST_ASSERT_EQUAL_MESSAGE(high, EAGLE_ECO_API_CLAMP(x, low, high), "Failed to clamp on higher range"); - - x = -2; - low = 0.3f; - high = 4; - TEST_ASSERT_EQUAL_MESSAGE(low, EAGLE_ECO_API_CLAMP(x, low, high), "Failed to clamp on lower range"); - - /* test with x on range limit*/ - x = 0.3f; - low = 0.3f; - high = 4; - TEST_ASSERT_EQUAL_MESSAGE(x, EAGLE_ECO_API_CLAMP(x, low, high), "Failed with x equal to lower range limit"); - - x = 4; - low = 0.3f; - high = 4; - TEST_ASSERT_EQUAL_MESSAGE(x, EAGLE_ECO_API_CLAMP(x, low, high), "Failed with x equal to higher range limit"); -} - -void test_eagle_eco_api_mapf() { - float x, in_min, in_max, out_min, out_max; - - /* test with positive range */ - x = 5.0f; - in_min = 0.0f, in_max = 10.0f; - out_min = 0.0f, out_max = 100.0f; - float result = eagle_eco_api_mapf(x, in_min, in_max, out_min, out_max); - TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 50.0f, result, "Failed with positive range"); - - /* test with negative input range */ - x = -5.0f; - in_min = -10.0f; - in_max = 0.0f; - out_min = 0.0f; - out_max = 100.0f; - result = eagle_eco_api_mapf(x, in_min, in_max, out_min, out_max); - TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 50.0f, result, "Failed with negative input range"); - - /* test with reversed output range */ - x = 2.5f; - in_min = 0.0f; - in_max = 5.0f; - out_min = 100.0f; - out_max = 0.0f; - result = eagle_eco_api_mapf(x, in_min, in_max, out_min, out_max); - TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 50.0f, result, "Failed with reversed output range"); - - /* test with input value outside range (no clamping) */ - x = 15.0f; - in_min = 0.0f; - in_max = 10.0f; - out_min = 0.0f; - out_max = 100.0f; - result = eagle_eco_api_mapf(x, in_min, in_max, out_min, out_max); - TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 150.0f, result, "Failed with value above input range"); - - /* test with identical input and output ranges (identity mapping) */ - x = 3.5f; - in_min = 0.0f; - in_max = 10.0f; - out_min = 0.0f; - out_max = 10.0f; - result = eagle_eco_api_mapf(x, in_min, in_max, out_min, out_max); - TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 3.5f, result, "Failed with identical ranges"); - - /* test with zero-length input range (division by zero case) */ - x = 5.0f; - in_min = 1.0f; - in_max = 1.0f; - out_min = 0.0f; - out_max = 10.0f; - result = eagle_eco_api_mapf(x, in_min, in_max, out_min, out_max); - TEST_ASSERT_TRUE_MESSAGE(isinf(result), "Failed to handle zero input range correctly"); -} - -void test_eagle_eco_api_normalize() { - float x, in_min, in_max, result; - - /* test with positive range */ - x = 5.0f; - in_min = 0.0f; - in_max = 10.0f; - result = eagle_eco_api_normalize(x, in_min, in_max); - TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 0.5f, result, "Failed with positive range"); - - /* test with negative range */ - x = -5.0f; - in_min = -10.0f; - in_max = 0.0f; - result = eagle_eco_api_normalize(x, in_min, in_max); - TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 0.5f, result, "Failed with negative input range"); - - /* test with reversed input range */ - x = 2.5f; - in_min = 5.0f; - in_max = 0.0f; - result = eagle_eco_api_normalize(x, in_min, in_max); - TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 0.5f, result, "Failed with reversed input range"); - - /* test with input value below range */ - x = -5.0f; - in_min = 0.0f; - in_max = 10.0f; - result = eagle_eco_api_normalize(x, in_min, in_max); - TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, -0.5f, result, "Failed with value below input range"); - - /* test with input value above range */ - x = 15.0f; - in_min = 0.0f; - in_max = 10.0f; - result = eagle_eco_api_normalize(x, in_min, in_max); - TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 1.5f, result, "Failed with value above input range"); - - /* test with identical input bounds (zero-length range) */ - x = 5.0f; - in_min = 1.0f; - in_max = 1.0f; - result = eagle_eco_api_normalize(x, in_min, in_max); - TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 0.0f, result, "Failed to handle zero input range correctly"); - - /* test with input at minimum boundary */ - x = 0.0f; - in_min = 0.0f; - in_max = 10.0f; - result = eagle_eco_api_normalize(x, in_min, in_max); - TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 0.0f, result, "Failed with input at minimum boundary"); - - /* test with input at maximum boundary */ - x = 10.0f; - in_min = 0.0f; - in_max = 10.0f; - result = eagle_eco_api_normalize(x, in_min, in_max); - TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 1.0f, result, "Failed with input at maximum boundary"); -} - -void test_eagle_eco_api_constrain_deadband() { - float x, deadband, result; - - /* test with value within positive deadband range */ - x = 0.05f; - deadband = 0.1f; - result = eagle_eco_api_constrain_deadband(x, deadband); - TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, 0.0f, result, "Failed when value within positive deadband"); - - /* test with value within negative deadband range */ - x = -0.05f; - deadband = 0.1f; - result = eagle_eco_api_constrain_deadband(x, deadband); - TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, 0.0f, result, "Failed when value within negative deadband"); - - /* test with value above deadband */ - x = 0.2f; - deadband = 0.1f; - result = eagle_eco_api_constrain_deadband(x, deadband); - TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, 0.2f, result, "Failed when value above positive deadband"); - - /* test with value below negative deadband */ - x = -0.2f; - deadband = 0.1f; - result = eagle_eco_api_constrain_deadband(x, deadband); - TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, -0.2f, result, "Failed when value below negative deadband"); - - /* test with value exactly equal to positive deadband */ - x = 0.1f; - deadband = 0.1f; - result = eagle_eco_api_constrain_deadband(x, deadband); - TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, 0.1f, result, "Failed when value equals positive deadband"); - - /* test with value exactly equal to negative deadband */ - x = -0.1f; - deadband = 0.1f; - result = eagle_eco_api_constrain_deadband(x, deadband); - TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, -0.1f, result, "Failed when value equals negative deadband"); - - /* test with zero input */ - x = 0.0f; - deadband = 0.1f; - result = eagle_eco_api_constrain_deadband(x, deadband); - TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, 0.0f, result, "Failed when x equals 0"); - - /* test with zero deadband (function acts as pass-through) */ - x = 0.25f; - deadband = 0.0f; - result = eagle_eco_api_constrain_deadband(x, deadband); - TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, 0.25f, result, "Failed when deadband equals 0 (positive)"); - - x = -0.25f; - result = eagle_eco_api_constrain_deadband(x, deadband); - TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, -0.25f, result, "Failed when deadband equals 0 (negative)"); -} - -void test_eagle_eco_api_constrain_threshold() { - float x, threshold, sub_val, sup_val, result; - - /* test that enum values are defined correctly*/ - TEST_ASSERT_EQUAL_INT_MESSAGE(0, EAGLE_ECO_THRESHOLD_MODE_ABOVE, "COMMON_THRESHOLD_ABOVE has different value than expected"); - TEST_ASSERT_EQUAL_INT_MESSAGE(1, EAGLE_ECO_THRESHOLD_MODE_BELOW, "COMMON_THRESHOLD_BELOW has different value than expected"); - - /* test COMMON_THRESHOLD_ABOVE - x above threshold */ - x = 10.0f; - threshold = 5.0f; - sub_val = -1.0f; - sup_val = 99.0f; - result = eagle_eco_api_constrain_threshold(x, threshold, EAGLE_ECO_THRESHOLD_MODE_ABOVE, sub_val, sup_val); - TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, 10.0f, result, "Failed when x > threshold (ABOVE mode)"); - - /* test COMMON_THRESHOLD_ABOVE - x below threshold */ - x = 3.0f; - threshold = 5.0f; - sub_val = -1.0f; - result = eagle_eco_api_constrain_threshold(x, threshold, EAGLE_ECO_THRESHOLD_MODE_ABOVE, sub_val, sup_val); - TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, -1.0f, result, "Failed when x < threshold (ABOVE mode)"); - - /* test COMMON_THRESHOLD_ABOVE - x exactly equal to threshold */ - x = 5.0f; - threshold = 5.0f; - result = eagle_eco_api_constrain_threshold(x, threshold, EAGLE_ECO_THRESHOLD_MODE_ABOVE, sub_val, sup_val); - TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, 5.0f, result, "Failed when x == threshold (ABOVE mode)"); - - /* test COMMON_THRESHOLD_BELOW - x below threshold */ - x = 3.0f; - threshold = 5.0f; - sup_val = 99.0f; - result = eagle_eco_api_constrain_threshold(x, threshold, EAGLE_ECO_THRESHOLD_MODE_BELOW, sub_val, sup_val); - TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, 3.0f, result, "Failed when x < threshold (BELOW mode)"); - - /* test COMMON_THRESHOLD_BELOW - x above threshold */ - x = 8.0f; - threshold = 5.0f; - sup_val = 99.0f; - result = eagle_eco_api_constrain_threshold(x, threshold, EAGLE_ECO_THRESHOLD_MODE_BELOW, sub_val, sup_val); - TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, 99.0f, result, "Failed when x > threshold (BELOW mode)"); - - /* test COMMON_THRESHOLD_BELOW - x exactly equal to threshold */ - x = 5.0f; - threshold = 5.0f; - result = eagle_eco_api_constrain_threshold(x, threshold, EAGLE_ECO_THRESHOLD_MODE_BELOW, sub_val, sup_val); - TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, 5.0f, result, "Failed when x == threshold (BELOW mode)"); - - /* test invalid mode fallback */ - x = 7.0f; - threshold = 5.0f; - result = eagle_eco_api_constrain_threshold(x, threshold, (enum eagle_eco_threshold_mode)999, sub_val, sup_val); - TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.0001f, 7.0f, result, "Failed invalid mode fallback"); -} - -int main() { - UNITY_BEGIN(); - - RUN_TEST(test_eagle_eco_api_min); - RUN_TEST(test_eagle_eco_api_max); - RUN_TEST(test_eagle_eco_api_clamp); - RUN_TEST(test_eagle_eco_api_mapf); - RUN_TEST(test_eagle_eco_api_normalize); - RUN_TEST(test_eagle_eco_api_constrain_deadband); - RUN_TEST(test_eagle_eco_api_constrain_threshold); - - UNITY_END(); -} \ No newline at end of file diff --git a/test/test-eagletrt.c b/test/test-eagletrt.c new file mode 100644 index 0000000..02131a9 --- /dev/null +++ b/test/test-eagletrt.c @@ -0,0 +1,444 @@ +/** + * @file test-eagletrt.c + * @brief Test suite for eagle-eco-api.c file + * + * @author Dorijan Di Zepp [dorijan.dizepp@eagletrt.it] + * @date 2025-11-06 + */ + +#include +#include "unity.h" +#include "eagletrt-api.h" + +/* Example external variable simulating system context */ +static int condition_counter = 0; + +/* Condition function for conditional toggle */ +static bool always_true(const void *ctx) { + EAGLETRT_UNUSED(ctx); + return true; +} +static bool always_false(const void *ctx) { + EAGLETRT_UNUSED(ctx); + return false; +} + +/* Non-trivial condition function: + * returns true only every 3rd call (like a periodic trigger) + */ +static bool toggle_every_third_call(const void *ctx) { + EAGLETRT_UNUSED(ctx); + condition_counter++; + return (condition_counter % 3 == 0); +} + +/* Eagletrt api min */ + +void test_eagletrt_api_min_positive_values(void) { + float a = 1.0f, b = 10.0f; + TEST_ASSERT_EQUAL_FLOAT_MESSAGE(a, EAGLETRT_API_MIN(a, b), "Expected smaller positive value"); +} + +void test_eagletrt_api_min_negative_values(void) { + float a = -10.0f, b = -7.0f; + TEST_ASSERT_EQUAL_FLOAT_MESSAGE(a, EAGLETRT_API_MIN(a, b), "Expected smaller negative value"); +} + +void test_eagletrt_api_min_mixed_sign(void) { + float a = -3.0f, b = 2.0f; + TEST_ASSERT_EQUAL_FLOAT_MESSAGE(a, EAGLETRT_API_MIN(a, b), "Expected negative value when compared to positive"); +} + +void test_eagletrt_api_min_equal_values(void) { + float a = 4.2f, b = 4.2f; + TEST_ASSERT_EQUAL_FLOAT_MESSAGE(a, EAGLETRT_API_MIN(a, b), "Expected same value when both equal"); +} + +void test_eagletrt_api_min_zero_and_positive(void) { + float a = 0.0f, b = 5.0f; + TEST_ASSERT_EQUAL_FLOAT_MESSAGE(a, EAGLETRT_API_MIN(a, b), "Expected zero when compared with positive value"); +} + +void test_eagletrt_api_min_zero_and_negative(void) { + float a = 0.0f, b = -2.5f; + TEST_ASSERT_EQUAL_FLOAT_MESSAGE(b, EAGLETRT_API_MIN(a, b), "Expected negative when compared with zero"); +} + +void test_eagletrt_api_min_infinity_and_finite(void) { + float a = INFINITY, b = 10.0f; + TEST_ASSERT_EQUAL_FLOAT_MESSAGE(b, EAGLETRT_API_MIN(a, b), "Expected finite value when compared with infinity"); +} + +void test_eagletrt_api_min_negative_infinity_and_finite(void) { + float a = -INFINITY, b = 10.0f; + TEST_ASSERT_EQUAL_FLOAT_MESSAGE(a, EAGLETRT_API_MIN(a, b), "Expected -inf to be minimum"); +} + +void test_eagletrt_api_min_nan_and_number(void) { + float a = NAN, b = 2.0f; + float result = EAGLETRT_API_MIN(a, b); + TEST_ASSERT_FALSE_MESSAGE(isnan(result), "Result should not be NaN"); + TEST_ASSERT_EQUAL_FLOAT_MESSAGE(b, result, "Expected valid number when comparing NaN vs finite"); +} + +void test_eagletrt_api_min_unsigned_integers(void) { + uint32_t a = 10U, b = 20U; + TEST_ASSERT_EQUAL_UINT_MESSAGE(a, EAGLETRT_API_MIN(a, b), "Expected smaller unsigned value"); +} + +void test_eagletrt_api_min_mixed_types(void) { + int a = -1; + float b = 1.5f; + TEST_ASSERT_EQUAL_FLOAT_MESSAGE((float)a, EAGLETRT_API_MIN(a, b), "Expected integer negative to be minimum"); +} + +/* ------------------------------------ */ + +/* Eagletrt api max */ + +void test_eagletrt_api_max_positive_values(void) { + float a = 10, b = 1; + TEST_ASSERT_EQUAL_MESSAGE(a, EAGLETRT_API_MAX(a, b), "Failed with both values positive (10, 1)"); + + a = 5.34f; + b = 10; + TEST_ASSERT_EQUAL_MESSAGE(b, EAGLETRT_API_MAX(a, b), "Failed with both values positive (5.34, 10)"); +} + +void test_eagletrt_api_max_negative_values(void) { + float a = -7, b = -10; + TEST_ASSERT_EQUAL_MESSAGE(a, EAGLETRT_API_MAX(a, b), "Failed with both values negative (-7, -10)"); + + a = -3.14f; + b = -0.15f; + TEST_ASSERT_EQUAL_MESSAGE(b, EAGLETRT_API_MAX(a, b), "Failed with both values negative (-3.14, -0.15)"); +} + +void test_eagletrt_api_max_mixed_sign(void) { + float a = sqrtf(2), b = -0.75f; + TEST_ASSERT_EQUAL_MESSAGE(a, EAGLETRT_API_MAX(a, b), "Failed with mixed sign (sqrt(2), -0.75)"); + + a = -sqrtf(2); + b = 12.75f; + TEST_ASSERT_EQUAL_MESSAGE(b, EAGLETRT_API_MAX(a, b), "Failed with mixed sign (-sqrt(2), 12.75)"); +} + +void test_eagletrt_api_max_equal_values(void) { + float a = 3, b = 3; + TEST_ASSERT_EQUAL_MESSAGE(b, EAGLETRT_API_MAX(a, b), "Failed with same positive value (3, 3)"); + + a = b = -cosf(12); + TEST_ASSERT_EQUAL_MESSAGE(b, EAGLETRT_API_MAX(a, b), "Failed with same negative value (-cos(12), -cos(12))"); +} + +void test_eagletrt_api_max_zero_and_positive(void) { + float a = 0.0f, b = 5.0f; + TEST_ASSERT_EQUAL_MESSAGE(b, EAGLETRT_API_MAX(a, b), "Failed with zero and positive value"); +} + +void test_eagletrt_api_max_zero_and_negative(void) { + float a = -5.0f, b = 0.0f; + TEST_ASSERT_EQUAL_MESSAGE(b, EAGLETRT_API_MAX(a, b), "Failed with zero and negative value"); +} + +void test_eagletrt_api_max_infinity_and_finite(void) { + float a = INFINITY, b = 1.0f; + TEST_ASSERT_EQUAL_MESSAGE(a, EAGLETRT_API_MAX(a, b), "Failed with infinity and finite value"); +} + +void test_eagletrt_api_max_negative_infinity_and_finite(void) { + float a = -INFINITY, b = 3.0f; + TEST_ASSERT_EQUAL_MESSAGE(b, EAGLETRT_API_MAX(a, b), "Failed with -infinity and finite value"); +} + +void test_eagletrt_api_max_nan_and_number(void) { + float a = NAN, b = 2.0f; + float result = EAGLETRT_API_MAX(a, b); + TEST_ASSERT_FALSE_MESSAGE(isnan(result), "Result should not be NaN"); + TEST_ASSERT_EQUAL_FLOAT_MESSAGE(b, result, "Expected valid number when comparing NaN vs finite"); +} + +void test_eagletrt_api_max_unsigned_integers(void) { + unsigned int a = 42, b = 99; + TEST_ASSERT_EQUAL_UINT_MESSAGE(b, EAGLETRT_API_MAX(a, b), "Failed with unsigned integers"); +} + +void test_eagletrt_api_max_mixed_types(void) { + int a = -10; + float b = 10.5; + TEST_ASSERT_EQUAL_FLOAT_MESSAGE(b, EAGLETRT_API_MAX(a, b), "Failed with mixed int/double types"); +} + +/* ------------------------------------ */ + +/* Eagletrt api clamp */ + +void test_eagletrt_api_clamp_within_positive_range(void) { + float x = 5, low = 0, high = 10; + TEST_ASSERT_EQUAL_FLOAT_MESSAGE(x, EAGLETRT_API_CLAMP(x, low, high), "Failed: x within positive range should remain unchanged"); +} + +void test_eagletrt_api_clamp_within_negative_range(void) { + float x = -5, low = -10, high = 0; + TEST_ASSERT_EQUAL_FLOAT_MESSAGE(x, EAGLETRT_API_CLAMP(x, low, high), "Failed: x within negative range should remain unchanged"); +} + +void test_eagletrt_api_clamp_within_mixed_range(void) { + float x = 5, low = -3.15f, high = 5.14f; + TEST_ASSERT_EQUAL_FLOAT_MESSAGE(x, EAGLETRT_API_CLAMP(x, low, high), "Failed: x within mixed negative/positive range should remain unchanged"); +} + +void test_eagletrt_api_clamp_above_high(void) { + float x = 5, low = 0, high = 4; + TEST_ASSERT_EQUAL_FLOAT_MESSAGE(high, EAGLETRT_API_CLAMP(x, low, high), "Failed: x above high limit should clamp to high"); +} + +void test_eagletrt_api_clamp_below_low(void) { + float x = -2, low = 0.3f, high = 4; + TEST_ASSERT_EQUAL_FLOAT_MESSAGE(low, EAGLETRT_API_CLAMP(x, low, high), "Failed: x below low limit should clamp to low"); +} + +void test_eagletrt_api_clamp_equal_to_low(void) { + float x = 0.3f, low = 0.3f, high = 4; + TEST_ASSERT_EQUAL_FLOAT_MESSAGE(x, EAGLETRT_API_CLAMP(x, low, high), "Failed: x equal to low limit should remain unchanged"); +} + +void test_eagletrt_api_clamp_equal_to_high(void) { + float x = 4, low = 0.3f, high = 4; + TEST_ASSERT_EQUAL_FLOAT_MESSAGE(x, EAGLETRT_API_CLAMP(x, low, high), "Failed: x equal to high limit should remain unchanged"); +} + +void test_eagletrt_api_clamp_inverted_limits(void) { + float x = 5, low = 10, high = 0; + float result = EAGLETRT_API_CLAMP(x, low, high); + // Behavior depends on macro definition, but you may want to assert consistent result + TEST_ASSERT_TRUE_MESSAGE(result == high || result == low, + "Failed: behavior with inverted limits should be consistent"); +} + +/* ------------------------------------ */ + +/* Eagletrt api bit operation */ + +void test_eagletrt_api_bit_operation_set(void) { + uint8_t test_val = 0x00; + bool result = eagletrt_api_bit_operation(&test_val, sizeof(test_val), 3, EAGLETRT_BIT_OPERATION_SET, NULL, NULL); + TEST_ASSERT_TRUE(result); + TEST_ASSERT_BITS(0x08, 0x08, test_val); // bit 3 set +} + +void test_eagletrt_api_bit_operation_reset(void) { + uint8_t test_val = 0xFF; + bool result = eagletrt_api_bit_operation(&test_val, sizeof(test_val), 3, EAGLETRT_BIT_OPERATION_RESET, NULL, NULL); + TEST_ASSERT_TRUE(result); + TEST_ASSERT_BITS(0x08, 0x00, test_val); // bit 3 cleared +} + +void test_eagletrt_api_bit_operation_toggle(void) { + uint8_t test_val = 0x08; + bool result = eagletrt_api_bit_operation(&test_val, sizeof(test_val), 3, EAGLETRT_BIT_OPERATION_TOGGLE, NULL, NULL); + TEST_ASSERT_TRUE(result); + TEST_ASSERT_BITS(0x08, 0x00, test_val); // bit 3 toggled off +} + +void test_eagletrt_api_bit_operation_toggle_if_true(void) { + uint8_t test_val = 0x00; + bool result = eagletrt_api_bit_operation(&test_val, sizeof(test_val), 1, EAGLETRT_BIT_OPERATION_TOGGLE_IF, always_true, NULL); + TEST_ASSERT_TRUE(result); + TEST_ASSERT_BITS(0x02, 0x02, test_val); // toggled +} + +void test_eagletrt_api_bit_operation_toggle_if_false(void) { + uint8_t test_val = 0x00; + bool result = eagletrt_api_bit_operation(&test_val, sizeof(test_val), 1, EAGLETRT_BIT_OPERATION_TOGGLE_IF, always_false, NULL); + TEST_ASSERT_TRUE(result); // operation completes successfully + TEST_ASSERT_BITS(0x02, 0x00, test_val); // no toggle +} + +void test_eagletrt_api_bit_operation_get(void) { + uint8_t test_val = 0x10; + bool result = eagletrt_api_bit_operation(&test_val, sizeof(test_val), 4, EAGLETRT_BIT_OPERATION_GET, NULL, NULL); + TEST_ASSERT_TRUE(result); // true = bit is set +} + +void test_eagletrt_api_bit_operation_invalid_bit(void) { + uint8_t test_val = 0x00; + bool result = eagletrt_api_bit_operation(&test_val, sizeof(test_val), 64, EAGLETRT_BIT_OPERATION_SET, NULL, NULL); + TEST_ASSERT_FALSE(result); // out of range +} + +void test_eagletrt_api_bit_operation_toggle_if_with_dynamic_condition(void) { + uint32_t val = 0b0001; /* initial value */ + uint32_t expected; + + /* 1st call: counter = 1 no toggle */ + expected = val; + eagletrt_api_bit_operation(&val, sizeof(val), 0, EAGLETRT_BIT_OPERATION_TOGGLE_IF, toggle_every_third_call, NULL); + TEST_ASSERT_EQUAL_UINT32_MESSAGE(expected, val, "Unexpected toggle on 1st call"); + + /* 2nd call: counter = 2 no toggle */ + expected = val; + eagletrt_api_bit_operation(&val, sizeof(val), 0, EAGLETRT_BIT_OPERATION_TOGGLE_IF, toggle_every_third_call, NULL); + TEST_ASSERT_EQUAL_UINT32_MESSAGE(expected, val, "Unexpected toggle on 2nd call"); + + /* 3rd call: counter = 3 should toggle */ + expected = val ^ (1u << 0); + eagletrt_api_bit_operation(&val, sizeof(val), 0, EAGLETRT_BIT_OPERATION_TOGGLE_IF, toggle_every_third_call, NULL); + TEST_ASSERT_EQUAL_UINT32_MESSAGE(expected, val, "Failed to toggle on 3rd call"); + + /* 4th call: counter = 4 no toggle */ + expected = val; + eagletrt_api_bit_operation(&val, sizeof(val), 0, EAGLETRT_BIT_OPERATION_TOGGLE_IF, toggle_every_third_call, NULL); + TEST_ASSERT_EQUAL_UINT32_MESSAGE(expected, val, "Unexpected toggle on 4th call"); +} + +/* ------------------------------------ */ + +/* Eagletrt api mapf */ + +void test_eagletrt_api_mapf_positive_range(void) { + float result = eagletrt_api_mapf(5.0f, 0.0f, 10.0f, 0.0f, 100.0f); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 50.0f, result, "Failed: mapping in positive range"); +} + +void test_eagletrt_api_mapf_negative_input_range(void) { + float result = eagletrt_api_mapf(-5.0f, -10.0f, 0.0f, 0.0f, 100.0f); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 50.0f, result, "Failed: mapping in negative input range"); +} + +void test_eagletrt_api_mapf_reversed_output_range(void) { + float result = eagletrt_api_mapf(2.5f, 0.0f, 5.0f, 100.0f, 0.0f); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 50.0f, result, "Failed: reversed output range"); +} + +void test_eagletrt_api_mapf_value_above_input_range(void) { + float result = eagletrt_api_mapf(15.0f, 0.0f, 10.0f, 0.0f, 100.0f); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 150.0f, result, "Failed: x above input range (no clamping expected)"); +} + +void test_eagletrt_api_mapf_identity_mapping(void) { + float result = eagletrt_api_mapf(3.5f, 0.0f, 10.0f, 0.0f, 10.0f); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 3.5f, result, "Failed: identical input/output range (identity mapping)"); +} + +void test_eagletrt_api_mapf_zero_length_input_range(void) { + float result = eagletrt_api_mapf(5.0f, 1.0f, 1.0f, 0.0f, 10.0f); + TEST_ASSERT_TRUE_MESSAGE(isinf(result), + "Failed: division by zero case not handled (expected inf)"); +} + +/* ------------------------------------ */ + +/* Eagletrt api normalize */ + +void test_eagletrt_api_normalize_positive_range(void) { + float result = eagletrt_api_normalize(5.0f, 0.0f, 10.0f); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 0.5f, result, "Failed: normalize in positive range"); +} + +void test_eagletrt_api_normalize_negative_input_range(void) { + float result = eagletrt_api_normalize(-5.0f, -10.0f, 0.0f); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 0.5f, result, "Failed: normalize in negative input range"); +} + +void test_eagletrt_api_normalize_reversed_input_range(void) { + float result = eagletrt_api_normalize(2.5f, 5.0f, 0.0f); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 0.5f, result, "Failed: reversed input range"); +} + +void test_eagletrt_api_normalize_value_below_range(void) { + float result = eagletrt_api_normalize(-5.0f, 0.0f, 10.0f); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, -0.5f, result, "Failed: x below input range (no clamping expected)"); +} + +void test_eagletrt_api_normalize_value_above_range(void) { + float result = eagletrt_api_normalize(15.0f, 0.0f, 10.0f); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 1.5f, result, "Failed: x above input range (no clamping expected)"); +} + +void test_eagletrt_api_normalize_zero_length_range(void) { + float result = eagletrt_api_normalize(5.0f, 1.0f, 1.0f); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 0.0f, result, "Failed: zero-length input range should return 0.0f"); +} + +void test_eagletrt_api_normalize_minimum_boundary(void) { + float result = eagletrt_api_normalize(0.0f, 0.0f, 10.0f); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 0.0f, result, "Failed: x at minimum boundary"); +} + +void test_eagletrt_api_normalize_maximum_boundary(void) { + float result = eagletrt_api_normalize(10.0f, 0.0f, 10.0f); + TEST_ASSERT_FLOAT_WITHIN_MESSAGE(0.001f, 1.0f, result, "Failed: x at maximum boundary"); +} + +/* ------------------------------------ */ + +int main() { + UNITY_BEGIN(); + + /* Eagletrt api min */ + RUN_TEST(test_eagletrt_api_min_positive_values); + RUN_TEST(test_eagletrt_api_min_negative_values); + RUN_TEST(test_eagletrt_api_min_mixed_sign); + RUN_TEST(test_eagletrt_api_min_equal_values); + RUN_TEST(test_eagletrt_api_min_zero_and_positive); + RUN_TEST(test_eagletrt_api_min_zero_and_negative); + RUN_TEST(test_eagletrt_api_min_infinity_and_finite); + RUN_TEST(test_eagletrt_api_min_negative_infinity_and_finite); + RUN_TEST(test_eagletrt_api_min_nan_and_number); + RUN_TEST(test_eagletrt_api_min_unsigned_integers); + RUN_TEST(test_eagletrt_api_min_mixed_types); + + /* Eagletrt api max */ + RUN_TEST(test_eagletrt_api_max_positive_values); + RUN_TEST(test_eagletrt_api_max_negative_values); + RUN_TEST(test_eagletrt_api_max_mixed_sign); + RUN_TEST(test_eagletrt_api_max_equal_values); + RUN_TEST(test_eagletrt_api_max_zero_and_positive); + RUN_TEST(test_eagletrt_api_max_zero_and_negative); + RUN_TEST(test_eagletrt_api_max_infinity_and_finite); + RUN_TEST(test_eagletrt_api_max_negative_infinity_and_finite); + RUN_TEST(test_eagletrt_api_max_nan_and_number); + RUN_TEST(test_eagletrt_api_max_unsigned_integers); + RUN_TEST(test_eagletrt_api_max_mixed_types); + + /* Eagletrt api clamp */ + RUN_TEST(test_eagletrt_api_clamp_within_positive_range); + RUN_TEST(test_eagletrt_api_clamp_within_negative_range); + RUN_TEST(test_eagletrt_api_clamp_within_mixed_range); + RUN_TEST(test_eagletrt_api_clamp_above_high); + RUN_TEST(test_eagletrt_api_clamp_below_low); + RUN_TEST(test_eagletrt_api_clamp_equal_to_low); + RUN_TEST(test_eagletrt_api_clamp_equal_to_high); + RUN_TEST(test_eagletrt_api_clamp_inverted_limits); + + /* Eagletrt api bit operation */ + RUN_TEST(test_eagletrt_api_bit_operation_set); + RUN_TEST(test_eagletrt_api_bit_operation_reset); + RUN_TEST(test_eagletrt_api_bit_operation_toggle); + RUN_TEST(test_eagletrt_api_bit_operation_toggle_if_true); + RUN_TEST(test_eagletrt_api_bit_operation_toggle_if_false); + RUN_TEST(test_eagletrt_api_bit_operation_get); + RUN_TEST(test_eagletrt_api_bit_operation_invalid_bit); + RUN_TEST(test_eagletrt_api_bit_operation_toggle_if_with_dynamic_condition); + + /* Eagletrt api mapf */ + RUN_TEST(test_eagletrt_api_mapf_positive_range); + RUN_TEST(test_eagletrt_api_mapf_negative_input_range); + RUN_TEST(test_eagletrt_api_mapf_reversed_output_range); + RUN_TEST(test_eagletrt_api_mapf_value_above_input_range); + RUN_TEST(test_eagletrt_api_mapf_identity_mapping); + RUN_TEST(test_eagletrt_api_mapf_zero_length_input_range); + + /* Eagletrt api normalize */ + RUN_TEST(test_eagletrt_api_normalize_positive_range); + RUN_TEST(test_eagletrt_api_normalize_negative_input_range); + RUN_TEST(test_eagletrt_api_normalize_reversed_input_range); + RUN_TEST(test_eagletrt_api_normalize_value_below_range); + RUN_TEST(test_eagletrt_api_normalize_value_above_range); + RUN_TEST(test_eagletrt_api_normalize_zero_length_range); + RUN_TEST(test_eagletrt_api_normalize_minimum_boundary); + RUN_TEST(test_eagletrt_api_normalize_maximum_boundary); + + UNITY_END(); +} \ No newline at end of file From cc16c74a8735bd4c60152dc35f0f6d76dc3e8b3d Mon Sep 17 00:00:00 2001 From: Dorijan Di Zepp Date: Wed, 12 Nov 2025 01:17:45 +0100 Subject: [PATCH 6/8] feat: add individual bit operation macros, new test cases #1 --- examples/example.c | 22 ++--- include/eagletrt-api.h | 123 ++++++++++++++++++++--- include/eagletrt.h | 19 +--- src/eagletrt-api.c | 47 +-------- test/test-eagletrt.c | 216 ++++++++++++++++++++++++++++++----------- 5 files changed, 284 insertions(+), 143 deletions(-) diff --git a/examples/example.c b/examples/example.c index 4cad783..5837924 100644 --- a/examples/example.c +++ b/examples/example.c @@ -2,7 +2,7 @@ * \file example.c * \brief Example usage of the Common library. * \author Dorijan Di Zepp [dorijan.dizepp@eagletrt.it] - * \date 2025-11-06 + * \date 2025-11-12 */ #include @@ -13,7 +13,7 @@ /* Example condition function for bit operation */ static bool example_condition_true(const void *ctx) { - EAGLETRT_UNUSED(ctx); + EAGLETRT_API_UNUSED(ctx); return true; } @@ -25,11 +25,11 @@ static bool example_condition_threshold(const void *ctx) { int main(void) { /* NOP / UNUSED */ int z = 5, w = 7, unused = 1; - EAGLETRT_UNUSED(unused); + EAGLETRT_API_UNUSED(unused); if (z > w) { - EAGLETRT_NOP(); + EAGLETRT_API_NOP(); } else { - EAGLETRT_NOP(); + EAGLETRT_API_NOP(); } /* MIN / MAX / CLAMP */ @@ -47,28 +47,28 @@ int main(void) { printf(" Initial value: 0x%02X\n", reg); /* SET bit 0 */ - eagletrt_api_bit_operation(®, sizeof(reg), 0, EAGLETRT_BIT_OPERATION_SET, NULL, NULL); + EAGLETRT_API_BIT_SET(reg, 0); printf(" After SET bit 0 -> 0x%02X\n", reg); /* RESET bit 3 */ - eagletrt_api_bit_operation(®, sizeof(reg), 3, EAGLETRT_BIT_OPERATION_RESET, NULL, NULL); + EAGLETRT_API_BIT_RESET(reg, 3); printf(" After RESET bit 3 -> 0x%02X\n", reg); /* TOGGLE bit 1 */ - eagletrt_api_bit_operation(®, sizeof(reg), 1, EAGLETRT_BIT_OPERATION_TOGGLE, NULL, NULL); + EAGLETRT_API_BIT_TOGGLE(reg, 1); printf(" After TOGGLE bit 1 -> 0x%02X\n", reg); /* TOGGLE_IF using a true condition */ - eagletrt_api_bit_operation(®, sizeof(reg), 2, EAGLETRT_BIT_OPERATION_TOGGLE_IF, example_condition_true, NULL); + EAGLETRT_API_BIT_TOGGLE_IF(reg, 2, example_condition_true, NULL); printf(" After TOGGLE_IF (always true) bit 2 -> 0x%02X\n", reg); /* TOGGLE_IF using a contextual condition */ float threshold_value = 0.3f; - eagletrt_api_bit_operation(®, sizeof(reg), 7, EAGLETRT_BIT_OPERATION_TOGGLE_IF, example_condition_threshold, &threshold_value); + EAGLETRT_API_BIT_TOGGLE_IF(reg, 7, example_condition_threshold, &threshold_value); printf(" After TOGGLE_IF (threshold=0.3f) bit 7 -> 0x%02X\n", reg); threshold_value = 0.8f; - eagletrt_api_bit_operation(®, sizeof(reg), 7, EAGLETRT_BIT_OPERATION_TOGGLE_IF, example_condition_threshold, &threshold_value); + EAGLETRT_API_BIT_TOGGLE_IF(reg, 7, example_condition_threshold, &threshold_value); printf(" After TOGGLE_IF (threshold=0.8f) bit 7 -> 0x%02X\n\n", reg); /* MAPF */ diff --git a/include/eagletrt-api.h b/include/eagletrt-api.h index 0ffb3fe..77d56de 100644 --- a/include/eagletrt-api.h +++ b/include/eagletrt-api.h @@ -1,11 +1,11 @@ /*! * \file eagletrt-api.h - * \date 2025-11-06 + * \date 2025-11-12 * \authors Dorijan Di Zepp [dorijan.dizepp@eagletrt.it] * * \brief A simple library providing a set of common utilities for all embedded projects. * - * \details This library provides a set of functions that are often needed in most embedded proejects. + * \details This library provides a set of functions that are often needed in most embedded projects. * This helps in reducing developing time and maintain consistency across multiple projects. */ @@ -21,13 +21,13 @@ * \brief A placeholder that has no side effects but is valid * wherever a statement is expected. */ -#define EAGLETRT_NOP() ((void)(0U)) +#define EAGLETRT_API_NOP() ((void)(0U)) /*! * \brief Marks a variable or parameter as intentionally * unused, to silence compiler warnings */ -#define EAGLETRT_UNUSED(_) ((void)(_)) +#define EAGLETRT_API_UNUSED(_) ((void)(_)) /*! * \brief Return the smaller of two values. @@ -58,17 +58,112 @@ #define EAGLETRT_API_CLAMP(x, l, h) (EAGLETRT_API_MAX(EAGLETRT_API_MIN((x), (h)), (l))) /*! - * \brief Operate on a specified bit of a value passed based on the operation to complete - * - * \param[in] val: The value to be read - * \param[in] val_size: Size of the pointed value in bytes - * \param[in] bit: The bit position to be modified - * \param[in] operation: Which operation has to be performed in the indicated bit (set, reset, toggle, ...) - * \param[in] condition: If an operation requires it, a condition has to be specified whether a bit has to be modified or not - * \param[in] context: Optional user context passed to the condition function. - * \return A boolean value indicating whether the operation has been completed successfully or not. + * \brief Set the specified bit in a given value. + * + * This macro sets the bit at position bit in val to 1. + * + * \param[in,out] val: The variable whose bit will be modified. + * \param[in] bit: The bit position to set (starting from 0). + */ +#define EAGLETRT_API_BIT_SET(val, bit) \ + do { \ + if ((bit) < (sizeof(val) * 8)) { \ + (val) |= (1ULL << (bit)); \ + } \ + } while (0) + +/*! + * \brief Reset (clear) the specified bit in a given value. + * This macro clears the bit at position bit in val to 0. + * + * \param[in,out] val: The variable whose bit will be modified. + * \param[in] bit: The bit position to clear (starting from 0). + */ +#define EAGLETRT_API_BIT_RESET(val, bit) \ + do { \ + if ((bit) < (sizeof(val) * 8)) { \ + (val) &= ~(1ULL << (bit)); \ + } \ + } while (0) + +/*! + * \brief Toggle (invert) the specified bit in a given value. + * This macro flips the bit at position bit in val. + * + * \param[in,out] val: The variable whose bit will be modified. + * \param[in] bit: The bit position to toggle (starting from 0). + */ +#define EAGLETRT_API_BIT_TOGGLE(val, bit) \ + do { \ + if ((bit) < (sizeof(val) * 8)) { \ + (val) ^= (1ULL << (bit)); \ + } \ + } while (0) + +/*! + * \brief Read the value of a specific bit from a variable. + * This macro retrieves the bit value (0 or 1) from the specified position. + * + * \param[in] val: The variable to read from. + * \param[in] bit: The bit position to read (starting from 0). + * \return The bit value (0 or 1) at the specified position. + */ +#define EAGLETRT_API_BIT_GET(val, bit) \ + (((bit) < (sizeof(val) * 8)) ? (((val) >> (bit)) & 1ULL) : 0ULL) + +/*! + * \brief Conditionally set the specified bit in a given value. + * This macro sets the bit at position bit in val to 1 only if + * condition is NULL or evaluates to true. + * + * \param[in,out] val: The variable whose bit will be modified. + * \param[in] bit: The bit position to set (starting from 0). + * \param[in] condition: Optional pointer to a function returning a boolean value. + * The function must have the signature: + * bool condition(const void *context); + * \param[in] context: Optional user-defined context passed to the condition function. + */ +#define EAGLETRT_API_BIT_SET_IF(val, bit, condition, context) \ + do { \ + if (((bit) < (sizeof(val) * 8)) && (condition)(context)) \ + (val) |= (1ULL << (bit)); \ + } while (0) + +/*! + * \brief Conditionally clear (reset) the specified bit in a given value. + * This macro clears the bit at position bit in val to 0 only if + * condition is NULL or evaluates to true. + * + * \param[in,out] val: The variable whose bit will be modified. + * \param[in] bit: The bit position to reset (starting from 0). + * \param[in] condition: Optional pointer to a function returning a boolean value. + * The function must have the signature: + * bool condition(const void *context); + * \param[in] context: Optional user-defined context passed to the condition function. + */ +#define EAGLETRT_API_BIT_RESET_IF(val, bit, condition, context) \ + do { \ + if (((bit) < (sizeof(val) * 8)) && (condition)(context)) \ + (val) &= ~(1ULL << (bit)); \ + } while (0) + +/*! + * \brief Conditionally toggle (invert) the specified bit in a given value. + * This macro flips the bit at position bit in val only if + * condition is NULL or evaluates to true. + * + * \param[in,out] val: The variable whose bit will be modified. + * \param[in] bit: The bit position to toggle (starting from 0). + * \param[in] condition: Optional pointer to a function returning a boolean value. + * The function must have the signature: + * bool condition(const void *context); + * \param[in] context: Optional user-defined context passed to the condition function. */ -bool eagletrt_api_bit_operation(void * val, size_t val_size, uint64_t bit, enum EagleTrtBitOperation operation, bool (*condition)(const void *context), const void *context); +#define EAGLETRT_API_BIT_TOGGLE_IF(val, bit, condition, context) \ + do { \ + if (((bit) < (sizeof(val) * 8)) && (condition)(context)) \ + (val) ^= (1ULL << (bit)); \ + } while (0) /*! * \brief Map a value from one range to another. diff --git a/include/eagletrt.h b/include/eagletrt.h index 4e8915b..51c86e3 100644 --- a/include/eagletrt.h +++ b/include/eagletrt.h @@ -1,11 +1,11 @@ /*! * \file eagletrt.h - * \date 2025-11-06 + * \date 2025-11-12 * \authors Dorijan Di Zepp [dorijan.dizepp@eagletrt.it] * * \brief A simple library providing a set of common utilities for all embedded projects. * - * \details This library provides a set of functions that are often needed in most embedded proejects. + * \details This library provides a set of functions that are often needed in most embedded projects. * This helps in reducing developing time and maintain consistency across multiple projects. */ @@ -17,22 +17,11 @@ #endif /* EAGLETRT_STATIC */ #ifndef EAGLETRT_STATIC_INLINE -#define EAGLETRT_STATIC_INLINE +#define EAGLETRT_STATIC_INLINE static inline #endif /* EAGLETRT_STATIC_INLINE */ #ifndef EAGLETRT_VOLATILE -#define EAGLETRT_VOLATILE +#define EAGLETRT_VOLATILE volatile #endif /* EAGLETRT_VOLATILE */ -/*! - * \brief The operation to be executed on a specified bit - */ -enum EagleTrtBitOperation { - EAGLETRT_BIT_OPERATION_GET, - EAGLETRT_BIT_OPERATION_SET, - EAGLETRT_BIT_OPERATION_RESET, - EAGLETRT_BIT_OPERATION_TOGGLE, - EAGLETRT_BIT_OPERATION_TOGGLE_IF, -}; - #endif /*! EAGLETRT_H */ \ No newline at end of file diff --git a/src/eagletrt-api.c b/src/eagletrt-api.c index b0f4baf..c41e200 100644 --- a/src/eagletrt-api.c +++ b/src/eagletrt-api.c @@ -1,60 +1,17 @@ /*! * \file eagletrt-api.c - * \date 2025-11-06 + * \date 2025-11-12 * \authors Dorijan Di Zepp [dorijan.dizepp@eagletrt.it] * * \brief A simple library providing a set of common utilities for all embedded projects. * - * \details This library provides a set of functions that are often needed in most embedded proejects. + * \details This library provides a set of functions that are often needed in most embedded projects. * This helps in reducing developing time and maintain consistency across multiple projects. */ #include #include "eagletrt-api.h" -bool eagletrt_api_bit_operation(void *val, size_t val_size, uint64_t bit, enum EagleTrtBitOperation operation, bool (*condition)(const void *context), const void *context) { - if (!val || val_size == 0) - return false; // invalid input - - uint64_t max_bits = val_size * 8ULL; - if (bit >= max_bits) - return false; // invalid bit index - - if (operation == EAGLETRT_BIT_OPERATION_TOGGLE_IF && !condition) - return false; // the condition function is not defined - - uint8_t *bytes = (uint8_t *)val; - size_t byte_index = bit / 8; - uint8_t bit_mask = (1U << (bit % 8)); - - switch (operation) { - case EAGLETRT_BIT_OPERATION_GET: - return (bytes[byte_index] & bit_mask) != 0; - - case EAGLETRT_BIT_OPERATION_SET: - bytes[byte_index] |= bit_mask; - break; - - case EAGLETRT_BIT_OPERATION_RESET: - bytes[byte_index] &= ~bit_mask; - break; - - case EAGLETRT_BIT_OPERATION_TOGGLE: - bytes[byte_index] ^= bit_mask; - break; - - case EAGLETRT_BIT_OPERATION_TOGGLE_IF: - if (condition(context)) - bytes[byte_index] ^= bit_mask; - break; - - default: - return false; - } - - return true; -} - float eagletrt_api_mapf(float x, float in_min, float in_max, float out_min, float out_max) { return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } diff --git a/test/test-eagletrt.c b/test/test-eagletrt.c index 02131a9..0d30706 100644 --- a/test/test-eagletrt.c +++ b/test/test-eagletrt.c @@ -3,7 +3,7 @@ * @brief Test suite for eagle-eco-api.c file * * @author Dorijan Di Zepp [dorijan.dizepp@eagletrt.it] - * @date 2025-11-06 + * @date 2025-11-12 */ #include @@ -15,11 +15,11 @@ static int condition_counter = 0; /* Condition function for conditional toggle */ static bool always_true(const void *ctx) { - EAGLETRT_UNUSED(ctx); + EAGLETRT_API_UNUSED(ctx); return true; } static bool always_false(const void *ctx) { - EAGLETRT_UNUSED(ctx); + EAGLETRT_API_UNUSED(ctx); return false; } @@ -27,7 +27,7 @@ static bool always_false(const void *ctx) { * returns true only every 3rd call (like a periodic trigger) */ static bool toggle_every_third_call(const void *ctx) { - EAGLETRT_UNUSED(ctx); + EAGLETRT_API_UNUSED(ctx); condition_counter++; return (condition_counter % 3 == 0); } @@ -220,76 +220,169 @@ void test_eagletrt_api_clamp_inverted_limits(void) { /* Eagletrt api bit operation */ -void test_eagletrt_api_bit_operation_set(void) { +void test_eagletrt_api_bit_set(void) { uint8_t test_val = 0x00; - bool result = eagletrt_api_bit_operation(&test_val, sizeof(test_val), 3, EAGLETRT_BIT_OPERATION_SET, NULL, NULL); - TEST_ASSERT_TRUE(result); + EAGLETRT_API_BIT_SET(test_val, 3); TEST_ASSERT_BITS(0x08, 0x08, test_val); // bit 3 set } -void test_eagletrt_api_bit_operation_reset(void) { +void test_eagletrt_api_bit_toggle(void) { + uint8_t test_val = 0x08; + EAGLETRT_API_BIT_TOGGLE(test_val, 3); + TEST_ASSERT_BITS(0x08, 0x00, test_val); // bit 3 toggled off +} + +void test_eagletrt_api_bit_get(void) { + uint8_t test_val = 0x10; + TEST_ASSERT_TRUE(EAGLETRT_API_BIT_GET(test_val, 4)); // true = bit is set +} + +void test_eagletrt_api_bit_invalid_bit(void) { + uint8_t test_val = 0x00; + uint8_t original = test_val; + size_t bit = 64; + TEST_ASSERT_FALSE(EAGLETRT_API_BIT_GET(test_val, bit)); // out of range + + EAGLETRT_API_BIT_SET(test_val, bit); // out of range + TEST_ASSERT_EQUAL_UINT8(original, test_val); // unchanged + + EAGLETRT_API_BIT_RESET(test_val, bit); // out of range + TEST_ASSERT_EQUAL_UINT8(original, test_val); + + EAGLETRT_API_BIT_TOGGLE(test_val, bit); // out of range + TEST_ASSERT_EQUAL_UINT8(original, test_val); +} + +void test_eagletrt_api_bit_set_if_true(void) { + uint8_t test_val = 0x00; + EAGLETRT_API_BIT_SET_IF(test_val, 2, always_true, NULL); + TEST_ASSERT_BITS(0x04, 0x04, test_val); +} + +void test_eagletrt_api_bit_set_if_false(void) { + uint8_t test_val = 0x00; + EAGLETRT_API_BIT_SET_IF(test_val, 2, always_false, NULL); + TEST_ASSERT_BITS(0x04, 0x00, test_val); +} + +void test_eagletrt_api_bit_reset_if_true(void) { uint8_t test_val = 0xFF; - bool result = eagletrt_api_bit_operation(&test_val, sizeof(test_val), 3, EAGLETRT_BIT_OPERATION_RESET, NULL, NULL); - TEST_ASSERT_TRUE(result); - TEST_ASSERT_BITS(0x08, 0x00, test_val); // bit 3 cleared + EAGLETRT_API_BIT_RESET_IF(test_val, 1, always_true, NULL); + TEST_ASSERT_BITS(0x02, 0x00, test_val); } -void test_eagletrt_api_bit_operation_toggle(void) { - uint8_t test_val = 0x08; - bool result = eagletrt_api_bit_operation(&test_val, sizeof(test_val), 3, EAGLETRT_BIT_OPERATION_TOGGLE, NULL, NULL); - TEST_ASSERT_TRUE(result); - TEST_ASSERT_BITS(0x08, 0x00, test_val); // bit 3 toggled off +void test_eagletrt_api_bit_reset_if_false(void) { + uint8_t test_val = 0xFF; + EAGLETRT_API_BIT_RESET_IF(test_val, 1, always_false, NULL); + TEST_ASSERT_BITS(0x02, 0x02, test_val); } -void test_eagletrt_api_bit_operation_toggle_if_true(void) { +void test_eagletrt_api_bit_toggle_if_true(void) { uint8_t test_val = 0x00; - bool result = eagletrt_api_bit_operation(&test_val, sizeof(test_val), 1, EAGLETRT_BIT_OPERATION_TOGGLE_IF, always_true, NULL); - TEST_ASSERT_TRUE(result); - TEST_ASSERT_BITS(0x02, 0x02, test_val); // toggled + EAGLETRT_API_BIT_TOGGLE_IF(test_val, 3, always_true, NULL); + TEST_ASSERT_BITS(0x08, 0x08, test_val); // toggled } -void test_eagletrt_api_bit_operation_toggle_if_false(void) { +void test_eagletrt_api_bit_toggle_if_false(void) { uint8_t test_val = 0x00; - bool result = eagletrt_api_bit_operation(&test_val, sizeof(test_val), 1, EAGLETRT_BIT_OPERATION_TOGGLE_IF, always_false, NULL); - TEST_ASSERT_TRUE(result); // operation completes successfully + EAGLETRT_API_BIT_TOGGLE_IF(test_val, 3, always_false, NULL); TEST_ASSERT_BITS(0x02, 0x00, test_val); // no toggle } -void test_eagletrt_api_bit_operation_get(void) { - uint8_t test_val = 0x10; - bool result = eagletrt_api_bit_operation(&test_val, sizeof(test_val), 4, EAGLETRT_BIT_OPERATION_GET, NULL, NULL); - TEST_ASSERT_TRUE(result); // true = bit is set +void test_eagletrt_api_bit_set_if_dynamic_condition(void) { + uint8_t test_val = 0x00; + uint8_t expected; + + condition_counter = 0; + + /* 1st call — no set */ + expected = test_val; + EAGLETRT_API_BIT_SET_IF(test_val, 0, toggle_every_third_call, NULL); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, test_val, "Unexpected set on 1st call"); + + /* 2nd call — no set */ + expected = test_val; + EAGLETRT_API_BIT_SET_IF(test_val, 0, toggle_every_third_call, NULL); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, test_val, "Unexpected set on 2nd call"); + + /* 3rd call — set occurs */ + expected = test_val | (1u << 0); + EAGLETRT_API_BIT_SET_IF(test_val, 0, toggle_every_third_call, NULL); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, test_val, "Failed to set on 3rd call"); + + /* 4th call — no set */ + expected = test_val; + EAGLETRT_API_BIT_SET_IF(test_val, 0, toggle_every_third_call, NULL); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, test_val, "Unexpected set on 4th call"); } -void test_eagletrt_api_bit_operation_invalid_bit(void) { - uint8_t test_val = 0x00; - bool result = eagletrt_api_bit_operation(&test_val, sizeof(test_val), 64, EAGLETRT_BIT_OPERATION_SET, NULL, NULL); - TEST_ASSERT_FALSE(result); // out of range +void test_eagletrt_api_bit_reset_if_dynamic_condition(void) { + uint8_t test_val = 0x01; + uint8_t expected; + + condition_counter = 0; + + /* 1st call — no clear */ + expected = test_val; + EAGLETRT_API_BIT_RESET_IF(test_val, 0, toggle_every_third_call, NULL); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, test_val, "Unexpected clear on 1st call"); + + /* 2nd call — no clear */ + expected = test_val; + EAGLETRT_API_BIT_RESET_IF(test_val, 0, toggle_every_third_call, NULL); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, test_val, "Unexpected clear on 2nd call"); + + /* 3rd call — clear occurs */ + expected = test_val & ~(1u << 0); + EAGLETRT_API_BIT_RESET_IF(test_val, 0, toggle_every_third_call, NULL); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, test_val, "Failed to clear on 3rd call"); + + /* 4th call — no clear */ + expected = test_val; + EAGLETRT_API_BIT_RESET_IF(test_val, 0, toggle_every_third_call, NULL); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, test_val, "Unexpected clear on 4th call"); } -void test_eagletrt_api_bit_operation_toggle_if_with_dynamic_condition(void) { - uint32_t val = 0b0001; /* initial value */ - uint32_t expected; +void test_eagletrt_api_bit_toggle_if_dynamic_condition(void) { + uint8_t test_val = 0x01; + uint8_t expected; + + condition_counter = 0; + + /* 1st call — no toggle */ + expected = test_val; + EAGLETRT_API_BIT_TOGGLE_IF(test_val, 0, toggle_every_third_call, NULL); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, test_val, "Unexpected toggle on 1st call"); - /* 1st call: counter = 1 no toggle */ - expected = val; - eagletrt_api_bit_operation(&val, sizeof(val), 0, EAGLETRT_BIT_OPERATION_TOGGLE_IF, toggle_every_third_call, NULL); - TEST_ASSERT_EQUAL_UINT32_MESSAGE(expected, val, "Unexpected toggle on 1st call"); + /* 2nd call — no toggle */ + expected = test_val; + EAGLETRT_API_BIT_TOGGLE_IF(test_val, 0, toggle_every_third_call, NULL); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, test_val, "Unexpected toggle on 2nd call"); + + /* 3rd call — toggle occurs */ + expected = test_val ^ (1u << 0); + EAGLETRT_API_BIT_TOGGLE_IF(test_val, 0, toggle_every_third_call, NULL); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, test_val, "Failed to toggle on 3rd call"); + + /* 4th call — no toggle */ + expected = test_val; + EAGLETRT_API_BIT_TOGGLE_IF(test_val, 0, toggle_every_third_call, NULL); + TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, test_val, "Unexpected toggle on 4th call"); +} + +void test_eagletrt_api_bit_if_invalid_bit(void) { + uint8_t test_val = 0x00; + uint8_t original = test_val; + size_t bit = 64; - /* 2nd call: counter = 2 no toggle */ - expected = val; - eagletrt_api_bit_operation(&val, sizeof(val), 0, EAGLETRT_BIT_OPERATION_TOGGLE_IF, toggle_every_third_call, NULL); - TEST_ASSERT_EQUAL_UINT32_MESSAGE(expected, val, "Unexpected toggle on 2nd call"); + EAGLETRT_API_BIT_SET_IF(test_val, bit, always_true, NULL); + TEST_ASSERT_EQUAL_UINT8(original, test_val); // unchanged - /* 3rd call: counter = 3 should toggle */ - expected = val ^ (1u << 0); - eagletrt_api_bit_operation(&val, sizeof(val), 0, EAGLETRT_BIT_OPERATION_TOGGLE_IF, toggle_every_third_call, NULL); - TEST_ASSERT_EQUAL_UINT32_MESSAGE(expected, val, "Failed to toggle on 3rd call"); + EAGLETRT_API_BIT_RESET_IF(test_val, bit, always_true, NULL); + TEST_ASSERT_EQUAL_UINT8(original, test_val); // unchanged - /* 4th call: counter = 4 no toggle */ - expected = val; - eagletrt_api_bit_operation(&val, sizeof(val), 0, EAGLETRT_BIT_OPERATION_TOGGLE_IF, toggle_every_third_call, NULL); - TEST_ASSERT_EQUAL_UINT32_MESSAGE(expected, val, "Unexpected toggle on 4th call"); + EAGLETRT_API_BIT_TOGGLE_IF(test_val, bit, always_true, NULL); + TEST_ASSERT_EQUAL_UINT8(original, test_val); // unchanged } /* ------------------------------------ */ @@ -413,14 +506,21 @@ int main() { RUN_TEST(test_eagletrt_api_clamp_inverted_limits); /* Eagletrt api bit operation */ - RUN_TEST(test_eagletrt_api_bit_operation_set); - RUN_TEST(test_eagletrt_api_bit_operation_reset); - RUN_TEST(test_eagletrt_api_bit_operation_toggle); - RUN_TEST(test_eagletrt_api_bit_operation_toggle_if_true); - RUN_TEST(test_eagletrt_api_bit_operation_toggle_if_false); - RUN_TEST(test_eagletrt_api_bit_operation_get); - RUN_TEST(test_eagletrt_api_bit_operation_invalid_bit); - RUN_TEST(test_eagletrt_api_bit_operation_toggle_if_with_dynamic_condition); + RUN_TEST(test_eagletrt_api_bit_set); + RUN_TEST(test_eagletrt_api_bit_toggle); + RUN_TEST(test_eagletrt_api_bit_get); + RUN_TEST(test_eagletrt_api_bit_invalid_bit); + + RUN_TEST(test_eagletrt_api_bit_set_if_true); + RUN_TEST(test_eagletrt_api_bit_set_if_false); + RUN_TEST(test_eagletrt_api_bit_reset_if_true); + RUN_TEST(test_eagletrt_api_bit_reset_if_false); + RUN_TEST(test_eagletrt_api_bit_toggle_if_true); + RUN_TEST(test_eagletrt_api_bit_toggle_if_false); + RUN_TEST(test_eagletrt_api_bit_set_if_dynamic_condition); + RUN_TEST(test_eagletrt_api_bit_reset_if_dynamic_condition); + RUN_TEST(test_eagletrt_api_bit_toggle_if_dynamic_condition); + RUN_TEST(test_eagletrt_api_bit_if_invalid_bit); /* Eagletrt api mapf */ RUN_TEST(test_eagletrt_api_mapf_positive_range); From b9eed793685a430bc0bef2900c2d8181066a1983 Mon Sep 17 00:00:00 2001 From: Dorijan Di Zepp Date: Thu, 13 Nov 2025 10:15:13 +0100 Subject: [PATCH 7/8] fix: removed from bit operation range check #1 --- examples/example.c | 14 ++++---- include/eagletrt-api.h | 45 ++++++------------------- test/test-eagletrt.c | 75 ++++++++++++------------------------------ 3 files changed, 38 insertions(+), 96 deletions(-) diff --git a/examples/example.c b/examples/example.c index 5837924..124e441 100644 --- a/examples/example.c +++ b/examples/example.c @@ -2,7 +2,7 @@ * \file example.c * \brief Example usage of the Common library. * \author Dorijan Di Zepp [dorijan.dizepp@eagletrt.it] - * \date 2025-11-12 + * \date 2025-11-13 */ #include @@ -47,28 +47,28 @@ int main(void) { printf(" Initial value: 0x%02X\n", reg); /* SET bit 0 */ - EAGLETRT_API_BIT_SET(reg, 0); + reg = EAGLETRT_API_BIT_SET(reg, 0); printf(" After SET bit 0 -> 0x%02X\n", reg); /* RESET bit 3 */ - EAGLETRT_API_BIT_RESET(reg, 3); + reg = EAGLETRT_API_BIT_RESET(reg, 3); printf(" After RESET bit 3 -> 0x%02X\n", reg); /* TOGGLE bit 1 */ - EAGLETRT_API_BIT_TOGGLE(reg, 1); + reg = EAGLETRT_API_BIT_TOGGLE(reg, 1); printf(" After TOGGLE bit 1 -> 0x%02X\n", reg); /* TOGGLE_IF using a true condition */ - EAGLETRT_API_BIT_TOGGLE_IF(reg, 2, example_condition_true, NULL); + reg = EAGLETRT_API_BIT_TOGGLE_IF(reg, 2, example_condition_true, NULL); printf(" After TOGGLE_IF (always true) bit 2 -> 0x%02X\n", reg); /* TOGGLE_IF using a contextual condition */ float threshold_value = 0.3f; - EAGLETRT_API_BIT_TOGGLE_IF(reg, 7, example_condition_threshold, &threshold_value); + reg = EAGLETRT_API_BIT_TOGGLE_IF(reg, 7, example_condition_threshold, &threshold_value); printf(" After TOGGLE_IF (threshold=0.3f) bit 7 -> 0x%02X\n", reg); threshold_value = 0.8f; - EAGLETRT_API_BIT_TOGGLE_IF(reg, 7, example_condition_threshold, &threshold_value); + reg = EAGLETRT_API_BIT_TOGGLE_IF(reg, 7, example_condition_threshold, &threshold_value); printf(" After TOGGLE_IF (threshold=0.8f) bit 7 -> 0x%02X\n\n", reg); /* MAPF */ diff --git a/include/eagletrt-api.h b/include/eagletrt-api.h index 77d56de..019bc88 100644 --- a/include/eagletrt-api.h +++ b/include/eagletrt-api.h @@ -1,6 +1,6 @@ /*! * \file eagletrt-api.h - * \date 2025-11-12 + * \date 2025-11-13 * \authors Dorijan Di Zepp [dorijan.dizepp@eagletrt.it] * * \brief A simple library providing a set of common utilities for all embedded projects. @@ -65,12 +65,7 @@ * \param[in,out] val: The variable whose bit will be modified. * \param[in] bit: The bit position to set (starting from 0). */ -#define EAGLETRT_API_BIT_SET(val, bit) \ - do { \ - if ((bit) < (sizeof(val) * 8)) { \ - (val) |= (1ULL << (bit)); \ - } \ - } while (0) +#define EAGLETRT_API_BIT_SET(val, bit) ((val) | (1ULL << (bit))) /*! * \brief Reset (clear) the specified bit in a given value. @@ -79,12 +74,7 @@ * \param[in,out] val: The variable whose bit will be modified. * \param[in] bit: The bit position to clear (starting from 0). */ -#define EAGLETRT_API_BIT_RESET(val, bit) \ - do { \ - if ((bit) < (sizeof(val) * 8)) { \ - (val) &= ~(1ULL << (bit)); \ - } \ - } while (0) +#define EAGLETRT_API_BIT_RESET(val, bit) ((val) & ~(1ULL << (bit))) /*! * \brief Toggle (invert) the specified bit in a given value. @@ -93,12 +83,7 @@ * \param[in,out] val: The variable whose bit will be modified. * \param[in] bit: The bit position to toggle (starting from 0). */ -#define EAGLETRT_API_BIT_TOGGLE(val, bit) \ - do { \ - if ((bit) < (sizeof(val) * 8)) { \ - (val) ^= (1ULL << (bit)); \ - } \ - } while (0) +#define EAGLETRT_API_BIT_TOGGLE(val, bit) ((val) ^ (1ULL << (bit))) /*! * \brief Read the value of a specific bit from a variable. @@ -108,8 +93,7 @@ * \param[in] bit: The bit position to read (starting from 0). * \return The bit value (0 or 1) at the specified position. */ -#define EAGLETRT_API_BIT_GET(val, bit) \ - (((bit) < (sizeof(val) * 8)) ? (((val) >> (bit)) & 1ULL) : 0ULL) +#define EAGLETRT_API_BIT_GET(val, bit) (((val) >> (bit)) & 1ULL) /*! * \brief Conditionally set the specified bit in a given value. @@ -123,11 +107,8 @@ * bool condition(const void *context); * \param[in] context: Optional user-defined context passed to the condition function. */ -#define EAGLETRT_API_BIT_SET_IF(val, bit, condition, context) \ - do { \ - if (((bit) < (sizeof(val) * 8)) && (condition)(context)) \ - (val) |= (1ULL << (bit)); \ - } while (0) +#define EAGLETRT_API_BIT_SET_IF(val, bit, condition, context) \ + (((condition)(context)) ? ((val) | (1ULL << (bit))) : (val)) /*! * \brief Conditionally clear (reset) the specified bit in a given value. @@ -141,11 +122,8 @@ * bool condition(const void *context); * \param[in] context: Optional user-defined context passed to the condition function. */ -#define EAGLETRT_API_BIT_RESET_IF(val, bit, condition, context) \ - do { \ - if (((bit) < (sizeof(val) * 8)) && (condition)(context)) \ - (val) &= ~(1ULL << (bit)); \ - } while (0) +#define EAGLETRT_API_BIT_RESET_IF(val, bit, condition, context) \ + (((condition)(context)) ? ((val) & ~(1ULL << (bit))) : (val)) /*! * \brief Conditionally toggle (invert) the specified bit in a given value. @@ -160,10 +138,7 @@ * \param[in] context: Optional user-defined context passed to the condition function. */ #define EAGLETRT_API_BIT_TOGGLE_IF(val, bit, condition, context) \ - do { \ - if (((bit) < (sizeof(val) * 8)) && (condition)(context)) \ - (val) ^= (1ULL << (bit)); \ - } while (0) + (((condition)(context)) ? ((val) ^ (1ULL << (bit))) : (val)) /*! * \brief Map a value from one range to another. diff --git a/test/test-eagletrt.c b/test/test-eagletrt.c index 0d30706..1129ae2 100644 --- a/test/test-eagletrt.c +++ b/test/test-eagletrt.c @@ -3,7 +3,7 @@ * @brief Test suite for eagle-eco-api.c file * * @author Dorijan Di Zepp [dorijan.dizepp@eagletrt.it] - * @date 2025-11-12 + * @date 2025-11-13 */ #include @@ -222,13 +222,13 @@ void test_eagletrt_api_clamp_inverted_limits(void) { void test_eagletrt_api_bit_set(void) { uint8_t test_val = 0x00; - EAGLETRT_API_BIT_SET(test_val, 3); + test_val = EAGLETRT_API_BIT_SET(test_val, 3); TEST_ASSERT_BITS(0x08, 0x08, test_val); // bit 3 set } void test_eagletrt_api_bit_toggle(void) { uint8_t test_val = 0x08; - EAGLETRT_API_BIT_TOGGLE(test_val, 3); + test_val = EAGLETRT_API_BIT_TOGGLE(test_val, 3); TEST_ASSERT_BITS(0x08, 0x00, test_val); // bit 3 toggled off } @@ -237,55 +237,39 @@ void test_eagletrt_api_bit_get(void) { TEST_ASSERT_TRUE(EAGLETRT_API_BIT_GET(test_val, 4)); // true = bit is set } -void test_eagletrt_api_bit_invalid_bit(void) { - uint8_t test_val = 0x00; - uint8_t original = test_val; - size_t bit = 64; - TEST_ASSERT_FALSE(EAGLETRT_API_BIT_GET(test_val, bit)); // out of range - - EAGLETRT_API_BIT_SET(test_val, bit); // out of range - TEST_ASSERT_EQUAL_UINT8(original, test_val); // unchanged - - EAGLETRT_API_BIT_RESET(test_val, bit); // out of range - TEST_ASSERT_EQUAL_UINT8(original, test_val); - - EAGLETRT_API_BIT_TOGGLE(test_val, bit); // out of range - TEST_ASSERT_EQUAL_UINT8(original, test_val); -} - void test_eagletrt_api_bit_set_if_true(void) { uint8_t test_val = 0x00; - EAGLETRT_API_BIT_SET_IF(test_val, 2, always_true, NULL); + test_val = EAGLETRT_API_BIT_SET_IF(test_val, 2, always_true, NULL); TEST_ASSERT_BITS(0x04, 0x04, test_val); } void test_eagletrt_api_bit_set_if_false(void) { uint8_t test_val = 0x00; - EAGLETRT_API_BIT_SET_IF(test_val, 2, always_false, NULL); + test_val = EAGLETRT_API_BIT_SET_IF(test_val, 2, always_false, NULL); TEST_ASSERT_BITS(0x04, 0x00, test_val); } void test_eagletrt_api_bit_reset_if_true(void) { uint8_t test_val = 0xFF; - EAGLETRT_API_BIT_RESET_IF(test_val, 1, always_true, NULL); + test_val = EAGLETRT_API_BIT_RESET_IF(test_val, 1, always_true, NULL); TEST_ASSERT_BITS(0x02, 0x00, test_val); } void test_eagletrt_api_bit_reset_if_false(void) { uint8_t test_val = 0xFF; - EAGLETRT_API_BIT_RESET_IF(test_val, 1, always_false, NULL); + test_val = EAGLETRT_API_BIT_RESET_IF(test_val, 1, always_false, NULL); TEST_ASSERT_BITS(0x02, 0x02, test_val); } void test_eagletrt_api_bit_toggle_if_true(void) { uint8_t test_val = 0x00; - EAGLETRT_API_BIT_TOGGLE_IF(test_val, 3, always_true, NULL); + test_val = EAGLETRT_API_BIT_TOGGLE_IF(test_val, 3, always_true, NULL); TEST_ASSERT_BITS(0x08, 0x08, test_val); // toggled } void test_eagletrt_api_bit_toggle_if_false(void) { uint8_t test_val = 0x00; - EAGLETRT_API_BIT_TOGGLE_IF(test_val, 3, always_false, NULL); + test_val = EAGLETRT_API_BIT_TOGGLE_IF(test_val, 3, always_false, NULL); TEST_ASSERT_BITS(0x02, 0x00, test_val); // no toggle } @@ -297,22 +281,22 @@ void test_eagletrt_api_bit_set_if_dynamic_condition(void) { /* 1st call — no set */ expected = test_val; - EAGLETRT_API_BIT_SET_IF(test_val, 0, toggle_every_third_call, NULL); + test_val = EAGLETRT_API_BIT_SET_IF(test_val, 0, toggle_every_third_call, NULL); TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, test_val, "Unexpected set on 1st call"); /* 2nd call — no set */ expected = test_val; - EAGLETRT_API_BIT_SET_IF(test_val, 0, toggle_every_third_call, NULL); + test_val = EAGLETRT_API_BIT_SET_IF(test_val, 0, toggle_every_third_call, NULL); TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, test_val, "Unexpected set on 2nd call"); /* 3rd call — set occurs */ expected = test_val | (1u << 0); - EAGLETRT_API_BIT_SET_IF(test_val, 0, toggle_every_third_call, NULL); + test_val = EAGLETRT_API_BIT_SET_IF(test_val, 0, toggle_every_third_call, NULL); TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, test_val, "Failed to set on 3rd call"); /* 4th call — no set */ expected = test_val; - EAGLETRT_API_BIT_SET_IF(test_val, 0, toggle_every_third_call, NULL); + test_val = EAGLETRT_API_BIT_SET_IF(test_val, 0, toggle_every_third_call, NULL); TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, test_val, "Unexpected set on 4th call"); } @@ -324,22 +308,22 @@ void test_eagletrt_api_bit_reset_if_dynamic_condition(void) { /* 1st call — no clear */ expected = test_val; - EAGLETRT_API_BIT_RESET_IF(test_val, 0, toggle_every_third_call, NULL); + test_val = EAGLETRT_API_BIT_RESET_IF(test_val, 0, toggle_every_third_call, NULL); TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, test_val, "Unexpected clear on 1st call"); /* 2nd call — no clear */ expected = test_val; - EAGLETRT_API_BIT_RESET_IF(test_val, 0, toggle_every_third_call, NULL); + test_val = EAGLETRT_API_BIT_RESET_IF(test_val, 0, toggle_every_third_call, NULL); TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, test_val, "Unexpected clear on 2nd call"); /* 3rd call — clear occurs */ expected = test_val & ~(1u << 0); - EAGLETRT_API_BIT_RESET_IF(test_val, 0, toggle_every_third_call, NULL); + test_val = EAGLETRT_API_BIT_RESET_IF(test_val, 0, toggle_every_third_call, NULL); TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, test_val, "Failed to clear on 3rd call"); /* 4th call — no clear */ expected = test_val; - EAGLETRT_API_BIT_RESET_IF(test_val, 0, toggle_every_third_call, NULL); + test_val = EAGLETRT_API_BIT_RESET_IF(test_val, 0, toggle_every_third_call, NULL); TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, test_val, "Unexpected clear on 4th call"); } @@ -351,40 +335,25 @@ void test_eagletrt_api_bit_toggle_if_dynamic_condition(void) { /* 1st call — no toggle */ expected = test_val; - EAGLETRT_API_BIT_TOGGLE_IF(test_val, 0, toggle_every_third_call, NULL); + test_val = EAGLETRT_API_BIT_TOGGLE_IF(test_val, 0, toggle_every_third_call, NULL); TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, test_val, "Unexpected toggle on 1st call"); /* 2nd call — no toggle */ expected = test_val; - EAGLETRT_API_BIT_TOGGLE_IF(test_val, 0, toggle_every_third_call, NULL); + test_val = EAGLETRT_API_BIT_TOGGLE_IF(test_val, 0, toggle_every_third_call, NULL); TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, test_val, "Unexpected toggle on 2nd call"); /* 3rd call — toggle occurs */ expected = test_val ^ (1u << 0); - EAGLETRT_API_BIT_TOGGLE_IF(test_val, 0, toggle_every_third_call, NULL); + test_val = EAGLETRT_API_BIT_TOGGLE_IF(test_val, 0, toggle_every_third_call, NULL); TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, test_val, "Failed to toggle on 3rd call"); /* 4th call — no toggle */ expected = test_val; - EAGLETRT_API_BIT_TOGGLE_IF(test_val, 0, toggle_every_third_call, NULL); + test_val = EAGLETRT_API_BIT_TOGGLE_IF(test_val, 0, toggle_every_third_call, NULL); TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, test_val, "Unexpected toggle on 4th call"); } -void test_eagletrt_api_bit_if_invalid_bit(void) { - uint8_t test_val = 0x00; - uint8_t original = test_val; - size_t bit = 64; - - EAGLETRT_API_BIT_SET_IF(test_val, bit, always_true, NULL); - TEST_ASSERT_EQUAL_UINT8(original, test_val); // unchanged - - EAGLETRT_API_BIT_RESET_IF(test_val, bit, always_true, NULL); - TEST_ASSERT_EQUAL_UINT8(original, test_val); // unchanged - - EAGLETRT_API_BIT_TOGGLE_IF(test_val, bit, always_true, NULL); - TEST_ASSERT_EQUAL_UINT8(original, test_val); // unchanged -} - /* ------------------------------------ */ /* Eagletrt api mapf */ @@ -509,7 +478,6 @@ int main() { RUN_TEST(test_eagletrt_api_bit_set); RUN_TEST(test_eagletrt_api_bit_toggle); RUN_TEST(test_eagletrt_api_bit_get); - RUN_TEST(test_eagletrt_api_bit_invalid_bit); RUN_TEST(test_eagletrt_api_bit_set_if_true); RUN_TEST(test_eagletrt_api_bit_set_if_false); @@ -520,7 +488,6 @@ int main() { RUN_TEST(test_eagletrt_api_bit_set_if_dynamic_condition); RUN_TEST(test_eagletrt_api_bit_reset_if_dynamic_condition); RUN_TEST(test_eagletrt_api_bit_toggle_if_dynamic_condition); - RUN_TEST(test_eagletrt_api_bit_if_invalid_bit); /* Eagletrt api mapf */ RUN_TEST(test_eagletrt_api_mapf_positive_range); From ae5db3dc111e46558a43ef588b9fcaab96431998 Mon Sep 17 00:00:00 2001 From: Dorijan Di Zepp Date: Fri, 14 Nov 2025 14:12:42 +0100 Subject: [PATCH 8/8] feat: change bit operation macros signature --- examples/example.c | 23 ++++++++++++--------- include/eagletrt-api.h | 32 ++++++++++++---------------- test/test-eagletrt.c | 47 ++++++++++++++++++++---------------------- 3 files changed, 48 insertions(+), 54 deletions(-) diff --git a/examples/example.c b/examples/example.c index 124e441..0132d7f 100644 --- a/examples/example.c +++ b/examples/example.c @@ -2,7 +2,7 @@ * \file example.c * \brief Example usage of the Common library. * \author Dorijan Di Zepp [dorijan.dizepp@eagletrt.it] - * \date 2025-11-13 + * \date 2025-11-14 */ #include @@ -12,14 +12,12 @@ #include "eagletrt-api.h" /* Example condition function for bit operation */ -static bool example_condition_true(const void *ctx) { - EAGLETRT_API_UNUSED(ctx); +static bool example_condition_true() { return true; } -static bool example_condition_threshold(const void *ctx) { - const float *value = (const float *)ctx; - return (*value > 0.5f); /* toggle only if above 0.5 */ +static bool example_condition_threshold(float value) { + return (value > 0.5f); /* toggle only if above 0.5 */ } int main(void) { @@ -59,17 +57,22 @@ int main(void) { printf(" After TOGGLE bit 1 -> 0x%02X\n", reg); /* TOGGLE_IF using a true condition */ - reg = EAGLETRT_API_BIT_TOGGLE_IF(reg, 2, example_condition_true, NULL); + reg = EAGLETRT_API_BIT_TOGGLE_IF(reg, 2, example_condition_true()); printf(" After TOGGLE_IF (always true) bit 2 -> 0x%02X\n", reg); /* TOGGLE_IF using a contextual condition */ float threshold_value = 0.3f; - reg = EAGLETRT_API_BIT_TOGGLE_IF(reg, 7, example_condition_threshold, &threshold_value); + reg = EAGLETRT_API_BIT_TOGGLE_IF(reg, 7, example_condition_threshold(threshold_value)); printf(" After TOGGLE_IF (threshold=0.3f) bit 7 -> 0x%02X\n", reg); threshold_value = 0.8f; - reg = EAGLETRT_API_BIT_TOGGLE_IF(reg, 7, example_condition_threshold, &threshold_value); - printf(" After TOGGLE_IF (threshold=0.8f) bit 7 -> 0x%02X\n\n", reg); + reg = EAGLETRT_API_BIT_TOGGLE_IF(reg, 7, example_condition_threshold(threshold_value)); + printf(" After TOGGLE_IF (threshold=0.8f) bit 7 -> 0x%02X\n", reg); + + reg = 0b00001010; /* initial value = 10 (bit3=1, bit1=1) */ + printf(" Initial value: 0x%02X\n", reg); + reg = EAGLETRT_API_BIT_SET_IF(reg, 0, (reg % 2) == 0); + printf(" After SET_IF bit 0 -> 0x%02X\n\n", reg); /* MAPF */ printf("[MAPF]\n"); diff --git a/include/eagletrt-api.h b/include/eagletrt-api.h index 019bc88..087fea7 100644 --- a/include/eagletrt-api.h +++ b/include/eagletrt-api.h @@ -1,6 +1,6 @@ /*! * \file eagletrt-api.h - * \date 2025-11-13 + * \date 2025-11-14 * \authors Dorijan Di Zepp [dorijan.dizepp@eagletrt.it] * * \brief A simple library providing a set of common utilities for all embedded projects. @@ -102,13 +102,11 @@ * * \param[in,out] val: The variable whose bit will be modified. * \param[in] bit: The bit position to set (starting from 0). - * \param[in] condition: Optional pointer to a function returning a boolean value. - * The function must have the signature: - * bool condition(const void *context); - * \param[in] context: Optional user-defined context passed to the condition function. + * \param[in] condition: Function, variable or condition expression + * that returns a boolean value */ -#define EAGLETRT_API_BIT_SET_IF(val, bit, condition, context) \ - (((condition)(context)) ? ((val) | (1ULL << (bit))) : (val)) +#define EAGLETRT_API_BIT_SET_IF(val, bit, condition) \ + ((condition) ? ((val) | (1ULL << (bit))) : (val)) /*! * \brief Conditionally clear (reset) the specified bit in a given value. @@ -117,13 +115,11 @@ * * \param[in,out] val: The variable whose bit will be modified. * \param[in] bit: The bit position to reset (starting from 0). - * \param[in] condition: Optional pointer to a function returning a boolean value. - * The function must have the signature: - * bool condition(const void *context); - * \param[in] context: Optional user-defined context passed to the condition function. + * \param[in] condition: Function, variable or condition expression + * that returns a boolean value */ -#define EAGLETRT_API_BIT_RESET_IF(val, bit, condition, context) \ - (((condition)(context)) ? ((val) & ~(1ULL << (bit))) : (val)) +#define EAGLETRT_API_BIT_RESET_IF(val, bit, condition) \ + ((condition) ? ((val) & ~(1ULL << (bit))) : (val)) /*! * \brief Conditionally toggle (invert) the specified bit in a given value. @@ -132,13 +128,11 @@ * * \param[in,out] val: The variable whose bit will be modified. * \param[in] bit: The bit position to toggle (starting from 0). - * \param[in] condition: Optional pointer to a function returning a boolean value. - * The function must have the signature: - * bool condition(const void *context); - * \param[in] context: Optional user-defined context passed to the condition function. + * \param[in] condition: Function, variable or condition expression + * that returns a boolean value */ -#define EAGLETRT_API_BIT_TOGGLE_IF(val, bit, condition, context) \ - (((condition)(context)) ? ((val) ^ (1ULL << (bit))) : (val)) +#define EAGLETRT_API_BIT_TOGGLE_IF(val, bit, condition) \ + ((condition) ? ((val) ^ (1ULL << (bit))) : (val)) /*! * \brief Map a value from one range to another. diff --git a/test/test-eagletrt.c b/test/test-eagletrt.c index 1129ae2..d08d4fc 100644 --- a/test/test-eagletrt.c +++ b/test/test-eagletrt.c @@ -3,7 +3,7 @@ * @brief Test suite for eagle-eco-api.c file * * @author Dorijan Di Zepp [dorijan.dizepp@eagletrt.it] - * @date 2025-11-13 + * @date 2025-11-14 */ #include @@ -14,20 +14,17 @@ static int condition_counter = 0; /* Condition function for conditional toggle */ -static bool always_true(const void *ctx) { - EAGLETRT_API_UNUSED(ctx); +static bool always_true() { return true; } -static bool always_false(const void *ctx) { - EAGLETRT_API_UNUSED(ctx); +static bool always_false() { return false; } /* Non-trivial condition function: * returns true only every 3rd call (like a periodic trigger) */ -static bool toggle_every_third_call(const void *ctx) { - EAGLETRT_API_UNUSED(ctx); +static bool toggle_every_third_call() { condition_counter++; return (condition_counter % 3 == 0); } @@ -239,37 +236,37 @@ void test_eagletrt_api_bit_get(void) { void test_eagletrt_api_bit_set_if_true(void) { uint8_t test_val = 0x00; - test_val = EAGLETRT_API_BIT_SET_IF(test_val, 2, always_true, NULL); + test_val = EAGLETRT_API_BIT_SET_IF(test_val, 2, always_true()); TEST_ASSERT_BITS(0x04, 0x04, test_val); } void test_eagletrt_api_bit_set_if_false(void) { uint8_t test_val = 0x00; - test_val = EAGLETRT_API_BIT_SET_IF(test_val, 2, always_false, NULL); + test_val = EAGLETRT_API_BIT_SET_IF(test_val, 2, always_false()); TEST_ASSERT_BITS(0x04, 0x00, test_val); } void test_eagletrt_api_bit_reset_if_true(void) { uint8_t test_val = 0xFF; - test_val = EAGLETRT_API_BIT_RESET_IF(test_val, 1, always_true, NULL); + test_val = EAGLETRT_API_BIT_RESET_IF(test_val, 1, always_true()); TEST_ASSERT_BITS(0x02, 0x00, test_val); } void test_eagletrt_api_bit_reset_if_false(void) { uint8_t test_val = 0xFF; - test_val = EAGLETRT_API_BIT_RESET_IF(test_val, 1, always_false, NULL); + test_val = EAGLETRT_API_BIT_RESET_IF(test_val, 1, always_false()); TEST_ASSERT_BITS(0x02, 0x02, test_val); } void test_eagletrt_api_bit_toggle_if_true(void) { uint8_t test_val = 0x00; - test_val = EAGLETRT_API_BIT_TOGGLE_IF(test_val, 3, always_true, NULL); + test_val = EAGLETRT_API_BIT_TOGGLE_IF(test_val, 3, always_true()); TEST_ASSERT_BITS(0x08, 0x08, test_val); // toggled } void test_eagletrt_api_bit_toggle_if_false(void) { uint8_t test_val = 0x00; - test_val = EAGLETRT_API_BIT_TOGGLE_IF(test_val, 3, always_false, NULL); + test_val = EAGLETRT_API_BIT_TOGGLE_IF(test_val, 3, always_false()); TEST_ASSERT_BITS(0x02, 0x00, test_val); // no toggle } @@ -281,22 +278,22 @@ void test_eagletrt_api_bit_set_if_dynamic_condition(void) { /* 1st call — no set */ expected = test_val; - test_val = EAGLETRT_API_BIT_SET_IF(test_val, 0, toggle_every_third_call, NULL); + test_val = EAGLETRT_API_BIT_SET_IF(test_val, 0, toggle_every_third_call()); TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, test_val, "Unexpected set on 1st call"); /* 2nd call — no set */ expected = test_val; - test_val = EAGLETRT_API_BIT_SET_IF(test_val, 0, toggle_every_third_call, NULL); + test_val = EAGLETRT_API_BIT_SET_IF(test_val, 0, toggle_every_third_call()); TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, test_val, "Unexpected set on 2nd call"); /* 3rd call — set occurs */ expected = test_val | (1u << 0); - test_val = EAGLETRT_API_BIT_SET_IF(test_val, 0, toggle_every_third_call, NULL); + test_val = EAGLETRT_API_BIT_SET_IF(test_val, 0, toggle_every_third_call()); TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, test_val, "Failed to set on 3rd call"); /* 4th call — no set */ expected = test_val; - test_val = EAGLETRT_API_BIT_SET_IF(test_val, 0, toggle_every_third_call, NULL); + test_val = EAGLETRT_API_BIT_SET_IF(test_val, 0, toggle_every_third_call()); TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, test_val, "Unexpected set on 4th call"); } @@ -308,22 +305,22 @@ void test_eagletrt_api_bit_reset_if_dynamic_condition(void) { /* 1st call — no clear */ expected = test_val; - test_val = EAGLETRT_API_BIT_RESET_IF(test_val, 0, toggle_every_third_call, NULL); + test_val = EAGLETRT_API_BIT_RESET_IF(test_val, 0, toggle_every_third_call()); TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, test_val, "Unexpected clear on 1st call"); /* 2nd call — no clear */ expected = test_val; - test_val = EAGLETRT_API_BIT_RESET_IF(test_val, 0, toggle_every_third_call, NULL); + test_val = EAGLETRT_API_BIT_RESET_IF(test_val, 0, toggle_every_third_call()); TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, test_val, "Unexpected clear on 2nd call"); /* 3rd call — clear occurs */ expected = test_val & ~(1u << 0); - test_val = EAGLETRT_API_BIT_RESET_IF(test_val, 0, toggle_every_third_call, NULL); + test_val = EAGLETRT_API_BIT_RESET_IF(test_val, 0, toggle_every_third_call()); TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, test_val, "Failed to clear on 3rd call"); /* 4th call — no clear */ expected = test_val; - test_val = EAGLETRT_API_BIT_RESET_IF(test_val, 0, toggle_every_third_call, NULL); + test_val = EAGLETRT_API_BIT_RESET_IF(test_val, 0, toggle_every_third_call()); TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, test_val, "Unexpected clear on 4th call"); } @@ -335,22 +332,22 @@ void test_eagletrt_api_bit_toggle_if_dynamic_condition(void) { /* 1st call — no toggle */ expected = test_val; - test_val = EAGLETRT_API_BIT_TOGGLE_IF(test_val, 0, toggle_every_third_call, NULL); + test_val = EAGLETRT_API_BIT_TOGGLE_IF(test_val, 0, toggle_every_third_call()); TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, test_val, "Unexpected toggle on 1st call"); /* 2nd call — no toggle */ expected = test_val; - test_val = EAGLETRT_API_BIT_TOGGLE_IF(test_val, 0, toggle_every_third_call, NULL); + test_val = EAGLETRT_API_BIT_TOGGLE_IF(test_val, 0, toggle_every_third_call()); TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, test_val, "Unexpected toggle on 2nd call"); /* 3rd call — toggle occurs */ expected = test_val ^ (1u << 0); - test_val = EAGLETRT_API_BIT_TOGGLE_IF(test_val, 0, toggle_every_third_call, NULL); + test_val = EAGLETRT_API_BIT_TOGGLE_IF(test_val, 0, toggle_every_third_call()); TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, test_val, "Failed to toggle on 3rd call"); /* 4th call — no toggle */ expected = test_val; - test_val = EAGLETRT_API_BIT_TOGGLE_IF(test_val, 0, toggle_every_third_call, NULL); + test_val = EAGLETRT_API_BIT_TOGGLE_IF(test_val, 0, toggle_every_third_call()); TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, test_val, "Unexpected toggle on 4th call"); }