diff --git a/.clangd b/.clangd index 32678e5..dee120f 100644 --- a/.clangd +++ b/.clangd @@ -1,5 +1,7 @@ CompileFlags: - Add: -ferror-limit=0 + Add: + - -ferror-limit=0 + - -Wall --- Diagnostics: diff --git a/.cmake-format b/.cmake-format index edb518b..9c458e6 100644 --- a/.cmake-format +++ b/.cmake-format @@ -1,6 +1,6 @@ format: tab_size: 2 - line_width: 100 + line_width: 150 max_subgroups_hwrap: 10 separate_ctrl_name_with_space: true separate_fn_name_with_space: false @@ -20,3 +20,45 @@ markup: fence_pattern: "^\\s*([`~]{3}[`~]*)(.*)$" ruler_pattern: "^\\s*[^\\w\\s]{3}.*[^\\w\\s]{3}$" enable_markup: true + +parse: + additional_commands: + logger_set_max_level: + spelling: logger_set_max_level + pargs: 1 + kwargs: + CHANNEL: 1 + CONFIG: "*" + cpmaddpackage: + pargs: + nargs: '*' + flags: [] + spelling: CPMAddPackage + kwargs: &cpmaddpackagekwargs + NAME: 1 + FORCE: 1 + VERSION: 1 + GIT_TAG: 1 + DOWNLOAD_ONLY: 1 + GITHUB_REPOSITORY: 1 + GITLAB_REPOSITORY: 1 + GIT_REPOSITORY: 1 + SVN_REPOSITORY: 1 + SVN_REVISION: 1 + SOURCE_DIR: 1 + DOWNLOAD_COMMAND: 1 + FIND_PACKAGE_ARGUMENTS: 1 + NO_CACHE: 1 + GIT_SHALLOW: 1 + URL: 1 + URL_HASH: 1 + URL_MD5: 1 + DOWNLOAD_NAME: 1 + DOWNLOAD_NO_EXTRACT: 1 + HTTP_USERNAME: 1 + HTTP_PASSWORD: 1 + EXCLUDE_FROM_ALL: 1 + SYSTEM: 1 + SOURCE_SUBDIR: 1 + PATCHES: + + OPTIONS: + diff --git a/.cspell.yaml b/.cspell.yaml deleted file mode 100644 index 4121068..0000000 --- a/.cspell.yaml +++ /dev/null @@ -1,25 +0,0 @@ -enabled: true -readonly: true -language: en -caseSensitive: false - -useGitignore: false # ensures better compatibility when used in multiple projects - -enabledFileTypes: -- cpp -- c -- markdown -- cmake -- json -- yaml - -files: /** -ignorePaths: -- doc/CMakeLists.txt -- .clangd -- .cspell.yaml -- build/** - -words: - - embeutils - - embetech \ No newline at end of file diff --git a/.cspell.yml b/.cspell.yml new file mode 100644 index 0000000..533b8b5 --- /dev/null +++ b/.cspell.yml @@ -0,0 +1,36 @@ +enabled: true +readonly: true +language: en +caseSensitive: false + +useGitignore: false # ensures better compatibility when used in multiple projects + +enabledFileTypes: + - cpp + - c + - markdown + - cmake + - json + - yaml + +files: /** +ignorePaths: + - .clangd + - .clang-format + - .cmake-format + - .cspell.yml + - build/** + +ignoreRegExpList: + - /-W(no)*[a-z]+/g # ignore compiler warning flags + - /-D[A-Z]+/g # ignore compiler define flags + +words: + - argn + - bugprone + - codacy + - cxxflags + - destdir + - endforeach + - embetech + - nolintnextline \ No newline at end of file diff --git a/.github/workflows/generate_artifacts.yml b/.github/workflows/generate_artifacts.yml index 8a26616..8bb1707 100644 --- a/.github/workflows/generate_artifacts.yml +++ b/.github/workflows/generate_artifacts.yml @@ -22,28 +22,28 @@ jobs: - { toolchain: gcc, architecture: thumbv8m.base-none-eabi } - { toolchain: gcc, architecture: thumbv8m.main-none-eabihf } env: - preset: ${{ matrix.config.toolchain }}::${{ matrix.config.architecture }} + preset: ${{ matrix.config.toolchain }}-${{ matrix.config.architecture }} steps: - - uses: lukka/get-cmake@latest + - uses: lukka/get-cmake@9e07ecdcee1b12e5037e42f410b67f03e2f626e1 # v4.2.1 - - uses: actions/checkout@v4 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - - uses: robinraju/release-downloader@v1 + - uses: robinraju/release-downloader@daf26c55d821e836577a15f77d86ddc078948b05 # v1.12 with: repository: embetech-official/cmake-presets tag: v0.0.1 fileName: CMakeUserPresets.json - - uses: lukka/run-cmake@v10 + - uses: lukka/run-cmake@af1be47fd7c933593f687731bc6fdbee024d3ff4 # v10.8 with: configurePreset: ${{ env.preset }} configurePresetAdditionalArgs: '["-DRING_BUFFER_TESTS=0", "-DRING_BUFFER_DOC=0", "-DRING_BUFFER_EXAMPLES=0"]' - buildPreset: ${{ env.preset }}::install + buildPreset: ${{ env.preset }}-install - name: Upload library install directory - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 with: name: libring_buffer-${{ matrix.config.architecture }} path: | install/${{ env.preset }}/** - if-no-files-found: error + if-no-files-found: error \ No newline at end of file diff --git a/.github/workflows/maintain_tags.yml b/.github/workflows/maintain_tags.yml index aba3e6b..59dd694 100644 --- a/.github/workflows/maintain_tags.yml +++ b/.github/workflows/maintain_tags.yml @@ -1,17 +1,13 @@ name: 'Tags' on: - release: - types: [published] + release: + types: [published] jobs: - tags: - name: 'Tags' - runs-on: ubuntu-latest - timeout-minutes: 5 - - steps: - - name: 'Update Tags' - uses: cssnr/update-version-tags-action@v1 - with: - token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + tags: + name: 'Tags' + runs-on: ubuntu-latest + steps: + - name: 'Update Tags' + uses: cssnr/update-version-tags-action@1ff20ac5555f024f5e72b7ccdf165b867878f953 # v2.0.0 \ No newline at end of file diff --git a/.github/workflows/on_push.yml b/.github/workflows/on_push.yml index a9c85f8..1658f51 100644 --- a/.github/workflows/on_push.yml +++ b/.github/workflows/on_push.yml @@ -1,19 +1,19 @@ -name: On Push +name: CI Tests on: push: - workflow_dispatch: - - + schedule: + - cron: '15 10 * * 1' # Run at 10:15 every Monday + jobs: build_all: - runs-on: [self-hosted, linux, x64] + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: ssciwr/doxygen-install@v1 - - uses: lukka/get-cmake@latest - - uses: lukka/run-cmake@v10 + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + - uses: ssciwr/doxygen-install@501e53b879da7648ab392ee226f5b90e42148449 # v1.6.4 + - uses: lukka/get-cmake@9e07ecdcee1b12e5037e42f410b67f03e2f626e1 # v4.2.1 + - uses: lukka/run-cmake@af1be47fd7c933593f687731bc6fdbee024d3ff4 # v10.8 with: - workflowPreset: 'default' + workflowPreset: 'native-gcc' \ No newline at end of file diff --git a/.gitignore b/.gitignore index 309cfe7..01647f8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ .vscode -**/.cache +.cache build install CMakeUserPresets.json \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a31ee4..c60398e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.25) -file(READ "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" PROJECT_VERSION) -project(ring_buffer VERSION ${PROJECT_VERSION}) +file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/VERSION.txt" PROJECT_VERSION) +project(ring_buffer VERSION ${PROJECT_VERSION}) option(RING_BUFFER_TESTS "Configure unit tests target" ${PROJECT_IS_TOP_LEVEL}) option(RING_BUFFER_DOC "Configure documentation target" ${PROJECT_IS_TOP_LEVEL}) diff --git a/CMakePresets.json b/CMakePresets.json index fbb0c41..ba25017 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -1,9 +1,10 @@ { - "version": 6, + "version": 8, "configurePresets": [ { - "name": "gcc-native", - "description": "Use any available GNU compiler", + "name": "native-gcc", + "displayName": "Native GCC Compiler", + "description": "First available GCC compiler", "generator": "Ninja Multi-Config", "binaryDir": "${sourceDir}/build/${presetName}", "installDir": "${sourceDir}/install/${presetName}", @@ -18,28 +19,30 @@ }, "environment": { "CFLAGS": "-Wall -Wextra -Wpedantic -Wunused-parameter -Winit-self -Wcast-align -Wconversion -Wnull-dereference -Wduplicated-cond -Wsign-conversion -Wlogical-op", - "CXXFLAGS": "-Wall -Wextra -Wpedantic -Wunused-parameter -Winit-self -Wcast-align -Wconversion -Wnull-dereference -Wduplicated-cond -Wsign-conversion -Wlogical-op" + "CXXFLAGS": "-Wall -Wextra" } } ], "buildPresets": [ { - "name": "all-release", - "displayName": "all [Release]", - "configurePreset": "gcc-native", - "configuration": "Release" - }, - { - "name": "all-debug", + "name": "native-gcc-all-debug", "displayName": "all [Debug]", - "configurePreset": "gcc-native", + "description": "Build all targets in Debug configuration", + "configurePreset": "native-gcc", "configuration": "Debug" }, { - "name": "install", - "displayName": "Install", - "configurePreset": "gcc-native", - "configuration": "Debug", + "name": "native-gcc-all-release", + "displayName": "all [Release]", + "description": "Build all targets in Release configuration", + "configurePreset": "native-gcc", + "configuration": "Release" + }, + { + "name": "native-gcc-install", + "displayName": "Install [Debug + Release]", + "description": "Install all targets (Release + Debug)", + "configurePreset": "native-gcc", "targets": [ "install:Release", "install:Debug" @@ -48,8 +51,10 @@ ], "testPresets": [ { - "name": "ut", - "configurePreset": "gcc-native", + "name": "native-gcc", + "displayName": "Run Tests [Debug]", + "description": "Run all tests in Debug configuration", + "configurePreset": "native-gcc", "configuration": "Debug", "output": { "outputOnFailure": true @@ -62,23 +67,25 @@ ], "workflowPresets": [ { - "name": "default", + "name": "native-gcc", + "displayName": "Native GCC Compiler Workflow", + "description": "Configure, Build all [Debug], Run Tests, Install", "steps": [ { "type": "configure", - "name": "gcc-native" + "name": "native-gcc" }, { "type": "build", - "name": "all-debug" + "name": "native-gcc-all-debug" }, { "type": "test", - "name": "ut" + "name": "native-gcc" }, { "type": "build", - "name": "install" + "name": "native-gcc-install" } ] } diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..dee505b --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Embetech + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 611ed34..6608ff8 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,24 @@ # Ring Buffer -[![C++ Unit Tests](https://github.com/embetech-official/ring_buffer/actions/workflows/cpp_unit_tests.yml/badge.svg)](https://github.com/embetech-official/ring_buffer/actions/workflows/cpp_unit_tests.yml) +[![CI Tests](https://github.com/embetech-official/ring_buffer/actions/workflows/on_push.yml/badge.svg)](https://github.com/embetech-official/ring_buffer/actions/workflows/on_push.yml) +![GitHub License](https://img.shields.io/github/license/embetech-official/ring_buffer) +![GitHub Release](https://img.shields.io/github/v/release/embetech-official/ring_buffer) ## Overview + Ring Buffer is a library providing circular buffer data structure -## Installation -The easiest way is to use built-in CMake FetchContent: +## Quick Start -```cmake -include(FetchContent) -FetchContent_Declare( - ring_buffer - GIT_REPOSITORY https://github.com/embetech-official/ring_buffer - GIT_TAG v1.0.0 -) +The easiest way to fetch this component is to use [CPM.cmake](https://github.com/cpm-cmake/CPM.cmake). +In your CMakeLists.txt add: -FetchContent_MakeAvailable(ring_buffer) +```cmake + CPMAddPackage("gh:embetech-official/ring_buffer@1") +``` -# ... +Then add link dependency +```cmake target_link_libraries( PRIVATE embetech::ring_buffer) -`````` - -## Configuration -- `CONFIG_RING_BUFFER_16_ENABLE` - Makes variant with 16-bit element available +``` diff --git a/VERSION b/VERSION.txt similarity index 100% rename from VERSION rename to VERSION.txt diff --git a/cmake/git_utils.cmake b/cmake/git_utils.cmake new file mode 100644 index 0000000..afbeff5 --- /dev/null +++ b/cmake/git_utils.cmake @@ -0,0 +1,69 @@ +# get_git_commit_id +# Retrieves the Git commit ID from a repository. +# +# Signature: +# get_git_commit_id( +# [DIRECTORY ] +# [LENGTH ] +# [REQUIRED] +# [QUIET]) +# +# Parameters: +# - OUTPUT_VAR: Name of the variable to set in the caller's scope with the commit ID. +# - DIRECTORY (optional): Path to repository root to query. Defaults to `CMAKE_SOURCE_DIR`. +# - LENGTH (optional): Number of characters to keep from the hash. If not set, returns the full hash. +# - REQUIRED (optional flag): When present, fails configuration if the Git query fails. +# - QUIET (optional flag): Suppresses error output from the Git command (no messages on failure). +# +# Behavior: +# - Requires Git to be available. +# - Runs `git rev-parse [--short=] HEAD` in the chosen directory. +# - Sets the provided OUTPUT_VAR in `PARENT_SCOPE`. +# - When `REQUIRED` is specified, and the Git query fails, configuration fails. +# - When `QUIET` is specified, stderr from the Git command is suppressed. +function (get_git_commit_id OUTPUT) + + set(oneValueArgs DIRECTORY LENGTH) + set(multiValueArgs) + set(options REQUIRED QUIET) + cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if (arg_REQUIRED) + set(error_msg_level FATAL_ERROR) + elseif (arg_QUIET) + set(error_msg_level DEBUG) + else () + set(error_msg_level WARNING) + endif () + + set(directory ${CMAKE_SOURCE_DIR}) + if (arg_DIRECTORY) + set(directory ${arg_DIRECTORY}) + endif () + + set(length 40) # Full length of SHA-1 hash + if (arg_LENGTH) + set(length ${arg_LENGTH}) + endif () + + # Find Git quietly; escalate if REQUIRED and missing + find_package(Git QUIET) + if (NOT GIT_FOUND) + message(${error_msg_level} "Failed to obtain git hash for directory ${directory}: git executable not found") + set(${OUTPUT} "${OUTPUT}-NOTFOUND" PARENT_SCOPE) + return() + endif () + + execute_process( + COMMAND ${GIT_EXECUTABLE} -C ${directory} rev-parse --short=${length} HEAD OUTPUT_VARIABLE commit_id OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE result ERROR_VARIABLE error_output + ) + + if (NOT result EQUAL 0) + message(${error_msg_level} "Failed to obtain git hash for directory ${directory} - command returned ${result}: ${error_output}") + set(${OUTPUT} "${OUTPUT}-NOTFOUND" PARENT_SCOPE) + return() + endif () + + set(${OUTPUT} ${commit_id} PARENT_SCOPE) +endfunction () diff --git a/cmake/install.cmake b/cmake/install.cmake index 4e499e0..14b9cbc 100644 --- a/cmake/install.cmake +++ b/cmake/install.cmake @@ -9,13 +9,10 @@ install(EXPORT ring_buffer-targets NAMESPACE embetech:: DESTINATION ${METADATA_D write_basic_package_version_file(ring_buffer-version.cmake COMPATIBILITY SameMajorVersion) configure_package_config_file( - ${CMAKE_CURRENT_LIST_DIR}/ring_buffer-config_template.cmake - ${CMAKE_CURRENT_BINARY_DIR}/ring_buffer-config.cmake INSTALL_DESTINATION ${METADATA_DIR} + ${CMAKE_CURRENT_LIST_DIR}/ring_buffer-config_template.cmake ${CMAKE_CURRENT_BINARY_DIR}/ring_buffer-config.cmake INSTALL_DESTINATION ${METADATA_DIR} NO_CHECK_REQUIRED_COMPONENTS_MACRO ) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/ring_buffer-config.cmake - ${CMAKE_CURRENT_BINARY_DIR}/ring_buffer-version.cmake DESTINATION ${METADATA_DIR} -) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/ring_buffer-config.cmake ${CMAKE_CURRENT_BINARY_DIR}/ring_buffer-version.cmake DESTINATION ${METADATA_DIR}) install(SCRIPT ${CMAKE_CURRENT_LIST_DIR}/install_header_licenses.cmake) diff --git a/cmake/install_header_licenses.cmake b/cmake/install_header_licenses.cmake index 5f0b0df..08bd282 100644 --- a/cmake/install_header_licenses.cmake +++ b/cmake/install_header_licenses.cmake @@ -1,6 +1,7 @@ set(INSTALL_DIR $ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}) -file(READ ${CMAKE_CURRENT_LIST_DIR}/../VERSION PROJECT_VERSION) +file(STRINGS ${CMAKE_CURRENT_LIST_DIR}/../VERSION.txt PROJECT_VERSION) + set(PROJECT_LICENSE "MIT License") set(PROJECT_COPYRIGHT "Embetech sp. z o.o.") @@ -8,4 +9,4 @@ file(GLOB_RECURSE HEADERS_TO_CONFIGURE "${INSTALL_DIR}/*.h") foreach (header ${HEADERS_TO_CONFIGURE}) message(DEBUG "Configuring doxygen header: ${header}") configure_file(${header} ${header}) -endforeach() +endforeach () diff --git a/cmake/requirements.cmake b/cmake/requirements.cmake index d1c7376..d3381f0 100644 --- a/cmake/requirements.cmake +++ b/cmake/requirements.cmake @@ -1,12 +1,9 @@ -file(DOWNLOAD https://github.com/cpm-cmake/CPM.cmake/releases/download/v0.42.0/CPM.cmake - ${CMAKE_BINARY_DIR}/cmake/CPM.cmake +file(DOWNLOAD https://github.com/cpm-cmake/CPM.cmake/releases/download/v0.42.0/CPM.cmake ${CMAKE_BINARY_DIR}/cmake/CPM.cmake EXPECTED_HASH SHA256=2020b4fc42dba44817983e06342e682ecfc3d2f484a581f11cc5731fbe4dce8a ) include(${CMAKE_BINARY_DIR}/cmake/CPM.cmake) -cpmaddpackage("gh:embetech-official/embeutils#v1") - if (RING_BUFFER_TESTS) - cpmaddpackage("gh:google/googletest#main") + CPMAddPackage("gh:google/googletest#main") endif () diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index ae5818c..52d358d 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -1,5 +1,5 @@ -include(FindDoxygen) -if (NOT DOXYGEN_FOUND) +find_package(Doxygen QUIET) +if (NOT Doxygen_FOUND) message(STATUS "Doxygen not found, documentation will not be generated") return() endif () @@ -19,13 +19,9 @@ set(DOXYGEN_HTML_COLORSTYLE DARK) set(DOXYGEN_GENERATE_LATEX NO) set(DOXYGEN_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) set(DOXYGEN_GENERATE_TAGFILE ${DOXYGEN_OUTPUT_DIRECTORY}/html/ring_buffer.tag) -set(DOXYGEN_ALIASES - [[purpose=@par Purpose:]] [[license=@par License:]] [[compiler=@par Compiler:]] - [[ hardware=@par Hardware:]] [[comments=@par Comments:]] [[doc=@par Documented using:]] +set(DOXYGEN_ALIASES [[purpose=@par Purpose:]] [[license=@par License:]] [[compiler=@par Compiler:]] [[ hardware=@par Hardware:]] + [[comments=@par Comments:]] [[doc=@par Documented using:]] ) set(DOXYGEN_WARN_AS_ERROR YES) -doxygen_add_docs( - ring_buffer_doc ALL ${CMAKE_CURRENT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/src/include/embetech - COMMENT "Generate documentation" -) +doxygen_add_docs(ring_buffer_doc ALL ${CMAKE_CURRENT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/src/include/embetech COMMENT "Generate documentation") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d9582f6..0547a90 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,8 @@ add_library(ring_buffer STATIC) add_library(embetech::ring_buffer ALIAS ring_buffer) +target_compile_features(ring_buffer PRIVATE c_std_99) + target_sources( ring_buffer PRIVATE ring_buffer.c ring_buffer_16bit.c ring_buffer_version.c @@ -13,26 +15,13 @@ target_sources( include/embetech/ring_buffer_16bit.h ) -target_link_libraries(ring_buffer PUBLIC embetech::utils) - if (PROJECT_IS_TOP_LEVEL) - # Retrieve the commit ID from the Git repository - find_package(Git REQUIRED) - execute_process( - COMMAND ${GIT_EXECUTABLE} -C ${CMAKE_SOURCE_DIR} rev-parse --short=8 HEAD - OUTPUT_VARIABLE COMMIT_ID OUTPUT_STRIP_TRAILING_WHITESPACE - ) - message(VERBOSE "Commit ID: ${COMMIT_ID}") -else () - # Ingrown build. Do not use meaningful commit ID - set(COMMIT_ID 0) + include(${PROJECT_SOURCE_DIR}/cmake/git_utils.cmake) + get_git_commit_id(RING_BUFFER_COMMIT_ID REQUIRED LENGTH 8) endif () -target_compile_definitions( - ring_buffer - PRIVATE RING_BUFFER_VERSION_MAJOR=${PROJECT_VERSION_MAJOR} - RING_BUFFER_VERSION_MINOR=${PROJECT_VERSION_MINOR} - RING_BUFFER_VERSION_PATCH=${PROJECT_VERSION_PATCH} - RING_BUFFER_VERSION_ID=0x${COMMIT_ID} - RING_BUFFER_VERSION=\"${PROJECT_VERSION}-${COMMIT_ID}\" -) +if (NOT RING_BUFFER_COMMIT_ID) + set(RING_BUFFER_COMMIT_ID "local") # Fallback for out of tree builds +endif () + +target_compile_definitions(ring_buffer PRIVATE RING_BUFFER_VERSION="${PROJECT_VERSION}+${RING_BUFFER_COMMIT_ID}") diff --git a/src/include/embetech/ring_buffer.h b/src/include/embetech/ring_buffer.h index 6b614c2..07b0f54 100644 --- a/src/include/embetech/ring_buffer.h +++ b/src/include/embetech/ring_buffer.h @@ -16,7 +16,6 @@ extern "C" { #endif -#include #include #include #include @@ -25,101 +24,106 @@ extern "C" { * @{ */ -/** Structure describing the ring buffer. */ +/** + * @brief Structure describing the ring buffer. + */ typedef struct { - /// pointer to the area of memory, where data will be stored + /// Pointer to the memory region used to store buffer data. uint8_t *dataBuffer; - /// size of the data buffer (in bytes) + + /// Size of the data buffer in bytes. size_t dataBufferSize; - /// number of elements currently stored within the buffer + + /// Number of elements currently stored in the buffer. size_t count; - /// pointer to the next element in the buffer that will be written + + /// Pointer to the next element position to be written. uint8_t *head; - /// pointer to the next element in the buffer that will be read + + /// Pointer to the next element position to be read. uint8_t *tail; } RingBuffer; /** - * Initializes the given ring buffer structure. + * @brief Initialize the given ring buffer instance. * - * @param ringBuffer pointer to a \ref RingBuffer structure - * @param dataBuffer pointer to a location in memory, where the ring buffer data will be stored - * @param dataBufferSize size in bytes of the dataBuffer - * @return true if all arguments are valid and the ring buffer is initialized successfully, false otherwise - */ -bool RingBuffer_Init(RingBuffer *ringBuffer, uint8_t *dataBuffer, size_t dataBufferSize); - -/** - * Clears contents of the given ring buffer. + * @param[in] instance Pointer to a @ref RingBuffer structure. + * @param[in] dataBuffer Pointer to memory where ring buffer data will be stored. + * @param[in] dataBufferSize Size of `dataBuffer` in bytes. * - * @param ringBuffer pointer to a \ref RingBuffer structure - * @return true if the ring buffer is cleared successfully, false otherwise + * @return true if arguments are valid and initialization succeeds; false otherwise. */ -bool RingBuffer_Clear(RingBuffer *ringBuffer); +bool RingBuffer_Init(RingBuffer *instance, uint8_t *dataBuffer, size_t dataBufferSize); /** - * Checks if the given ring buffer is empty. + * @brief Clear contents of the given ring buffer. + * + * @param[in] instance Pointer to a @ref RingBuffer structure. * - * @param ringBuffer pointer to a \ref RingBuffer structure - * @return true if the ring buffer holds no data, false otherwise + * @return true if the ring buffer is cleared successfully; false otherwise. */ -bool RingBuffer_IsEmpty(RingBuffer const *ringBuffer); +bool RingBuffer_Clear(RingBuffer *instance); /** - * Gets the length (in bytes) of the data stored in the given ring buffer. + * @brief Check if the given ring buffer is empty. * - * @param ringBuffer pointer to a \ref RingBuffer structure - * @return length (in bytes) of the data stored in the ring buffer + * @param[in] instance Pointer to a @ref RingBuffer structure. + * + * @return true if the ring buffer holds no data; false otherwise. */ -size_t RingBuffer_GetLen(RingBuffer const *ringBuffer); +bool RingBuffer_IsEmpty(RingBuffer const *instance); /** - * Returns the capacity (in bytes) of the given buffer. + * @brief Get the length in bytes of data stored in the ring buffer. + * + * @param[in] instance Pointer to a @ref RingBuffer structure. * - * @param ringBuffer pointer to a \ref RingBuffer structure - * @return capacity (in bytes) of the ring buffer (how much characters can it store) + * @return Length in bytes of the data stored in the ring buffer. */ -size_t RingBuffer_GetCapacity(RingBuffer const *ringBuffer); +size_t RingBuffer_GetLen(RingBuffer const *instance); /** - * Returns the space (in bytes) left in the given buffer. + * @brief Get the capacity in bytes of the given buffer. * - * @param ringBuffer pointer to a \ref RingBuffer structure - * @return space (in bytes) of the ring buffer (how much characters can be still written to it) + * @param[in] instance Pointer to a @ref RingBuffer structure. + * + * @return Capacity in bytes of the ring buffer. */ -size_t RingBuffer_GetSpace(RingBuffer const *ringBuffer); +size_t RingBuffer_GetCapacity(RingBuffer const *instance); /** - * Appends a single character to the ring buffer. The stored data length will be - * increased by 1. + * @brief Get the remaining free space in bytes in the buffer. + * + * @param[in] instance Pointer to a @ref RingBuffer structure. * - * @param ringBuffer pointer to a \ref RingBuffer structure - * @param c character to append - * @return true if the character was added successfully, false otherwise + * @return Free space in bytes available in the ring buffer. */ -bool RingBuffer_PutChar(RingBuffer *ringBuffer, uint8_t c); +size_t RingBuffer_GetSpace(RingBuffer const *instance); /** - * Pulls out a single character from the ring buffer. The stored data length will be - * decreased by 1. + * @brief Append a single character to the ring buffer. * - * @param ringBuffer pointer to a \ref RingBuffer structure - * @param c pointer to a place where character will be stored - * @return true if the character was pulled out successfully, false otherwise + * @param[in] instance Pointer to a @ref RingBuffer structure. + * @param[in] data Character to append. + * + * @return true if the character was added successfully; false otherwise. */ -bool RingBuffer_GetChar(RingBuffer *ringBuffer, uint8_t *c); +bool RingBuffer_PutChar(RingBuffer *instance, uint8_t data); /** - * @brief Get library version as a SemanticVersion structure. + * @brief Retrieve a single character from the ring buffer. + * + * @param[in] instance Pointer to a @ref RingBuffer structure. + * @param[in,out] readData Pointer to where the read character will be stored. * - * @return SemanticVersion value representing the library version. + * @return true if the character was retrieved successfully; false otherwise. */ -SemanticVersion RingBuffer_GetVersion(void); +bool RingBuffer_GetChar(RingBuffer *instance, uint8_t *readData); /** * @brief Get library version as a NUL-terminated string. * - * @return Pointer to a read-only, statically-allocated string in semantic version format (e.g., "1.2.3"). Must not be freed or modified. + * @return Pointer to a read-only, statically allocated string in semantic version format (e.g., "1.2.3+extra_info"). Must not be freed or modified. */ char const *RingBuffer_GetVersionString(void); diff --git a/src/include/embetech/ring_buffer_16bit.h b/src/include/embetech/ring_buffer_16bit.h index c5a87e7..9949f7e 100644 --- a/src/include/embetech/ring_buffer_16bit.h +++ b/src/include/embetech/ring_buffer_16bit.h @@ -24,89 +24,101 @@ extern "C" { * @{ */ -/** Structure describing the ring buffer. */ +/** + * @brief Structure describing the 16-bit ring buffer. + */ typedef struct { - /// pointer to the area of memory, where data will be stored + /// Pointer to the memory region used to store 16-bit buffer data. uint16_t *dataBuffer; - /// size of the data buffer (in bytes) + + /// Size of the data buffer in bytes. size_t dataBufferSize; - /// number of elements currently stored within the buffer + + /// Number of elements currently stored in the buffer. size_t count; - /// pointer to the next element in the buffer that will be written + + /// Pointer to the next element position to be written. uint16_t *head; - /// pointer to the next element in the buffer that will be read + + /// Pointer to the next element position to be read. uint16_t *tail; } RingBuffer16Bit; /** - * Initializes the given ring buffer structure. + * @brief Initialize the given 16-bit ring buffer instance. + * + * @param[in] instance Pointer to a @ref RingBuffer16Bit structure. + * @param[in] dataBuffer Pointer to memory where ring buffer data will be stored. + * @param[in] dataBufferSize Size of `dataBuffer` in bytes. * - * @param RingBuffer16Bit pointer to a \ref RingBuffer16Bit structure - * @param dataBuffer pointer to a location in memory, where the ring buffer data will be stored - * @param dataBufferSize size in bytes of the dataBuffer - * @return true if all arguments are valid and the ring buffer is initialized successfully, false otherwise + * @return true if arguments are valid and initialization succeeds; false otherwise. */ -bool RingBuffer16Bit_Init(RingBuffer16Bit *RingBuffer16Bit, uint16_t *dataBuffer, size_t dataBufferSize); +bool RingBuffer16Bit_Init(RingBuffer16Bit *instance, uint16_t *dataBuffer, size_t dataBufferSize); /** - * Clears contents of the given ring buffer. + * @brief Clear contents of the given ring buffer. * - * @param RingBuffer16Bit pointer to a \ref RingBuffer16Bit structure - * @return true if the ring buffer is cleared successfully, false otherwise + * @param[in] instance Pointer to a @ref RingBuffer16Bit structure. + * + * @return true if the ring buffer is cleared successfully; false otherwise. */ -bool RingBuffer16Bit_Clear(RingBuffer16Bit *RingBuffer16Bit); +bool RingBuffer16Bit_Clear(RingBuffer16Bit *instance); /** - * Checks if the given ring buffer is empty. + * @brief Check if the given ring buffer is empty. + * + * @param[in] instance Pointer to a @ref RingBuffer16Bit structure. * - * @param RingBuffer16Bit pointer to a \ref RingBuffer16Bit structure - * @return true if the ring buffer holds no data, false otherwise + * @return true if the ring buffer holds no data; false otherwise. */ -bool RingBuffer16Bit_IsEmpty(RingBuffer16Bit const *RingBuffer16Bit); +bool RingBuffer16Bit_IsEmpty(RingBuffer16Bit const *instance); /** - * Gets the length (in bytes) of the data stored in the given ring buffer. + * @brief Get the length in bytes of data stored in the ring buffer. * - * @param RingBuffer16Bit pointer to a \ref RingBuffer16Bit structure - * @return length (in bytes) of the data stored in the ring buffer + * @param[in] instance Pointer to a @ref RingBuffer16Bit structure. + * + * @return Length in bytes of the data stored in the ring buffer. */ -size_t RingBuffer16Bit_GetLen(RingBuffer16Bit const *RingBuffer16Bit); +size_t RingBuffer16Bit_GetLen(RingBuffer16Bit const *instance); /** - * Returns the capacity (in bytes) of the given buffer. + * @brief Get the capacity in bytes of the given buffer. + * + * @param[in] instance Pointer to a @ref RingBuffer16Bit structure. * - * @param RingBuffer16Bit pointer to a \ref RingBuffer16Bit structure - * @return capacity (in bytes) of the ring buffer (how much characters can it store) + * @return Capacity in bytes of the ring buffer. */ -size_t RingBuffer16Bit_GetCapacity(RingBuffer16Bit const *RingBuffer16Bit); +size_t RingBuffer16Bit_GetCapacity(RingBuffer16Bit const *instance); /** - * Returns the space (in bytes) left in the given buffer. + * @brief Get the remaining free space in bytes in the buffer. * - * @param RingBuffer16Bit pointer to a \ref RingBuffer16Bit structure - * @return space (in bytes) of the ring buffer (how much characters can be still written to it) + * @param[in] instance Pointer to a @ref RingBuffer16Bit structure. + * + * @return Free space in bytes available in the ring buffer. */ -size_t RingBuffer16Bit_GetSpace(RingBuffer16Bit const *RingBuffer16Bit); +size_t RingBuffer16Bit_GetSpace(RingBuffer16Bit const *instance); /** - * Appends a single character to the ring buffer. The stored data length will be - * increased by 1. + * @brief Append a single 16-bit value to the ring buffer. + * + * @param[in] instance Pointer to a @ref RingBuffer16Bit structure. + * @param[in] data 16-bit value to append. * - * @param RingBuffer16Bit pointer to a \ref RingBuffer16Bit structure - * @param c character to append - * @return true if the character was added successfully, false otherwise + * @return true if the value was added successfully; false otherwise. */ -bool RingBuffer16Bit_PutChar(RingBuffer16Bit *RingBuffer16Bit, uint16_t c); +bool RingBuffer16Bit_PutChar(RingBuffer16Bit *instance, uint16_t data); /** - * Pulls out a single character from the ring buffer. The stored data length will be - * decreased by 1. + * @brief Retrieve a single 16-bit value from the ring buffer. + * + * @param[in] instance Pointer to a @ref RingBuffer16Bit structure. + * @param[in,out] readData Pointer to where the read 16-bit value will be stored. * - * @param RingBuffer16Bit pointer to a \ref RingBuffer16Bit structure - * @param c pointer to a place where character will be stored - * @return true if the character was pulled out successfully, false otherwise + * @return true if the value was retrieved successfully; false otherwise. */ -bool RingBuffer16Bit_GetChar(RingBuffer16Bit *RingBuffer16Bit, uint16_t *c); +bool RingBuffer16Bit_GetChar(RingBuffer16Bit *instance, uint16_t *readData); /** * @} diff --git a/src/ring_buffer.c b/src/ring_buffer.c index d8a3d42..781531b 100644 --- a/src/ring_buffer.c +++ b/src/ring_buffer.c @@ -1,79 +1,59 @@ #include "embetech/ring_buffer.h" -bool RingBuffer_Init(RingBuffer *ringBuffer, uint8_t *dataBuffer, size_t dataBufferSize) { - if((ringBuffer) && (dataBuffer) && (dataBufferSize > 0)) { - ringBuffer->dataBuffer = dataBuffer; - ringBuffer->dataBufferSize = dataBufferSize; - ringBuffer->count = 0; - ringBuffer->head = dataBuffer; - ringBuffer->tail = dataBuffer; - return true; - } - - return false; +bool RingBuffer_Init(RingBuffer *instance, uint8_t *dataBuffer, size_t dataBufferSize) { + if((NULL == instance) || (NULL == dataBuffer) || (0 == dataBufferSize)) { + return false; + } + instance->dataBuffer = dataBuffer; + instance->dataBufferSize = dataBufferSize; + instance->count = 0; + instance->head = dataBuffer; + instance->tail = dataBuffer; + return true; } -bool RingBuffer_Clear(RingBuffer *ringBuffer) { - if(ringBuffer) { - ringBuffer->count = 0; - ringBuffer->head = ringBuffer->dataBuffer; - ringBuffer->tail = ringBuffer->dataBuffer; - return true; +bool RingBuffer_Clear(RingBuffer *instance) { + if(NULL == instance) { + return false; } - return false; + instance->count = 0; + instance->head = instance->dataBuffer; + instance->tail = instance->dataBuffer; + return true; } -bool RingBuffer_IsEmpty(RingBuffer const *ringBuffer) { - if(ringBuffer) { - return (ringBuffer->count == 0); - } +size_t RingBuffer_GetLen(RingBuffer const *instance) { return (instance != NULL) ? instance->count : 0U; } - return true; -} +bool RingBuffer_IsEmpty(RingBuffer const *instance) { return (0U == RingBuffer_GetLen(instance)); } -size_t RingBuffer_GetLen(RingBuffer const *ringBuffer) { - if(ringBuffer) { - return ringBuffer->count; - } - return 0; -} +size_t RingBuffer_GetCapacity(RingBuffer const *instance) { return (instance != NULL) ? instance->dataBufferSize : 0U; } -size_t RingBuffer_GetCapacity(RingBuffer const *ringBuffer) { - if(ringBuffer) { - return ringBuffer->dataBufferSize; +size_t RingBuffer_GetSpace(RingBuffer const *instance) { return (instance != NULL) ? (size_t)(instance->dataBufferSize - instance->count) : 0U; } + +bool RingBuffer_PutChar(RingBuffer *instance, uint8_t data) { + if(0 == RingBuffer_GetSpace(instance)) { + return false; } - return 0; -} -size_t RingBuffer_GetSpace(RingBuffer const *ringBuffer) { - if(ringBuffer) { - return ringBuffer->dataBufferSize - ringBuffer->count; + *instance->head = data; + ++instance->count; + ++instance->head; + if(instance->head >= instance->dataBuffer + instance->dataBufferSize) { + instance->head = instance->dataBuffer; } - return 0; + return true; } -bool RingBuffer_PutChar(RingBuffer *ringBuffer, uint8_t c) { - if((ringBuffer) && (ringBuffer->count < ringBuffer->dataBufferSize)) { - *ringBuffer->head = c; - ringBuffer->count++; - ringBuffer->head++; - if(ringBuffer->head >= ringBuffer->dataBuffer + ringBuffer->dataBufferSize) { - ringBuffer->head = ringBuffer->dataBuffer; - } - return true; +bool RingBuffer_GetChar(RingBuffer *instance, uint8_t *readData) { + if(RingBuffer_IsEmpty(instance) || (NULL == readData)) { + return false; } - return false; -} -bool RingBuffer_GetChar(RingBuffer *ringBuffer, uint8_t *c) { - if((ringBuffer) && (c) && (ringBuffer->count)) { - *c = *ringBuffer->tail; - ringBuffer->count--; - ringBuffer->tail++; - if(ringBuffer->tail >= ringBuffer->dataBuffer + ringBuffer->dataBufferSize) { - ringBuffer->tail = ringBuffer->dataBuffer; - } - return true; + *readData = *instance->tail; + instance->count--; + instance->tail++; + if(instance->tail >= instance->dataBuffer + instance->dataBufferSize) { + instance->tail = instance->dataBuffer; } - return false; + return true; } diff --git a/src/ring_buffer_16bit.c b/src/ring_buffer_16bit.c index 4d8b4b9..155ae11 100644 --- a/src/ring_buffer_16bit.c +++ b/src/ring_buffer_16bit.c @@ -1,79 +1,59 @@ #include "embetech/ring_buffer_16bit.h" -bool RingBuffer16Bit_Init(RingBuffer16Bit *ringBuffer, uint16_t *dataBuffer, size_t dataBufferSize) { - if((ringBuffer) && (dataBuffer) && (dataBufferSize > 0)) { - ringBuffer->dataBuffer = dataBuffer; - ringBuffer->dataBufferSize = dataBufferSize; - ringBuffer->count = 0; - ringBuffer->head = dataBuffer; - ringBuffer->tail = dataBuffer; - return true; - } - - return false; +bool RingBuffer16Bit_Init(RingBuffer16Bit *instance, uint16_t *dataBuffer, size_t dataBufferSize) { + if((NULL == instance) || (NULL == dataBuffer) || (0 == dataBufferSize)) { + return false; + } + instance->dataBuffer = dataBuffer; + instance->dataBufferSize = dataBufferSize; + instance->count = 0; + instance->head = dataBuffer; + instance->tail = dataBuffer; + return true; } -bool RingBuffer16Bit_Clear(RingBuffer16Bit *ringBuffer) { - if(ringBuffer) { - ringBuffer->count = 0; - ringBuffer->head = ringBuffer->dataBuffer; - ringBuffer->tail = ringBuffer->dataBuffer; - return true; +bool RingBuffer16Bit_Clear(RingBuffer16Bit *instance) { + if(NULL == instance) { + return false; } - return false; + instance->count = 0; + instance->head = instance->dataBuffer; + instance->tail = instance->dataBuffer; + return true; } -bool RingBuffer16Bit_IsEmpty(RingBuffer16Bit const *ringBuffer) { - if(ringBuffer) { - return (ringBuffer->count == 0); - } +size_t RingBuffer16Bit_GetLen(RingBuffer16Bit const *instance) { return (instance != NULL) ? instance->count : 0U; } - return true; -} +bool RingBuffer16Bit_IsEmpty(RingBuffer16Bit const *instance) { return (0U == RingBuffer16Bit_GetLen(instance)); } -size_t RingBuffer16Bit_GetLen(RingBuffer16Bit const *ringBuffer) { - if(ringBuffer) { - return ringBuffer->count; - } - return 0; -} +size_t RingBuffer16Bit_GetCapacity(RingBuffer16Bit const *instance) { return (instance != NULL) ? instance->dataBufferSize : 0U; } -size_t RingBuffer16Bit_GetCapacity(RingBuffer16Bit const *ringBuffer) { - if(ringBuffer) { - return ringBuffer->dataBufferSize; - } - return 0; +size_t RingBuffer16Bit_GetSpace(RingBuffer16Bit const *instance) { + return (instance != NULL) ? (size_t)(instance->dataBufferSize - instance->count) : 0U; } -size_t RingBuffer16Bit_GetSpace(RingBuffer16Bit const *ringBuffer) { - if(ringBuffer) { - return ringBuffer->dataBufferSize - ringBuffer->count; +bool RingBuffer16Bit_PutChar(RingBuffer16Bit *instance, uint16_t data) { + if(0 == RingBuffer16Bit_GetSpace(instance)) { + return false; } - return 0; -} - -bool RingBuffer16Bit_PutChar(RingBuffer16Bit *ringBuffer, uint16_t c) { - if((ringBuffer) && (ringBuffer->count < ringBuffer->dataBufferSize)) { - *ringBuffer->head = c; - ringBuffer->count++; - ringBuffer->head++; - if(ringBuffer->head >= ringBuffer->dataBuffer + ringBuffer->dataBufferSize) { - ringBuffer->head = ringBuffer->dataBuffer; - } - return true; + *instance->head = data; + instance->count++; + instance->head++; + if(instance->head >= instance->dataBuffer + instance->dataBufferSize) { + instance->head = instance->dataBuffer; } - return false; + return true; } -bool RingBuffer16Bit_GetChar(RingBuffer16Bit *ringBuffer, uint16_t *c) { - if((ringBuffer) && (c) && (ringBuffer->count)) { - *c = *ringBuffer->tail; - ringBuffer->count--; - ringBuffer->tail++; - if(ringBuffer->tail >= ringBuffer->dataBuffer + ringBuffer->dataBufferSize) { - ringBuffer->tail = ringBuffer->dataBuffer; - } - return true; +bool RingBuffer16Bit_GetChar(RingBuffer16Bit *instance, uint16_t *readData) { + if(RingBuffer16Bit_IsEmpty(instance) || (NULL == readData)) { + return false; + } + *readData = *instance->tail; + instance->count--; + instance->tail++; + if(instance->tail >= instance->dataBuffer + instance->dataBufferSize) { + instance->tail = instance->dataBuffer; } - return false; + return true; } diff --git a/src/ring_buffer_version.c b/src/ring_buffer_version.c index bb59fd6..508ee7c 100644 --- a/src/ring_buffer_version.c +++ b/src/ring_buffer_version.c @@ -1,18 +1,10 @@ #include "embetech/ring_buffer.h" +#include -#ifndef RING_BUFFER_VERSION_MAJOR -#define RING_BUFFER_VERSION_MAJOR 0 -#define RING_BUFFER_VERSION_MINOR 0 -#define RING_BUFFER_VERSION_PATCH 0 -#define RING_BUFFER_VERSION_ID 0 -#define RING_BUFFER_VERSION "0.0.0-0" +#ifndef RING_BUFFER_VERSION +#error "RING_BUFFER_VERSION is not defined" #endif -SemanticVersion RingBuffer_GetVersion(void) { - return (SemanticVersion){.major = (RING_BUFFER_VERSION_MAJOR), - .minor = (RING_BUFFER_VERSION_MINOR), - .patch = (RING_BUFFER_VERSION_PATCH), - .id = (RING_BUFFER_VERSION_ID)}; -} +static_assert(sizeof(RING_BUFFER_VERSION) <= 64, "RING_BUFFER_VERSION too long"); // NOLINT(readability-magic-numbers) - 64 bytes max char const *RingBuffer_GetVersionString(void) { return (RING_BUFFER_VERSION); } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index e2af2d9..c794532 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,9 +1,5 @@ include(GoogleTest) -# Workaround for https://github.com/google/googletest/issues/4671 -target_compile_options(gtest PRIVATE -Wno-null-dereference) - - add_executable(ring_buffer_ut ring_buffer_ut.cpp) target_link_libraries(ring_buffer_ut PRIVATE embetech::ring_buffer GTest::gtest_main)