From 10159507ef2ddd6662d406b001b8e0249e4d27cf Mon Sep 17 00:00:00 2001 From: Pascal Brunot Date: Sun, 14 Jul 2024 15:46:29 +0200 Subject: [PATCH] Experimental : Arduino 3.0.2 + IDF v5.1.4.240629 platform (#31) * Arduino 3.0, IDF 5.1 changes * Updated to Arduino-3.0.0-rc3 * Removed constexpr due to linker warnings * Fixed compiler warning on format string * Updated watchdog to IDF v5.1 API * Logging : now working with Arduino 3.0 * Tests: fixed logging * Watchdog: fixed failed initialization * Esp32: compatibility with IDF 5.1 * Reduced warnings/errors * Added colored output * Update test_mqtt.cpp * Updated workflows to run if needed * Update sizes.yml * Github actions: added sizes * Updating to latest IDF 5.1.14+Arduino 3.0.0 * Generate unique firmware artifact names * Warnings due to IDF 5.x redefining types from IDF 4.x * Fixing regression * Update build.yml * Update build.yml * Espressif: bugfix MAC address * compilation error * Added PIOENV as build info * Bugfix #32 + Buzzer class and tests * removed conf::machine::BEEP_PERIOD * Wrapped ESP.reset() inside esp32 namespace * LCD: Removed Warning if text is too long * Update Tasks.hpp * Tasks: simplify sorting * Lang: #ifdef instead of #if * MQTT: streaming Arduino String can be done without cstr() * Lcd: removed BaseLCDWrapper, as mockup is not needed * Tests: fix after LCDWrapper refactor * Update conf.hpp * Upgrade to released espressif platform from Jason2866 see https://github.com/Jason2866/platform-espressif32/releases/tag/2024.07.20 * Upgrade to Tasmota Espressif32 platform based on Arduino 3.0.2 * MQTT: bugfix only first IP char is sent in aliveMessage * Tasks: using std::chrono ::steady_clock::time_point instead of millis --- .github/workflows/build.yml | 5 +- .github/workflows/tags_sizes.yml | 102 ++++++++++++ .github/workflows/tests.yml | 1 + .gitignore | 2 + .vscode/settings.json | 9 +- include/AuthProvider.hpp | 9 +- include/CachedCards.hpp | 3 +- include/Logging.hpp | 7 +- include/Machine.hpp | 5 +- include/Tasks.hpp | 37 +++-- include/card.hpp | 1 + include/mock/MockMrfc522.hpp | 2 +- platformio.ini | 179 ++++++++++----------- src/AuthProvider.cpp | 6 +- src/BoardLogic.cpp | 5 +- src/BufferedMsg.cpp | 5 +- src/FabBackend.cpp | 4 +- src/Machine.cpp | 16 +- src/RFIDWrapper.tpp | 5 +- src/Tasks.cpp | 114 +++++++------ src/main.cpp | 2 + src/mock/MockMrfc522.cpp | 5 +- test/test_chrono/test_chrono.cpp | 66 ++++++++ test/test_logic/test_common.cpp | 7 +- test/test_logic/test_logic.cpp | 2 + test/test_mqtt/test_mqtt.cpp | 21 ++- test/test_savedconfig/test_savedconfig.cpp | 2 + test/test_tasks/test_tasks.cpp | 18 ++- 28 files changed, 430 insertions(+), 210 deletions(-) create mode 100644 .github/workflows/tags_sizes.yml create mode 100644 test/test_chrono/test_chrono.cpp diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4c4162f6..8ce95834 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -44,10 +44,13 @@ jobs: run: cp conf/secrets.hpp.example conf/secrets.hpp - name: Build PlatformIO Project ${{ matrix.variant }} run: pio run --environment ${{ matrix.variant }} + - name: Set sha_short variable + id: vars + run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT - name: Upload firmware image for ${{ matrix.variant }} uses: actions/upload-artifact@v4 with: - name: Firmware files for ${{ matrix.variant }} + name: FW-${{ matrix.variant }}-${{ steps.vars.outputs.sha_short }} path: | .pio/build/${{ matrix.variant }}/firmware.bin .pio/build/${{ matrix.variant }}/firmware_metrics.txt diff --git a/.github/workflows/tags_sizes.yml b/.github/workflows/tags_sizes.yml new file mode 100644 index 00000000..ad99233f --- /dev/null +++ b/.github/workflows/tags_sizes.yml @@ -0,0 +1,102 @@ +name: Compare firmware sizes (tag) + +on: + workflow_dispatch: + push: + tags: + - '*' # Trigger on all tags + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + size_report: + runs-on: ubuntu-latest + strategy: + matrix: + variant: + - hardware-rev0-it_IT + - esp32-devboard + steps: + - name: Check out the code + uses: actions/checkout@v4 + with: + fetch-depth: 50 + + - name: Install PlatformIO Core + uses: actions/setup-python@v5 + with: + python-version: '3.11' + - run: pip install --upgrade platformio + + - name: Use secrets.hpp.example as base for the build + run: cp conf/secrets.hpp.example conf/secrets.hpp + + - name: Build PlatformIO Project (current version) + run: pio run --environment ${{ matrix.variant }} + + - name: Copy latest MAP file + run: cp .pio/build/${{ matrix.variant }}/firmware.map ../firmware.map.latest + + - name: Find previous tag + id: prev_tag + run: | + tags=$(git tag --sort=-creatordate) + for tag in $tags; do + if [ "$tag" != "${GITHUB_REF#refs/tags/}" ]; then + echo "previous_tag=$tag" >> $GITHUB_ENV + break + fi + done + + - name: Check out previous tag + run: git checkout ${{ env.previous_tag }} + + - name: Use secrets.hpp.example as base for the build + run: cp conf/secrets.hpp.example conf/secrets.hpp + + - name: Build PlatformIO Project (previous version) + run: pio run --environment ${{ matrix.variant }} + + - name: Copy previous MAP file + run: cp .pio/build/${{ matrix.variant }}/firmware.map ../firmware.map.previous + + - name: Compare MAP files + run: python -m esp_idf_size --format=text --diff=../firmware.map.previous ../firmware.map.latest -o size_report.txt + + - name: Detailed report + run: python -m esp_idf_size --archives --format=text --diff=../firmware.map.previous ../firmware.map.latest -o size_report_details.txt + + - name: Upload size report + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.variant }}_size_report + path: | + size_report.txt + size_report_details.txt + retention-days: 90 + + - name: Comment size changes on release/tag page + if: startsWith(github.ref, 'refs/tags/') + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const fs = require('fs'); + const report = fs.readFileSync('size_report.txt', 'utf8'); + const previousTag = process.env.previous_tag; + if (report) { + const release = await github.rest.repos.getReleaseByTag({ + owner: context.repo.owner, + repo: context.repo.repo, + tag: context.ref.substring(10) + }); + const truncatedReport = report.length > 63*1024 ? report.substring(0, 63*1024) + '... (truncated)' : report; + await github.rest.repos.updateRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + release_id: release.data.id, + body: release.data.body + '\n\n## Firmware size changes for ${{ matrix.variant }}\n\nCommit CURRENT ' + context.sha + ' vs REFERENCE ' + previousTag + '\n```\n' + truncatedReport + '\n```' + }); + } diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 033bd0ec..bcf1bf5b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -26,6 +26,7 @@ jobs: - test_logic - test_savedconfig - test_tasks + - test_chrono steps: - uses: actions/checkout@v4 with: diff --git a/.gitignore b/.gitignore index eba1909a..2da9cdf4 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ log.txt rfid-arduino.code-workspace secrets.hpp tools/__pycache__/ +build/ +managed_components/ \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 25c918b3..5ba4dbc9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -67,7 +67,14 @@ "set": "cpp", "future": "cpp", "variant": "cpp", - "any": "cpp" + "any": "cpp", + "bit": "cpp", + "compare": "cpp", + "concepts": "cpp", + "netfwd": "cpp", + "numbers": "cpp", + "semaphore": "cpp", + "stop_token": "cpp" }, "cmake.sourceDirectory": "D:/GitHub/rfid-arduino/.pio/libdeps/desktop/ArduinoJson", "cmake.configureOnOpen": false, diff --git a/include/AuthProvider.hpp b/include/AuthProvider.hpp index fab8cd2b..89db8237 100644 --- a/include/AuthProvider.hpp +++ b/include/AuthProvider.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "FabUser.hpp" #include "secrets.hpp" @@ -20,10 +21,10 @@ namespace fabomatic WhiteList whitelist; mutable CachedCards cache; mutable size_t cache_idx{0}; - [[nodiscard]] auto uidInWhitelist(card::uid_t uid) const -> std::optional; - [[nodiscard]] auto uidInCache(card::uid_t uid) const -> std::optional; - [[nodiscard]] auto searchCache(card::uid_t candidate_uid) const -> std::optional; - auto updateCache(card::uid_t candidate_uid, FabUser::UserLevel level) const -> void; + [[nodiscard]] constexpr auto uidInWhitelist(card::uid_t uid) const -> std::optional; + [[nodiscard]] constexpr auto uidInCache(card::uid_t uid) const -> std::optional; + [[nodiscard]] constexpr auto searchCache(card::uid_t candidate_uid) const -> std::optional; + constexpr auto updateCache(card::uid_t candidate_uid, FabUser::UserLevel level) const -> void; public: AuthProvider() = delete; diff --git a/include/CachedCards.hpp b/include/CachedCards.hpp index 05621ed6..d56b6e16 100644 --- a/include/CachedCards.hpp +++ b/include/CachedCards.hpp @@ -2,6 +2,7 @@ #define CACHEDCARDS_HPP #include +#include #include "FabUser.hpp" #include "conf.hpp" @@ -32,7 +33,7 @@ namespace fabomatic return {cards[i], levels[i]}; } - auto find_uid(const card::uid_t &search_uid) const -> const std::optional + constexpr auto find_uid(const card::uid_t &search_uid) const -> const std::optional { if (search_uid == card::INVALID) { diff --git a/include/Logging.hpp b/include/Logging.hpp index 4b49bb56..9ad0a3c4 100644 --- a/include/Logging.hpp +++ b/include/Logging.hpp @@ -1,8 +1,13 @@ #ifndef LOGGING_HPP_ #define LOGGING_HPP_ -#include "esp_log.h" +#ifndef LOG_LOCAL_LEVEL +#define LOG_LOCAL_LEVEL 5 +#endif +#undef TAG [[maybe_unused]] static const char *const TAG = "FAB-O-MATIC"; // Required for ESP32 Logging +#include "esp_log.h" + #endif // LOGGING_HPP_ \ No newline at end of file diff --git a/include/Machine.hpp b/include/Machine.hpp index 1854dff1..c59b767e 100644 --- a/include/Machine.hpp +++ b/include/Machine.hpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace fabomatic { @@ -106,8 +107,8 @@ namespace fabomatic bool active{false}; FabUser current_user{}; - std::optional> usage_start_timestamp{std::nullopt}; // When did the machine start? - std::optional> logoff_timestamp{std::nullopt}; // When did the last user log off? + std::optional usage_start_timestamp{std::nullopt}; // When did the machine start? + std::optional logoff_timestamp{std::nullopt}; // When did the last user log off? PowerState power_state{PowerState::PoweredOff}; /// @brief If true, machine needs maintenance diff --git a/include/Tasks.hpp b/include/Tasks.hpp index 82f788c6..6bb9309b 100644 --- a/include/Tasks.hpp +++ b/include/Tasks.hpp @@ -3,14 +3,20 @@ #include #include +#include "Arduino.h" +#include /// @brief This namespace contains the classes that implement a cooperative task scheduler namespace fabomatic::Tasks { using milliseconds = std::chrono::milliseconds; - using time_point_sc = std::chrono::time_point; using namespace std::chrono_literals; + [[nodiscard]] inline auto arduinoNow() -> const std::chrono::steady_clock::time_point + { + return std::chrono::steady_clock::now(); + } + class Scheduler; /// @brief A task class which represents a function to be called at requested intervals @@ -63,7 +69,7 @@ namespace fabomatic::Tasks [[nodiscard]] auto isActive() const -> bool; /// @brief Current period of the task - [[nodiscard]] auto getPeriod() const -> milliseconds; + [[nodiscard]] auto getPeriod() const -> const milliseconds; /// @brief Function to be called when task is run /// @return Callback function @@ -74,28 +80,30 @@ namespace fabomatic::Tasks /// @brief Get the initial delay before the task is run at given period /// @return Delay in milliseconds - [[nodiscard]] auto getDelay() const -> milliseconds; + [[nodiscard]] auto getDelay() const -> const milliseconds; /// @brief Get the average tardiness, i.e. the average period between scheduled start and actual start of execution. - [[nodiscard]] auto getAvgTardiness() const -> milliseconds; + [[nodiscard]] auto getAvgTardiness() const -> const milliseconds; /// @brief Gets the number of times the task has been run. [[nodiscard]] auto getRunCounter() const -> unsigned long; /// @brief Gets the total execution time of the task. Useful to spot slowest tasks - [[nodiscard]] auto getTotalRuntime() const -> milliseconds; + [[nodiscard]] auto getTotalRuntime() const -> const milliseconds; /// @brief When shall the task be run again /// @return time_point of the next run or time_point::max() if the task will not run. - [[nodiscard]] auto getNextRun() const -> time_point_sc; + [[nodiscard]] auto getNextRun() const -> const std::chrono::steady_clock::time_point; + + [[nodiscard]] auto toString() const -> const std::string; private: bool active; const std::string id; milliseconds period; milliseconds delay; - time_point_sc last_run; - time_point_sc next_run; + std::chrono::steady_clock::time_point last_run; + std::chrono::steady_clock::time_point next_run; milliseconds average_tardiness; milliseconds total_runtime; std::function callback; @@ -106,12 +114,13 @@ namespace fabomatic::Tasks class Scheduler { public: - auto addTask(Task &task) -> void; - auto removeTask(const Task &task) -> void; + constexpr Scheduler(){}; + auto addTask(Task *task) -> void; + auto removeTask(const Task *task) -> void; /// @brief Execute all tasks that are ready to run /// @details Tasks will be ordered by next_run time ascending, then run sequentially - auto execute() const -> void; + auto execute() -> void; /// @brief Recompute all the next run times for all the tasks auto updateSchedules() const -> void; @@ -119,11 +128,11 @@ namespace fabomatic::Tasks /// @brief Gets the number of tasks in the scheduler [[nodiscard]] auto taskCount() const -> size_t; - /// @brief Get a vector of references to the tasks - [[nodiscard]] auto getTasks() const -> const std::vector>; + /// @brief Get a copy vector of task pointers + [[nodiscard]] auto getTasks() const -> const std::vector; private: - std::vector> tasks; // Vector containing references to the tasks, not the tasks themselves + std::vector tasks; auto printStats() const -> void; }; diff --git a/include/card.hpp b/include/card.hpp index a93920fe..d3782805 100644 --- a/include/card.hpp +++ b/include/card.hpp @@ -8,6 +8,7 @@ #include "conf.hpp" #include "Logging.hpp" +#include namespace fabomatic::card { diff --git a/include/mock/MockMrfc522.hpp b/include/mock/MockMrfc522.hpp index c2690cfd..7b8d030e 100644 --- a/include/mock/MockMrfc522.hpp +++ b/include/mock/MockMrfc522.hpp @@ -19,7 +19,7 @@ namespace fabomatic { private: std::optional uid{std::nullopt}; - std::optional> stop_uid_simulate_time{std::nullopt}; + std::optional stop_uid_simulate_time{std::nullopt}; std::optional getSimulatedUid() const; public: diff --git a/platformio.ini b/platformio.ini index a3fa4744..208f16e2 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,72 +9,62 @@ ; https://docs.platformio.org/page/projectconf.html [platformio] -build_cache_dir = .pio/build_cache -name = fab-o-matic +build_cache_dir = .pio/build_cache +name = fab-o-matic [env] -platform = espressif32@^6.7.0 -platform_packages = framework-arduinoespressif32 -framework = arduino -test_framework = unity -check_tool = clangtidy -check_flags = clangtidy: --checks=-*,cert-*,clang-analyzer-*,llvm-*,cppcoreguidelines-*,-cppcoreguidelines-pro-type-vararg,-cppcoreguidelines-avoid-magic-numbers,-cppcoreguidelines-pro-bounds-array-to-pointer-decay -monitor_speed = 115200 -test_build_src = yes +platform = https://github.com/tasmota/platform-espressif32/releases/download/2024.07.10/platform-espressif32.zip +framework = arduino +test_framework = unity +check_tool = clangtidy +check_flags = clangtidy: --checks=-*,cert-*,clang-analyzer-*,llvm-*,cppcoreguidelines-*,-cppcoreguidelines-pro-type-vararg,-cppcoreguidelines-avoid-magic-numbers,-cppcoreguidelines-pro-bounds-array-to-pointer-decay +monitor_speed = 115200 +test_build_src = yes monitor_filters = esp32_exception_decoder - colorize -lib_ldf_mode = chain+ -lib_deps = https://github.com/PBrunot/LiquidCrystal.git#use_const - https://github.com/bblanchon/ArduinoJson.git#v7.0.4 - 256dpi/MQTT - https://github.com/OSSLibraries/Arduino_MFRC522v2.git#2.0.4 - Wire - adafruit/Adafruit NeoPixel@^1.12.0 - https://github.com/tzapu/WiFiManager.git@2.0.17 - https://github.com/terrorsl/sMQTTBroker.git - ArduinoOTA -build_unflags = -std=gnu++11 -fexceptions -build_flags = -std=gnu++2a - -ffunction-sections - -fdata-sections - -g3 - -fno-exceptions # Arduino does not use exceptions - -Os - -I conf - -Wno-deprecated-declarations - -D CONFIG_LOG_COLORS + colorize +lib_ldf_mode = deep +lib_deps = https://github.com/PBrunot/LiquidCrystal.git#use_const + https://github.com/bblanchon/ArduinoJson.git#v7.0.4 + 256dpi/MQTT + https://github.com/OSSLibraries/Arduino_MFRC522v2.git#2.0.4 + Wire + adafruit/Adafruit NeoPixel@^1.12.2 + https://github.com/tzapu/WiFiManager.git@2.0.17 + https://github.com/terrorsl/sMQTTBroker.git + ArduinoOTA +build_unflags = -std=gnu++11 -fexceptions +build_flags = -std=gnu++2b + -ffunction-sections + -fdata-sections + -g3 + -fno-exceptions + -Os + -I conf + -Wno-deprecated-declarations + -Wno-attributes + -Wno-maybe-uninitialized + -D CORE_DEBUG_LEVEL=0 + -D CONFIG_LOG_COLORS build_src_flags = -Wformat=2 - -Wformat-truncation - -Wall - -Wextra - -Wl,-Map,firmware.map,--cref - -Wstack-usage=2048 - -D FABOMATIC_BUILD="\"$PIOENV\"" -debug_build_flags = ${env.build_flags} - -Og - -D DEBUG - -Wall - -Wextra -extra_scripts = pre:tools/git_version.py - post:tools/metrics_firmware.py + -Wformat-truncation + -Wall + -Wextra + -Wl,-Map,firmware.map,--cref,--no-warn-rwx-segments + -Wstack-usage=2048 + -D LOG_LOCAL_LEVEL=ESP_LOG_VERBOSE + -D FABOMATIC_BUILD="\"$PIOENV\"" +debug_build_flags = ${env.build_flags} + -Og + -D DEBUG + -Wall + -Wextra +extra_scripts = pre:tools/git_version.py + post:tools/metrics_firmware.py + -[env:esp32-s3] -board = esp32-s3-devkitc-1 -build_type = release -board_build.f_cpu = 160000000L -board_build.f_flash = 80000000L -board_build.flash_mode = dio -build_src_flags = ${env.build_src_flags} - -D CORE_DEBUG_LEVEL=3 - -D MQTT_SIMULATION=false - -D RFID_SIMULATION=false - -D PINS_ESP32S3 - -D DEBUG - -D FABOMATIC_LANG_IT_IT - [hardware-base] -board = esp32-s3-devkitc-1 -board_build.partitions = default.csv +board = esp32-s3-devkitc-1 +board_build.partitions = default.csv board_upload.flash_size = 4MB build_type = debug board_build.f_cpu = 240000000L @@ -87,48 +77,45 @@ build_src_flags = ${env.build_src_flags} -D RFID_SIMULATION=false -D PINS_HARDWARE_REV0 -D DEBUG + [env:hardware-rev0-it_IT] -extends = hardware-base -build_src_flags = ${hardware-base.build_src_flags} - -D FABOMATIC_LANG_IT_IT +extends = hardware-base +build_src_flags = ${hardware-base.build_src_flags} + -D FABOMATIC_LANG_IT_IT [env:hardware-rev0-en_US] -extends = hardware-base -build_src_flags = ${hardware-base.build_src_flags} - -D FABOMATIC_LANG_EN_US +extends = hardware-base +build_src_flags = ${hardware-base.build_src_flags} + -D FABOMATIC_LANG_EN_US [env:esp32-devboard] -board = esp32dev -build_type = release -build_src_flags = ${env.build_src_flags} - -D CORE_DEBUG_LEVEL=3 - -D MQTT_SIMULATION=false - -D RFID_SIMULATION=false - -D PINS_ESP32 - -D FABOMATIC_LANG_IT_IT - -upload_protocol = espota -upload_port = 192.168.45.82 +board = esp32dev +build_type = release +build_src_flags = ${env.build_src_flags} + -D MQTT_SIMULATION=false + -D RFID_SIMULATION=false + -D PINS_ESP32 + -D FABOMATIC_LANG_IT_IT +upload_protocol = espota +upload_port = 192.168.45.82 [env:wokwi] -board = esp32-s2-saola-1 -build_type = debug -build_src_flags = ${env.build_src_flags} - -D CORE_DEBUG_LEVEL=4 - -D MQTT_SIMULATION=true - -D RFID_SIMULATION=true - -D PINS_WOKWI - -D FABOMATIC_LANG_EN_US +board = esp32-s2-saola-1 +build_type = debug +build_src_flags = ${env.build_src_flags} + -D MQTT_SIMULATION=true + -D RFID_SIMULATION=true + -D PINS_WOKWI + -D FABOMATIC_LANG_EN_US [env:wrover-kit-it_IT] -board = esp-wrover-kit -build_type = debug -debug_tool = ftdi -debug_init_break = break setup -build_src_flags = ${env.build_src_flags} - -D CORE_DEBUG_LEVEL=3 - -D MQTT_SIMULATION=false - -D RFID_SIMULATION=true - -D PINS_ESP32_WROVERKIT - -D DEBUG - -D FABOMATIC_LANG_IT_IT \ No newline at end of file +board = esp-wrover-kit +build_type = debug +debug_tool = ftdi +debug_init_break = break setup +build_src_flags = ${env.build_src_flags} + -D MQTT_SIMULATION=false + -D RFID_SIMULATION=true + -D PINS_ESP32_WROVERKIT + -D DEBUG + -D FABOMATIC_LANG_IT_IT diff --git a/src/AuthProvider.cpp b/src/AuthProvider.cpp index b075de84..c632f0f5 100644 --- a/src/AuthProvider.cpp +++ b/src/AuthProvider.cpp @@ -21,7 +21,7 @@ namespace fabomatic /// @param uid card id of the user /// @param name name of the user to be cached /// @param level priviledge level of the user - void AuthProvider::updateCache(card::uid_t uid, FabUser::UserLevel level) const + constexpr void AuthProvider::updateCache(card::uid_t uid, FabUser::UserLevel level) const { // Search for the card in the cache const auto pos = std::find(cache.cards.cbegin(), cache.cards.cend(), uid); @@ -128,7 +128,7 @@ namespace fabomatic /// @brief Checks if the card ID is whitelisted /// @param uid card ID /// @return a whitelistentry object if the card is found in whitelist - auto AuthProvider::uidInWhitelist(card::uid_t candidate_uid) const -> std::optional + constexpr auto AuthProvider::uidInWhitelist(card::uid_t candidate_uid) const -> std::optional { if (candidate_uid == card::INVALID) { @@ -154,7 +154,7 @@ namespace fabomatic /// @brief Checks if the card ID is whitelisted /// @param uid card ID /// @return a whitelistentry object if the card is found in whitelist - auto AuthProvider::uidInCache(card::uid_t candidate_uid) const -> std::optional + constexpr auto AuthProvider::uidInCache(card::uid_t candidate_uid) const -> std::optional { return cache.find_uid(candidate_uid); } diff --git a/src/BoardLogic.cpp b/src/BoardLogic.cpp index 2e460830..a81a423c 100644 --- a/src/BoardLogic.cpp +++ b/src/BoardLogic.cpp @@ -20,6 +20,7 @@ #ifndef GIT_VERSION #define GIT_VERSION "??????" #endif +#include namespace fabomatic { @@ -136,7 +137,7 @@ namespace fabomatic getLcd().setRow(1, ss.str()); getLcd().update(bi); - const auto start = std::chrono::system_clock::now(); + const auto start = fabomatic::Tasks::arduinoNow(); if (!getRfid().cardStillThere(card, delay_per_step)) { getLcd().setRow(1, strings::S_CANCELLED); @@ -145,7 +146,7 @@ namespace fabomatic } // cardStillThere may have returned immediately, so we need to wait a bit - const auto elapsed = std::chrono::duration_cast(std::chrono::system_clock::now() - start); + const auto elapsed = std::chrono::duration_cast(fabomatic::Tasks::arduinoNow() - start); if (delay_per_step - elapsed > 10ms) { Tasks::delay(delay_per_step - elapsed); diff --git a/src/BufferedMsg.cpp b/src/BufferedMsg.cpp index d7637c1a..1ca5a670 100644 --- a/src/BufferedMsg.cpp +++ b/src/BufferedMsg.cpp @@ -1,5 +1,6 @@ #include "BufferedMsg.hpp" +#include #include #include "Logging.hpp" @@ -18,7 +19,7 @@ namespace fabomatic } has_changed = true; - ESP_LOGI(TAG, "Buffered %s on %s, %lu messages queued", + ESP_LOGI(TAG, "Buffered %s on %s, %u messages queued", message.mqtt_message.c_str(), message.mqtt_topic.c_str(), msg_queue.size()); @@ -37,7 +38,7 @@ namespace fabomatic } has_changed = true; - ESP_LOGI(TAG, "Buffered %s on %s, %lu messages queued", + ESP_LOGI(TAG, "Buffered %s on %s, %u messages queued ", message.mqtt_message.c_str(), message.mqtt_topic.c_str(), msg_queue.size()); diff --git a/src/FabBackend.cpp b/src/FabBackend.cpp index 47e333d7..af2a49cc 100644 --- a/src/FabBackend.cpp +++ b/src/FabBackend.cpp @@ -203,7 +203,7 @@ namespace fabomatic */ bool FabBackend::waitForAnswer(std::chrono::milliseconds max_duration) { - const auto start_time = std::chrono::system_clock::now(); + const auto start_time = Tasks::arduinoNow(); const auto DELAY_MS = 25ms; do { @@ -221,7 +221,7 @@ namespace fabomatic { return true; } - } while (std::chrono::system_clock::now() < (start_time + max_duration)); + } while (Tasks::arduinoNow() < (start_time + max_duration)); ESP_LOGE(TAG, "Failure, no answer from MQTT server (timeout:%lld ms)", max_duration.count()); return false; diff --git a/src/Machine.cpp b/src/Machine.cpp index b9a93176..f88c7359 100644 --- a/src/Machine.cpp +++ b/src/Machine.cpp @@ -9,6 +9,7 @@ #include #include #include +#include namespace fabomatic { @@ -69,7 +70,7 @@ namespace fabomatic active = true; current_user = user; power(true); - usage_start_timestamp = std::chrono::system_clock::now(); + usage_start_timestamp = fabomatic::Tasks::arduinoNow(); return true; } return false; @@ -93,7 +94,7 @@ namespace fabomatic usage_start_timestamp = std::nullopt; // Sets the countdown to power off - logoff_timestamp = std::chrono::system_clock::now(); + logoff_timestamp = fabomatic::Tasks::arduinoNow(); if (config.value().grace_period == 0s) { @@ -115,7 +116,7 @@ namespace fabomatic CHECK_CONFIGURED(bool); return (power_state == PowerState::WaitingPowerOff && - std::chrono::system_clock::now() - logoff_timestamp.value() > config.value().grace_period); + fabomatic::Tasks::arduinoNow() - logoff_timestamp.value() > config.value().grace_period); } /// @brief indicates if the machine is about to shudown and board should beep @@ -128,7 +129,7 @@ namespace fabomatic CHECK_CONFIGURED(bool); return (power_state == PowerState::WaitingPowerOff && - std::chrono::system_clock::now() - logoff_timestamp.value() <= config.value().grace_period); + fabomatic::Tasks::arduinoNow() - logoff_timestamp.value() <= config.value().grace_period); } /// @brief sets the machine power to on (true) or off (false) @@ -227,7 +228,7 @@ namespace fabomatic { if (usage_start_timestamp.has_value()) { - return std::chrono::duration_cast(std::chrono::system_clock::now() - usage_start_timestamp.value()); + return std::chrono::duration_cast(fabomatic::Tasks::arduinoNow() - usage_start_timestamp.value()); } return 0s; } @@ -259,7 +260,10 @@ namespace fabomatic sstream << ", MaintenanceNeeded:" << maintenanceNeeded; sstream << ", " << config.value().toString(); sstream << ", Active:" << active; - sstream << ", Last logoff:" << (logoff_timestamp.has_value() ? logoff_timestamp.value().time_since_epoch().count() : 0); + if (logoff_timestamp) + { + sstream << ", Last logoff:" << logoff_timestamp.value().time_since_epoch(); + } sstream << ", GracePeriod (s):" << getGracePeriod().count(); sstream << ")"; diff --git a/src/RFIDWrapper.tpp b/src/RFIDWrapper.tpp index 2712c9cb..0ecbccc7 100644 --- a/src/RFIDWrapper.tpp +++ b/src/RFIDWrapper.tpp @@ -6,6 +6,7 @@ #include "card.hpp" #include "conf.hpp" #include "pins.hpp" +#include "Tasks.hpp" namespace fabomatic { @@ -47,7 +48,7 @@ namespace fabomatic template auto RFIDWrapper::cardStillThere(const card::uid_t original, std::chrono::milliseconds max_delay) const -> bool { - const auto start = std::chrono::system_clock::now(); + const auto start = fabomatic::Tasks::arduinoNow(); do { // Detect Tag without looking for collisions @@ -60,7 +61,7 @@ namespace fabomatic return true; } delay(20); - } while (std::chrono::system_clock::now() - start < max_delay); + } while (fabomatic::Tasks::arduinoNow() - start < max_delay); return false; } diff --git a/src/Tasks.cpp b/src/Tasks.cpp index 6d083f26..93f90213 100644 --- a/src/Tasks.cpp +++ b/src/Tasks.cpp @@ -5,25 +5,27 @@ #include "Arduino.h" #include "ArduinoOTA.h" #include +#include #include "Logging.hpp" namespace fabomatic::Tasks { using milliseconds = std::chrono::milliseconds; - using time_point_sc = std::chrono::time_point; + using namespace std::chrono_literals; - auto Scheduler::addTask(Task &task) -> void + auto Scheduler::addTask(Task *task) -> void { - tasks.push_back(task); + if (task != nullptr) + tasks.push_back(task); } - auto Scheduler::removeTask(const Task &task) -> void + auto Scheduler::removeTask(const Task *task) -> void { tasks.erase(std::remove_if(tasks.begin(), tasks.end(), [&task](const auto &t) - { return t.get().getId() == task.getId(); }), + { return t->getId() == task->getId(); }), tasks.end()); } @@ -31,7 +33,7 @@ namespace fabomatic::Tasks { for (const auto &task : tasks) { - task.get().updateSchedule(); + task->updateSchedule(); } } @@ -42,8 +44,8 @@ namespace fabomatic::Tasks for (const auto &task : tasks) { - avg_delay += task.get().getAvgTardiness() * task.get().getRunCounter(); - nb_runs += task.get().getRunCounter(); + avg_delay += task->getAvgTardiness() * task->getRunCounter(); + nb_runs += task->getRunCounter(); } if (nb_runs > 0) { @@ -54,43 +56,38 @@ namespace fabomatic::Tasks for (const auto &task : tasks) { - if (task.get().isActive()) + if (task->isActive()) { - if (task.get().getRunCounter() > 0) + if (task->getRunCounter() > 0) { ESP_LOGD(TAG, "\t Task: %s, %lu runs, avg tardiness/run: %llu ms, period %llu ms, delay %llu ms, average task duration %llu ms\r\n", - task.get().getId().c_str(), task.get().getRunCounter(), - task.get().getAvgTardiness().count(), task.get().getPeriod().count(), - task.get().getDelay().count(), - task.get().getTotalRuntime().count() / task.get().getRunCounter()); + task->getId().c_str(), task->getRunCounter(), + task->getAvgTardiness().count(), task->getPeriod().count(), + task->getDelay().count(), + task->getTotalRuntime().count() / task->getRunCounter()); } else { ESP_LOGD(TAG, "\t Task: %s, never ran, period %llu ms, delay %llu ms\r\n", - task.get().getId().c_str(), task.get().getPeriod().count(), - task.get().getDelay().count()); + task->getId().c_str(), task->getPeriod().count(), + task->getDelay().count()); } } else { - ESP_LOGD(TAG, "\t Task: %s, inactive\r\n", task.get().getId().c_str()); + ESP_LOGD(TAG, "\t Task: %s, inactive\r\n", task->getId().c_str()); } } } - auto Scheduler::execute() const -> void + auto Scheduler::execute() -> void { - // Need a copy to mutate the order - std::vector mutableTasks(tasks.begin(), tasks.end()); - - // Tasks shall be run in order of expiration (the most expired task shall run first) - std::sort(mutableTasks.begin(), mutableTasks.end(), [](const Task &a, const Task &b) - { return a.getNextRun() < b.getNextRun(); }); + std::sort(tasks.begin(), tasks.end(), [](const auto &x, const auto &y) + { return x->getNextRun() < y->getNextRun(); }); - // Now iterate over the sorted tasks to run the tasks - for (const auto &it : mutableTasks) + for (const auto &t : tasks) { - it.get().run(); + t->run(); } if (conf::debug::ENABLE_TASK_LOGS && millis() % 1024 == 0) @@ -110,7 +107,7 @@ namespace fabomatic::Tasks return tasks.size(); } - auto Scheduler::getTasks() const -> const std::vector> + auto Scheduler::getTasks() const -> const std::vector { return {tasks}; } @@ -126,31 +123,45 @@ namespace fabomatic::Tasks std::function callback, Scheduler &scheduler, bool active, milliseconds delay) : active{active}, id{id}, period{period}, delay{delay}, - last_run{std::chrono::system_clock::now() + delay}, next_run{last_run}, average_tardiness{0ms}, total_runtime{0ms}, callback{callback}, run_counter{0} { - scheduler.addTask(std::ref(*this)); + last_run = arduinoNow() + period; + scheduler.addTask(this); + if constexpr (conf::debug::ENABLE_TASK_LOGS) + { + ESP_LOGD(TAG, "Constructor(%s)\r\n", toString().c_str()); + } + } + + auto Task::toString() const -> const std::string + { + std::stringstream ss; + ss << "Task " << getId() << ", active=" << active + << ",Period=" << period << ", Delay=" << delay + << ",Last run=" << last_run.time_since_epoch() + << ",Next_run=" << next_run.time_since_epoch() + << ",Avg tardiness=" << average_tardiness + << ",total_runtime " << total_runtime + << ",run_counter=" << run_counter + << ",clock=" << millis(); + return ss.str(); } auto Task::run() -> void { - if (isActive() && std::chrono::system_clock::now() >= next_run) + auto time_to_run = (arduinoNow() - next_run).count() > 0; + if (isActive() && time_to_run) { run_counter++; - auto last_period = std::chrono::duration_cast(std::chrono::system_clock::now() - last_run); - average_tardiness = (average_tardiness * (run_counter - 1) + last_period) / run_counter; - last_run = std::chrono::system_clock::now(); - - if (conf::debug::ENABLE_TASK_LOGS) - { - ESP_LOGD(TAG, "Task %s\r\n", getId().c_str()); - } + auto last_duration = std::chrono::duration_cast(arduinoNow() - last_run); + average_tardiness = (average_tardiness * (run_counter - 1) + last_duration) / run_counter; + last_run = arduinoNow(); callback(); - total_runtime += std::chrono::duration_cast(std::chrono::system_clock::now() - last_run); + total_runtime += std::chrono::duration_cast(arduinoNow() - last_run); if (period > 0ms) { @@ -158,7 +169,12 @@ namespace fabomatic::Tasks } else { - next_run = std::chrono::system_clock::time_point::max(); // Disable the task + next_run = next_run.max(); // Disable the task + } + + if constexpr (conf::debug::ENABLE_TASK_LOGS) + { + ESP_LOGD(TAG, "Completed(%s)\r\n", toString().c_str()); } } } @@ -177,7 +193,7 @@ namespace fabomatic::Tasks /// @brief recompute the next run time (now + delay) auto Task::updateSchedule() -> void { - last_run = std::chrono::system_clock::now() + delay; + last_run = arduinoNow() + delay; next_run = last_run; } @@ -196,7 +212,7 @@ namespace fabomatic::Tasks return active; } - auto Task::getPeriod() const -> milliseconds + auto Task::getPeriod() const -> const milliseconds { return period; } @@ -211,7 +227,7 @@ namespace fabomatic::Tasks return id; } - auto Task::getAvgTardiness() const -> milliseconds + auto Task::getAvgTardiness() const -> const milliseconds { if (average_tardiness > period) { @@ -225,7 +241,7 @@ namespace fabomatic::Tasks return run_counter; } - auto Task::getDelay() const -> milliseconds + auto Task::getDelay() const -> const milliseconds { return delay; } @@ -235,12 +251,12 @@ namespace fabomatic::Tasks delay = new_delay; } - auto Task::getTotalRuntime() const -> milliseconds + auto Task::getTotalRuntime() const -> const milliseconds { return total_runtime; } - auto Task::getNextRun() const -> std::chrono::time_point + auto Task::getNextRun() const -> const std::chrono::steady_clock::time_point { return next_run; } @@ -257,11 +273,11 @@ namespace fabomatic::Tasks return; } - const auto start = std::chrono::system_clock::now(); + const auto &start = arduinoNow(); do { ::delay(50); ArduinoOTA.handle(); - } while (std::chrono::system_clock::now() - start < duration); + } while (arduinoNow() - start < duration); } } // namespace fabomatic::Tasks \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index a760f2a5..42469b0e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -419,6 +419,8 @@ void setup() Serial.begin(fabomatic::conf::debug::SERIAL_SPEED_BDS); // Initialize serial communications with the PC for debugging. delay(3000); + esp_log_level_set(TAG, LOG_LOCAL_LEVEL); + if constexpr (fabomatic::conf::debug::ENABLE_LOGS) { Serial.setDebugOutput(true); diff --git a/src/mock/MockMrfc522.cpp b/src/mock/MockMrfc522.cpp index f1db933d..1c9210e4 100644 --- a/src/mock/MockMrfc522.cpp +++ b/src/mock/MockMrfc522.cpp @@ -1,4 +1,5 @@ #include "mock/MockMrfc522.hpp" +#include "Tasks.hpp" #include @@ -45,7 +46,7 @@ namespace fabomatic this->uid = uid; if (max_delay.has_value()) { - stop_uid_simulate_time = std::chrono::system_clock::now() + max_delay.value(); + stop_uid_simulate_time = fabomatic::Tasks::arduinoNow() + max_delay.value(); } else { @@ -61,7 +62,7 @@ namespace fabomatic auto MockMrfc522::getSimulatedUid() const -> std::optional { - if (stop_uid_simulate_time.has_value() && std::chrono::system_clock::now() > stop_uid_simulate_time.value()) + if (stop_uid_simulate_time.has_value() && fabomatic::Tasks::arduinoNow() > stop_uid_simulate_time.value()) { return std::nullopt; } diff --git a/test/test_chrono/test_chrono.cpp b/test/test_chrono/test_chrono.cpp new file mode 100644 index 00000000..bfa455f4 --- /dev/null +++ b/test/test_chrono/test_chrono.cpp @@ -0,0 +1,66 @@ +#include +#include +#include + +#include +#define UNITY_INCLUDE_PRINT_FORMATTED +#include +#include "Tasks.hpp" +#include "Logging.hpp" +#include "Espressif.hpp" + +[[maybe_unused]] static const char *TAG4 = "test_chrono"; + +using namespace std::chrono_literals; + +namespace fabomatic::tests +{ + using Task = fabomatic::Tasks::Task; + using Scheduler = fabomatic::Tasks::Scheduler; + + void tearDown(void) + { + } + + void setUp(void) + { + // set stuff up here + } + + void test_steady_clock(void) + { + static constexpr auto nb_tests = 100; + + auto cpt = 0; + TEST_ASSERT_TRUE_MESSAGE(std::chrono::steady_clock::is_steady, "Steady clock available"); + auto previous_val = std::chrono::steady_clock::now(); + while (cpt < nb_tests) + { + auto val = std::chrono::steady_clock::now(); + auto duration = (val - previous_val); + auto count = duration.count(); + std::stringstream ss{}; + ss << "Duration = " << duration << ", tse=" << val.time_since_epoch(); + auto log = ss.str().c_str(); + ESP_LOGI(TAG4, "%s", log); + TEST_ASSERT_GREATER_THAN_MESSAGE(0, count, "Duration"); + ::delay(10); + previous_val = val; + cpt++; + } + } + +} // namespace fabomatic::tests + +void setup() +{ + delay(1000); + esp_log_level_set(TAG4, LOG_LOCAL_LEVEL); + UNITY_BEGIN(); + RUN_TEST(fabomatic::tests::test_steady_clock); + UNITY_END(); // stop unit testing +} + +void loop() +{ +} \ No newline at end of file diff --git a/test/test_logic/test_common.cpp b/test/test_logic/test_common.cpp index 56758829..f613ed76 100644 --- a/test/test_logic/test_common.cpp +++ b/test/test_logic/test_common.cpp @@ -7,6 +7,7 @@ #include "mock/MockMrfc522.hpp" #include "test_common.h" #include "unity.h" +#include "Tasks.hpp" namespace fabomatic::tests { @@ -30,12 +31,14 @@ namespace fabomatic::tests { driver.setUid(uid.value(), duration_tap); TEST_ASSERT_TRUE_MESSAGE(uid == rfid.getUid(), "Card UID not equal"); - auto start = millis(); + auto start = fabomatic::Tasks::arduinoNow(); + do { logic.checkRfid(); delay(50); - } while (duration_tap.has_value() && millis() - start < duration_tap.value_or(0ms).count()); + } while (duration_tap.has_value() && fabomatic::Tasks::arduinoNow() - start < duration_tap); + } else if (duration_tap) { diff --git a/test/test_logic/test_logic.cpp b/test/test_logic/test_logic.cpp index db386949..94d28b18 100644 --- a/test/test_logic/test_logic.cpp +++ b/test/test_logic/test_logic.cpp @@ -354,6 +354,8 @@ void setUp(void) void setup() { delay(1000); + esp_log_level_set(TAG, LOG_LOCAL_LEVEL); + auto config = fabomatic::SavedConfig::LoadFromEEPROM(); UNITY_BEGIN(); RUN_TEST(fabomatic::tests::test_machine_defaults); diff --git a/test/test_mqtt/test_mqtt.cpp b/test/test_mqtt/test_mqtt.cpp index 806b82f6..42c5c1d2 100644 --- a/test/test_mqtt/test_mqtt.cpp +++ b/test/test_mqtt/test_mqtt.cpp @@ -113,9 +113,9 @@ namespace fabomatic::tests exit_request = false; pthread_create(&thread_mqtt_broker, &attr_mqtt_broker, threadMQTTServer, NULL); - auto start = std::chrono::system_clock::now(); + auto start = fabomatic::Tasks::arduinoNow(); constexpr auto timeout = 5s; - while (!broker.isRunning() && std::chrono::system_clock::now() - start < timeout) + while (!broker.isRunning() && fabomatic::Tasks::arduinoNow() - start < timeout) { delay(100); } @@ -284,10 +284,7 @@ namespace fabomatic::tests } if (initialized) { - if (!esp32::signalWatchdog()) - { - ESP_LOGE(TAG, "Failure to signal watchdog"); - } + TEST_ASSERT_TRUE_MESSAGE(esp32::signalWatchdog(), "Watchdog signalling failed"); } } } @@ -328,17 +325,17 @@ namespace fabomatic::tests { test_scheduler.updateSchedules(); TEST_ASSERT_EQUAL_UINT32_MESSAGE(6, test_scheduler.taskCount(), "Scheduler does not contain all tasks"); - auto start = std::chrono::system_clock::now(); - while (std::chrono::system_clock::now() - start <= 1min) + auto start = fabomatic::Tasks::arduinoNow(); + while (fabomatic::Tasks::arduinoNow() - start <= 1min) { test_scheduler.execute(); delay(25); } // Check that all tasks ran at least once - for (const auto &tw : test_scheduler.getTasks()) + for (const auto tp : test_scheduler.getTasks()) { - auto &t = tw.get(); - ESP_LOGD(TAG3, "Task %s: %lu runs, %lu ms total runtime, %lu ms avg tardiness", t.getId().c_str(), t.getRunCounter(), t.getTotalRuntime().count(), t.getAvgTardiness().count()); + const auto t = *tp; + ESP_LOGD(TAG3, "Task %s: %lu runs, %llu ms total runtime, %llu ms avg tardiness", t.getId().c_str(), t.getRunCounter(), t.getTotalRuntime().count(), t.getAvgTardiness().count()); TEST_ASSERT_GREATER_OR_EQUAL_MESSAGE(1, t.getRunCounter(), "Task did not run"); } // Remove the HW Watchdog @@ -357,6 +354,8 @@ void setUp(void) void setup() { delay(1000); + esp_log_level_set(TAG, LOG_LOCAL_LEVEL); + // Save original config auto original = fabomatic::SavedConfig::LoadFromEEPROM(); diff --git a/test/test_savedconfig/test_savedconfig.cpp b/test/test_savedconfig/test_savedconfig.cpp index 4ad8e479..ca477101 100644 --- a/test/test_savedconfig/test_savedconfig.cpp +++ b/test/test_savedconfig/test_savedconfig.cpp @@ -318,6 +318,8 @@ void setUp(void) void setup() { delay(1000); + esp_log_level_set(TAG, LOG_LOCAL_LEVEL); + auto original = fabomatic::SavedConfig::LoadFromEEPROM(); UNITY_BEGIN(); diff --git a/test/test_tasks/test_tasks.cpp b/test/test_tasks/test_tasks.cpp index e01464f7..5a44e3ec 100644 --- a/test/test_tasks/test_tasks.cpp +++ b/test/test_tasks/test_tasks.cpp @@ -22,18 +22,17 @@ namespace fabomatic::tests Task *tasks[NB_TASKS]{nullptr}; size_t task_counter{0}; Scheduler scheduler; - auto execute = []() + const auto execute = []() { scheduler.execute(); }; void delete_tasks(void) { - for (auto &t : tasks) + for (auto t : tasks) { if (t != nullptr) { - scheduler.removeTask(*t); // Because Task adds itself on creation + scheduler.removeTask(t); // Because Task adds itself on creation delete t; - t = nullptr; } } } @@ -70,8 +69,8 @@ namespace fabomatic::tests void run_for_duration(std::function callback, std::chrono::milliseconds duration) { - auto start = std::chrono::high_resolution_clock::now(); - while (std::chrono::high_resolution_clock::now() - start < duration) + auto start = fabomatic::Tasks::arduinoNow(); + while (fabomatic::Tasks::arduinoNow() - start < duration) { callback(); } @@ -87,8 +86,10 @@ namespace fabomatic::tests create_tasks(scheduler, 150ms); TEST_ASSERT_EQUAL_MESSAGE(NB_TASKS, scheduler.taskCount(), "Scheduler does not contain all tasks"); - run_for_duration(execute, 100ms); - TEST_ASSERT_EQUAL_MESSAGE(NB_TASKS, task_counter, "All tasks were not called once in 100 ms"); + scheduler.updateSchedules(); + + run_for_duration(execute, 140ms); + TEST_ASSERT_EQUAL_MESSAGE(NB_TASKS, task_counter, "All tasks were not called once in 140 ms"); delay(50); @@ -144,6 +145,7 @@ namespace fabomatic::tests void setup() { delay(1000); + esp_log_level_set(TAG, LOG_LOCAL_LEVEL); UNITY_BEGIN(); RUN_TEST(fabomatic::tests::test_execute_runs_all_tasks); RUN_TEST(fabomatic::tests::test_stop_start_tasks);