From c15b2622733f11024df2021beae5b4912e62295b Mon Sep 17 00:00:00 2001 From: Sergei Shirokov Date: Wed, 3 Apr 2024 16:16:36 +0300 Subject: [PATCH 01/17] first attempt to restore CI build --- .github/workflows/tests.yml | 41 +-- .gitignore | 14 +- .vscode/settings.json | 5 +- CMakeLists.txt | 2 +- CONTRIBUTING.md | 13 +- README.md | 2 +- build-tools/bin/verify.py | 2 +- cmake/compiler_flag_sets/default.cmake | 2 +- cmake/modules/Findcetl.cmake | 2 +- cmake/modules/Findcyphal.cmake | 4 +- docs/CMakeLists.txt | 2 +- docs/design/unique_any_poc.cpp | 283 ------------------ docs/examples/example_01_hello_world.cpp | 21 +- include/libcyphal/libcyphal.hpp | 16 + test/unittest/test_hello_libcyphal.cpp | 33 -- test/unittest/test_libcyphal.cpp | 20 ++ .../unittest/test_transport_ip_v4_address.cpp | 144 --------- 17 files changed, 103 insertions(+), 503 deletions(-) delete mode 100644 docs/design/unique_any_poc.cpp create mode 100644 include/libcyphal/libcyphal.hpp delete mode 100644 test/unittest/test_hello_libcyphal.cpp create mode 100644 test/unittest/test_libcyphal.cpp delete mode 100644 test/unittest/test_transport_ip_v4_address.cpp diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index acfdd040f..bf98db7fc 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -4,12 +4,16 @@ on: push: branches: [ "main" ] pull_request: - branches: [ "main" ] + branches: + - main + - 'issue/*' + # todo: temp - remove this later! + - 'sshirokov/CI_*' # To test use https://github.com/nektos/act and specify the event as "act" # For example: # -# act act -j verifiation --bind --reuse +# act act -j verification --bind --reuse # # That command will run the verification job locally and bind the current directory # into the container (You'll probably need to delete any existing build directory @@ -66,15 +70,15 @@ jobs: - name: get nunavut run: > pip install nunavut - # - name: release - # run: > - # ./build-tools/bin/verify.py - # --verbose - # --asserts - # --cpp-standard 14 - # --build-flavor ${{ matrix.flavor }} - # --toolchain ${{ matrix.toolchain }} - # clean-release + - name: release + run: > + ./build-tools/bin/verify.py + --verbose + --asserts + --cpp-standard 14 + --build-flavor ${{ matrix.flavor }} + --toolchain ${{ matrix.toolchain }} + clean-release docs: runs-on: ubuntu-latest container: ghcr.io/opencyphal/toolshed:ts22.4.3 @@ -96,12 +100,12 @@ jobs: pip install nunavut - name: doc-gen run: > - # ./build-tools/bin/verify.py - # --verbose - # --asserts - # --cpp-standard 14 - # --build-flavor Debug - # build-docs + ./build-tools/bin/verify.py + --verbose + --asserts + --cpp-standard 14 + --build-flavor Debug + build-docs - name: Setup Pages if: ${{ github.event_name != 'pull_request' && github.event_name != 'act' }} uses: actions/configure-pages@v3 @@ -116,5 +120,4 @@ jobs: with: name: pr-docs path: "build/docs/html/" - #if-no-files-found: error - + if-no-files-found: error diff --git a/.gitignore b/.gitignore index 8362d3632..3c9f7560a 100755 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,15 @@ +# Dumb OS crap +.DS_Store +*.bak clang-format-diff-warnings -build external/**/* -.DS_Store + +# Build folders +**/build/ +**/build_*/ + + +# JetBrains +.idea/* +cmake-build-*/ diff --git a/.vscode/settings.json b/.vscode/settings.json index d1406e569..369612a5c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -151,7 +151,10 @@ "span": "cpp", "__functional_base": "cpp", "__nullptr": "cpp", - "__string": "cpp" + "__string": "cpp", + "charconv": "cpp", + "complex": "cpp", + "execution": "cpp" }, "python.analysis.typeCheckingMode": "basic", "sonarlint.pathToCompileCommands": "${workspaceFolder}/build/compile_commands.json", diff --git a/CMakeLists.txt b/CMakeLists.txt index b299f2566..8cace2941 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ include(cmake/CMakeCommon.cmake REQUIRED) project(libcyphal VERSION ${LIBCYPHAL_VERSION} LANGUAGES CXX C - HOMEPAGE_URL https://github.com/OpenCyphal/libcyphal + HOMEPAGE_URL https://github.com/OpenCyphal-Garage/libcyphal ) add_subdirectory(test/unittest) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8af3d3159..0a571d0dc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -68,14 +68,8 @@ More abstractly, libcyphal's design goals should be mutually compatible. There i | + external/ <-- external project mount-point. Sub-folders are not | included in git history. -| -+ libcyphal/ -| + CMakeLists.txt <-- builds a cmake module to support inclusion as an -| ExternalProject. Also supports building various -| release formats. -| + include/ <-- where the magic happens! -| + validation/ <-- parametrized googletest tests for building a -| platform-specific validation suite for libcyphal. ++ include/ +| + libcyphal/ <-- where the magic happens! | | test/ | + unittest/ <-- googletest unit tests of libcyphal code. @@ -84,6 +78,7 @@ More abstractly, libcyphal's design goals should be mutually compatible. There i + .github/ <-- github actions CI + .devcontainer/ <-- vscode/github developer container integration | (OpenCyphal toolshed image) +| + .vscode/ <-- common vscode development settings ``` @@ -136,7 +131,7 @@ This is a list that will move to an external project and road-map at some point. ## CETL -[CETL](https://github.com/OpenCyphal/CETL) is a primary dependency of libcyphal along with the "args" (e.g. libudpard, libcanard, etc) but CETL is both a runtime and build time dependency. At build time, libcyphal uses the CETLVaSt (CETL Verification Suite) cmake modules and CETL's verify.py cli to build its own verification suites and to integrate with CI services in a similar manner to CETL. +[CETL](https://github.com/OpenCyphal/CETL) is a primary dependency of libcyphal along with the "ards" (e.g. libudpard, libcanard, etc) but CETL is both a runtime and build time dependency. At build time, libcyphal uses the CETLVaSt (CETL Verification Suite) cmake modules and CETL's verify.py cli to build its own verification suites and to integrate with CI services in a similar manner to CETL. ## ![visual-studio code](.vscode/vscode-alt.svg#gh-dark-mode-only) ![visual-studio code](.vscode/vscode.svg#gh-light-mode-only) We support the vscode IDE using diff --git a/README.md b/README.md index 425541068..7a37fd9ca 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![Cyphal](doc_source/images/html/opencyphal_logo.svg) Cyphal stack in C++ +![Cyphal](docs/images/html/opencyphal_logo.svg) Cyphal stack in C++ =================== [![Build Status](https://badge.buildkite.com/af844974c06af6406e3b2192d98298b02b30f6ebebb5f8b16c.svg)](https://buildkite.com/uavcan/libcyphal-v1) diff --git a/build-tools/bin/verify.py b/build-tools/bin/verify.py index 390a014e8..3bff777e5 100755 --- a/build-tools/bin/verify.py +++ b/build-tools/bin/verify.py @@ -161,7 +161,7 @@ def only(self) -> bool: def _make_parser() -> argparse.ArgumentParser: prolog = textwrap.dedent( - """ + r""" _ _ ___ _ __ ___ _ __ ___ _ _ _ __ | |__ __ _| | / _ \| '_ \ / _ | '_ \ / __| | | | '_ \| '_ \ / _` | | diff --git a/cmake/compiler_flag_sets/default.cmake b/cmake/compiler_flag_sets/default.cmake index bf54222c2..1598097cc 100644 --- a/cmake/compiler_flag_sets/default.cmake +++ b/cmake/compiler_flag_sets/default.cmake @@ -67,7 +67,7 @@ endif() if (CETLVAST_DISABLE_CPP_EXCEPTIONS) message(DEBUG "CETLVAST_DISABLE_CPP_EXCEPTIONS is true. Adding -fno-exceptions to compiler flags.") - list(APPEND C_FLAG_SET + list(APPEND CXX_FLAG_SET "-fno-exceptions") endif() diff --git a/cmake/modules/Findcetl.cmake b/cmake/modules/Findcetl.cmake index 0f7dc3e47..2c2a574f6 100644 --- a/cmake/modules/Findcetl.cmake +++ b/cmake/modules/Findcetl.cmake @@ -6,7 +6,7 @@ include(FetchContent) set(cetl_GIT_REPOSITORY "https://github.com/OpenCyphal/cetl.git") -set(cetl_GIT_TAG "71e0ccdd601e24744f7710bd6b60fc24a3840e02") +set(cetl_GIT_TAG "c1c2ae21ed446a7b25394d0067f3f4bec43a881b") FetchContent_Declare( cetl diff --git a/cmake/modules/Findcyphal.cmake b/cmake/modules/Findcyphal.cmake index 1291a6132..9ea6cbc37 100644 --- a/cmake/modules/Findcyphal.cmake +++ b/cmake/modules/Findcyphal.cmake @@ -10,12 +10,12 @@ find_package(cetl REQUIRED) # +---------------------------------------------------------------------------+ # | (lib)cyphal # +---------------------------------------------------------------------------+ -cmake_path(APPEND LIBCYPHAL_ROOT "libcyphal" "include" OUTPUT_VARIABLE LIBCYPHAL_INCLUDE) +cmake_path(APPEND LIBCYPHAL_ROOT "include" OUTPUT_VARIABLE LIBCYPHAL_INCLUDE) add_project_library( NAME cyphal HEADER_PATH - ${LIBCYPHAL_INCLUDE} + ${LIBCYPHAL_INCLUDE}/ LIBRARIES canard udpard diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index c045c458e..f472df504 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -129,7 +129,7 @@ endfunction(create_docs_target) file(GLOB_RECURSE DOXYGEN_INPUT_LIST LIST_DIRECTORIES false CONFIGURE_DEPENDS - ${LIBCYPHAL_ROOT}/libcyphal/include/**/*.hpp + ${LIBCYPHAL_ROOT}/include/libcyphal/**/*.hpp ) get_property(LOCAL_EXAMPLES DIRECTORY "examples" PROPERTY IN_BUILD_TESTS) diff --git a/docs/design/unique_any_poc.cpp b/docs/design/unique_any_poc.cpp deleted file mode 100644 index 764facf49..000000000 --- a/docs/design/unique_any_poc.cpp +++ /dev/null @@ -1,283 +0,0 @@ -#include -#include -#include -#include - -/// A simplified substitute for RTTI that allows querying the identity of types. -/// Returns an entity of an unspecified type for which operator== and operator!= are defined. -/// Entities for the same type compare equal. Ordering is not defined. -/// If RTTI is enabled, this solution can wrap typeid() directly. -template -auto getTypeID() noexcept -{ - static const struct{} placeholder{}; - return static_cast(&placeholder); -} -using TypeID = decltype(getTypeID()); - -#if __cplusplus < 201703L -template auto* launder(T* const src) { return src; } -#else -using std::launder; -#endif - -/// This interface is useful when the concrete type of the any class is not relevant. -class IAny -{ -public: - IAny() = default; - IAny(const IAny&) = default; - IAny(IAny&&) = default; - IAny& operator=(const IAny&) = default; - IAny& operator=(IAny&&) = default; - - [[nodiscard]] bool has_value() const noexcept { return type() != getTypeID(); } - - /// Returns a pointer to the contained value unless (the instance is empty OR the type is incorrect). - template , void>::value>> - [[nodiscard]] T* cast() noexcept - { - if (type() == getTypeID()) - { - return launder(static_cast(ptr())); - } - return nullptr; - } - template , void>::value>> - [[nodiscard]] const T* cast() const noexcept - { - if (type() == getTypeID()) - { - return launder(static_cast(ptr())); - } - return nullptr; - } - - /// The result equals getTypeID() if empty. - [[nodiscard]] virtual TypeID type() const noexcept = 0; - -protected: - [[nodiscard]] virtual void* ptr() noexcept = 0; - [[nodiscard]] virtual const void* ptr() const noexcept = 0; - - virtual ~IAny() = default; -}; - -/// Implementation of the non-throwing versions of std::any_cast. -template -const T* any_cast(const IAny* const operand) noexcept { return operand->cast(); } -template -T* any_cast(IAny* const operand) noexcept { return operand->cast(); } - -template class UniqueAny; - -namespace detail -{ -template struct IsUniqueAny final { static constexpr bool Value = false; }; -template struct IsUniqueAny> final { static constexpr bool Value = true; }; -} -template -constexpr bool IsUniqueAny = detail::IsUniqueAny>::Value; - -/// UniqueAny is designed for types that cannot be copied but can be moved. -/// The contained type shall be move-initializable. -/// The contained object is stored directly inside the instance of UniqueAny without the use of heap. -/// The Footprint must be large enough to accommodate the stored entity; if it is not large enough, a compile-time error will result. -template -class UniqueAny final : public IAny -{ - using Storage = std::aligned_storage_t; - template friend class UniqueAny; - -public: - /// Constructs an empty any by default; has_value() = false. - UniqueAny() = default; - - /// The type is not copy-constructible. The contained type also does not have to be copy-constructible. - UniqueAny(const UniqueAny& other) = delete; - - /// An alias for the move assignment operator. - template - UniqueAny(UniqueAny&& other) { *this = std::move(other); } - - /// Moves an object into this instance. The source cannot be any itself. - template >>> - UniqueAny(T&& source) { emplace(std::move(source)); } - - ~UniqueAny() override { reset(); } - - /// The type is not copyable. The contained type also does not have to be copyable. - UniqueAny& operator=(const UniqueAny& other) = delete; - - /// The move constructor will be invoked to perform the move. - template - UniqueAny& operator=(UniqueAny&& other) - { - static_assert(Footprint >= F, "Moving Any into Any when F > L is not safe as it may cause overflow"); - if (this != static_cast(&other)) - { - reset(); - fn_destroy_ = other.fn_destroy_; - fn_move_ = other.fn_move_; - ty_ = other.ty_; - if (fn_move_ != nullptr) - { - fn_move_(&storage_, &other.storage_); - } - other.reset(); - } - return *this; - } - - template >>> - void emplace(Args&&... as) - { - using T = std::decay_t; - static_assert(sizeof(T) <= Footprint, "Enlarge the footprint"); - static_assert(alignof(T) <= alignof(Storage), "Insufficient alignment requirement"); - reset(); - new (&storage_) T(std::forward(as)...); - fn_destroy_ = [](void* const p) { static_cast(p)->~T(); }; - fn_move_ = [](void* const sto, void* const src) { new (sto) T(std::move(*static_cast(src))); }; - ty_ = getTypeID(); - } - - void reset() - { - if (fn_destroy_ != nullptr) - { - fn_destroy_(ptr()); - } - fn_destroy_ = nullptr; - fn_move_ = nullptr; - ty_ = getTypeID(); - } - - [[nodiscard]] TypeID type() const noexcept override { return ty_; } - -private: - [[nodiscard]] void* ptr() noexcept override { return &storage_; } - [[nodiscard]] const void* ptr() const noexcept override { return &storage_; } - - void (*fn_destroy_)(void*) = nullptr; - void (*fn_move_)(void*, void*) = nullptr; - TypeID ty_ = getTypeID(); - Storage storage_; -}; - -/// The instance is always initialized with a valid value, but it may turn valueless if the value is moved. -/// The Any type can be either std::any or a custom alternative. -template -class ImplementationCell final -{ -public: - template::value>> - explicit ImplementationCell(Impl&& object) : - storage_(std::forward(object)), - fn_getter_mut_([](Any& sto) -> Iface* { return any_cast(&sto); }), - fn_getter_const_([](const Any& sto) -> const Iface* { return any_cast(&sto); }) - {} - - /// Behavior undefined if the instance is valueless. - [[nodiscard]] Iface* operator->() { return fn_getter_mut_(storage_); } - [[nodiscard]] const Iface* operator->() const { return fn_getter_const_(storage_); } - - [[nodiscard]] operator bool() const { return storage_.has_value(); } - -private: - Any storage_; - Iface* (*fn_getter_mut_)(Any&); - const Iface* (*fn_getter_const_)(const Any&); -}; - -/// The buffer is movable but not copyable, because copying the contents of a buffer is considered wasteful. -/// The buffer behaves as if it's empty if the underlying implementation is moved away. -class DynamicBuffer final -{ -public: - static constexpr std::size_t ImplementationFootprint = sizeof(void*) * 8; - - class Iface /// Lizard-specific implementation hidden from the user. - { - public: - [[nodiscard]] virtual std::size_t copy(const std::size_t offset_bytes, - void* const destination, - const std::size_t length_bytes) const = 0; - [[nodiscard]] virtual std::size_t size() const = 0; - Iface() = default; - Iface(const Iface&) = delete; - Iface(Iface&&) = default; - Iface& operator=(const Iface&) = delete; - Iface& operator=(Iface&&) = delete; - virtual ~Iface() = default; - }; - - /// Accepts a Lizard-specific implementation of Iface and moves it into the internal storage. - template::value>> - explicit DynamicBuffer(T&& source) : impl_(std::move(source)) {} - - /// Copies a fragment of the specified size at the specified offset out of the buffer. - /// The request is truncated to prevent out-of-range memory access. - /// Returns the number of bytes copied. - /// Does nothing and returns zero if the instance has been moved away. - [[nodiscard]] std::size_t copy(const std::size_t offset_bytes, void* const destination, const std::size_t length_bytes) const - { - return impl_ ? impl_->copy(offset_bytes, destination, length_bytes) : 0; - } - /// The number of bytes stored in the buffer (possibly scattered, but this is hidden from the user). - /// Returns zero if the buffer is moved away. - [[nodiscard]] std::size_t size() const { return impl_ ? impl_->size() : 0; } - -private: - ImplementationCell> impl_; -}; - -int main() -{ - UniqueAny<100> str(std::string("Hello world!")); - UniqueAny<200> str2 = std::move(str); - str.emplace(123); - std::cout << str.cast() << std::endl; - std::cout << str2.cast() << std::endl; - - struct MyCustomBuffer final : public DynamicBuffer::Iface - { - MyCustomBuffer(const std::size_t sz, void* const ptr) : size_bytes(sz), data(ptr) {} - MyCustomBuffer(const MyCustomBuffer&) = delete; - MyCustomBuffer(MyCustomBuffer&& other) : size_bytes(other.size_bytes), data(other.data) - { - other.size_bytes = 0; - other.data = nullptr; - } - ~MyCustomBuffer() override { std::free(data); } - - MyCustomBuffer& operator=(const MyCustomBuffer&) = delete; - MyCustomBuffer& operator=(MyCustomBuffer&&) = delete; - - std::size_t copy(const std::size_t offset_bytes, void* const destination, const std::size_t length_bytes) const override - { - const std::size_t off = std::min(offset_bytes, size_bytes); - const std::size_t sz = std::min(length_bytes, size_bytes - off); - std::memmove(destination, static_cast(data) + off, sz); - return sz; - } - std::size_t size() const override { return size_bytes; } - - std::size_t size_bytes; - void* data; - }; - - const char hello[] = "Hello!"; - void* const ptr = std::malloc(sizeof(hello)); - std::memcpy(ptr, hello, sizeof(hello)); - DynamicBuffer my_buffer(MyCustomBuffer{sizeof(hello), ptr}); - - DynamicBuffer another_buffer = std::move(my_buffer); - std::cout << my_buffer.size() << std::endl; // contents moved, returns zero - std::cout << another_buffer.size() << std::endl; - - char result[4]{0}; - std::cout << another_buffer.copy(2, result, 3) << " " << result << std::endl; - - return 0; -} diff --git a/docs/examples/example_01_hello_world.cpp b/docs/examples/example_01_hello_world.cpp index 45ff1eb55..1669a7a59 100644 --- a/docs/examples/example_01_hello_world.cpp +++ b/docs/examples/example_01_hello_world.cpp @@ -6,14 +6,20 @@ /// Copyright Amazon.com Inc. or its affiliates. /// SPDX-License-Identifier: MIT /// + #include "libcyphal/libcyphal.hpp" -#include -#include -#include -#include + +// TODO: Uncomment this when we have a real example to test. +// +// #include +// #include +// #include +// #include #include +// TODO: Uncomment this when we have a real example to test. +/* #include "cetl/pf17/sys/memory_resource.hpp" #include "cetl/pf17/byte.hpp" #include "cetl/variable_length_array.hpp" @@ -46,8 +52,13 @@ using FooStorageType = std::aligned_storage +/// Copyright Amazon.com Inc. or its affiliates. +/// SPDX-License-Identifier: MIT + +#ifndef LIBCYPHAL_LIBCYPHAL_HPP_INCLUDED +#define LIBCYPHAL_LIBCYPHAL_HPP_INCLUDED + +namespace libcyphal +{ +} // namespace libcyphal + +#endif // LIBCYPHAL_LIBCYPHAL_HPP_INCLUDED diff --git a/test/unittest/test_hello_libcyphal.cpp b/test/unittest/test_hello_libcyphal.cpp deleted file mode 100644 index 6389c0525..000000000 --- a/test/unittest/test_hello_libcyphal.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/// @file -/// Delete me once you have at least one test built. -/// -/// @copyright -/// Copyright (C) OpenCyphal Development Team -/// Copyright Amazon.com Inc. or its affiliates. -/// SPDX-License-Identifier: MIT -/// - -#include "gtest/gtest.h" -#include "gmock/gmock.h" - -#include "libcyphal/util/math.hpp" -#include "libcyphal/platform/memory.hpp" - -namespace -{ - -TEST(HelloGoogleTest, HelloWorld) -{ - ASSERT_STREQ("Hello World!", "Hello World!"); - libcyphal::platform::memory::PoolAllocator<24, 8> p; - (void)p.allocate(1); -} - -TEST(HelloGoogleTest, Math) -{ - // teo - ASSERT_EQ(std::numeric_limits::max(), - libcyphal::util::saturating_add(std::numeric_limits::max(), 1)); -} - -} // namespace diff --git a/test/unittest/test_libcyphal.cpp b/test/unittest/test_libcyphal.cpp new file mode 100644 index 000000000..5171145bd --- /dev/null +++ b/test/unittest/test_libcyphal.cpp @@ -0,0 +1,20 @@ +/// @file +/// libcyphal common header. +/// +/// @copyright +/// Copyright (C) OpenCyphal Development Team +/// Copyright Amazon.com Inc. or its affiliates. +/// SPDX-License-Identifier: MIT + +#include "libcyphal/libcyphal.hpp" + +#include + +namespace { + +// TODO: Add tests here +TEST(test_libcyphal, rename_me) +{ +} + +} // namespace diff --git a/test/unittest/test_transport_ip_v4_address.cpp b/test/unittest/test_transport_ip_v4_address.cpp deleted file mode 100644 index 341b52906..000000000 --- a/test/unittest/test_transport_ip_v4_address.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/// @file -/// Test of crap in the IP v4 address class. -/// -/// @copyright -/// Copyright (C) OpenCyphal Development Team -/// Copyright Amazon.com Inc. or its affiliates. -/// SPDX-License-Identifier: MIT -/// -// cSpell: words cted - -#ifndef __clang__ -// The octetFromBase10String tests intentionally truncate the nullptr in several -// variations to ensure this is handled correctly. You shouldn't need to disable -// this warning in real code and should just include the null terminator in your -// length values passed into this method. -// This is found in GCC 8 and newer: -// https://gcc.gnu.org/git/?p=gcc.git&a=commit;h=025d57f037ad13eb479818b677ef4be4d97b639c -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpragmas" -#pragma GCC diagnostic ignored "-Wstringop-truncation" -#endif -#include "libcyphal/transport/ip/v4/address.hpp" -#ifndef __clang__ -#pragma GCC diagnostic pop -#endif - -#include "gtest/gtest.h" -#include "gmock/gmock.h" - -namespace -{ - - -TEST(TransportsIpV4AddressTest, DefaultCtor) -{ - libcyphal::transport::ip::v4::Address subject{}; - ASSERT_EQ(subject.asInteger(), 0u); - ASSERT_FALSE(subject.isLocal()); - ASSERT_FALSE(subject.isMulticast()); - ASSERT_EQ(static_cast(subject), 0U); - ASSERT_FALSE(subject.isValid()); -} - -TEST(TransportsIpV4AddressTest, IntegerCtor) -{ - libcyphal::transport::ip::v4::Address int_cted{167772162u}; - libcyphal::transport::ip::v4::Address oct_cted{10u, 0u, 0u, 2u}; - ASSERT_EQ(int_cted, oct_cted); -} - -TEST(TransportsIpV4AddressTest, IsValid) -{ - libcyphal::transport::ip::v4::Address subject_0{0u, 0u, 0u, 0u}; - ASSERT_FALSE(subject_0.isValid()); - libcyphal::transport::ip::v4::Address subject_max{255u, 255u, 255u, 255u}; - ASSERT_FALSE(subject_max.isValid()); - libcyphal::transport::ip::v4::Address subject_home{192u, 168u, 0u, 10u}; - ASSERT_TRUE(subject_home.isValid()); -} - -TEST(TransportsIpV4AddressTest, MoveOps) -{ - libcyphal::transport::ip::v4::Address subject_moved{libcyphal::transport::ip::v4::Address{192u, 168u, 10u, 8u}}; - ASSERT_EQ(subject_moved.asInteger(), 3232238088u); - libcyphal::transport::ip::v4::Address subject_moved_assigned{}; - subject_moved_assigned = libcyphal::transport::ip::v4::Address{192u, 168u, 10u, 8u}; - ASSERT_EQ(subject_moved_assigned.asInteger(), 3232238088u); -} - -TEST(TransportsIpV4AddressTest, CopyOps) -{ - libcyphal::transport::ip::v4::Address subject0{192u, 168u, 10u, 8u}; - libcyphal::transport::ip::v4::Address subject_copied{subject0}; - ASSERT_EQ(subject_copied.asInteger(), 3232238088u); - ASSERT_EQ(subject0.asInteger(), 3232238088u); - - libcyphal::transport::ip::v4::Address subject1{10u, 0u, 0u, 1u}; - libcyphal::transport::ip::v4::Address subject_copied_assigned{}; - subject_copied_assigned = subject1; - ASSERT_EQ(subject_copied_assigned.asInteger(), 167772161u); - ASSERT_EQ(subject1.asInteger(), 167772161u); -} - -TEST(TransportsIpV4AddressTest, octetFromBase10String) -{ - ASSERT_EQ(0, libcyphal::transport::ip::v4::Address::octetFromBase10String(nullptr, 4)); - ASSERT_EQ(0, libcyphal::transport::ip::v4::Address::octetFromBase10String("", 0)); - ASSERT_EQ(0, libcyphal::transport::ip::v4::Address::octetFromBase10String("", 1)); - ASSERT_EQ(2, libcyphal::transport::ip::v4::Address::octetFromBase10String("2", 1)); - - // Don't do anything insane if the input buffer is too large. - ASSERT_EQ(0, libcyphal::transport::ip::v4::Address::octetFromBase10String("Hi there. How ya doin'?", 23)); - ASSERT_EQ(255, libcyphal::transport::ip::v4::Address::octetFromBase10String("99999999999999999999999999", 26)); - ASSERT_EQ(0, libcyphal::transport::ip::v4::Address::octetFromBase10String("00000000000000000000000000", 26)); - ASSERT_EQ(1, libcyphal::transport::ip::v4::Address::octetFromBase10String("00000000000000000000000001", 26)); - ASSERT_EQ(255, libcyphal::transport::ip::v4::Address::octetFromBase10String("-2", 2)); - - // base 10 - ASSERT_EQ(255, libcyphal::transport::ip::v4::Address::octetFromBase10String("1024", 4)); - ASSERT_EQ(255, libcyphal::transport::ip::v4::Address::octetFromBase10String("1024", 5)); - ASSERT_EQ(255, libcyphal::transport::ip::v4::Address::octetFromBase10String("255", 3)); - ASSERT_EQ(255, libcyphal::transport::ip::v4::Address::octetFromBase10String("255", 4)); - ASSERT_EQ(0, libcyphal::transport::ip::v4::Address::octetFromBase10String("0", 1)); - ASSERT_EQ(0, libcyphal::transport::ip::v4::Address::octetFromBase10String("0", 2)); - ASSERT_EQ(127, libcyphal::transport::ip::v4::Address::octetFromBase10String("127", 3)); -} - - -TEST(TransportsIpV4AddressTest, AddressFromString) -{ - ASSERT_EQ(0, libcyphal::transport::ip::v4::Address::addressFromString(nullptr).asInteger()); - ASSERT_EQ(0, libcyphal::transport::ip::v4::Address::addressFromString("").asInteger()); - - // VALID - ASSERT_EQ(3232238088u, libcyphal::transport::ip::v4::Address::addressFromString("192.168.10.8").asInteger()); - ASSERT_TRUE(libcyphal::transport::ip::v4::Address::addressFromString("127.0.0.1").isLocal()); - - // all zeros - ASSERT_EQ(0u, libcyphal::transport::ip::v4::Address::addressFromString("0").asInteger()); - ASSERT_EQ(0u, libcyphal::transport::ip::v4::Address::addressFromString("0.0").asInteger()); - ASSERT_EQ(0u, libcyphal::transport::ip::v4::Address::addressFromString("0.0.0").asInteger()); - ASSERT_EQ(0u, libcyphal::transport::ip::v4::Address::addressFromString("0.0.0.0").asInteger()); - ASSERT_EQ(0u, libcyphal::transport::ip::v4::Address::addressFromString("0.0.0.0.0").asInteger()); - - // all 0xFF - ASSERT_EQ(4278190080u, libcyphal::transport::ip::v4::Address::addressFromString("255").asInteger()); - ASSERT_EQ(4294901760u, libcyphal::transport::ip::v4::Address::addressFromString("255.255").asInteger()); - ASSERT_EQ(4294967040u, libcyphal::transport::ip::v4::Address::addressFromString("255.255.255").asInteger()); - ASSERT_EQ(4294967295u, libcyphal::transport::ip::v4::Address::addressFromString("255.255.255.255").asInteger()); - ASSERT_EQ(4294967295u, libcyphal::transport::ip::v4::Address::addressFromString("255.255.255.255.255").asInteger()); - - // weirdness - ASSERT_EQ(4278190090u, libcyphal::transport::ip::v4::Address::addressFromString("255...10").asInteger()); - ASSERT_EQ(3232238088u, libcyphal::transport::ip::v4::Address::addressFromString("192.168.010.008").asInteger()); - ASSERT_EQ(192u << 24, libcyphal::transport::ip::v4::Address::addressFromString("192,168,10,8").asInteger()); - // 0 10 20 30 40 50 - // 01234567890123456789012345678901234567890123456789012345 - char mem[56] = "xxx 192.168.10.82the brown fox jumped over the red cow."; - ASSERT_EQ(3232238088u, libcyphal::transport::ip::v4::Address::addressFromString(&mem[4], 16 - 4).asInteger()); - mem[16] = 0; - ASSERT_EQ(3232238088u, libcyphal::transport::ip::v4::Address::addressFromString(&mem[4]).asInteger()); -} - -} // namespace From e421c0d7b59ba518e24a26f6322d627a6f276b63 Mon Sep 17 00:00:00 2001 From: Sergei Shirokov Date: Wed, 3 Apr 2024 16:31:58 +0300 Subject: [PATCH 02/17] run CI on push (on `issue/*`) --- .github/workflows/tests.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index bf98db7fc..0c9919715 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -2,7 +2,11 @@ name: "libcyphal_test" on: push: - branches: [ "main" ] + branches: + - main + - 'issue/*' + # todo: temp - remove this later! + - 'sshirokov/CI_*' pull_request: branches: - main From 3a68367844abbe3643ba4a40c6dcb8bbe6e8f289 Mon Sep 17 00:00:00 2001 From: Sergei Shirokov Date: Wed, 3 Apr 2024 18:04:06 +0300 Subject: [PATCH 03/17] attempt to fix "Node.js 16 actions are deprecated. Please update the following actions to use Node.js 20:" warnings --- .github/workflows/tests.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 0c9919715..c3d8eabbe 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -27,12 +27,12 @@ jobs: runs-on: ubuntu-latest container: ghcr.io/opencyphal/toolshed:ts22.4.3 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 if: ${{ github.event_name != 'act' }} - name: Cache ext modules if: ${{ github.event_name != 'act' }} id: libcyphal-ext - uses: actions/cache@v3 + uses: actions/cache@v4 env: cache-name: libcyphal-ext-cache with: @@ -60,12 +60,12 @@ jobs: flavor: [Release, Debug] toolchain: [gcc, clang] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 if: ${{ github.event_name != 'act' }} - name: Cache ext modules if: ${{ github.event_name != 'act' }} id: libcyphal-ext - uses: actions/cache@v3 + uses: actions/cache@v4 env: cache-name: libcyphal-ext-cache with: @@ -88,12 +88,12 @@ jobs: container: ghcr.io/opencyphal/toolshed:ts22.4.3 needs: [warmup] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 if: ${{ github.event_name != 'act' }} - name: Cache ext modules if: ${{ github.event_name != 'act' }} id: libcyphal-ext - uses: actions/cache@v3 + uses: actions/cache@v4 env: cache-name: libcyphal-ext-cache with: @@ -112,15 +112,15 @@ jobs: build-docs - name: Setup Pages if: ${{ github.event_name != 'pull_request' && github.event_name != 'act' }} - uses: actions/configure-pages@v3 + uses: actions/configure-pages@v5 - name: Upload docs if: ${{ github.event_name != 'pull_request' && github.event_name != 'act' }} - uses: actions/upload-pages-artifact@v1 + uses: actions/upload-pages-artifact@v3 with: path: "build/docs/html/" - name: upload-pr-docs if: ${{ github.event_name == 'pull_request' && github.event_name != 'act' }} - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: pr-docs path: "build/docs/html/" From 3395a9fc26c8a3dcb33ce8ceb8931ea90cd1795c Mon Sep 17 00:00:00 2001 From: Sergei Shirokov Date: Wed, 3 Apr 2024 18:08:51 +0300 Subject: [PATCH 04/17] try fail unit test - to make sure CI will fail --- test/unittest/test_libcyphal.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/test/unittest/test_libcyphal.cpp b/test/unittest/test_libcyphal.cpp index 5171145bd..c040a90c0 100644 --- a/test/unittest/test_libcyphal.cpp +++ b/test/unittest/test_libcyphal.cpp @@ -15,6 +15,7 @@ namespace { // TODO: Add tests here TEST(test_libcyphal, rename_me) { + EXPECT_EQ(1, 2); } } // namespace From 7e660231709ada9a16029da07ac1616d57a8f2e9 Mon Sep 17 00:00:00 2001 From: Sergei Shirokov Date: Wed, 3 Apr 2024 18:13:17 +0300 Subject: [PATCH 05/17] revert intentional unit test failure --- test/unittest/test_libcyphal.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/test/unittest/test_libcyphal.cpp b/test/unittest/test_libcyphal.cpp index c040a90c0..5171145bd 100644 --- a/test/unittest/test_libcyphal.cpp +++ b/test/unittest/test_libcyphal.cpp @@ -15,7 +15,6 @@ namespace { // TODO: Add tests here TEST(test_libcyphal, rename_me) { - EXPECT_EQ(1, 2); } } // namespace From 4853747a96a8d9174531ca830bc7332cf0e576eb Mon Sep 17 00:00:00 2001 From: Sergei Shirokov Date: Wed, 3 Apr 2024 19:51:17 +0300 Subject: [PATCH 06/17] added placeholder versions of runnable and transport interfaces --- .clang-format | 2 +- docs/examples/example_01_hello_world.cpp | 2 +- include/libcyphal/libcyphal.hpp | 16 ------ include/libcyphal/runnable.hpp | 38 +++++++++++++ include/libcyphal/transport/transport.hpp | 42 +++++++++++++++ include/libcyphal/types.hpp | 65 +++++++++++++++++++++++ test/unittest/test_libcyphal.cpp | 5 +- 7 files changed, 150 insertions(+), 20 deletions(-) delete mode 100644 include/libcyphal/libcyphal.hpp create mode 100644 include/libcyphal/runnable.hpp create mode 100644 include/libcyphal/transport/transport.hpp create mode 100644 include/libcyphal/types.hpp diff --git a/.clang-format b/.clang-format index f5021158e..0b2b21ebf 100644 --- a/.clang-format +++ b/.clang-format @@ -28,7 +28,6 @@ BraceWrapping: AfterStruct: true AfterClass: true AfterControlStatement: true - AfterEnum: true AfterFunction: true AfterUnion: true AfterNamespace: true @@ -50,6 +49,7 @@ DisableFormat: false FixNamespaceComments: true ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] IncludeBlocks: Preserve +InsertNewlineAtEOF: true IndentCaseLabels: false IndentPPDirectives: AfterHash IndentWidth: 4 diff --git a/docs/examples/example_01_hello_world.cpp b/docs/examples/example_01_hello_world.cpp index 1669a7a59..1f0ecd3b0 100644 --- a/docs/examples/example_01_hello_world.cpp +++ b/docs/examples/example_01_hello_world.cpp @@ -7,7 +7,7 @@ /// SPDX-License-Identifier: MIT /// -#include "libcyphal/libcyphal.hpp" +#include "libcyphal/types.hpp" // TODO: Uncomment this when we have a real example to test. // diff --git a/include/libcyphal/libcyphal.hpp b/include/libcyphal/libcyphal.hpp deleted file mode 100644 index 0dd58360e..000000000 --- a/include/libcyphal/libcyphal.hpp +++ /dev/null @@ -1,16 +0,0 @@ -/// @file -/// libcyphal common header. -/// -/// @copyright -/// Copyright (C) OpenCyphal Development Team -/// Copyright Amazon.com Inc. or its affiliates. -/// SPDX-License-Identifier: MIT - -#ifndef LIBCYPHAL_LIBCYPHAL_HPP_INCLUDED -#define LIBCYPHAL_LIBCYPHAL_HPP_INCLUDED - -namespace libcyphal -{ -} // namespace libcyphal - -#endif // LIBCYPHAL_LIBCYPHAL_HPP_INCLUDED diff --git a/include/libcyphal/runnable.hpp b/include/libcyphal/runnable.hpp new file mode 100644 index 000000000..a84448908 --- /dev/null +++ b/include/libcyphal/runnable.hpp @@ -0,0 +1,38 @@ +/// @file +/// libcyphal common header. +/// +/// @copyright +/// Copyright (C) OpenCyphal Development Team +/// Copyright Amazon.com Inc. or its affiliates. +/// SPDX-License-Identifier: MIT + +#ifndef LIBCYPHAL_RUNNABLE_HPP_INCLUDED +#define LIBCYPHAL_RUNNABLE_HPP_INCLUDED + +#include "libcyphal/types.hpp" + +namespace libcyphal +{ + +/// @brief Declares an abstract Cyphal runnable interface. +/// +/// Runnable objects do work asynchronously but only when `run()` is called. +/// This allows super-loop firmware to separate execution into application work and library work, +/// and for threaded software applications to service the library from dedicated threads. +/// Each object that implements `IRunnable` shall document how when it must be run to achieve certain functionality and +/// timing guarantees. +/// +class IRunnable +{ +public: + /// @brief Runs the runnable object. + virtual void run(TimePoint now) = 0; + +protected: + virtual ~IRunnable() = default; + +}; // IRunnable + +} // namespace libcyphal + +#endif // LIBCYPHAL_RUNNABLE_HPP_INCLUDED diff --git a/include/libcyphal/transport/transport.hpp b/include/libcyphal/transport/transport.hpp new file mode 100644 index 000000000..b5c4f05a8 --- /dev/null +++ b/include/libcyphal/transport/transport.hpp @@ -0,0 +1,42 @@ +/// @file +/// Defines the Transport interface for Transport Layer implementations. +/// +/// @copyright +/// Copyright (C) OpenCyphal Development Team +/// Copyright Amazon.com Inc. or its affiliates. +/// SPDX-License-Identifier: MIT + +#ifndef LIBCYPHAL_TRANSPORT_TRANSPORT_HPP_INCLUDED +#define LIBCYPHAL_TRANSPORT_TRANSPORT_HPP_INCLUDED + +#include "libcyphal/runnable.hpp" + +namespace libcyphal +{ +namespace transport +{ + +/// @brief Declares an abstract Cyphal transport interface. +/// +class ITransport : public IRunnable +{ +public: + /// The node-ID is set once during initialization of the transport, + /// either explicitly (e.g., CAN) or by deriving the node-ID value from the configuration + /// of the underlying protocol layers (e.g., UDP/IP). + /// + /// If the transport does not have a node-ID, this property has the value of `cetl::nullopt`. + /// and the transport (and the node that uses it) is said to be in the anonymous mode. + /// While in the anonymous mode, some transports may choose to operate in a particular regime to facilitate + /// plug-and-play node-ID allocation (for example, a CAN transport may disable automatic retransmission). + /// + /// @return Optional integer representing the local node-ID. + /// + virtual cetl::optional getLocalNodeId() const = 0; + +}; // ITransport + +} // namespace transport +} // namespace libcyphal + +#endif // LIBCYPHAL_TRANSPORT_TRANSPORT_HPP_INCLUDED diff --git a/include/libcyphal/types.hpp b/include/libcyphal/types.hpp new file mode 100644 index 000000000..76a050cc8 --- /dev/null +++ b/include/libcyphal/types.hpp @@ -0,0 +1,65 @@ +/// @file +/// libcyphal common types. +/// +/// @copyright +/// Copyright (C) OpenCyphal Development Team +/// Copyright Amazon.com Inc. or its affiliates. +/// SPDX-License-Identifier: MIT + +#ifndef LIBCYPHAL_TYPES_HPP_INCLUDED +#define LIBCYPHAL_TYPES_HPP_INCLUDED + +#include + +#include +#include +#include + +namespace libcyphal +{ + +/// @brief `NodeId` is a 16-bit unsigned integer that represents a node in a Cyphal network. +/// +/// Anonymity is represented by an empty `optional` (see `cetl::nullopt`). +/// +using NodeId = std::uint16_t; + +/// @brief The internal time representation is in microseconds. +/// +/// This is in line with the lizards that use `uint64_t`-typed microsecond counters throughout. +/// +struct MonotonicClock final +{ + using rep = std::int64_t; + using period = std::micro; + using duration = std::chrono::duration; + using time_point = std::chrono::time_point; + + static constexpr bool is_steady = true; + + /// @brief Gets the current time point. + /// + /// Method is NOT implemented by the library; the user code is expected to provide a suitable implementation + /// instead depending on the requirements of the application. + /// A possible implementation on a POSIX-like platform is: + /// ``` + /// MonotonicClock::time_point MonotonicClock::now() noexcept + /// { + /// return std::chrono::time_point_cast(std::chrono::steady_clock::now()); + /// } + /// ``` + CETL_NODISCARD static time_point now() noexcept; + +}; // MonotonicClock + +/// @brief Defines libcyphal time point type. +/// +using TimePoint = MonotonicClock::time_point; + +/// @brief Defines libcyphal time duration type. +/// +using Duration = MonotonicClock::duration; + +} // namespace libcyphal + +#endif // LIBCYPHAL_TYPES_HPP_INCLUDED diff --git a/test/unittest/test_libcyphal.cpp b/test/unittest/test_libcyphal.cpp index 5171145bd..1ff71b836 100644 --- a/test/unittest/test_libcyphal.cpp +++ b/test/unittest/test_libcyphal.cpp @@ -6,11 +6,12 @@ /// Copyright Amazon.com Inc. or its affiliates. /// SPDX-License-Identifier: MIT -#include "libcyphal/libcyphal.hpp" +#include "libcyphal/transport/transport.hpp" #include -namespace { +namespace +{ // TODO: Add tests here TEST(test_libcyphal, rename_me) From 54d080ed17365531331bebeeea7d07202473bdfd Mon Sep 17 00:00:00 2001 From: Sergei Shirokov Date: Wed, 3 Apr 2024 20:21:24 +0300 Subject: [PATCH 07/17] added `ITransport::getProtocolParams` --- include/libcyphal/transport/transport.hpp | 46 ++++++++++++++++++++++- include/libcyphal/types.hpp | 2 +- 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/include/libcyphal/transport/transport.hpp b/include/libcyphal/transport/transport.hpp index b5c4f05a8..13097ee9d 100644 --- a/include/libcyphal/transport/transport.hpp +++ b/include/libcyphal/transport/transport.hpp @@ -16,11 +16,49 @@ namespace libcyphal namespace transport { +/// @brief Declares basic transport capabilities. +/// +/// These parameters are defined by the underlying transport specifications. +/// +/// Normally, the values should never change for a particular transport instance. +/// This is not a hard guarantee, however. +/// For example, a redundant transport aggregator may return a different set of parameters after +/// the set of aggregated transports is changed (i.e., a transport is added or removed). +/// +struct ProtocolParams final +{ + /// @brief The cardinality of the set of distinct transfer-ID values; i.e., the overflow period. + /// + /// All high-overhead transports (UDP, Serial, etc.) use a sufficiently large value that will never overflow + /// in a realistic, practical scenario. + /// The background and motivation are explained at + /// https://forum.opencyphal.org/t/alternative-transport-protocols/324. + /// Example: 32 for CAN, (2**64) for UDP. + /// + std::uint64_t transfer_id_modulo; + + /// @brief How many nodes can the transport accommodate in a given network. + /// + /// Example: 128 for CAN, 65535 for UDP (0xFFFF is reserved). + /// + NodeId max_nodes; + + /// @brief The largest maximum number of payload bytes in a single-frame transfer + /// for the group of network interfaces used by the transport. + /// + /// This number can change on systems where the value is configurable. + /// + std::size_t mtu_bytes; + +}; // ProtocolParams + /// @brief Declares an abstract Cyphal transport interface. /// class ITransport : public IRunnable { public: + /// @brief Gets (optional) local node-ID assigned to this transport. + /// /// The node-ID is set once during initialization of the transport, /// either explicitly (e.g., CAN) or by deriving the node-ID value from the configuration /// of the underlying protocol layers (e.g., UDP/IP). @@ -32,7 +70,13 @@ class ITransport : public IRunnable /// /// @return Optional integer representing the local node-ID. /// - virtual cetl::optional getLocalNodeId() const = 0; + virtual cetl::optional getLocalNodeId() const noexcept = 0; + + /// @brief Provides information about the properties of the transport protocol implemented by the instance. + /// + /// @return `ProtocolParameters` object if the transport is initialized, otherwise ResultCode::UninitializedError. + /// + virtual ProtocolParams getProtocolParams() const noexcept = 0; }; // ITransport diff --git a/include/libcyphal/types.hpp b/include/libcyphal/types.hpp index 76a050cc8..c1d67cd5a 100644 --- a/include/libcyphal/types.hpp +++ b/include/libcyphal/types.hpp @@ -20,7 +20,7 @@ namespace libcyphal /// @brief `NodeId` is a 16-bit unsigned integer that represents a node in a Cyphal network. /// -/// Anonymity is represented by an empty `optional` (see `cetl::nullopt`). +/// Anonymity is represented by an empty `cetl::optional` (see `cetl::nullopt`). /// using NodeId = std::uint16_t; From d9e24611077e7cf1cb521cf612f0e108c54b4575 Mon Sep 17 00:00:00 2001 From: Sergei Shirokov Date: Thu, 4 Apr 2024 09:28:41 +0300 Subject: [PATCH 08/17] revert `InsertNewlineAtEOF` clang-format option --- .clang-format | 1 - 1 file changed, 1 deletion(-) diff --git a/.clang-format b/.clang-format index 0b2b21ebf..ba36fb92a 100644 --- a/.clang-format +++ b/.clang-format @@ -49,7 +49,6 @@ DisableFormat: false FixNamespaceComments: true ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] IncludeBlocks: Preserve -InsertNewlineAtEOF: true IndentCaseLabels: false IndentPPDirectives: AfterHash IndentWidth: 4 From 7f0ee88f54503f834935df6ad5f0d507e24bea16 Mon Sep 17 00:00:00 2001 From: Sergei Shirokov Date: Thu, 4 Apr 2024 09:38:50 +0300 Subject: [PATCH 09/17] run clang-format at docker --- include/libcyphal/transport/transport.hpp | 2 +- include/libcyphal/types.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/libcyphal/transport/transport.hpp b/include/libcyphal/transport/transport.hpp index 13097ee9d..35e6d7418 100644 --- a/include/libcyphal/transport/transport.hpp +++ b/include/libcyphal/transport/transport.hpp @@ -50,7 +50,7 @@ struct ProtocolParams final /// std::size_t mtu_bytes; -}; // ProtocolParams +}; // ProtocolParams /// @brief Declares an abstract Cyphal transport interface. /// diff --git a/include/libcyphal/types.hpp b/include/libcyphal/types.hpp index c1d67cd5a..3379a67ce 100644 --- a/include/libcyphal/types.hpp +++ b/include/libcyphal/types.hpp @@ -58,7 +58,7 @@ using TimePoint = MonotonicClock::time_point; /// @brief Defines libcyphal time duration type. /// -using Duration = MonotonicClock::duration; +using Duration = MonotonicClock::duration; } // namespace libcyphal From ec57aab8f31c0dff73fb761af006b063eea21ce0 Mon Sep 17 00:00:00 2001 From: Sergei Shirokov Date: Thu, 4 Apr 2024 09:43:18 +0300 Subject: [PATCH 10/17] add "std: [14, 17, 20]" to the build matrix --- .github/workflows/tests.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c3d8eabbe..9ec0da44e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -58,6 +58,7 @@ jobs: strategy: matrix: flavor: [Release, Debug] + std: [14, 17, 20] toolchain: [gcc, clang] steps: - uses: actions/checkout@v4 @@ -79,7 +80,7 @@ jobs: ./build-tools/bin/verify.py --verbose --asserts - --cpp-standard 14 + --cpp-standard ${{ matrix.std }} --build-flavor ${{ matrix.flavor }} --toolchain ${{ matrix.toolchain }} clean-release From 82e4f17e54ea1e612a3caf6c93baee47ecece6ed Mon Sep 17 00:00:00 2001 From: Sergei Shirokov Date: Thu, 4 Apr 2024 10:00:06 +0300 Subject: [PATCH 11/17] make `CETL_NODISCARD` available --- include/libcyphal/types.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/libcyphal/types.hpp b/include/libcyphal/types.hpp index 3379a67ce..55e913f85 100644 --- a/include/libcyphal/types.hpp +++ b/include/libcyphal/types.hpp @@ -10,6 +10,7 @@ #define LIBCYPHAL_TYPES_HPP_INCLUDED #include +#include #include #include From 2a76c4f687a8b84be992a087f65990e8591328bd Mon Sep 17 00:00:00 2001 From: Sergei Shirokov Date: Thu, 4 Apr 2024 11:19:47 +0300 Subject: [PATCH 12/17] added all session interfaces and params --- .../transport/session/msg_sessions.hpp | 61 ++++++++++++ .../libcyphal/transport/session/session.hpp | 32 ++++++ .../transport/session/svc_sessions.hpp | 99 +++++++++++++++++++ include/libcyphal/transport/transport.hpp | 7 +- include/libcyphal/types.hpp | 9 ++ 5 files changed, 205 insertions(+), 3 deletions(-) create mode 100644 include/libcyphal/transport/session/msg_sessions.hpp create mode 100644 include/libcyphal/transport/session/session.hpp create mode 100644 include/libcyphal/transport/session/svc_sessions.hpp diff --git a/include/libcyphal/transport/session/msg_sessions.hpp b/include/libcyphal/transport/session/msg_sessions.hpp new file mode 100644 index 000000000..4b8518d5e --- /dev/null +++ b/include/libcyphal/transport/session/msg_sessions.hpp @@ -0,0 +1,61 @@ +/// @file +/// Defines the Session interface for Transport Layer implementations. +/// +/// @copyright +/// Copyright (C) OpenCyphal Development Team +/// Copyright Amazon.com Inc. or its affiliates. +/// SPDX-License-Identifier: MIT + +#ifndef LIBCYPHAL_TRANSPORT_SESSION_MSG_SESSIONS_HPP_INCLUDED +#define LIBCYPHAL_TRANSPORT_SESSION_MSG_SESSIONS_HPP_INCLUDED + +#include "session.hpp" + +namespace libcyphal +{ +namespace transport +{ +inline namespace session +{ + +/// @brief Declares message RX session parameters. +/// +struct MessageRxParams final +{ + PortId subject_id; + std::size_t extent_bytes; + +}; // MessageRxParams + +/// @brief Declares message TX session parameters. +/// +struct MessageTxParams final +{ + PortId subject_id; + +}; // MessageTxParams + +/// @brief Declares an abstract Cyphal transport message RX session interface. +/// +class IMessageRxSession : public IRunnable +{ +public: + CETL_NODISCARD virtual MessageRxParams getParams() const noexcept = 0; + virtual void setTransferIdTimeout(Duration timeout) = 0; + +}; // IMessageRxSession + +/// @brief Declares an abstract Cyphal transport message TX session interface. +/// +class IMessageTxSession : public IRunnable +{ +public: + CETL_NODISCARD virtual MessageTxParams getParams() const noexcept = 0; + +}; // IMessageTxSession + +} // namespace session +} // namespace transport +} // namespace libcyphal + +#endif // LIBCYPHAL_TRANSPORT_SESSION_MSG_SESSIONS_HPP_INCLUDED diff --git a/include/libcyphal/transport/session/session.hpp b/include/libcyphal/transport/session/session.hpp new file mode 100644 index 000000000..365f4c258 --- /dev/null +++ b/include/libcyphal/transport/session/session.hpp @@ -0,0 +1,32 @@ +/// @file +/// Defines the Session interface for Transport Layer implementations. +/// +/// @copyright +/// Copyright (C) OpenCyphal Development Team +/// Copyright Amazon.com Inc. or its affiliates. +/// SPDX-License-Identifier: MIT + +#ifndef LIBCYPHAL_TRANSPORT_SESSION_SESSION_HPP_INCLUDED +#define LIBCYPHAL_TRANSPORT_SESSION_SESSION_HPP_INCLUDED + +#include "libcyphal/runnable.hpp" + +namespace libcyphal +{ +namespace transport +{ +inline namespace session +{ + +/// @brief Declares an abstract Cyphal transport session interface. +/// +class ISession : public IRunnable +{ +public: +}; // ISession + +} // namespace session +} // namespace transport +} // namespace libcyphal + +#endif // LIBCYPHAL_TRANSPORT_SESSION_SESSION_HPP_INCLUDED diff --git a/include/libcyphal/transport/session/svc_sessions.hpp b/include/libcyphal/transport/session/svc_sessions.hpp new file mode 100644 index 000000000..485fc0271 --- /dev/null +++ b/include/libcyphal/transport/session/svc_sessions.hpp @@ -0,0 +1,99 @@ +/// @file +/// Defines the Service Session interfaces for Transport Layer implementations. +/// +/// @copyright +/// Copyright (C) OpenCyphal Development Team +/// Copyright Amazon.com Inc. or its affiliates. +/// SPDX-License-Identifier: MIT + +#ifndef LIBCYPHAL_TRANSPORT_SESSION_SVC_SESSION_HPP_INCLUDED +#define LIBCYPHAL_TRANSPORT_SESSION_SVC_SESSION_HPP_INCLUDED + +#include "session.hpp" + +namespace libcyphal +{ +namespace transport +{ +inline namespace session +{ + +/// @brief Declares service request RX session parameters. +/// +struct RequestRxParams final +{ + PortId service_id; + std::size_t extent_bytes; + +}; // RequestRxParams + +/// @brief Declares service request TX session parameters. +/// +struct RequestTxParams final +{ + PortId service_id; + NodeId server_node_id; + +}; // RequestTxParams + +/// @brief Declares service response RX session parameters. +/// +struct ResponseRxParams final +{ + PortId service_id; + NodeId server_node_id; + std::size_t extent_bytes; + +}; // ResponseRxParams + +/// @brief Declares service response TX session parameters. +/// +struct ResponseTxParams final +{ + PortId service_id; + +}; // ResponseTxParams + +/// @brief Declares an abstract Cyphal transport request RX session interface. +/// +class IRequestRxSession : public ISession +{ +public: + CETL_NODISCARD virtual RequestRxParams getParams() const noexcept = 0; + virtual void setTransferIdTimeout(Duration timeout) = 0; + +}; // IRequestRxSession + +/// @brief Declares an abstract Cyphal transport request TX session interface. +/// +class IRequestTxSession : public ISession +{ +public: + CETL_NODISCARD virtual RequestTxParams getParams() const noexcept = 0; + +}; // IRequestTxSession + +/// @brief Declares an abstract Cyphal transport response RX session interface. +/// +class IResponseRxSession : public ISession +{ +public: + CETL_NODISCARD virtual ResponseRxParams getParams() const noexcept = 0; + virtual void setTransferIdTimeout(Duration timeout) = 0; + +}; // IResponseRxSession + +/// @brief Declares an abstract Cyphal transport response TX session interface. +/// +class IResponseTxSession : public ISession +{ +public: + CETL_NODISCARD virtual ResponseTxParams getParams() const noexcept = 0; + +}; // IResponseTxSession + +} // namespace session +} // namespace transport +} // namespace libcyphal + +#endif // LIBCYPHAL_TRANSPORT_SESSION_SVC_SESSION_HPP_INCLUDED diff --git a/include/libcyphal/transport/transport.hpp b/include/libcyphal/transport/transport.hpp index 35e6d7418..02fe59758 100644 --- a/include/libcyphal/transport/transport.hpp +++ b/include/libcyphal/transport/transport.hpp @@ -9,7 +9,8 @@ #ifndef LIBCYPHAL_TRANSPORT_TRANSPORT_HPP_INCLUDED #define LIBCYPHAL_TRANSPORT_TRANSPORT_HPP_INCLUDED -#include "libcyphal/runnable.hpp" +#include "session/msg_sessions.hpp" +#include "session/svc_sessions.hpp" namespace libcyphal { @@ -70,13 +71,13 @@ class ITransport : public IRunnable /// /// @return Optional integer representing the local node-ID. /// - virtual cetl::optional getLocalNodeId() const noexcept = 0; + CETL_NODISCARD virtual cetl::optional getLocalNodeId() const noexcept = 0; /// @brief Provides information about the properties of the transport protocol implemented by the instance. /// /// @return `ProtocolParameters` object if the transport is initialized, otherwise ResultCode::UninitializedError. /// - virtual ProtocolParams getProtocolParams() const noexcept = 0; + CETL_NODISCARD virtual ProtocolParams getProtocolParams() const noexcept = 0; }; // ITransport diff --git a/include/libcyphal/types.hpp b/include/libcyphal/types.hpp index 55e913f85..0a35f5dc9 100644 --- a/include/libcyphal/types.hpp +++ b/include/libcyphal/types.hpp @@ -25,6 +25,15 @@ namespace libcyphal /// using NodeId = std::uint16_t; +/// @brief `PortId` is a 16-bit unsigned integer that represents a port (subject & service) in a Cyphal network. +/// +using PortId = std::uint16_t; + +/// @brief `TransferId` is a 64-bit unsigned integer that represents a service transfer (request & response) +/// in a Cyphal network. +/// +using TransferId = std::uint64_t; + /// @brief The internal time representation is in microseconds. /// /// This is in line with the lizards that use `uint64_t`-typed microsecond counters throughout. From d45347f0ae858d56060b8b66fd889c202b9620a7 Mon Sep 17 00:00:00 2001 From: Sergei Shirokov Date: Thu, 4 Apr 2024 11:37:17 +0300 Subject: [PATCH 13/17] Add hash tag triggering by #verification #docs tags --- .github/workflows/tests.yml | 19 +++++++++++-------- CONTRIBUTING.md | 22 ++++++++++++++++++++++ 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 9ec0da44e..85fea603a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,18 +1,11 @@ name: "libcyphal_test" on: - push: - branches: - - main - - 'issue/*' - # todo: temp - remove this later! - - 'sshirokov/CI_*' + push: # Further filtering is done in the jobs. pull_request: branches: - main - 'issue/*' - # todo: temp - remove this later! - - 'sshirokov/CI_*' # To test use https://github.com/nektos/act and specify the event as "act" # For example: @@ -52,6 +45,11 @@ jobs: --build-flavor Debug clean-configure verification: + if: > + contains(github.event.head_commit.message, '#verification') || + contains(github.ref, '/main') || + contains(github.ref, '/issue/') || + (github.event_name == 'pull_request') runs-on: ubuntu-latest container: ghcr.io/opencyphal/toolshed:ts22.4.3 needs: [warmup] @@ -85,6 +83,11 @@ jobs: --toolchain ${{ matrix.toolchain }} clean-release docs: + if: > + contains(github.event.head_commit.message, '#docs') || + contains(github.ref, '/main') || + contains(github.ref, '/issue/') || + (github.event_name == 'pull_request') runs-on: ubuntu-latest container: ghcr.io/opencyphal/toolshed:ts22.4.3 needs: [warmup] diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0a571d0dc..6ef7368c9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -193,6 +193,28 @@ Reviewers, please check the following items when reviewing a pull-request: * Are the tests maintainable? * Is the code in the right namespace/class/function? +### Format the sources + +Clang-Format may format the sources differently depending on the version used. +To ensure that the formatting matches the expectations of the CI suite, +invoke Clang-Format of the correct version from the container (be sure to use the correct image tag): + +``` +docker run --rm -v ${PWD}:/repo ghcr.io/opencyphal/toolshed:ts22.4.3 ./build-tools/bin/verify.py build-danger-danger-repo-clang-format-in-place +``` + +### `issue/*` and hashtag-based CI triggering + +Normally, the CI will only run on pull requests (PR), releases, and perhaps some other special occasions on `main` branch. +Often, however, you will want to run it on your branch before proposing the changes to ensure all checks are +green and test coverage is adequate - to do that: +- either target your PR to any `issue/NN_LABEL` branch, where `NN` is the issue number and `LABEL` is a small title giving context (like `issue/83_any`) +- or add a hashtag with the name of the workflow you need to run to the head commit; +for example, making a commit with a message like `Add feature such and such #verification #docs #sonar` +will force the CI to execute jobs named `verification`, `docs`, and `sonar`. + +Note that if the job you requested is dependent on other jobs that are not triggered, it will not run; +for example, if `sonar` requires `docs`, pushing a commit with `#sonar` alone will not make it run. ## CAN bus Physical Layer Notes From 9730ec748d90fc9f6d6aba08676d18ac01fc8690 Mon Sep 17 00:00:00 2001 From: Sergei Shirokov Date: Thu, 4 Apr 2024 11:39:58 +0300 Subject: [PATCH 14/17] Warmup should be also support hash tags like #docs --- .github/workflows/tests.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 85fea603a..7bcc1ccec 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -17,6 +17,12 @@ on: # before running act). jobs: warmup: + if: > + contains(github.event.head_commit.message, '#verification') || + contains(github.event.head_commit.message, '#docs') || + contains(github.ref, '/main') || + contains(github.ref, '/issue/') || + (github.event_name == 'pull_request') runs-on: ubuntu-latest container: ghcr.io/opencyphal/toolshed:ts22.4.3 steps: From b669d8d0b603d8cdf7664c9bd12c0e9d363776ef Mon Sep 17 00:00:00 2001 From: Sergei Shirokov Date: Thu, 4 Apr 2024 13:21:13 +0300 Subject: [PATCH 15/17] strip repo absolute path prefix from doxygen file pathes #docs --- docs/CMakeLists.txt | 3 ++- docs/doxygen.ini | 2 +- include/libcyphal/runnable.hpp | 2 +- include/libcyphal/transport/session/msg_sessions.hpp | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index f472df504..d6ca46ceb 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -64,6 +64,7 @@ function (create_docs_target ARG_DOCS_DOXY_ROOT set(DOXYGEN_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) set(DOXYGEN_CONFIG_FILE ${DOXYGEN_OUTPUT_DIRECTORY}/doxygen.config) set(DOXYGEN_EXAMPLE_PATH ${ARG_EXAMPLES_PATH}) + set(DOXYGEN_STRIP_FROM_PATH ${ARG_DOCS_DOXY_ROOT}/../include/libcyphal) list(APPEND DOXYGEN_INPUT_LIST ${ARG_INPUT_LIST}) list(JOIN DOXYGEN_INPUT_LIST "\\\n " DOXYGEN_INPUT ) @@ -129,7 +130,7 @@ endfunction(create_docs_target) file(GLOB_RECURSE DOXYGEN_INPUT_LIST LIST_DIRECTORIES false CONFIGURE_DEPENDS - ${LIBCYPHAL_ROOT}/include/libcyphal/**/*.hpp + ${LIBCYPHAL_ROOT}/include/**/*.hpp ) get_property(LOCAL_EXAMPLES DIRECTORY "examples" PROPERTY IN_BUILD_TESTS) diff --git a/docs/doxygen.ini b/docs/doxygen.ini index 4e8e799b5..814093a88 100644 --- a/docs/doxygen.ini +++ b/docs/doxygen.ini @@ -184,7 +184,7 @@ FULL_PATH_NAMES = YES # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. -STRIP_FROM_PATH = +STRIP_FROM_PATH = @DOXYGEN_STRIP_FROM_PATH@ # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which diff --git a/include/libcyphal/runnable.hpp b/include/libcyphal/runnable.hpp index a84448908..3a780b347 100644 --- a/include/libcyphal/runnable.hpp +++ b/include/libcyphal/runnable.hpp @@ -9,7 +9,7 @@ #ifndef LIBCYPHAL_RUNNABLE_HPP_INCLUDED #define LIBCYPHAL_RUNNABLE_HPP_INCLUDED -#include "libcyphal/types.hpp" +#include "types.hpp" namespace libcyphal { diff --git a/include/libcyphal/transport/session/msg_sessions.hpp b/include/libcyphal/transport/session/msg_sessions.hpp index 4b8518d5e..8b20c26dd 100644 --- a/include/libcyphal/transport/session/msg_sessions.hpp +++ b/include/libcyphal/transport/session/msg_sessions.hpp @@ -1,5 +1,5 @@ /// @file -/// Defines the Session interface for Transport Layer implementations. +/// Defines the Message Session interfaces for Transport Layer implementations. /// /// @copyright /// Copyright (C) OpenCyphal Development Team From 51a8f1bd21d6d3349f555c43f1e5fc81c20c2ed9 Mon Sep 17 00:00:00 2001 From: Sergei Shirokov Date: Thu, 4 Apr 2024 19:01:07 +0300 Subject: [PATCH 16/17] pr fixes --- include/libcyphal/runnable.hpp | 15 +---- include/libcyphal/transport/defines.hpp | 40 ++++++++++++ .../transport/session/msg_sessions.hpp | 32 +++------- .../libcyphal/transport/session/session.hpp | 16 ++--- .../transport/session/svc_sessions.hpp | 59 +++++------------ include/libcyphal/transport/transport.hpp | 63 +------------------ include/libcyphal/types.hpp | 25 +------- 7 files changed, 76 insertions(+), 174 deletions(-) create mode 100644 include/libcyphal/transport/defines.hpp diff --git a/include/libcyphal/runnable.hpp b/include/libcyphal/runnable.hpp index 3a780b347..ca0d6cded 100644 --- a/include/libcyphal/runnable.hpp +++ b/include/libcyphal/runnable.hpp @@ -1,6 +1,3 @@ -/// @file -/// libcyphal common header. -/// /// @copyright /// Copyright (C) OpenCyphal Development Team /// Copyright Amazon.com Inc. or its affiliates. @@ -14,24 +11,14 @@ namespace libcyphal { -/// @brief Declares an abstract Cyphal runnable interface. -/// -/// Runnable objects do work asynchronously but only when `run()` is called. -/// This allows super-loop firmware to separate execution into application work and library work, -/// and for threaded software applications to service the library from dedicated threads. -/// Each object that implements `IRunnable` shall document how when it must be run to achieve certain functionality and -/// timing guarantees. -/// class IRunnable { public: - /// @brief Runs the runnable object. virtual void run(TimePoint now) = 0; protected: virtual ~IRunnable() = default; - -}; // IRunnable +}; } // namespace libcyphal diff --git a/include/libcyphal/transport/defines.hpp b/include/libcyphal/transport/defines.hpp new file mode 100644 index 000000000..a2407afc2 --- /dev/null +++ b/include/libcyphal/transport/defines.hpp @@ -0,0 +1,40 @@ +/// @copyright +/// Copyright (C) OpenCyphal Development Team +/// Copyright Amazon.com Inc. or its affiliates. +/// SPDX-License-Identifier: MIT + +#ifndef LIBCYPHAL_TRANSPORT_DEFINES_HPP_INCLUDED +#define LIBCYPHAL_TRANSPORT_DEFINES_HPP_INCLUDED + +namespace libcyphal +{ +namespace transport +{ + +/// @brief `NodeId` is a 16-bit unsigned integer that represents a node in a Cyphal network. +/// +/// Anonymity is represented by an empty `cetl::optional` (see `cetl::nullopt`). +/// +using NodeId = std::uint16_t; + +/// @brief `PortId` is a 16-bit unsigned integer that represents a port (subject & service) in a Cyphal network. +/// +using PortId = std::uint16_t; + +/// @brief `TransferId` is a 64-bit unsigned integer that represents a service transfer (request & response) +/// in a Cyphal network. +/// +using TransferId = std::uint64_t; + +struct ProtocolParams final +{ + NodeId max_nodes; + std::size_t mtu_bytes; + std::uint64_t transfer_id_modulo; + +}; // ProtocolParams + +} // namespace transport +} // namespace libcyphal + +#endif // LIBCYPHAL_TRANSPORT_DEFINES_HPP_INCLUDED diff --git a/include/libcyphal/transport/session/msg_sessions.hpp b/include/libcyphal/transport/session/msg_sessions.hpp index 8b20c26dd..20ade748b 100644 --- a/include/libcyphal/transport/session/msg_sessions.hpp +++ b/include/libcyphal/transport/session/msg_sessions.hpp @@ -1,6 +1,3 @@ -/// @file -/// Defines the Message Session interfaces for Transport Layer implementations. -/// /// @copyright /// Copyright (C) OpenCyphal Development Team /// Copyright Amazon.com Inc. or its affiliates. @@ -15,44 +12,31 @@ namespace libcyphal { namespace transport { -inline namespace session +namespace session { -/// @brief Declares message RX session parameters. -/// struct MessageRxParams final { - PortId subject_id; std::size_t extent_bytes; + PortId subject_id; +}; -}; // MessageRxParams - -/// @brief Declares message TX session parameters. -/// struct MessageTxParams final { PortId subject_id; +}; -}; // MessageTxParams - -/// @brief Declares an abstract Cyphal transport message RX session interface. -/// -class IMessageRxSession : public IRunnable +class IMessageRxSession : public IRxSession { public: - CETL_NODISCARD virtual MessageRxParams getParams() const noexcept = 0; - virtual void setTransferIdTimeout(Duration timeout) = 0; - -}; // IMessageRxSession + CETL_NODISCARD virtual MessageRxParams getParams() const noexcept = 0; +}; -/// @brief Declares an abstract Cyphal transport message TX session interface. -/// class IMessageTxSession : public IRunnable { public: CETL_NODISCARD virtual MessageTxParams getParams() const noexcept = 0; - -}; // IMessageTxSession +}; } // namespace session } // namespace transport diff --git a/include/libcyphal/transport/session/session.hpp b/include/libcyphal/transport/session/session.hpp index 365f4c258..7e792bd85 100644 --- a/include/libcyphal/transport/session/session.hpp +++ b/include/libcyphal/transport/session/session.hpp @@ -1,6 +1,3 @@ -/// @file -/// Defines the Session interface for Transport Layer implementations. -/// /// @copyright /// Copyright (C) OpenCyphal Development Team /// Copyright Amazon.com Inc. or its affiliates. @@ -10,20 +7,25 @@ #define LIBCYPHAL_TRANSPORT_SESSION_SESSION_HPP_INCLUDED #include "libcyphal/runnable.hpp" +#include "libcyphal/transport/defines.hpp" namespace libcyphal { namespace transport { -inline namespace session +namespace session { -/// @brief Declares an abstract Cyphal transport session interface. -/// class ISession : public IRunnable { public: -}; // ISession +}; + +class IRxSession : public ISession +{ +public: + virtual void setTransferIdTimeout(const Duration timeout) = 0; +}; } // namespace session } // namespace transport diff --git a/include/libcyphal/transport/session/svc_sessions.hpp b/include/libcyphal/transport/session/svc_sessions.hpp index 485fc0271..75f68dfc9 100644 --- a/include/libcyphal/transport/session/svc_sessions.hpp +++ b/include/libcyphal/transport/session/svc_sessions.hpp @@ -1,6 +1,3 @@ -/// @file -/// Defines the Service Session interfaces for Transport Layer implementations. -/// /// @copyright /// Copyright (C) OpenCyphal Development Team /// Copyright Amazon.com Inc. or its affiliates. @@ -15,82 +12,56 @@ namespace libcyphal { namespace transport { -inline namespace session +namespace session { -/// @brief Declares service request RX session parameters. -/// struct RequestRxParams final { - PortId service_id; std::size_t extent_bytes; + PortId service_id; +}; -}; // RequestRxParams - -/// @brief Declares service request TX session parameters. -/// struct RequestTxParams final { PortId service_id; NodeId server_node_id; +}; -}; // RequestTxParams - -/// @brief Declares service response RX session parameters. -/// struct ResponseRxParams final { + std::size_t extent_bytes; PortId service_id; NodeId server_node_id; - std::size_t extent_bytes; +}; -}; // ResponseRxParams - -/// @brief Declares service response TX session parameters. -/// struct ResponseTxParams final { PortId service_id; +}; -}; // ResponseTxParams - -/// @brief Declares an abstract Cyphal transport request RX session interface. -/// -class IRequestRxSession : public ISession +class IRequestRxSession : public IRxSession { public: - CETL_NODISCARD virtual RequestRxParams getParams() const noexcept = 0; - virtual void setTransferIdTimeout(Duration timeout) = 0; - -}; // IRequestRxSession + CETL_NODISCARD virtual RequestRxParams getParams() const noexcept = 0; +}; -/// @brief Declares an abstract Cyphal transport request TX session interface. -/// class IRequestTxSession : public ISession { public: CETL_NODISCARD virtual RequestTxParams getParams() const noexcept = 0; +}; -}; // IRequestTxSession - -/// @brief Declares an abstract Cyphal transport response RX session interface. -/// -class IResponseRxSession : public ISession +class IResponseRxSession : public IRxSession { public: - CETL_NODISCARD virtual ResponseRxParams getParams() const noexcept = 0; - virtual void setTransferIdTimeout(Duration timeout) = 0; - -}; // IResponseRxSession + CETL_NODISCARD virtual ResponseRxParams getParams() const noexcept = 0; +}; -/// @brief Declares an abstract Cyphal transport response TX session interface. -/// class IResponseTxSession : public ISession { public: CETL_NODISCARD virtual ResponseTxParams getParams() const noexcept = 0; - -}; // IResponseTxSession +}; } // namespace session } // namespace transport diff --git a/include/libcyphal/transport/transport.hpp b/include/libcyphal/transport/transport.hpp index 02fe59758..44f639eb7 100644 --- a/include/libcyphal/transport/transport.hpp +++ b/include/libcyphal/transport/transport.hpp @@ -1,6 +1,3 @@ -/// @file -/// Defines the Transport interface for Transport Layer implementations. -/// /// @copyright /// Copyright (C) OpenCyphal Development Team /// Copyright Amazon.com Inc. or its affiliates. @@ -17,67 +14,11 @@ namespace libcyphal namespace transport { -/// @brief Declares basic transport capabilities. -/// -/// These parameters are defined by the underlying transport specifications. -/// -/// Normally, the values should never change for a particular transport instance. -/// This is not a hard guarantee, however. -/// For example, a redundant transport aggregator may return a different set of parameters after -/// the set of aggregated transports is changed (i.e., a transport is added or removed). -/// -struct ProtocolParams final -{ - /// @brief The cardinality of the set of distinct transfer-ID values; i.e., the overflow period. - /// - /// All high-overhead transports (UDP, Serial, etc.) use a sufficiently large value that will never overflow - /// in a realistic, practical scenario. - /// The background and motivation are explained at - /// https://forum.opencyphal.org/t/alternative-transport-protocols/324. - /// Example: 32 for CAN, (2**64) for UDP. - /// - std::uint64_t transfer_id_modulo; - - /// @brief How many nodes can the transport accommodate in a given network. - /// - /// Example: 128 for CAN, 65535 for UDP (0xFFFF is reserved). - /// - NodeId max_nodes; - - /// @brief The largest maximum number of payload bytes in a single-frame transfer - /// for the group of network interfaces used by the transport. - /// - /// This number can change on systems where the value is configurable. - /// - std::size_t mtu_bytes; - -}; // ProtocolParams - -/// @brief Declares an abstract Cyphal transport interface. -/// class ITransport : public IRunnable { public: - /// @brief Gets (optional) local node-ID assigned to this transport. - /// - /// The node-ID is set once during initialization of the transport, - /// either explicitly (e.g., CAN) or by deriving the node-ID value from the configuration - /// of the underlying protocol layers (e.g., UDP/IP). - /// - /// If the transport does not have a node-ID, this property has the value of `cetl::nullopt`. - /// and the transport (and the node that uses it) is said to be in the anonymous mode. - /// While in the anonymous mode, some transports may choose to operate in a particular regime to facilitate - /// plug-and-play node-ID allocation (for example, a CAN transport may disable automatic retransmission). - /// - /// @return Optional integer representing the local node-ID. - /// - CETL_NODISCARD virtual cetl::optional getLocalNodeId() const noexcept = 0; - - /// @brief Provides information about the properties of the transport protocol implemented by the instance. - /// - /// @return `ProtocolParameters` object if the transport is initialized, otherwise ResultCode::UninitializedError. - /// - CETL_NODISCARD virtual ProtocolParams getProtocolParams() const noexcept = 0; + CETL_NODISCARD virtual cetl::optional getLocalNodeId() const noexcept = 0; + CETL_NODISCARD virtual ProtocolParams getProtocolParams() const noexcept = 0; }; // ITransport diff --git a/include/libcyphal/types.hpp b/include/libcyphal/types.hpp index 0a35f5dc9..067101fcc 100644 --- a/include/libcyphal/types.hpp +++ b/include/libcyphal/types.hpp @@ -1,6 +1,3 @@ -/// @file -/// libcyphal common types. -/// /// @copyright /// Copyright (C) OpenCyphal Development Team /// Copyright Amazon.com Inc. or its affiliates. @@ -19,21 +16,6 @@ namespace libcyphal { -/// @brief `NodeId` is a 16-bit unsigned integer that represents a node in a Cyphal network. -/// -/// Anonymity is represented by an empty `cetl::optional` (see `cetl::nullopt`). -/// -using NodeId = std::uint16_t; - -/// @brief `PortId` is a 16-bit unsigned integer that represents a port (subject & service) in a Cyphal network. -/// -using PortId = std::uint16_t; - -/// @brief `TransferId` is a 64-bit unsigned integer that represents a service transfer (request & response) -/// in a Cyphal network. -/// -using TransferId = std::uint64_t; - /// @brief The internal time representation is in microseconds. /// /// This is in line with the lizards that use `uint64_t`-typed microsecond counters throughout. @@ -62,13 +44,8 @@ struct MonotonicClock final }; // MonotonicClock -/// @brief Defines libcyphal time point type. -/// using TimePoint = MonotonicClock::time_point; - -/// @brief Defines libcyphal time duration type. -/// -using Duration = MonotonicClock::duration; +using Duration = MonotonicClock::duration; } // namespace libcyphal From e164d475cb1a6e0a535020aef0f6a7f7acf3ae26 Mon Sep 17 00:00:00 2001 From: Sergei Shirokov Date: Thu, 4 Apr 2024 19:08:36 +0300 Subject: [PATCH 17/17] minor fix --- include/libcyphal/runnable.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/libcyphal/runnable.hpp b/include/libcyphal/runnable.hpp index ca0d6cded..15281627f 100644 --- a/include/libcyphal/runnable.hpp +++ b/include/libcyphal/runnable.hpp @@ -14,7 +14,7 @@ namespace libcyphal class IRunnable { public: - virtual void run(TimePoint now) = 0; + virtual void run(const TimePoint now) = 0; protected: virtual ~IRunnable() = default;