├── .doxygen ├── LICENSE.doxygen-awesome ├── doxygen-awesome-darkmode-toggle.js ├── doxygen-awesome-sidebar-only-darkmode-toggle.css ├── doxygen-awesome-sidebar-only.css └── doxygen-awesome.css ├── .github └── workflows │ └── main.yml ├── .gitignore ├── CMakeLists.txt ├── Doxyfile ├── LICENSE ├── README.md ├── include ├── zpp.hpp └── zpp │ ├── atomic_bitset.hpp │ ├── atomic_var.hpp │ ├── clock.hpp │ ├── condition_variable.hpp │ ├── error_code.hpp │ ├── fifo.hpp │ ├── fmt.hpp │ ├── futex.hpp │ ├── heap.hpp │ ├── lock_guard.hpp │ ├── mem_slab.hpp │ ├── memory.hpp │ ├── mutex.hpp │ ├── poll.hpp │ ├── poll_event.hpp │ ├── poll_event_set.hpp │ ├── poll_signal.hpp │ ├── result.hpp │ ├── sched.hpp │ ├── sem.hpp │ ├── sys_mutex.hpp │ ├── thread.hpp │ ├── thread_attr.hpp │ ├── thread_data.hpp │ ├── thread_id.hpp │ ├── thread_prio.hpp │ ├── thread_stack.hpp │ ├── timer.hpp │ ├── unique_lock.hpp │ └── utils.hpp ├── samples ├── hello_world │ ├── CMakeLists.txt │ ├── README.md │ ├── hello_world.yaml │ ├── prj.conf │ └── src │ │ └── main.cpp └── kernel │ └── condition_variables │ ├── condvar │ ├── CMakeLists.txt │ ├── prj.conf │ ├── sample.yaml │ └── src │ │ └── main.cpp │ └── simple │ ├── CMakeLists.txt │ ├── prj.conf │ ├── sample.yaml │ └── src │ └── main.cpp ├── tests ├── atomic │ ├── CMakeLists.txt │ ├── prj.conf │ ├── src │ │ └── main.cpp │ └── testcase.yaml ├── clock │ ├── CMakeLists.txt │ ├── prj.conf │ ├── src │ │ └── main.cpp │ └── testcase.yaml ├── compile │ ├── CMakeLists.txt │ ├── prj.conf │ ├── src │ │ └── main.cpp │ └── testcase.yaml ├── condition_variable │ ├── CMakeLists.txt │ ├── prj.conf │ ├── src │ │ └── main.cpp │ └── testcase.yaml ├── fifo │ ├── CMakeLists.txt │ ├── prj.conf │ ├── src │ │ └── main.cpp │ └── testcase.yaml ├── heap │ ├── CMakeLists.txt │ ├── prj.conf │ ├── src │ │ └── main.cpp │ └── testcase.yaml ├── mem_slab │ ├── CMakeLists.txt │ ├── prj.conf │ ├── src │ │ └── main.cpp │ └── testcase.yaml ├── mutex │ ├── CMakeLists.txt │ ├── prj.conf │ ├── src │ │ └── main.cpp │ └── testcase.yaml ├── poll │ ├── CMakeLists.txt │ ├── prj.conf │ ├── src │ │ └── main.cpp │ └── testcase.yaml ├── print │ ├── CMakeLists.txt │ ├── prj.conf │ ├── src │ │ └── main.cpp │ └── testcase.yaml ├── result │ ├── CMakeLists.txt │ ├── prj.conf │ ├── src │ │ └── main.cpp │ └── testcase.yaml ├── sem │ ├── CMakeLists.txt │ ├── prj.conf │ ├── src │ │ └── main.cpp │ └── testcase.yaml ├── thread │ ├── CMakeLists.txt │ ├── prj.conf │ ├── src │ │ └── main.cpp │ └── testcase.yaml └── timer │ ├── CMakeLists.txt │ ├── prj.conf │ ├── src │ └── main.cpp │ └── testcase.yaml └── zephyr └── module.yml /.doxygen/LICENSE.doxygen-awesome: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 jothepro 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.doxygen/doxygen-awesome-darkmode-toggle.js: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | Doxygen Awesome 4 | https://github.com/jothepro/doxygen-awesome-css 5 | 6 | MIT License 7 | 8 | Copyright (c) 2021 jothepro 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in all 18 | copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | SOFTWARE. 27 | 28 | */ 29 | 30 | class DoxygenAwesomeDarkModeToggle extends HTMLElement { 31 | static prefersLightModeInDarkModeKey = "prefers-light-mode-in-dark-mode" 32 | static prefersDarkModeInLightModeKey = "prefers-dark-mode-in-light-mode" 33 | 34 | static _staticConstructor = function() { 35 | DoxygenAwesomeDarkModeToggle.darkModeEnabled = DoxygenAwesomeDarkModeToggle.userPreference 36 | DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.darkModeEnabled) 37 | // Update the color scheme when the browsers preference changes 38 | // without user interaction on the website. 39 | window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => { 40 | DoxygenAwesomeDarkModeToggle.onSystemPreferenceChanged() 41 | }) 42 | // Update the color scheme when the tab is made visible again. 43 | // It is possible that the appearance was changed in another tab 44 | // while this tab was in the background. 45 | document.addEventListener("visibilitychange", visibilityState => { 46 | if (document.visibilityState === 'visible') { 47 | DoxygenAwesomeDarkModeToggle.onSystemPreferenceChanged() 48 | } 49 | }); 50 | }() 51 | 52 | constructor() { 53 | super(); 54 | this.onclick=this.toggleDarkMode 55 | } 56 | 57 | /** 58 | * @returns `true` for dark-mode, `false` for light-mode system preference 59 | */ 60 | static get systemPreference() { 61 | return window.matchMedia('(prefers-color-scheme: dark)').matches 62 | } 63 | 64 | /** 65 | * @returns `true` for dark-mode, `false` for light-mode user preference 66 | */ 67 | static get userPreference() { 68 | return (!DoxygenAwesomeDarkModeToggle.systemPreference && localStorage.getItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey)) || 69 | (DoxygenAwesomeDarkModeToggle.systemPreference && !localStorage.getItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey)) 70 | } 71 | 72 | static set userPreference(userPreference) { 73 | DoxygenAwesomeDarkModeToggle.darkModeEnabled = userPreference 74 | if(!userPreference) { 75 | if(DoxygenAwesomeDarkModeToggle.systemPreference) { 76 | localStorage.setItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey, true) 77 | } else { 78 | localStorage.removeItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey) 79 | } 80 | } else { 81 | if(!DoxygenAwesomeDarkModeToggle.systemPreference) { 82 | localStorage.setItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey, true) 83 | } else { 84 | localStorage.removeItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey) 85 | } 86 | } 87 | DoxygenAwesomeDarkModeToggle.onUserPreferenceChanged() 88 | } 89 | 90 | static enableDarkMode(enable) { 91 | let head = document.getElementsByTagName('head')[0] 92 | if(enable) { 93 | document.documentElement.classList.add("dark-mode") 94 | document.documentElement.classList.remove("light-mode") 95 | } else { 96 | document.documentElement.classList.remove("dark-mode") 97 | document.documentElement.classList.add("light-mode") 98 | } 99 | } 100 | 101 | static onSystemPreferenceChanged() { 102 | DoxygenAwesomeDarkModeToggle.darkModeEnabled = DoxygenAwesomeDarkModeToggle.userPreference 103 | DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.darkModeEnabled) 104 | } 105 | 106 | static onUserPreferenceChanged() { 107 | DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.darkModeEnabled) 108 | } 109 | 110 | toggleDarkMode() { 111 | DoxygenAwesomeDarkModeToggle.userPreference = !DoxygenAwesomeDarkModeToggle.userPreference 112 | } 113 | } 114 | 115 | customElements.define("doxygen-awesome-dark-mode-toggle", DoxygenAwesomeDarkModeToggle); 116 | -------------------------------------------------------------------------------- /.doxygen/doxygen-awesome-sidebar-only-darkmode-toggle.css: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | 4 | Doxygen Awesome 5 | https://github.com/jothepro/doxygen-awesome-css 6 | 7 | MIT License 8 | 9 | Copyright (c) 2021 jothepro 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in all 19 | copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | SOFTWARE. 28 | 29 | */ 30 | 31 | @media screen and (min-width: 768px) { 32 | 33 | #MSearchBox { 34 | width: calc(var(--side-nav-fixed-width) - calc(2 * var(--spacing-medium)) - var(--searchbar-height) - 1px); 35 | } 36 | 37 | #MSearchField { 38 | width: calc(var(--side-nav-fixed-width) - calc(2 * var(--spacing-medium)) - 66px - var(--searchbar-height)); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /.doxygen/doxygen-awesome-sidebar-only.css: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | Doxygen Awesome 4 | https://github.com/jothepro/doxygen-awesome-css 5 | 6 | MIT License 7 | 8 | Copyright (c) 2021 jothepro 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in all 18 | copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | SOFTWARE. 27 | 28 | */ 29 | 30 | html { 31 | /* side nav width. MUST be = `TREEVIEW_WIDTH`. 32 | * Make sure it is wide enought to contain the page title (logo + title + version) 33 | */ 34 | --side-nav-fixed-width: 340px; 35 | --menu-display: none; 36 | 37 | --top-height: 120px; 38 | } 39 | 40 | 41 | @media screen and (min-width: 768px) { 42 | html { 43 | --searchbar-background: var(--page-background-color); 44 | } 45 | 46 | #side-nav { 47 | min-width: var(--side-nav-fixed-width); 48 | max-width: var(--side-nav-fixed-width); 49 | top: var(--top-height); 50 | } 51 | 52 | #nav-tree, #side-nav { 53 | height: calc(100vh - var(--top-height)) !important; 54 | } 55 | 56 | #nav-tree { 57 | padding: 0; 58 | } 59 | 60 | #top { 61 | display: block; 62 | border-bottom: none; 63 | height: var(--top-height); 64 | margin-bottom: calc(0px - var(--top-height)); 65 | max-width: var(--side-nav-fixed-width); 66 | background: var(--side-nav-background); 67 | } 68 | #main-nav { 69 | float: left; 70 | padding-right: 0; 71 | } 72 | 73 | .ui-resizable-handle { 74 | cursor: default; 75 | width: 1px !important; 76 | box-shadow: 0 calc(-2 * var(--top-height)) 0 0 var(--separator-color); 77 | } 78 | 79 | #nav-path { 80 | position: fixed; 81 | right: 0; 82 | left: var(--side-nav-fixed-width); 83 | bottom: 0; 84 | width: auto; 85 | } 86 | 87 | #doc-content { 88 | height: calc(100vh - 31px) !important; 89 | padding-bottom: calc(3 * var(--spacing-large)); 90 | padding-top: calc(var(--top-height) - 80px); 91 | box-sizing: border-box; 92 | margin-left: var(--side-nav-fixed-width) !important; 93 | } 94 | 95 | #MSearchBox { 96 | width: calc(var(--side-nav-fixed-width) - calc(2 * var(--spacing-medium))); 97 | } 98 | 99 | #MSearchField { 100 | width: calc(var(--side-nav-fixed-width) - calc(2 * var(--spacing-medium)) - 65px); 101 | } 102 | 103 | #MSearchResultsWindow { 104 | left: var(--spacing-medium) !important; 105 | right: auto; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Doxygen Documentation 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build-doxygen-documentation: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v2 15 | 16 | - name: Doxygen Action 17 | uses: mattnotmitt/doxygen-action@v1.3.1 18 | with: 19 | doxyfile-path: ./Doxyfile 20 | working-directory: . 21 | 22 | - name: GH Pages Deployment 23 | uses: peaceiris/actions-gh-pages@v3 24 | with: 25 | github_token: ${{ secrets.GITHUB_TOKEN }} 26 | publish_dir: ./doc/html/ 27 | enable_jekyll: false 28 | allow_empty_commit: false 29 | force_orphan: true 30 | publish_branch: gh-pages 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | doc/ 2 | 3 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # ZPP is a header only library, so the only thing we do here is 3 | # making sure the user can do #include 4 | # 5 | zephyr_include_directories(include) 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Zephyr C++20 Framework - ZPP 2 | 3 | First, it is not the intention of ZPP to implement a `std::` library for 4 | Zephyr. ZPP tries to wrap the Zephyr C-API in C++20 without causing to 5 | much runtime and/or memory overhead. 6 | 7 | The current state of ZPP is experimental/early alpha, things are still changing 8 | a lot, and the API is not stable what so ever. 9 | 10 | To add zpp to your own project just add the git repo to your west.yml manifest 11 | file like this; 12 | 13 | ``` 14 | manifest: 15 | projects: 16 | - name: zpp 17 | remote: https://github.com/lowlander 18 | revision: master 19 | path: modules/zpp 20 | ``` 21 | 22 | If you just want to test it the 23 | repository has some scripts that already have a west setup for more easy testing 24 | 25 | ## Usage 26 | 27 | Everything of ZPP is placed in the `zpp::` namespace. All header files are 28 | in the `zpp/` subdirectory and have a `.hpp` extension, so they can be 29 | included as follows `#include ` 30 | 31 | 32 | ## Doxygen Documentation 33 | 34 | The automatically generated Doxygen API documentation can be found on 35 | github 36 | 37 | ## Source Code 38 | 39 | The source code repository can be found on github 40 | -------------------------------------------------------------------------------- /include/zpp.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019 Erwin Rol 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | 7 | #ifndef ZPP_INCLUDE_ZPP_HPP 8 | #define ZPP_INCLUDE_ZPP_HPP 9 | 10 | #ifndef __cplusplus 11 | #error "ZPP is a C++ only library" 12 | #else 13 | #if __cplusplus < 201709L 14 | #error "ZPP needs C++20 or newer" 15 | #endif 16 | #endif 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | #endif // ZPP_INCLUDE_ZPP_HPP 42 | -------------------------------------------------------------------------------- /include/zpp/atomic_bitset.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019 Erwin Rol 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | 7 | #ifndef ZPP_INCLUDE_ZPP_ATOMIC_BITSET_HPP 8 | #define ZPP_INCLUDE_ZPP_ATOMIC_BITSET_HPP 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | namespace zpp { 16 | 17 | /// 18 | /// @brief class wrapping an atomic_var_t array 19 | /// 20 | /// @param BitsetSize the size of the bitset in bits 21 | /// 22 | template 23 | class atomic_bitset { 24 | public: 25 | /// 26 | /// @brief default constructor 27 | /// 28 | /// The default constructor initializes the atomic_bitset 29 | /// to all bits set to 0. 30 | /// 31 | constexpr atomic_bitset() noexcept = default; 32 | 33 | /// 34 | /// @brief return size of the bitset 35 | /// 36 | /// @return the size of the bitset in bits 37 | /// 38 | constexpr size_t bit_count() const noexcept 39 | { 40 | return T_BitsetSize; 41 | } 42 | 43 | /// 44 | /// @brief atomically get a bit from the bitset 45 | /// 46 | /// @param bit the index of the bit to return 47 | /// 48 | /// @return the requested bit value 49 | /// 50 | [[nodiscard]] bool load(size_t bit) const noexcept 51 | { 52 | __ASSERT_NO_MSG(bit < T_BitsetSize); 53 | return atomic_test_bit(m_var, bit); 54 | } 55 | 56 | /// 57 | /// @brief atomically set a bit a value 58 | /// 59 | /// @param bit the index of the bit to set 60 | /// @param val the value the bit should be set to 61 | /// 62 | void store(size_t bit, bool val) noexcept 63 | { 64 | __ASSERT_NO_MSG(bit < T_BitsetSize); 65 | atomic_set_bit_to(m_var, bit, val); 66 | } 67 | 68 | /// 69 | /// @brief atomically set a bit to true/1 70 | /// 71 | /// @param bit the index of the bit to set 72 | /// 73 | void set(size_t bit) noexcept 74 | { 75 | __ASSERT_NO_MSG(bit < T_BitsetSize); 76 | atomic_set_bit(m_var, bit); 77 | } 78 | 79 | /// 80 | /// @brief atomically set a bit to false/0 81 | /// 82 | /// @param bit the index of the bit to set 83 | /// 84 | void clear(size_t bit) noexcept 85 | { 86 | __ASSERT_NO_MSG(bit < T_BitsetSize); 87 | atomic_clear_bit(m_var, bit); 88 | } 89 | 90 | /// 91 | /// @brief atomically clear a bit while returning the previous value. 92 | /// 93 | /// @param bit the index of the bit to set 94 | /// 95 | /// @return the bit value before it was cleared 96 | /// 97 | [[nodiscard]] bool fetch_and_clear(size_t bit) noexcept 98 | { 99 | __ASSERT_NO_MSG(bit < T_BitsetSize); 100 | return atomic_test_and_clear_bit(m_var, bit); 101 | } 102 | 103 | /// 104 | /// @brief atomically set a bit while returning the previous value. 105 | /// 106 | /// @param bit the index of the bit to set 107 | /// 108 | /// @return the bit value before it was set 109 | /// 110 | [[nodiscard]] bool fetch_and_set(size_t bit) noexcept 111 | { 112 | __ASSERT_NO_MSG(bit < T_BitsetSize); 113 | return atomic_test_and_set_bit(m_var, bit); 114 | } 115 | private: 116 | ATOMIC_DEFINE(m_var, T_BitsetSize) {}; 117 | public: 118 | atomic_bitset(const atomic_bitset&) = delete; 119 | atomic_bitset(atomic_bitset&&) = delete; 120 | atomic_bitset& operator=(const atomic_bitset&) = delete; 121 | atomic_bitset& operator=(atomic_bitset&&) = delete; 122 | }; 123 | 124 | } // namespace zpp 125 | 126 | #endif // ZPP_INCLUDE_ZPP_ATOMIC_BITSET_HPP 127 | -------------------------------------------------------------------------------- /include/zpp/clock.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019 Erwin Rol 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | 7 | #ifndef ZPP_INCLUDE_ZPP_CLOCK_HPP 8 | #define ZPP_INCLUDE_ZPP_CLOCK_HPP 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | namespace zpp { 18 | 19 | /// 20 | /// @brief Clock measuring elapsed time since the system booted. 21 | /// 22 | class uptime_clock { 23 | public: 24 | using rep = int64_t; 25 | using period = std::nano; 26 | using duration = std::chrono::duration; 27 | using time_point = std::chrono::time_point; 28 | static constexpr bool is_steady = false; 29 | 30 | /// 31 | /// @brief Get current uptime. 32 | /// 33 | /// @return current uptime as time_point. 34 | /// 35 | static time_point now() noexcept 36 | { 37 | return time_point(duration(k_ticks_to_ns_floor64(k_uptime_ticks()))); 38 | } 39 | }; 40 | 41 | 42 | /// 43 | /// @brief Clock representing the system’s hardware clock. 44 | /// 45 | class cycle_clock { 46 | public: 47 | using rep = uint64_t; 48 | using period = std::nano; 49 | using duration = std::chrono::duration; 50 | using time_point = std::chrono::time_point; 51 | static constexpr bool is_steady = false; 52 | 53 | /// 54 | /// @brief Get current cycle count. 55 | /// 56 | /// @return current cycle count as time_point 57 | /// 58 | static time_point now() noexcept 59 | { 60 | return time_point(duration(k_cyc_to_ns_floor64(k_cycle_get_32()))); 61 | } 62 | }; 63 | 64 | /// 65 | /// @brief convert a duration to tick 66 | /// 67 | /// @param d the std::chrono::duration to convert 68 | /// 69 | /// @return the number of tick @a d represents 70 | /// 71 | template 72 | constexpr k_ticks_t to_tick(const std::chrono::duration& d) noexcept 73 | { 74 | using namespace std::chrono; 75 | 76 | return k_ns_to_ticks_floor64(duration_cast(d).count()); 77 | } 78 | 79 | 80 | /// 81 | /// @brief convert a duration to tick 82 | /// 83 | /// @param d the std::chrono::duration to convert 84 | /// 85 | /// @return the number of tick @a d represents 86 | /// 87 | template 88 | constexpr k_timeout_t to_timeout(const std::chrono::duration& d) noexcept 89 | { 90 | return { to_tick(d) }; 91 | } 92 | 93 | } // namespace zpp 94 | 95 | #endif // ZPP_INCLUDE_ZPP_CLOCK_HPP 96 | -------------------------------------------------------------------------------- /include/zpp/error_code.hpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (c) 2021 Erwin Rol 3 | /// 4 | /// SPDX-License-Identifier: Apache-2.0 5 | /// 6 | 7 | #ifndef ZPP_INCLUDE_ZPP_ERROR_CODE_HPP 8 | #define ZPP_INCLUDE_ZPP_ERROR_CODE_HPP 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace zpp { 15 | 16 | /// 17 | /// @brief enum with zephyr error codes 18 | /// 19 | enum class error_code { 20 | k_perm = EPERM, ///< Not owner 21 | k_noent = ENOENT, ///< No such file or directory 22 | k_srch = ESRCH, ///< No such context 23 | k_intr = EINTR, ///< Interrupted system call 24 | k_io = EIO, ///< I/O error 25 | k_nxio = ENXIO, ///< No such device or address 26 | k_2big = E2BIG, ///< Arg list too long 27 | k_noexec = ENOEXEC, ///< Exec format error 28 | k_badf = EBADF, ///< Bad file number 29 | k_child = ECHILD, ///< No children 30 | k_again = EAGAIN, ///< No more contexts 31 | k_nomem = ENOMEM, ///< Not enough core 32 | k_acces = EACCES, ///< Permission denied 33 | k_fault = EFAULT, ///< Bad address 34 | k_notblk = ENOTBLK, ///< Block device required 35 | k_busy = EBUSY, ///< Mount device busy 36 | k_exits = EEXIST, ///< File exists 37 | k_xdev = EXDEV, ///< Cross-device link 38 | k_nodev = ENODEV, ///< No such device 39 | k_notdir = ENOTDIR, ///< Not a directory 40 | k_isdir = EISDIR, ///< Is a directory 41 | k_inval = EINVAL, ///< Invalid argument 42 | k_nfile = ENFILE, ///< File table overflow 43 | k_mfile = EMFILE, ///< Too many open files 44 | k_notty = ENOTTY, ///< Not a typewriter 45 | k_txtbsy = ETXTBSY, ///< Text file busy 46 | k_fbig = EFBIG, ///< File too large 47 | k_nospc = ENOSPC, ///< No space left on device 48 | k_spipe = ESPIPE, ///< Illegal seek 49 | k_rofs = EROFS, ///< Read-only file system 50 | k_mlink = EMLINK, ///< Too many links 51 | k_pipe = EPIPE, ///< Broken pipe 52 | k_dom = EDOM, ///< Argument too large 53 | k_range = ERANGE, ///< Result too large 54 | k_nomsg = ENOMSG, ///< Unexpected message type 55 | k_deadlk = EDEADLK, ///< Resource deadlock avoided 56 | k_nolck = ENOLCK, ///< No locks available 57 | k_nostr = ENOSTR, ///< STREAMS device required 58 | k_nodata = ENODATA, ///< Missing expected message data 59 | k_time = ETIME, ///< STREAMS timeout occurred 60 | k_nosr = ENOSR, ///< Insufficient memory 61 | k_proto = EPROTO, ///< Generic STREAMS error 62 | k_badmsg = EBADMSG, ///< Invalid STREAMS message 63 | k_nosys = ENOSYS, ///< Function not implemented 64 | k_notempty = ENOTEMPTY, ///< Directory not empty 65 | k_nametoolong = ENAMETOOLONG, ///< File name too long 66 | k_loop = ELOOP, ///< Too many levels of symbolic links 67 | k_opnotsupp = EOPNOTSUPP, ///< Operation not supported on socket 68 | k_pfnosupport = EPFNOSUPPORT, ///< Protocol family not supported 69 | k_connreset = ECONNRESET, ///< Connection reset by peer 70 | k_nobufs = ENOBUFS, ///< No buffer space available 71 | k_afnosupport = EAFNOSUPPORT, ///< Addr family not supported 72 | k_prototype = EPROTOTYPE, ///< Protocol wrong type for socket 73 | k_notsock = ENOTSOCK, ///< Socket operation on non-socket 74 | k_noprotoopt = ENOPROTOOPT, ///< Protocol not available 75 | k_shutdown = ESHUTDOWN, ///< Can’t send after socket shutdown 76 | k_connrefused = ECONNREFUSED, ///< Connection refused 77 | k_addrinuse = EADDRINUSE, ///< Address already in use 78 | k_connaborted = ECONNABORTED, ///< Software caused connection abort 79 | k_netunreach = ENETUNREACH, ///< Network is unreachable 80 | k_netdown = ENETDOWN, ///< Network is down 81 | k_timeout = ETIMEDOUT, ///< Connection timed out 82 | k_hostdown = EHOSTDOWN, ///< Host is down 83 | k_hostunreach = EHOSTUNREACH, ///< No route to host 84 | k_inprogress = EINPROGRESS, ///< Operation now in progress 85 | k_already = EALREADY, ///< Operation already in progress 86 | k_destaddrreq = EDESTADDRREQ, ///< Destination address required 87 | k_msgsize = EMSGSIZE, ///< Message size 88 | k_protonosupport = EPROTONOSUPPORT, ///< Protocol not supported 89 | k_socktnosupport = ESOCKTNOSUPPORT, ///< Socket type not supported 90 | k_addrnotavail = EADDRNOTAVAIL, ///< Can’t assign requested address 91 | k_netreset = ENETRESET, ///< Network dropped connection on reset 92 | k_isconn = EISCONN, ///< Socket is already connected 93 | k_notconn = ENOTCONN, ///< Socket is not connected 94 | k_toomanyrefs = ETOOMANYREFS, ///< Too many references: can’t splice 95 | k_notsup = ENOTSUP, ///< Unsupported value 96 | k_ilseq = EILSEQ, ///< Illegal byte sequence 97 | k_overflow = EOVERFLOW, ///< Value overflow 98 | k_canceled = ECANCELED, ///< Operation canceled 99 | k_wouldblock = EWOULDBLOCK, ///< Operation would block 100 | }; 101 | 102 | constexpr error_code to_error_code(int v) noexcept 103 | { 104 | return static_cast(v); 105 | } 106 | 107 | static_assert(error_code::k_perm == to_error_code(EPERM)); 108 | static_assert(error_code::k_wouldblock == to_error_code(EWOULDBLOCK)); 109 | 110 | } // namespace zpp 111 | 112 | #endif // ZPP_INCLUDE_ZPP_ERROR_CODE_HPP 113 | -------------------------------------------------------------------------------- /include/zpp/fifo.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019 Erwin Rol 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | 7 | #ifndef ZPP_INCLUDE_ZPP_FIFO_HPP 8 | #define ZPP_INCLUDE_ZPP_FIFO_HPP 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | namespace zpp { 19 | 20 | /// 21 | /// @brief Fifo CRTP base class 22 | /// 23 | /// @param T_BaseFifoType the CRTP derived type 24 | /// @param T_BaseItemType the item to store in this fifo 25 | /// 26 | template typename T_BaseFifoType, typename T_BaseItemType> 27 | class fifo_base { 28 | public: 29 | using native_type = struct k_fifo; 30 | using native_pointer = native_type *; 31 | using native_const_pointer = native_type const *; 32 | 33 | using item_type = T_BaseItemType; 34 | using item_pointer = item_type*; 35 | using item_const_pointer = item_type const *; 36 | protected: 37 | /// 38 | /// @brief default constructor, can only be called from derived types 39 | /// 40 | fifo_base() noexcept 41 | { 42 | static_assert(std::is_standard_layout_v); 43 | static_assert(std::is_same_v); 44 | static_assert(offsetof(item_type, fifo_reserved) == 0); 45 | } 46 | public: 47 | /// 48 | /// @brief get the Zephyr native fifo handle 49 | /// 50 | /// @return pointer to a k_fifo 51 | /// 52 | [[nodiscard]] constexpr auto native_handle() noexcept -> native_pointer 53 | { 54 | return static_cast*>(this)->native_handle(); 55 | } 56 | 57 | /// 58 | /// @brief get the Zephyr native fifo handle 59 | /// 60 | /// @return pointer to a k_fifo 61 | /// 62 | [[nodiscard]] constexpr auto native_handle() const noexcept -> native_const_pointer 63 | { 64 | return static_cast*>(this)->native_handle(); 65 | } 66 | 67 | /// 68 | /// @brief force a waiting thread to return with a timeout error 69 | /// 70 | void cancel_wait() noexcept 71 | { 72 | k_fifo_cancel_wait(native_handle()); 73 | } 74 | 75 | /// 76 | /// @brief push an item on the back of the fifo 77 | /// 78 | /// @param item Pointer to a item, the fifo does not take ownership 79 | /// 80 | void push_back(item_pointer item) noexcept 81 | { 82 | k_fifo_put(native_handle(), item); 83 | } 84 | 85 | /// 86 | /// @brief pop item from fifo waiting for ever 87 | /// 88 | /// @return the item or nullptr on error 89 | /// 90 | [[nodiscard]] item_pointer 91 | pop_front() noexcept 92 | { 93 | return static_cast( 94 | k_fifo_get(native_handle(), K_FOREVER)); 95 | } 96 | 97 | /// 98 | /// @brief try to pop item from the fifo without waiting 99 | /// 100 | /// @return the item or nullptr on error/timeout 101 | /// 102 | [[nodiscard]] item_pointer 103 | try_pop_front() noexcept 104 | { 105 | return static_cast( 106 | k_fifo_get(native_handle(), K_NO_WAIT)); 107 | } 108 | 109 | /// 110 | /// @brief try to pop item from the fifo waiting a certain amount of time 111 | /// 112 | /// @param timeout The timeout before returning 113 | /// 114 | /// @return the item or nullptr on error/timeout 115 | /// 116 | template 117 | [[nodiscard]] item_pointer 118 | try_pop_front_for(const std::chrono::duration& timeout) noexcept 119 | { 120 | using namespace std::chrono; 121 | 122 | return static_cast( 123 | k_fifo_get(native_handle(), 124 | duration_cast(timeout).count())); 125 | } 126 | 127 | /// 128 | /// @brief get item at the front without removing it from the fifo 129 | /// 130 | /// @return the item or nullptr on error/timeout 131 | /// 132 | [[nodiscard]] item_pointer 133 | front() noexcept 134 | { 135 | return static_cast( 136 | k_fifo_peek_head(native_handle())); 137 | } 138 | 139 | /// 140 | /// @brief get item at the back without removing it from the fifo 141 | /// 142 | /// @return the item or nullptr on error/timeout 143 | /// 144 | [[nodiscard]] item_pointer back() noexcept 145 | { 146 | return static_cast( 147 | k_fifo_peek_tail(native_handle())); 148 | } 149 | 150 | /// 151 | /// @brief check if the fifo is empty 152 | /// 153 | /// @return true if the fifo is empty 154 | /// 155 | [[nodiscard]] bool empty() noexcept 156 | { 157 | auto res = k_fifo_is_empty(native_handle()); 158 | if (res == 0) { 159 | return false; 160 | } else { 161 | return true; 162 | } 163 | } 164 | public: 165 | fifo_base(const fifo_base&) = delete; 166 | fifo_base(fifo_base&&) = delete; 167 | fifo_base& operator=(const fifo_base&) = delete; 168 | fifo_base& operator=(fifo_base&&) = delete; 169 | }; 170 | 171 | /// 172 | /// @brief fifo that manages a k_fifo object 173 | /// 174 | template 175 | class fifo : public fifo_base { 176 | public: 177 | using typename fifo_base::native_type; 178 | using typename fifo_base::native_pointer; 179 | using typename fifo_base::native_const_pointer; 180 | public: 181 | /// 182 | /// @brief create new fifo 183 | /// 184 | fifo() noexcept 185 | { 186 | k_fifo_init(&m_fifo); 187 | } 188 | 189 | /// 190 | /// @brief get the Zephyr native fifo handle 191 | /// 192 | /// @return pointer to a k_fifo 193 | /// 194 | [[nodiscard]] constexpr auto native_handle() noexcept -> native_pointer 195 | { 196 | return &m_fifo; 197 | } 198 | 199 | /// 200 | /// @brief get the Zephyr native fifo handle 201 | /// 202 | /// @return pointer to a k_fifo 203 | /// 204 | [[nodiscard]] constexpr auto native_handle() const noexcept -> native_const_pointer 205 | { 206 | return &m_fifo; 207 | } 208 | private: 209 | native_type m_fifo; 210 | public: 211 | fifo(const fifo&) = delete; 212 | fifo(fifo&&) = delete; 213 | fifo& operator=(const fifo&) = delete; 214 | fifo& operator=(fifo&&) = delete; 215 | }; 216 | 217 | /// 218 | /// @brief fifo that references a k_fifo object 219 | /// 220 | template 221 | class fifo_ref : public fifo_base { 222 | public: 223 | using typename fifo_base::native_type; 224 | using typename fifo_base::native_pointer; 225 | using typename fifo_base::native_const_pointer; 226 | public: 227 | /// 228 | /// @brief wrap k_fifo 229 | /// 230 | /// @param f the k_fifo to reference 231 | /// 232 | /// @warning @a f must stay valid for the lifetime of this object 233 | /// 234 | constexpr explicit fifo_ref(native_pointer f) noexcept 235 | : m_fifo_ptr(f) 236 | { 237 | __ASSERT_NO_MSG(m_fifo_ptr != nullptr); 238 | } 239 | 240 | /// 241 | /// @brief Reference another fifo object 242 | /// 243 | /// @param f the object to reference 244 | /// 245 | /// @warning @a f must stay valid for the lifetime of this object 246 | /// 247 | template class T_Fifo> 248 | constexpr explicit fifo_ref(T_Fifo& f) noexcept 249 | : m_fifo_ptr(f.native_handle()) 250 | { 251 | __ASSERT_NO_MSG(m_fifo_ptr != nullptr); 252 | } 253 | 254 | /// 255 | /// @brief Reference another fifo object 256 | /// 257 | /// @param f the object to reference 258 | /// 259 | /// @return *this 260 | /// 261 | /// @warning @a f must stay valid for the lifetime of this object 262 | /// 263 | constexpr fifo_ref& operator=(native_pointer f) noexcept 264 | { 265 | m_fifo_ptr = f; 266 | __ASSERT_NO_MSG(m_fifo_ptr != nullptr); 267 | return *this; 268 | } 269 | 270 | /// 271 | /// @brief Reference another fifo object 272 | /// 273 | /// @param f the object to reference 274 | /// 275 | /// @return *this 276 | /// 277 | /// @warning @a f must stay valid for the lifetime of this object 278 | /// 279 | template class T_Fifo> 280 | constexpr fifo_ref& operator=(const T_Fifo& f) noexcept 281 | { 282 | m_fifo_ptr = f.native_handle(); 283 | __ASSERT_NO_MSG(m_fifo_ptr != nullptr); 284 | return *this; 285 | } 286 | 287 | /// 288 | /// @brief get the Zephyr native fifo handle 289 | /// 290 | /// @return pointer to a k_fifo 291 | /// 292 | [[nodiscard]] constexpr auto native_handle() noexcept -> native_pointer 293 | { 294 | return m_fifo_ptr; 295 | } 296 | 297 | /// 298 | /// @brief get the Zephyr native fifo handle 299 | /// 300 | /// @return pointer to a k_fifo 301 | /// 302 | [[nodiscard]] constexpr auto native_handle() const noexcept -> native_const_pointer 303 | { 304 | return m_fifo_ptr; 305 | } 306 | private: 307 | native_pointer m_fifo_ptr{ nullptr }; 308 | public: 309 | fifo_ref() = delete; 310 | }; 311 | 312 | } // namespace zpp 313 | 314 | #endif // ZPP_INCLUDE_ZPP_FIFO_HPP 315 | -------------------------------------------------------------------------------- /include/zpp/fmt.hpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (c) 2019 Erwin Rol 3 | /// 4 | /// SPDX-License-Identifier: Apache-2.0 5 | /// 6 | 7 | #ifndef ZPP_INCLUDE_ZPP_FMT_HPP 8 | #define ZPP_INCLUDE_ZPP_FMT_HPP 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | namespace zpp { 18 | 19 | namespace internal { 20 | 21 | inline void print_arg() noexcept { } 22 | inline void print_arg(bool v) noexcept { printk("%d", (int)v); } 23 | inline void print_arg(float v) noexcept { printk("%f", v); } 24 | inline void print_arg(double v) noexcept { printk("%g", v); } 25 | inline void print_arg(char v) noexcept { printk("%c", v); } 26 | inline void print_arg(const char* v) noexcept { printk("%s", v); } 27 | inline void print_arg(const void* v) noexcept { printk("%p", v); } 28 | inline void print_arg(uint8_t v) noexcept { printk("%d", (uint32_t)v); } 29 | inline void print_arg(int8_t v) noexcept { printk("%d", (int32_t)v); } 30 | inline void print_arg(uint16_t v) noexcept { printk("%d", (uint32_t)v); } 31 | inline void print_arg(int16_t v) noexcept { printk("%d", (int32_t)v); } 32 | inline void print_arg(uint32_t v) noexcept { printk("%d", v); } 33 | inline void print_arg(int32_t v) noexcept { printk("%d", v); } 34 | inline void print_arg(uint64_t v) noexcept { printk("%lld", v); } 35 | inline void print_arg(int64_t v) noexcept { printk("%lld", v); } 36 | 37 | template 38 | inline void print_arg(std::chrono::duration v) 39 | { 40 | using namespace std::chrono; 41 | 42 | auto s = duration_cast(v); 43 | v -= duration_cast(s); 44 | auto ms = duration_cast(v); 45 | v -= duration_cast(ms); 46 | auto us = duration_cast(v); 47 | v -= duration_cast(us); 48 | auto ns = duration_cast(v); 49 | 50 | printk("%d.%03d%03d%03ds", 51 | (int)s.count(), (int)ms.count(), 52 | (int)us.count(), (int)ns.count()); 53 | } 54 | 55 | template 56 | inline void print_arg(std::chrono::time_point v) 57 | { 58 | print_arg(v.time_since_epoch()); 59 | } 60 | 61 | inline void print_helper(const char* fmt) noexcept 62 | { 63 | printk("%s", fmt); 64 | } 65 | 66 | template 67 | inline void print_helper(const char* fmt, T_FirstArg&& first, T_Args&&... args) noexcept 68 | { 69 | enum class state { normal, format, open_brace, close_brace, done }; 70 | 71 | state s = state::normal; 72 | size_t n = 0; 73 | 74 | while (true) { 75 | char c = fmt[n++]; 76 | 77 | if (c == '\0') { 78 | return; 79 | } 80 | 81 | switch (s) { 82 | case state::normal: 83 | switch (c) { 84 | case '{': 85 | s = state::open_brace; 86 | break; 87 | case '}': 88 | s = state::close_brace; 89 | break; 90 | default: 91 | printk("%c", c); 92 | break; 93 | } 94 | break; 95 | 96 | case state::open_brace: 97 | switch(c) { 98 | case '{': 99 | s = state::normal; 100 | printk("{"); 101 | break; 102 | 103 | case '}': 104 | s = state::done; 105 | break; 106 | 107 | default: 108 | s = state::format; 109 | break; 110 | } 111 | break; 112 | 113 | case state::close_brace: 114 | if (c == '}') { 115 | printk("}"); 116 | } 117 | s = state::normal; 118 | break; 119 | 120 | case state::format: 121 | switch (c) { 122 | case '}': 123 | s = state::done; 124 | break; 125 | default: 126 | break; 127 | } 128 | break; 129 | 130 | case state::done: 131 | break; 132 | 133 | } 134 | 135 | if (s == state::done) { 136 | break; 137 | } 138 | } 139 | 140 | print_arg(std::forward(first)); 141 | print_helper(&(fmt[n]), std::forward(args)...); 142 | } 143 | 144 | } // namespace internal 145 | 146 | /// 147 | /// @brief simple typesafe print function 148 | /// 149 | /// print uses the same format string syntax as the fmt C++ lib, just 150 | /// that the feature set is very limited. It only supports {} without 151 | /// any options, for example print("Nr: {}", 1); 152 | /// 153 | /// @param fmt The format string using {} as place holder 154 | /// @param args The needed arguments to print 155 | /// 156 | template 157 | inline void print(const char* fmt, T_Args&&... args) noexcept 158 | { 159 | internal::print_helper(fmt, std::forward(args)...); 160 | } 161 | 162 | } // namespace zpp 163 | 164 | #endif // ZPP_INCLUDE_ZPP_FMT_HPP 165 | -------------------------------------------------------------------------------- /include/zpp/futex.hpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (c) 2021 Erwin Rol 3 | /// 4 | /// SPDX-License-Identifier: Apache-2.0 5 | /// 6 | 7 | #ifndef ZPP_INCLUDE_ZPP_FUTEX_HPP 8 | #define ZPP_INCLUDE_ZPP_FUTEX_HPP 9 | 10 | #ifdef CONFIG_USERSPACE 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | namespace zpp { 18 | 19 | /// 20 | /// @brief A CRTP futex base class. 21 | /// 22 | template 23 | class futex_base 24 | { 25 | public: 26 | using native_type = struct k_futex; 27 | using native_pointer = native_type *; 28 | using native_const_pointer = native_type const *; 29 | protected: 30 | /// 31 | /// @brief Default constructor 32 | /// 33 | constexpr futex_base() noexcept 34 | { 35 | } 36 | 37 | public: 38 | /// 39 | /// @brief Wait for the futex. 40 | /// 41 | /// @param expected the expected value 42 | /// 43 | /// @return true if successfull 44 | /// 45 | [[nodiscard]] bool wait(int expected) noexcept 46 | { 47 | if (futex_wait(native_handle(), expected, K_FOREVER) == 0) { 48 | return true; 49 | } else { 50 | return false; 51 | } 52 | } 53 | 54 | /// 55 | /// @brief Try wait for the futex. 56 | /// 57 | /// @param expected the expected value 58 | /// 59 | /// @return true if successfull 60 | /// 61 | [[nodiscard]] bool try_wait(int expected) noexcept 62 | { 63 | if (futex_wait(native_handle(), expected, K_NO_WAIT) == 0) { 64 | return true; 65 | } else { 66 | return false; 67 | } 68 | } 69 | 70 | /// 71 | /// @brief Wait for the futex. 72 | /// 73 | /// @param expected the expected value 74 | /// @param timeout the timeout before returning 75 | /// 76 | /// @return true if successfull 77 | /// 78 | template 79 | [[nodiscard]] bool 80 | try_wait_for(int expected, const std::chrono::duration& timeout) noexcept 81 | { 82 | using namespace std::chrono; 83 | 84 | if (futex_wait(native_handle(), expected, to_timeout(timeout)) == 0) 85 | { 86 | return true; 87 | } else { 88 | return false; 89 | } 90 | } 91 | 92 | /// 93 | /// @brief Wakeup one waiting thread 94 | /// 95 | void wake_one() noexcept 96 | { 97 | futex_wake(native_handle(), false); 98 | } 99 | 100 | /// 101 | /// @brief Wakeup all waiting threads 102 | /// 103 | void wake_all() noexcept 104 | { 105 | futex_wake(native_handle(), true); 106 | } 107 | 108 | /// 109 | /// @brief get the native zephyr futex handle. 110 | /// 111 | /// @return A pointer to the zephyr k_futex. 112 | /// 113 | auto native_handle() noexcept -> native_pointer 114 | { 115 | return static_cast(this)->native_handle(); 116 | } 117 | 118 | /// 119 | /// @brief get the native zephyr futex handle. 120 | /// 121 | /// @return A pointer to the zephyr k_futex. 122 | /// 123 | auto native_handle() const noexcept -> native_const_pointer 124 | { 125 | return static_cast(this)->native_handle(); 126 | } 127 | public: 128 | futex_base(const futex_base&) = delete; 129 | futex_base(futex_base&&) = delete; 130 | futex_base& operator=(const futex_base&) = delete; 131 | futex_base& operator=(futex_base&&) = delete; 132 | }; 133 | 134 | /// 135 | /// @brief A futex class. 136 | /// 137 | class futex : public futex_base { 138 | public: 139 | /// 140 | /// @brief get the native zephyr futex handle. 141 | /// 142 | /// @return A pointer to the zephyr k_futex. 143 | /// 144 | constexpr auto native_handle() noexcept -> native_pointer 145 | { 146 | return &m_futex; 147 | } 148 | 149 | /// 150 | /// @brief get the native zephyr futex handle. 151 | /// 152 | /// @return A pointer to the zephyr k_futex. 153 | /// 154 | constexpr auto native_handle() const noexcept -> native_const_pointer 155 | { 156 | return &m_futex; 157 | } 158 | private: 159 | native_type m_futex{}; 160 | public: 161 | futex(const futex&) = delete; 162 | futex(futex&&) = delete; 163 | futex& operator=(const futex&) = delete; 164 | futex& operator=(futex&&) = delete; 165 | }; 166 | 167 | /// 168 | /// @brief A futex class referencing another futex object. 169 | /// 170 | class futex_ref : public futex_base { 171 | public: 172 | /// 173 | /// @brief Construct a futex using a native k_futex* 174 | /// 175 | /// @param f The k_futex to use. @a f must already be 176 | /// initialized and will not be freed. 177 | /// 178 | explicit constexpr futex_ref(native_pointer f) noexcept 179 | : m_futex_ptr(f) 180 | { 181 | __ASSERT_NO_MSG(m_futex_ptr != nullptr); 182 | } 183 | 184 | /// 185 | /// @brief Construct a futex using another futex object 186 | /// 187 | /// @param f The futex to use. @a f must already be 188 | /// initialized and will not be freed. 189 | /// 190 | template 191 | explicit constexpr futex_ref(T_Futex& f) noexcept 192 | : m_futex_ptr(f.native_handle()) 193 | { 194 | __ASSERT_NO_MSG(m_futex_ptr != nullptr); 195 | } 196 | 197 | /// 198 | /// @brief copy operator 199 | /// 200 | /// @param f The k_futex to use. @a f must already be 201 | /// initialized and will not be freed. 202 | /// 203 | /// @return Reference to this object 204 | /// 205 | constexpr futex_ref& operator=(native_pointer f) noexcept 206 | { 207 | m_futex_ptr = f; 208 | __ASSERT_NO_MSG(m_futex_ptr != nullptr); 209 | return *this; 210 | } 211 | 212 | /// 213 | /// @brief copy operator 214 | /// 215 | /// @param f The futex object to use. @a f must already be 216 | /// initialized and will not be freed. 217 | /// 218 | /// @return Reference to this object 219 | /// 220 | template 221 | constexpr futex_ref& operator=(T_Futex& f) noexcept 222 | { 223 | m_futex_ptr = f.native_handle(); 224 | __ASSERT_NO_MSG(m_futex_ptr != nullptr); 225 | return *this; 226 | } 227 | 228 | /// 229 | /// @brief get the native zephyr futex handle. 230 | /// 231 | /// @return A pointer to the zephyr k_futex. 232 | /// 233 | constexpr auto native_handle() noexcept -> native_pointer 234 | { 235 | return m_futex_ptr; 236 | } 237 | 238 | /// 239 | /// @brief get the native zephyr futex handle. 240 | /// 241 | /// @return A pointer to the zephyr k_futex. 242 | /// 243 | constexpr auto native_handle() const noexcept -> native_const_pointer 244 | { 245 | return m_futex_ptr; 246 | } 247 | private: 248 | native_pointer m_futex_ptr{ nullptr }; 249 | public: 250 | futex_ref() = delete; 251 | }; 252 | 253 | } // namespace zpp 254 | 255 | #endif // CONFIG_USERSPACE 256 | 257 | #endif // ZPP_INCLUDE_ZPP_FUTEX_HPP 258 | -------------------------------------------------------------------------------- /include/zpp/heap.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2021 Erwin Rol 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | 7 | #ifndef ZPP_INCLUDE_ZPP_HEAP_HPP 8 | #define ZPP_INCLUDE_ZPP_HEAP_HPP 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | namespace zpp { 18 | 19 | /// 20 | /// @brief Heap memory allocater CRTP base class 21 | /// 22 | template 23 | class base_heap { 24 | public: 25 | using native_type = struct k_heap; 26 | using native_pointer = native_type*; 27 | using native_const_pointer = native_type const *; 28 | protected: 29 | /// 30 | /// @brief default protected constructor so only derived objects can be created 31 | /// 32 | constexpr base_heap() noexcept { } 33 | public: 34 | /// 35 | /// @brief Allocate memory from this heap wainting forever 36 | /// 37 | /// @param bytes the number of bytes to allocate 38 | /// 39 | /// @return The memory or nullptr on failure 40 | /// 41 | [[nodiscard]] void* 42 | allocate(size_t bytes) noexcept 43 | { 44 | return k_heap_alloc(native_handle(), bytes, K_FOREVER); 45 | } 46 | 47 | /// 48 | /// @brief Allocate memory from this heap waiting forever 49 | /// 50 | /// @param bytes the number of bytes to allocate 51 | /// @param align the alignment of the allocated memory 52 | /// 53 | /// @return The memory or nullptr on failure 54 | /// 55 | [[nodiscard]] void* 56 | allocate(size_t bytes, size_t align) noexcept 57 | { 58 | return k_heap_aligned_alloc(native_handle(), align, bytes, K_FOREVER); 59 | } 60 | 61 | /// 62 | /// @brief Allocate memory from this heap without waiting 63 | /// 64 | /// @param bytes the number of bytes to allocate 65 | /// 66 | /// @return The memory or nullptr on failure 67 | /// 68 | [[nodiscard]] void* 69 | try_allocate(size_t bytes) noexcept 70 | { 71 | return k_heap_alloc(native_handle(), bytes, K_NO_WAIT); 72 | } 73 | 74 | /// 75 | /// @brief Allocate memory from this heap without waiting 76 | /// 77 | /// @param bytes the number of bytes to allocate 78 | /// @param align the alignment of the allocated memory 79 | /// 80 | /// @return The memory or nullptr on failure 81 | /// 82 | [[nodiscard]] void* 83 | try_allocate(size_t bytes, size_t align) noexcept 84 | { 85 | return k_heap_aligned_alloc(native_handle(), align, bytes, K_NO_WAIT); 86 | } 87 | 88 | /// 89 | /// @brief Allocate memory from this heap waiting with a timeout 90 | /// 91 | /// @param bytes the number of bytes to allocate 92 | /// @param timeout the time to try the allocation 93 | /// 94 | /// @return The memory or nullptr on failure 95 | /// 96 | template 97 | [[nodiscard]] void* 98 | try_allocate_for(size_t bytes, const std::chrono::duration& timeout) noexcept 99 | { 100 | return k_heap_alloc(native_handle(), bytes, to_timeout(timeout)); 101 | } 102 | 103 | /// 104 | /// @brief Allocate memory from this heap waiting with a timeout 105 | /// 106 | /// @param bytes the number of bytes to allocate 107 | /// @param align the alignment of the allocated memory 108 | /// @param timeout the time to try the allocation 109 | /// 110 | /// @return The memory or nullptr on failure 111 | /// 112 | template 113 | [[nodiscard]] void* 114 | try_allocate_for(size_t bytes, size_t align, const std::chrono::duration& timeout) noexcept 115 | { 116 | return k_heap_aligned_alloc(native_handle(), align, bytes, to_timeout(timeout)); 117 | } 118 | 119 | /// 120 | /// @brief Deallocate memory previously allocated 121 | /// 122 | /// @param mem the memory to deallocate 123 | /// 124 | void deallocate(void* mem) noexcept 125 | { 126 | k_heap_free(native_handle(), mem); 127 | } 128 | 129 | /// 130 | /// @brief get the native zephyr heap handle. 131 | /// 132 | /// @return A pointer to the zephyr k_heap. 133 | /// 134 | auto native_handle() noexcept -> native_pointer 135 | { 136 | return static_cast(this)->native_handle(); 137 | } 138 | 139 | /// 140 | /// @brief get the native zephyr heap handle. 141 | /// 142 | /// @return A pointer to the zephyr k_heap. 143 | /// 144 | auto native_handle() const noexcept -> native_const_pointer 145 | { 146 | return static_cast(this)->native_handle(); 147 | } 148 | public: 149 | base_heap(const base_heap&) = delete; 150 | base_heap(base_heap&&) = delete; 151 | base_heap& operator=(const base_heap&) = delete; 152 | base_heap& operator=(base_heap&&) = delete; 153 | }; 154 | 155 | /// 156 | /// @brief heap class 157 | /// 158 | template 159 | class heap : public base_heap> { 160 | public: 161 | using typename base_heap>::native_type; 162 | using typename base_heap>::native_pointer; 163 | using typename base_heap>::native_const_pointer; 164 | public: 165 | /// 166 | /// @brief The default constructor 167 | /// 168 | heap() noexcept { 169 | k_heap_init(&m_heap, m_mem.data(), m_mem.size()); 170 | } 171 | 172 | /// 173 | /// @brief Return the total size of this heap 174 | /// 175 | /// @return The heap size in bytes 176 | /// 177 | static constexpr size_t size() noexcept { 178 | return T_Size; 179 | } 180 | 181 | /// 182 | /// @brief get the native zephyr heap handle. 183 | /// 184 | /// @return A pointer to the zephyr k_heap. 185 | /// 186 | constexpr auto native_handle() noexcept -> native_pointer 187 | { 188 | return &m_heap; 189 | } 190 | 191 | /// 192 | /// @brief get the native zephyr heap handle. 193 | /// 194 | /// @return A pointer to the zephyr k_heap. 195 | /// 196 | constexpr auto native_handle() const noexcept -> native_const_pointer 197 | { 198 | return &m_heap; 199 | } 200 | private: 201 | native_type m_heap{}; 202 | std::array m_mem; 203 | public: 204 | heap(const heap&) = delete; 205 | heap(heap&&) = delete; 206 | heap& operator=(const heap&) = delete; 207 | heap& operator=(heap&&) = delete; 208 | }; 209 | 210 | /// 211 | /// @brief heap reference class 212 | /// 213 | /// @warning the referenced object must outlife the reference object 214 | /// 215 | class heap_ref : public base_heap { 216 | public: 217 | /// 218 | /// @brief reference native heap object 219 | /// 220 | /// @param h the native heap object 221 | /// 222 | /// @warning The native heap object @a h must be valid for the lifetime 223 | /// of this object 224 | /// 225 | constexpr explicit heap_ref(native_pointer h) noexcept 226 | : m_heap(h) 227 | { 228 | __ASSERT_NO_MSG(m_heap != nullptr); 229 | } 230 | 231 | /// 232 | /// @brief reference heap object 233 | /// 234 | /// @param h the heap object 235 | /// 236 | /// @warning The heap object @a h must be valid for the lifetime 237 | /// of this object 238 | /// 239 | template 240 | constexpr explicit heap_ref(T_Heap& h) noexcept 241 | : m_heap(h.native_handle()) 242 | { 243 | __ASSERT_NO_MSG(m_heap != nullptr); 244 | } 245 | 246 | /// 247 | /// @brief assign new native heap object 248 | /// 249 | /// @param h the native heap object 250 | /// 251 | /// @return reference to this object 252 | /// 253 | /// @warning The native heap object @a h must be valid for the lifetime 254 | /// of this object 255 | /// 256 | constexpr heap_ref& operator=(native_pointer h) noexcept 257 | { 258 | m_heap = h; 259 | __ASSERT_NO_MSG(m_heap != nullptr); 260 | return *this; 261 | } 262 | 263 | /// 264 | /// @brief assign new heap object 265 | /// 266 | /// @param h the heap object 267 | /// 268 | /// @return reference to this object 269 | /// 270 | /// @warning The heap object @a h must be valid for the lifetime 271 | /// of this object 272 | /// 273 | template 274 | constexpr heap_ref& operator=(T_Heap& rhs) noexcept 275 | { 276 | m_heap = rhs.native_handle(); 277 | __ASSERT_NO_MSG(m_heap != nullptr); 278 | return *this; 279 | } 280 | 281 | /// 282 | /// @brief get the native zephyr heap handle. 283 | /// 284 | /// @return A pointer to the zephyr k_heap. 285 | /// 286 | constexpr auto native_handle() noexcept -> native_pointer 287 | { 288 | return m_heap; 289 | } 290 | 291 | /// 292 | /// @brief get the native zephyr heap handle. 293 | /// 294 | /// @return A pointer to the zephyr k_heap. 295 | /// 296 | constexpr auto native_handle() const noexcept -> native_const_pointer 297 | { 298 | return m_heap; 299 | } 300 | private: 301 | native_pointer m_heap{nullptr}; 302 | public: 303 | heap_ref() = delete; 304 | }; 305 | 306 | } // namespace zpp 307 | 308 | #endif // ZPP_INCLUDE_ZPP_HEAP_HPP 309 | -------------------------------------------------------------------------------- /include/zpp/lock_guard.hpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (c) 2021 Erwin Rol 3 | /// 4 | /// SPDX-License-Identifier: Apache-2.0 5 | /// 6 | 7 | #ifndef ZPP_INCLUDE_ZPP_LOCK_GUARD_HPP 8 | #define ZPP_INCLUDE_ZPP_LOCK_GUARD_HPP 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | namespace zpp { 16 | 17 | /// 18 | /// @brief lock_guard using zpp::mutex as a lock. 19 | /// 20 | /// @param T_Mutex the mutex type to use 21 | /// 22 | template 23 | class lock_guard { 24 | public: 25 | /// 26 | /// @brief Try locking the mutex waiting forever. 27 | /// 28 | /// @param lock the mutex to lock 29 | /// 30 | explicit lock_guard(T_Mutex& lock) noexcept 31 | : m_lock(lock) 32 | { 33 | auto res = m_lock.lock(); 34 | __ASSERT_NO_MSG(res != false); 35 | } 36 | 37 | /// 38 | /// @brief unlock the mutex. 39 | /// 40 | ~lock_guard() 41 | { 42 | auto res = m_lock.unlock(); 43 | __ASSERT_NO_MSG(res != false); 44 | } 45 | private: 46 | T_Mutex& m_lock; 47 | public: 48 | lock_guard() = delete; 49 | lock_guard(lock_guard&&) = delete; 50 | lock_guard(const lock_guard&) = delete; 51 | lock_guard& operator=(lock_guard&&) = delete; 52 | lock_guard& operator=(const lock_guard&) = delete; 53 | }; 54 | 55 | } // namespace zpp 56 | 57 | #endif // ZPP_INCLUDE_ZPP_LOCK_GUARD_HPP 58 | -------------------------------------------------------------------------------- /include/zpp/mem_slab.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2021 Erwin Rol 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | 7 | #ifndef ZPP_INCLUDE_ZPP_MEM_SLAB_HPP 8 | #define ZPP_INCLUDE_ZPP_MEM_SLAB_HPP 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | 19 | namespace zpp { 20 | 21 | /// 22 | /// @brief Allocator that uses k_mem_slab for memory 23 | /// 24 | /// @param T_MemSlab the CRTP type 25 | /// 26 | template 27 | class mem_slab_base { 28 | public: 29 | using native_type = struct k_mem_slab; 30 | using native_pointer = native_type*; 31 | using native_const_pointer = native_type const *; 32 | protected: 33 | constexpr mem_slab_base() noexcept {} 34 | public: 35 | /// 36 | /// @brief allocate a memory block, waiting forever 37 | /// 38 | /// @return pointer to memory or nullptr on error 39 | /// 40 | [[nodiscard]] void* 41 | allocate() noexcept 42 | { 43 | void* vp{nullptr}; 44 | 45 | auto rc = k_mem_slab_alloc(native_handle(), &vp, K_FOREVER); 46 | 47 | if (rc == 0) { 48 | return vp; 49 | } else { 50 | return nullptr; 51 | } 52 | } 53 | 54 | /// 55 | /// @brief try allocate a memory block, not waiting 56 | /// 57 | /// @return pointer to memory or nullptr on error 58 | /// 59 | [[nodiscard]] void* 60 | try_allocate() noexcept 61 | { 62 | void* vp{nullptr}; 63 | 64 | auto rc = k_mem_slab_alloc(native_handle(), &vp, K_NO_WAIT); 65 | 66 | if (rc == 0) { 67 | return vp; 68 | } else { 69 | return nullptr; 70 | } 71 | } 72 | 73 | /// 74 | /// @brief try allocate a memory block waiting with a timeout 75 | /// 76 | /// @param timeout the time to try 77 | /// 78 | /// @return pointer to memory or nullptr on error 79 | /// 80 | template 81 | [[nodiscard]] void* 82 | try_allocate_for(const std::chrono::duration& timeout) noexcept 83 | { 84 | using namespace std::chrono; 85 | 86 | void* vp{nullptr}; 87 | 88 | auto rc = k_mem_slab_alloc(native_handle(), &vp, to_timeout(timeout)); 89 | 90 | if (rc == 0) { 91 | return vp; 92 | } else { 93 | return nullptr; 94 | } 95 | } 96 | 97 | /// 98 | /// @brief deallocate memory 99 | /// 100 | /// @param vp the pointer to free 101 | /// 102 | void deallocate(void* vp) noexcept 103 | { 104 | if (vp != nullptr) { 105 | k_mem_slab_free(native_handle(), &vp); 106 | } 107 | } 108 | 109 | /// 110 | /// @brief the size of the memory blocks 111 | /// 112 | /// @return the size of the memory blocks in bytes 113 | /// 114 | constexpr auto block_size() const noexcept 115 | { 116 | return native_handle()->block_size; 117 | } 118 | 119 | /// 120 | /// @brief get maximm number of blocks that can be allocated 121 | /// 122 | /// @return the maximum number of blocks that can be allocated 123 | /// 124 | constexpr auto total_block_count() const noexcept 125 | { 126 | return native_handle()->num_blocks; 127 | } 128 | 129 | /// 130 | /// @brief get current number of used blocks 131 | /// 132 | /// @return the current number of used blocks 133 | /// 134 | constexpr auto used_block_count() noexcept 135 | { 136 | return k_mem_slab_num_used_get(native_handle()); 137 | } 138 | 139 | /// 140 | /// @brief get current number of free blocks 141 | /// 142 | /// @return the current number of free blocks 143 | /// 144 | constexpr auto free_block_count() noexcept 145 | { 146 | return k_mem_slab_num_free_get(native_handle()); 147 | } 148 | 149 | 150 | /// 151 | /// @brief get the native zephyr mem slab handle. 152 | /// 153 | /// @return A pointer to the zephyr k_mem_slab. 154 | /// 155 | auto native_handle() noexcept -> native_pointer 156 | { 157 | return static_cast(this)->native_handle(); 158 | } 159 | 160 | /// 161 | /// @brief get the native zephyr mem slab handle. 162 | /// 163 | /// @return A pointer to the zephyr k_mem_slab. 164 | /// 165 | auto native_handle() const noexcept -> native_const_pointer 166 | { 167 | return static_cast(this)->native_handle(); 168 | } 169 | public: 170 | mem_slab_base(const mem_slab_base&) = delete; 171 | mem_slab_base(mem_slab_base&&) = delete; 172 | mem_slab_base& operator=(const mem_slab_base&) = delete; 173 | mem_slab_base& operator=(mem_slab_base&&) = delete; 174 | }; 175 | 176 | 177 | /// 178 | /// @brief A memory slab class. 179 | /// 180 | template 181 | class mem_slab : public mem_slab_base> 182 | { 183 | static_assert(T_BlockCount > 0); 184 | static_assert(is_multiple_of(T_BlockSize, 4) == true); 185 | static_assert(T_Align >= sizeof(void*)); 186 | static_assert(is_power_of_two(T_Align)); 187 | static_assert(T_BlockSize >= T_Align); 188 | static_assert((T_BlockSize % T_Align) == 0); 189 | public: 190 | using typename mem_slab_base>::native_type; 191 | using typename mem_slab_base>::native_pointer; 192 | using typename mem_slab_base>::native_const_pointer; 193 | public: 194 | /// 195 | /// @brief Default constructor 196 | /// 197 | mem_slab() noexcept 198 | { 199 | k_mem_slab_init(&m_mem_slab, m_mem_buffer.data(), T_BlockSize, T_BlockCount); 200 | } 201 | 202 | /// 203 | /// @brief get the native zephyr mem slab handle. 204 | /// 205 | /// @return A pointer to the zephyr k_mem_slab. 206 | /// 207 | constexpr auto native_handle() noexcept -> native_pointer 208 | { 209 | return &m_mem_slab; 210 | } 211 | 212 | /// 213 | /// @brief get the native zephyr mem slab handle. 214 | /// 215 | /// @return A pointer to the zephyr k_mem_slab. 216 | /// 217 | constexpr auto native_handle() const noexcept -> native_const_pointer 218 | { 219 | return &m_mem_slab; 220 | } 221 | private: 222 | native_type m_mem_slab{}; 223 | alignas(T_Align) std::array m_mem_buffer; 224 | public: 225 | mem_slab(const mem_slab&) = delete; 226 | mem_slab(mem_slab&&) = delete; 227 | mem_slab& operator=(const mem_slab&) = delete; 228 | mem_slab& operator=(mem_slab&&) = delete; 229 | }; 230 | 231 | /// 232 | /// @brief A mem_slab class referencing another mem slab object. 233 | /// 234 | class mem_slab_ref : public mem_slab_base { 235 | public: 236 | /// 237 | /// @brief Construct a reference to a native k_mem_slab* 238 | /// 239 | /// @param m The k_mem_slab to reference. @a m must already be 240 | /// initialized and will not be freed. 241 | /// 242 | explicit constexpr mem_slab_ref(native_pointer m) noexcept 243 | : m_mem_slab_ptr(m) 244 | { 245 | __ASSERT_NO_MSG(m_mem_slab_ptr != nullptr); 246 | } 247 | 248 | /// 249 | /// @brief Construct a reference to another mem_slab object 250 | /// 251 | /// @param m The object to reference. @a m must already be 252 | /// initialized and will not be freed. 253 | /// 254 | template 255 | explicit constexpr mem_slab_ref(T_MemSlab& m) noexcept 256 | : m_mem_slab_ptr(m.native_handle()) 257 | { 258 | __ASSERT_NO_MSG(m_mem_slab_ptr != nullptr); 259 | } 260 | 261 | /// 262 | /// @brief Assign a new native k_mem_slab* object 263 | /// 264 | /// @param m The k_mem_slab to reference. @a m must already be 265 | /// initialized and will not be freed. 266 | /// 267 | /// @return reference to this object 268 | /// 269 | constexpr mem_slab_ref& operator=(native_pointer m) noexcept 270 | { 271 | m_mem_slab_ptr = m; 272 | __ASSERT_NO_MSG(m_mem_slab_ptr != nullptr); 273 | return *this; 274 | } 275 | 276 | /// 277 | /// @brief Assign a new native mem slab object 278 | /// 279 | /// @param m The object to reference. @a m must already be 280 | /// initialized and will not be freed. 281 | /// 282 | /// @return reference to this object 283 | /// 284 | template 285 | constexpr mem_slab_ref& operator=(T_MemSlab& m) noexcept 286 | { 287 | m_mem_slab_ptr = m.native_handle(); 288 | __ASSERT_NO_MSG(m_mem_slab_ptr != nullptr); 289 | return *this; 290 | } 291 | 292 | /// 293 | /// @brief get the native zephyr mem slab handle. 294 | /// 295 | /// @return A pointer to the zephyr k_mem_slab. 296 | /// 297 | constexpr auto native_handle() noexcept -> native_pointer 298 | { 299 | return m_mem_slab_ptr; 300 | } 301 | 302 | /// 303 | /// @brief get the native zephyr mem slab handle. 304 | /// 305 | /// @return A pointer to the zephyr k_mem_slab. 306 | /// 307 | constexpr auto native_handle() const noexcept -> native_const_pointer 308 | { 309 | return m_mem_slab_ptr; 310 | } 311 | private: 312 | native_pointer m_mem_slab_ptr{ nullptr }; 313 | public: 314 | mem_slab_ref() = delete; 315 | }; 316 | 317 | } // namespace zpp 318 | 319 | #endif // ZPP_INCLUDE_ZPP_MEM_SLAB_HPP 320 | -------------------------------------------------------------------------------- /include/zpp/memory.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2021 Erwin Rol 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | 7 | #ifndef ZPP_INCLUDE_ZPP_MEMORY_HPP 8 | #define ZPP_INCLUDE_ZPP_MEMORY_HPP 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | [[nodiscard]] void* operator new(std::size_t) noexcept 16 | { 17 | return nullptr; 18 | } 19 | 20 | [[nodiscard]] void* operator new[](std::size_t) noexcept 21 | { 22 | return nullptr; 23 | } 24 | 25 | [[nodiscard]] void* operator new(std::size_t, std::align_val_t) noexcept 26 | { 27 | return nullptr; 28 | } 29 | 30 | [[nodiscard]] void* operator new[](std::size_t, std::align_val_t) noexcept 31 | { 32 | return nullptr; 33 | } 34 | 35 | [[nodiscard]] void* operator new(std::size_t, const std::nothrow_t&) noexcept 36 | { 37 | return nullptr; 38 | } 39 | 40 | [[nodiscard]] void* operator new[](std::size_t, const std::nothrow_t&) noexcept 41 | { 42 | return nullptr; 43 | } 44 | 45 | [[nodiscard]] void* operator new(std::size_t, std::align_val_t, const std::nothrow_t&) noexcept 46 | { 47 | return nullptr; 48 | } 49 | 50 | [[nodiscard]] void* operator new[](std::size_t, std::align_val_t, const std::nothrow_t&) noexcept 51 | { 52 | return nullptr; 53 | } 54 | 55 | #endif // ZPP_INCLUDE_ZPP_MEMORY_HPP 56 | -------------------------------------------------------------------------------- /include/zpp/mutex.hpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (c) 2019 Erwin Rol 3 | /// 4 | /// SPDX-License-Identifier: Apache-2.0 5 | /// 6 | 7 | #ifndef ZPP_INCLUDE_ZPP_MUTEX_HPP 8 | #define ZPP_INCLUDE_ZPP_MUTEX_HPP 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | namespace zpp { 19 | 20 | /// 21 | /// @brief A recursive mutex CRTP base class. 22 | /// 23 | template 24 | class mutex_base 25 | { 26 | public: 27 | using native_type = struct k_mutex; 28 | using native_pointer = native_type*; 29 | using native_const_pointer = native_type const *; 30 | protected: 31 | /// 32 | /// @brief Protected default constructor so only derived objects can be created 33 | /// 34 | constexpr mutex_base() noexcept 35 | { 36 | } 37 | 38 | public: 39 | /// 40 | /// @brief Lock the mutex. Wait forever until it is locked. 41 | /// 42 | /// @return true if successfully locked. 43 | /// 44 | [[nodiscard]] auto lock() noexcept 45 | { 46 | result res; 47 | 48 | auto rc = k_mutex_lock(native_handle(), K_FOREVER); 49 | if (rc == 0) { 50 | res.assign_value(); 51 | } else { 52 | res.assign_error(to_error_code(-rc)); 53 | } 54 | 55 | return res; 56 | } 57 | 58 | /// 59 | /// @brief Try locking the mutex without waiting. 60 | /// 61 | /// @return true if successfully locked. 62 | /// 63 | [[nodiscard]] auto try_lock() noexcept 64 | { 65 | result res; 66 | 67 | auto rc = k_mutex_lock(native_handle(), K_NO_WAIT); 68 | if (rc == 0) { 69 | res.assign_value(); 70 | } else { 71 | res.assign_error(to_error_code(-rc)); 72 | } 73 | 74 | return res; 75 | } 76 | 77 | /// 78 | /// @brief Try locking the mutex with a timeout. 79 | /// 80 | /// @param timeout The time to wait before returning 81 | /// 82 | /// @return true if successfully locked. 83 | /// 84 | template 85 | [[nodiscard]] auto 86 | try_lock_for(const std::chrono::duration& timeout) noexcept 87 | { 88 | using namespace std::chrono; 89 | 90 | result res; 91 | 92 | auto rc = k_mutex_lock(native_handle(), to_timeout(timeout)); 93 | if (rc == 0) { 94 | res.assign_value(); 95 | } else { 96 | res.assign_error(to_error_code(-rc)); 97 | } 98 | 99 | return res; 100 | } 101 | 102 | /// 103 | /// @brief Unlock the mutex. 104 | /// 105 | /// @return true on success 106 | /// 107 | [[nodiscard]] auto unlock() noexcept 108 | { 109 | result res; 110 | 111 | auto rc = k_mutex_unlock(native_handle()); 112 | if (rc == 0) { 113 | res.assign_value(); 114 | } else { 115 | res.assign_error(to_error_code(-rc)); 116 | } 117 | 118 | return res; 119 | } 120 | 121 | /// 122 | /// @brief get the native zephyr mutex handle. 123 | /// 124 | /// @return A pointer to the zephyr k_mutex. 125 | /// 126 | auto native_handle() noexcept -> native_pointer 127 | { 128 | return static_cast(this)->native_handle(); 129 | } 130 | 131 | /// 132 | /// @brief get the native zephyr mutex handle. 133 | /// 134 | /// @return A pointer to the zephyr k_mutex. 135 | /// 136 | auto native_handle() const noexcept -> native_const_pointer 137 | { 138 | return static_cast(this)->native_handle(); 139 | } 140 | public: 141 | mutex_base(const mutex_base&) = delete; 142 | mutex_base(mutex_base&&) = delete; 143 | mutex_base& operator=(const mutex_base&) = delete; 144 | mutex_base& operator=(mutex_base&&) = delete; 145 | }; 146 | 147 | /// 148 | /// @brief A recursive mutex class. 149 | /// 150 | class mutex : public mutex_base { 151 | public: 152 | /// 153 | /// @brief Default contructor 154 | /// 155 | mutex() noexcept 156 | { 157 | k_mutex_init(&m_mutex); 158 | } 159 | 160 | /// 161 | /// @brief get the native zephyr mutex handle. 162 | /// 163 | /// @return A pointer to the zephyr k_mutex. 164 | /// 165 | constexpr auto native_handle() noexcept -> native_pointer 166 | { 167 | return &m_mutex; 168 | } 169 | 170 | /// 171 | /// @brief get the native zephyr mutex handle. 172 | /// 173 | /// @return A pointer to the zephyr k_mutex. 174 | /// 175 | constexpr auto native_handle() const noexcept -> native_const_pointer 176 | { 177 | return &m_mutex; 178 | } 179 | private: 180 | native_type m_mutex{}; 181 | public: 182 | mutex(const mutex&) = delete; 183 | mutex(mutex&&) = delete; 184 | mutex& operator=(const mutex&) = delete; 185 | mutex& operator=(mutex&&) = delete; 186 | }; 187 | 188 | /// 189 | /// @brief A recursive mutex class borrowing the native mutex. 190 | /// 191 | class mutex_ref : public mutex_base { 192 | public: 193 | /// 194 | /// @brief Construct a mutex using a native k_mutex* 195 | /// 196 | /// @param m The k_mutex to use. @a m must already be 197 | /// initialized and will not be freed. 198 | /// 199 | explicit constexpr mutex_ref(native_pointer m) noexcept 200 | : m_mutex_ptr(m) 201 | { 202 | __ASSERT_NO_MSG(m_mutex_ptr != nullptr); 203 | } 204 | 205 | /// 206 | /// @brief Construct a mutex using another mutex object 207 | /// 208 | /// @param m The mutex object to use. @a m must already be 209 | /// initialized and will not be freed. 210 | /// 211 | template 212 | explicit constexpr mutex_ref(T_Mutex& m) noexcept 213 | : m_mutex_ptr(m.native_handle()) 214 | { 215 | __ASSERT_NO_MSG(m_mutex_ptr != nullptr); 216 | } 217 | 218 | /// 219 | /// @brief Assing another mutex object 220 | /// 221 | /// @param m The k_mutex to use. @a m must already be 222 | /// initialized and will not be freed. 223 | /// 224 | /// @return reference to this object 225 | /// 226 | constexpr mutex_ref& operator=(native_pointer m) noexcept 227 | { 228 | m_mutex_ptr = m; 229 | __ASSERT_NO_MSG(m_mutex_ptr != nullptr); 230 | return *this; 231 | } 232 | 233 | /// 234 | /// @brief Assing another mutex object 235 | /// 236 | /// @param m The mutex object to use. @a m must already be 237 | /// initialized and will not be freed. 238 | /// 239 | /// @return reference to this object 240 | /// 241 | template 242 | constexpr mutex_ref& operator=(T_Mutex& m) noexcept 243 | { 244 | m_mutex_ptr = m.native_handle(); 245 | __ASSERT_NO_MSG(m_mutex_ptr != nullptr); 246 | return *this; 247 | } 248 | 249 | /// 250 | /// @brief get the native zephyr mutex handle. 251 | /// 252 | /// @return A pointer to the zephyr k_mutex. 253 | /// 254 | constexpr auto native_handle() noexcept -> native_pointer 255 | { 256 | return m_mutex_ptr; 257 | } 258 | 259 | /// 260 | /// @brief get the native zephyr mutex handle. 261 | /// 262 | /// @return A pointer to the zephyr k_mutex. 263 | /// 264 | constexpr auto native_handle() const noexcept -> native_const_pointer 265 | { 266 | return m_mutex_ptr; 267 | } 268 | private: 269 | native_pointer m_mutex_ptr{ nullptr }; 270 | public: 271 | mutex_ref() = delete; 272 | }; 273 | 274 | } // namespace zpp 275 | 276 | #endif // ZPP_INCLUDE_ZPP_MUTEX_HPP 277 | -------------------------------------------------------------------------------- /include/zpp/poll.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019 Erwin Rol 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | 7 | #ifndef ZPP_INCLUDE_ZPP_POLL_HPP 8 | #define ZPP_INCLUDE_ZPP_POLL_HPP 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #endif // ZPP_INCLUDE_ZPP_POLL_HPP 15 | -------------------------------------------------------------------------------- /include/zpp/poll_event.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019 Erwin Rol 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | 7 | #ifndef ZPP_INCLUDE_ZPP_POLL_EVENT_HPP 8 | #define ZPP_INCLUDE_ZPP_POLL_EVENT_HPP 9 | 10 | #ifdef CONFIG_POLL 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | namespace zpp { 25 | 26 | /// 27 | /// @brief wrapper class around a k_poll_event 28 | /// 29 | class poll_event { 30 | public: 31 | /// 32 | /// @brief type of event sources 33 | /// 34 | enum class type_tag : uint8_t { 35 | type_unknown, 36 | type_sem, 37 | type_fifo, 38 | type_signal, 39 | type_ignore, 40 | }; 41 | 42 | /// 43 | /// @brief wrap a k_poll_event pointer 44 | /// 45 | /// @param event the event to wrap 46 | /// 47 | poll_event(k_poll_event* event) noexcept 48 | : m_event(event) 49 | { 50 | __ASSERT_NO_MSG(m_event != nullptr); 51 | } 52 | 53 | /// 54 | /// @brief assign a null event (that will be ignored when polling) 55 | /// 56 | void assign(std::nullptr_t) noexcept 57 | { 58 | __ASSERT_NO_MSG(m_event != nullptr); 59 | 60 | m_event->obj = nullptr; 61 | m_event->state = K_POLL_STATE_NOT_READY; 62 | m_event->mode = K_POLL_MODE_NOTIFY_ONLY; 63 | m_event->type = K_POLL_TYPE_IGNORE; 64 | m_event->tag = (int)type_tag::type_ignore; 65 | } 66 | 67 | /// 68 | /// @brief assign a semaphore to this event 69 | /// 70 | /// @param s the semaphore to poll 71 | /// 72 | void assign(sem& s) noexcept 73 | { 74 | __ASSERT_NO_MSG(m_event != nullptr); 75 | k_poll_event_init(m_event, 76 | K_POLL_TYPE_SEM_AVAILABLE, 77 | K_POLL_MODE_NOTIFY_ONLY, 78 | s.native_handle()); 79 | m_event->tag = (int)type_tag::type_sem; 80 | } 81 | 82 | /// 83 | /// @brief assign a semaphore to this event 84 | /// 85 | /// @param s the semaphore to poll 86 | /// 87 | void assign(sem_ref& s) noexcept 88 | { 89 | __ASSERT_NO_MSG(m_event != nullptr); 90 | k_poll_event_init(m_event, 91 | K_POLL_TYPE_SEM_AVAILABLE, 92 | K_POLL_MODE_NOTIFY_ONLY, 93 | s.native_handle()); 94 | m_event->tag = (int)type_tag::type_sem; 95 | } 96 | 97 | /// 98 | /// @brief assign a fifo to this event 99 | /// 100 | /// @param f the fifo to poll 101 | /// 102 | template 103 | void assign(fifo& f) noexcept 104 | { 105 | __ASSERT_NO_MSG(m_event != nullptr); 106 | k_poll_event_init(m_event, 107 | K_POLL_TYPE_FIFO_DATA_AVAILABLE, 108 | K_POLL_MODE_NOTIFY_ONLY, 109 | f.native_handle()); 110 | m_event->tag = (int)type_tag::type_fifo; 111 | } 112 | 113 | /// 114 | /// @brief assign a fifo to this event 115 | /// 116 | /// @param f the fifo to poll 117 | /// 118 | template 119 | void assign(fifo_ref& f) noexcept 120 | { 121 | __ASSERT_NO_MSG(m_event != nullptr); 122 | k_poll_event_init(m_event, 123 | K_POLL_TYPE_FIFO_DATA_AVAILABLE, 124 | K_POLL_MODE_NOTIFY_ONLY, 125 | f.native_handle()); 126 | m_event->tag = (int)type_tag::type_fifo; 127 | } 128 | 129 | /// 130 | /// @brief assign a signal to this event 131 | /// 132 | /// @param s the signal to poll 133 | /// 134 | void assign(poll_signal& s) noexcept 135 | { 136 | __ASSERT_NO_MSG(m_event != nullptr); 137 | k_poll_event_init(m_event, 138 | K_POLL_TYPE_SIGNAL, 139 | K_POLL_MODE_NOTIFY_ONLY, 140 | s.native_handle()); 141 | m_event->tag = (int)type_tag::type_signal; 142 | } 143 | 144 | /// 145 | /// @brief assign a signal to this event 146 | /// 147 | /// @param s the signal to poll 148 | /// 149 | void assign(poll_signal_ref& s) noexcept 150 | { 151 | __ASSERT_NO_MSG(m_event != nullptr); 152 | k_poll_event_init(m_event, 153 | K_POLL_TYPE_SIGNAL, 154 | K_POLL_MODE_NOTIFY_ONLY, 155 | s.native_handle()); 156 | m_event->tag = (int)type_tag::type_signal; 157 | } 158 | 159 | 160 | /// 161 | /// @brief check if this event is ready 162 | /// 163 | /// @return true if the event is ready 164 | /// 165 | bool is_ready() noexcept 166 | { 167 | __ASSERT_NO_MSG(m_event != nullptr); 168 | __ASSERT_NO_MSG(m_event->tag != (int)type_tag::type_unknown); 169 | 170 | switch((type_tag)m_event->tag) { 171 | case type_tag::type_unknown: 172 | return false; 173 | case type_tag::type_sem: 174 | return (m_event->state & K_POLL_STATE_SEM_AVAILABLE); 175 | case type_tag::type_fifo: 176 | return (m_event->state & K_POLL_STATE_FIFO_DATA_AVAILABLE); 177 | case type_tag::type_signal: 178 | return (m_event->state & K_POLL_STATE_SIGNALED); 179 | case type_tag::type_ignore: 180 | return false; 181 | } 182 | 183 | return false; 184 | } 185 | 186 | /// 187 | /// @brief reset event to non ready state 188 | /// 189 | void reset() noexcept 190 | { 191 | __ASSERT_NO_MSG(m_event != nullptr); 192 | 193 | m_event->state = K_POLL_STATE_NOT_READY; 194 | } 195 | 196 | /// 197 | /// @brief check if this event is cancelled 198 | /// 199 | /// @return true if the event is cancelled 200 | /// 201 | bool is_cancelled() noexcept 202 | { 203 | __ASSERT_NO_MSG(m_event != nullptr); 204 | __ASSERT_NO_MSG(m_event->tag != (int)type_tag::type_unknown); 205 | 206 | if (m_event->state & K_POLL_STATE_CANCELLED) { 207 | return true; 208 | } else { 209 | return false; 210 | } 211 | } 212 | 213 | /// 214 | /// @brief get access to the fifo of the event 215 | /// 216 | /// @warning the event must be an fifo event and the fifo ItemType 217 | /// must match with the registerred ItemType 218 | /// 219 | /// @return a fifo_ref that points to the registered fifo 220 | /// 221 | template 222 | auto fifo() noexcept 223 | { 224 | __ASSERT_NO_MSG(m_event != nullptr); 225 | __ASSERT_NO_MSG(m_event->tag == (int)type_tag::type_fifo); 226 | __ASSERT_NO_MSG(m_event->fifo != nullptr); 227 | 228 | return fifo_ref(m_event->fifo); 229 | } 230 | 231 | /// 232 | /// @brief get access to the sem of the event 233 | /// 234 | /// @warning the event must be a sem event 235 | /// 236 | /// @return a sem_ref that points to the registered sem 237 | /// 238 | auto sem() noexcept 239 | { 240 | __ASSERT_NO_MSG(m_event != nullptr); 241 | __ASSERT_NO_MSG(m_event->tag == (int)type_tag::type_sem); 242 | __ASSERT_NO_MSG(m_event->sem != nullptr); 243 | 244 | return sem_ref(m_event->sem); 245 | } 246 | 247 | /// 248 | /// @brief get access to the signal of the event 249 | /// 250 | /// @warning the event must be a signal event 251 | /// 252 | /// @return a borrowed_poll_signal that points to the registered signal 253 | /// 254 | auto signal() noexcept 255 | { 256 | __ASSERT_NO_MSG(m_event != nullptr); 257 | __ASSERT_NO_MSG(m_event->tag == (int)type_tag::type_signal); 258 | __ASSERT_NO_MSG(m_event->signal != nullptr); 259 | 260 | return poll_signal_ref(m_event->signal); 261 | } 262 | private: 263 | k_poll_event* m_event{ nullptr }; 264 | public: 265 | poll_event(const poll_event&) = delete; 266 | poll_event(poll_event&&) = delete; 267 | poll_event& operator=(const poll_event&) = delete; 268 | poll_event& operator=(poll_event&&) = delete; 269 | }; 270 | 271 | } // namespace zpp 272 | 273 | #endif // CONFIG_POLL 274 | 275 | #endif // ZPP_INCLUDE_ZPP_POLL_EVENT_HPP 276 | -------------------------------------------------------------------------------- /include/zpp/poll_event_set.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019 Erwin Rol 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | 7 | #ifndef ZPP_INCLUDE_ZPP_POLL_EVENT_SET_HPP 8 | #define ZPP_INCLUDE_ZPP_POLL_EVENT_SET_HPP 9 | 10 | #ifdef CONFIG_POLL 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | 29 | namespace zpp { 30 | 31 | /// 32 | /// @brief A set of poll events 33 | /// 34 | /// @param Size the size of the set 35 | /// 36 | template 37 | class poll_event_set 38 | { 39 | public: 40 | auto begin() noexcept { return m_events.begin(); } 41 | auto end() noexcept { return m_events.end(); } 42 | public: 43 | /// 44 | /// @brief default constructor 45 | /// 46 | poll_event_set() noexcept 47 | { 48 | } 49 | 50 | /// 51 | /// @brief constructor that takes arguments for initialization 52 | /// 53 | /// @param t the arguments to use for initialization 54 | /// 55 | template 56 | poll_event_set(T_Args&&... t) noexcept 57 | { 58 | assign(0, std::forward(t)...); 59 | } 60 | 61 | /// 62 | /// @brief access an element of the set 63 | /// 64 | /// @param idx the index of the event to get 65 | /// 66 | /// @return a poll_event that has a reference to the indexed event 67 | /// 68 | auto operator[](size_t idx) noexcept 69 | { 70 | __ASSERT_NO_MSG(idx < T_Size); 71 | return poll_event(&m_events[idx]); 72 | } 73 | 74 | /// 75 | /// @brief poll events waiting for ever 76 | /// 77 | /// @return false on error 78 | /// 79 | auto poll() noexcept 80 | { 81 | return poll(K_FOREVER); 82 | } 83 | 84 | /// 85 | /// @brief try poll events without waiting 86 | /// 87 | /// @return false on error 88 | /// 89 | auto try_poll() noexcept 90 | { 91 | return poll(K_NO_WAIT); 92 | } 93 | 94 | /// 95 | /// @brief try poll events waiting for e certain time 96 | /// 97 | /// @param timeout the time to wait 98 | /// 99 | /// @return false on error 100 | /// 101 | template 102 | auto try_poll_for(const std::chrono::duration& 103 | timeout) noexcept 104 | { 105 | using namespace std::chrono; 106 | 107 | return poll(to_timeout(timeout)); 108 | } 109 | private: 110 | /// 111 | /// @brief try poll events waiting for e certain time 112 | /// 113 | /// @param timeout the time to wait 114 | /// 115 | /// @return false on error 116 | /// 117 | void assign(int index) noexcept 118 | { 119 | __ASSERT_NO_MSG(index == T_Size); 120 | } 121 | 122 | /// 123 | /// @brief try poll events waiting for e certain time 124 | /// 125 | /// @param timeout the time to wait 126 | /// 127 | /// @return false on error 128 | /// 129 | template 130 | void assign(int index, T_FirstArg&& f, T_Args&&... t) noexcept 131 | { 132 | poll_event(&m_events[index]).assign(std::forward(f)); 133 | assign(index+1, std::forward(t)...); 134 | } 135 | 136 | /// 137 | /// @brief try poll events waiting for e certain time 138 | /// 139 | /// @param timeout the time to wait 140 | /// 141 | /// @return false on error 142 | /// 143 | auto poll(k_timeout_t timeout) noexcept 144 | { 145 | for (auto& e: m_events) { 146 | e.state = K_POLL_STATE_NOT_READY; 147 | if (e.tag == (int)poll_event::type_tag::type_signal) { 148 | __ASSERT_NO_MSG(e.signal != nullptr); 149 | e.signal->signaled = 0; 150 | } 151 | } 152 | 153 | auto rc = k_poll(m_events.data(), m_events.size(), timeout); 154 | 155 | if (rc == 0) { 156 | return true; 157 | } else { 158 | return false; 159 | } 160 | } 161 | private: 162 | std::array m_events; 163 | }; 164 | 165 | /// 166 | /// @brief try poll events waiting for e certain time 167 | /// 168 | /// @param timeout the time to wait 169 | /// 170 | /// @return false on error 171 | /// 172 | template 173 | poll_event_set(T_Args&&... t) noexcept -> poll_event_set; 174 | 175 | } // namespace zpp 176 | 177 | #endif // CONFIG_POLL 178 | 179 | #endif // ZPP_INCLUDE_ZPP_POLL_EVENT_SET_HPP 180 | -------------------------------------------------------------------------------- /include/zpp/poll_signal.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019 Erwin Rol 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | 7 | #ifndef ZPP_INCLUDE_ZPP_POLL_SIGNAL_HPP 8 | #define ZPP_INCLUDE_ZPP_POLL_SIGNAL_HPP 9 | 10 | #ifdef CONFIG_POLL 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | namespace zpp { 19 | 20 | /// 21 | /// @brief CRTP base class for poll_signals 22 | /// 23 | /// @param PollSignal the CRTP derived class 24 | /// 25 | template 26 | class poll_signal_base { 27 | public: 28 | using native_type = struct k_poll_signal; 29 | using native_pointer = native_type *; 30 | using native_const_pointer = native_type const *; 31 | protected: 32 | /// 33 | /// @brief default contructor only to be used by derived classes 34 | /// 35 | poll_signal_base() noexcept 36 | { 37 | } 38 | public: 39 | /// 40 | /// @brief check if the signal was signaled 41 | /// 42 | /// @return when the signal was signaled the signal value 43 | /// 44 | std::optional check() noexcept 45 | { 46 | unsigned int signaled{0}; 47 | int result{0}; 48 | 49 | k_poll_signal_check(native_handle(), &signaled, &result); 50 | 51 | if (signaled != 0) { 52 | return { result }; 53 | } else { 54 | return {}; 55 | } 56 | } 57 | 58 | /// 59 | /// @brief signal the signal 60 | /// 61 | /// @param result the value that check will return 62 | /// 63 | /// @return false if the signalling failed 64 | /// 65 | bool raise(int result) noexcept 66 | { 67 | auto rc = k_poll_signal_raise(native_handle(), result); 68 | if (rc == 0) { 69 | return true; 70 | } else { 71 | return false; 72 | } 73 | } 74 | 75 | /// 76 | /// @brief reset the state to non-signalled 77 | /// 78 | void reset() noexcept 79 | { 80 | k_poll_signal_reset(native_handle()); 81 | } 82 | 83 | /// 84 | /// @brief get the native k_poll_signal handle 85 | /// 86 | /// @return pointer to a k_poll_signal 87 | /// 88 | auto native_handle() noexcept -> native_pointer 89 | { 90 | return static_cast(this)->native_handle(); 91 | } 92 | 93 | /// 94 | /// @brief get the native k_poll_signal handle 95 | /// 96 | /// @return pointer to a k_poll_signal 97 | /// 98 | auto native_handle() const noexcept -> native_const_pointer 99 | { 100 | return static_cast(this)->native_handle(); 101 | } 102 | public: 103 | poll_signal_base(const poll_signal_base&) = delete; 104 | poll_signal_base(poll_signal_base&&) = delete; 105 | poll_signal_base& operator=(const poll_signal_base&) = delete; 106 | poll_signal_base& operator=(poll_signal_base&&) = delete; 107 | }; 108 | 109 | /// 110 | /// @brief class owning a k_poll_signal 111 | /// 112 | class poll_signal 113 | : public poll_signal_base 114 | { 115 | public: 116 | /// 117 | /// @brief default constructor initializing the signal 118 | /// 119 | poll_signal() noexcept 120 | { 121 | k_poll_signal_init(&m_signal); 122 | } 123 | 124 | /// 125 | /// @brief get the native k_poll_signal handle 126 | /// 127 | /// @return pointer to a k_poll_signal 128 | /// 129 | auto native_handle() noexcept -> native_pointer 130 | { 131 | return &m_signal; 132 | } 133 | 134 | /// 135 | /// @brief get the native k_poll_signal handle 136 | /// 137 | /// @return pointer to a k_poll_signal 138 | /// 139 | auto native_handle() const noexcept -> native_const_pointer 140 | { 141 | return &m_signal; 142 | } 143 | private: 144 | native_type m_signal; 145 | public: 146 | poll_signal(const poll_signal&) = delete; 147 | poll_signal(poll_signal&&) = delete; 148 | poll_signal& operator=(const poll_signal&) = delete; 149 | poll_signal& operator=(poll_signal&&) = delete; 150 | }; 151 | 152 | /// 153 | /// @brief class wrapping a k_poll_signal 154 | /// 155 | class poll_signal_ref 156 | : public poll_signal_base 157 | { 158 | public: 159 | /// 160 | /// @brief create a wrapper around a k_poll_signal 161 | /// 162 | /// @param s the signal to wrap 163 | /// 164 | poll_signal_ref(native_pointer s) noexcept 165 | : m_signal_ptr(s) 166 | { 167 | __ASSERT_NO_MSG(m_signal_ptr != nullptr); 168 | } 169 | 170 | /// 171 | /// @brief create a wrapper around a k_poll_signal 172 | /// 173 | /// @param s the signal to wrap 174 | /// 175 | template 176 | poll_signal_ref(T_PollSignal& s) noexcept 177 | : m_signal_ptr(s.native_handle()) 178 | { 179 | __ASSERT_NO_MSG(m_signal_ptr != nullptr); 180 | } 181 | 182 | /// 183 | /// @brief create a wrapper around a k_poll_signal 184 | /// 185 | /// @param s the signal to wrap 186 | /// 187 | poll_signal_ref& operator=(native_pointer s) noexcept 188 | { 189 | m_signal_ptr = s; 190 | __ASSERT_NO_MSG(m_signal_ptr != nullptr); 191 | return *this; 192 | } 193 | 194 | /// 195 | /// @brief create a wrapper around a k_poll_signal 196 | /// 197 | /// @param s the signal to wrap 198 | /// 199 | template 200 | poll_signal_ref& operator=(T_PollSignal& s) noexcept 201 | { 202 | m_signal_ptr = s.native_handle(); 203 | __ASSERT_NO_MSG(m_signal_ptr != nullptr); 204 | return *this; 205 | } 206 | 207 | /// 208 | /// @brief get the native k_poll_signal handle 209 | /// 210 | /// @return pointer to a k_poll_signal 211 | /// 212 | auto native_handle() noexcept -> native_pointer 213 | { 214 | return m_signal_ptr; 215 | } 216 | 217 | /// 218 | /// @brief get the native k_poll_signal handle 219 | /// 220 | /// @return pointer to a k_poll_signal 221 | /// 222 | auto native_handle() const noexcept -> native_const_pointer 223 | { 224 | return m_signal_ptr; 225 | } 226 | private: 227 | native_pointer m_signal_ptr{ nullptr }; 228 | public: 229 | poll_signal_ref() = delete; 230 | }; 231 | 232 | } // namespace zpp 233 | 234 | #endif // CONFIG_POLL 235 | 236 | #endif // ZPP_INCLUDE_ZPP_POLL_SIGNAL_HPP 237 | -------------------------------------------------------------------------------- /include/zpp/sched.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019 Erwin Rol 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | 7 | #ifndef ZPP_INCLUDE_ZPP_SCHED_HPP 8 | #define ZPP_INCLUDE_ZPP_SCHED_HPP 9 | 10 | #include 11 | #include 12 | 13 | namespace zpp { 14 | 15 | /// 16 | /// @brief Lock the scheduler. 17 | /// 18 | inline void sched_lock() noexcept 19 | { 20 | k_sched_lock(); 21 | } 22 | 23 | /// 24 | /// @brief Unlock the scheduler. 25 | /// 26 | inline void sched_unlock() noexcept 27 | { 28 | k_sched_unlock(); 29 | } 30 | 31 | /// 32 | /// @brief Guard to automatically lock/unlock scheduler. 33 | /// 34 | class sched_lock_guard { 35 | public: 36 | /// 37 | /// @brief Default constructor that calls scheck_lock() 38 | /// 39 | sched_lock_guard() noexcept 40 | { 41 | sched_lock(); 42 | } 43 | 44 | /// 45 | /// @brief Destructor that calls sched_unlock() 46 | /// 47 | ~sched_lock_guard() 48 | { 49 | sched_unlock(); 50 | } 51 | public: 52 | sched_lock_guard(const sched_lock_guard&) = delete; 53 | sched_lock_guard& operator=(const sched_lock_guard&) = delete; 54 | sched_lock_guard(sched_lock_guard&&) noexcept = delete; 55 | sched_lock_guard& operator=(sched_lock_guard&&) noexcept = delete; 56 | }; 57 | 58 | } // namespace zpp 59 | 60 | #endif // ZPP_INCLUDE_ZPP_SCHED_HPP 61 | -------------------------------------------------------------------------------- /include/zpp/sem.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019 Erwin Rol 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | 7 | #ifndef ZPP_INCLUDE_ZPP_SEM_HPP 8 | #define ZPP_INCLUDE_ZPP_SEM_HPP 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | namespace zpp { 19 | 20 | /// 21 | /// @brief Counting semaphore base class 22 | /// 23 | template 24 | class sem_base 25 | { 26 | public: 27 | using native_type = struct k_sem; 28 | using native_pointer = native_type*; 29 | using native_const_pointer = native_type const *; 30 | 31 | /// 32 | /// @brief Type used as counter 33 | /// 34 | using counter_type = uint32_t; 35 | 36 | /// 37 | /// @brief Maximum value of the counter 38 | /// 39 | constexpr static counter_type max_count = 40 | std::numeric_limits::max(); 41 | protected: 42 | /// 43 | /// @brief Default constructor, only allowed derived objects 44 | /// 45 | constexpr sem_base() noexcept 46 | { 47 | } 48 | public: 49 | /// 50 | /// @brief Take the semaphore waiting forever 51 | /// 52 | /// @return true when semaphore was taken 53 | /// 54 | [[nodiscard]] bool take() noexcept 55 | { 56 | if (k_sem_take(native_handle(), K_FOREVER) == 0) { 57 | return true; 58 | } else { 59 | return false; 60 | } 61 | } 62 | 63 | /// 64 | /// @brief Try to take the semaphore without waiting 65 | /// 66 | /// @return true when semaphore was taken 67 | /// 68 | [[nodiscard]] bool try_take() noexcept 69 | { 70 | if (k_sem_take(native_handle(), K_NO_WAIT) == 0) { 71 | return true; 72 | } else { 73 | return false; 74 | } 75 | } 76 | 77 | /// 78 | /// @brief Try to take the semaphore waiting a certain timeout 79 | /// 80 | /// @param timeout_duration The timeout to wait before giving up 81 | /// 82 | /// @return true when semaphore was taken 83 | /// 84 | template 85 | [[nodiscard]] bool 86 | try_take_for(const std::chrono::duration& 87 | timeout_duration) noexcept 88 | { 89 | if (k_sem_take(native_handle(), to_timeout(timeout_duration)) == 0) { 90 | return true; 91 | } else { 92 | return false; 93 | } 94 | } 95 | 96 | /// 97 | /// @brief Give the semaphore. 98 | /// 99 | void give() noexcept 100 | { 101 | k_sem_give(native_handle()); 102 | } 103 | 104 | /// 105 | /// @brief Reset the semaphore counter to zero. 106 | /// 107 | void reset() noexcept 108 | { 109 | k_sem_reset(native_handle()); 110 | } 111 | 112 | /// 113 | /// @brief Get current semaphore count 114 | /// 115 | /// @return The current semaphore count. 116 | /// 117 | counter_type count() noexcept 118 | { 119 | return k_sem_count_get(native_handle()); 120 | } 121 | 122 | /// 123 | /// @brief Give the semaphore. 124 | /// 125 | void operator++(int) noexcept 126 | { 127 | give(); 128 | } 129 | 130 | /// 131 | /// @brief Take the semaphore waiting forever 132 | /// 133 | void operator--(int) noexcept 134 | { 135 | while (!take()) { 136 | this_thread::yield(); 137 | } 138 | } 139 | 140 | /// 141 | /// @brief Give the semaphore n times. 142 | /// 143 | /// @param n The number of times to give the semaphore 144 | /// 145 | void operator+=(int n) noexcept 146 | { 147 | while (n-- > 0) { 148 | give(); 149 | } 150 | } 151 | 152 | /// 153 | /// @brief Take the semaphore n times, waiting forever. 154 | /// 155 | /// @param n The number of times to take the semaphore 156 | /// 157 | void operator-=(int n) noexcept 158 | { 159 | while (n-- > 0) { 160 | while (!take()) { 161 | this_thread::yield(); 162 | } 163 | } 164 | } 165 | 166 | /// 167 | /// @brief get the native zephyr sem handle. 168 | /// 169 | /// @return A pointer to the zephyr k_sem. 170 | /// 171 | auto native_handle() noexcept -> native_pointer 172 | { 173 | return static_cast(this)->native_handle(); 174 | } 175 | 176 | /// 177 | /// @brief get the native zephyr sem handle. 178 | /// 179 | /// @return A pointer to the zephyr k_sem. 180 | /// 181 | auto native_handle() const noexcept -> native_const_pointer 182 | { 183 | return static_cast(this)->native_handle(); 184 | } 185 | public: 186 | sem_base(const sem_base&) = delete; 187 | sem_base(sem_base&&) = delete; 188 | sem_base& operator=(const sem_base&) = delete; 189 | sem_base& operator=(sem_base&&) = delete; 190 | }; 191 | 192 | 193 | /// 194 | /// @brief A counting semaphore class. 195 | /// 196 | class sem : public sem_base { 197 | public: 198 | /// 199 | /// @brief Constructor initializing initial count and count limit. 200 | /// 201 | /// @param initial_count The initial count value for the semaphore 202 | /// @param count_limit The maxium count the semaphore can have 203 | /// 204 | sem(counter_type initial_count, counter_type count_limit) noexcept 205 | { 206 | k_sem_init(&m_sem, initial_count, count_limit); 207 | } 208 | 209 | /// 210 | /// @brief Constructor initializing initial count. 211 | /// 212 | /// Contructor initializing initial count to @a initial_count and 213 | /// the maxium count limit to max_count. 214 | /// 215 | /// @param initial_count The initial count value for the semaphore 216 | /// 217 | explicit sem(counter_type initial_count) noexcept 218 | : sem(initial_count, max_count) 219 | { 220 | } 221 | 222 | /// 223 | /// @brief Default onstructor. 224 | /// 225 | /// Contructor initializing initial count to 0 and the maxium count 226 | /// limit to max_count. 227 | // 228 | sem() noexcept 229 | : sem(0, max_count) 230 | { 231 | } 232 | 233 | /// 234 | /// @brief get the native zephyr mutex handle. 235 | /// 236 | /// @return A pointer to the zephyr k_mutex. 237 | /// 238 | constexpr auto native_handle() noexcept -> native_pointer 239 | { 240 | return &m_sem; 241 | } 242 | 243 | /// 244 | /// @brief get the native zephyr mutex handle. 245 | /// 246 | /// @return A pointer to the zephyr k_mutex. 247 | /// 248 | constexpr auto native_handle() const noexcept -> native_const_pointer 249 | { 250 | return &m_sem; 251 | } 252 | private: 253 | native_type m_sem; 254 | public: 255 | sem(const sem&) = delete; 256 | sem(sem&&) = delete; 257 | sem& operator=(const sem&) = delete; 258 | sem& operator=(sem&&) = delete; 259 | }; 260 | 261 | /// 262 | /// @brief A counting semaphore class borrowing the native sem. 263 | /// 264 | class sem_ref : public sem_base { 265 | public: 266 | /// 267 | /// @brief Construct a sem using a native k_sem* 268 | /// 269 | /// @param s The k_sem to use. @a s must already be 270 | /// initialized and will not be freed. 271 | /// 272 | explicit constexpr sem_ref(native_pointer s) noexcept 273 | : m_sem_ptr(s) 274 | { 275 | __ASSERT_NO_MSG(m_sem_ptr != nullptr); 276 | } 277 | 278 | /// 279 | /// @brief Construct a sem using a native k_sem* 280 | /// 281 | /// @param s The k_sem to use. @a s must already be 282 | /// initialized and will not be freed. 283 | /// 284 | template 285 | explicit constexpr sem_ref(T_Sem& s) noexcept 286 | : m_sem_ptr(s.native_handle()) 287 | { 288 | __ASSERT_NO_MSG(m_sem_ptr != nullptr); 289 | } 290 | 291 | /// 292 | /// @brief Assign a sem using a native k_sem* 293 | /// 294 | /// @param s The k_sem to use. @a s must already be 295 | /// initialized and will not be freed. 296 | /// 297 | /// @return reference to this object 298 | /// 299 | constexpr sem_ref& operator=(native_pointer s) noexcept 300 | { 301 | m_sem_ptr = s; 302 | __ASSERT_NO_MSG(m_sem_ptr != nullptr); 303 | return *this; 304 | } 305 | 306 | /// 307 | /// @brief Assign a sem using another sem object 308 | /// 309 | /// @param s The sem to use. @a s must already be 310 | /// initialized and will not be freed. 311 | /// 312 | /// @return reference to this object 313 | /// 314 | template 315 | constexpr sem_ref& operator=(T_Sem& s) noexcept 316 | { 317 | m_sem_ptr = s.native_handle(); 318 | __ASSERT_NO_MSG(m_sem_ptr != nullptr); 319 | return *this; 320 | } 321 | 322 | /// 323 | /// @brief get the native zephyr sem handle. 324 | /// 325 | /// @return A pointer to the zephyr k_sem. 326 | /// 327 | constexpr auto native_handle() noexcept -> native_pointer 328 | { 329 | __ASSERT_NO_MSG(m_sem_ptr != nullptr); 330 | 331 | return m_sem_ptr; 332 | } 333 | 334 | /// 335 | /// @brief get the native zephyr sem handle. 336 | /// 337 | /// @return A pointer to the zephyr k_sem. 338 | /// 339 | constexpr auto native_handle() const noexcept -> native_const_pointer 340 | { 341 | __ASSERT_NO_MSG(m_sem_ptr != nullptr); 342 | 343 | return m_sem_ptr; 344 | } 345 | private: 346 | native_pointer m_sem_ptr{ nullptr }; 347 | public: 348 | sem_ref() = delete; 349 | }; 350 | 351 | } // namespace zpp 352 | 353 | #endif // ZPP_INCLUDE_ZPP_SEM_HPP 354 | -------------------------------------------------------------------------------- /include/zpp/sys_mutex.hpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (c) 2019 Erwin Rol 3 | /// 4 | /// SPDX-License-Identifier: Apache-2.0 5 | /// 6 | 7 | #ifndef ZPP_INCLUDE_ZPP_SYS_MUTEX_HPP 8 | #define ZPP_INCLUDE_ZPP_SYS_MUTEX_HPP 9 | 10 | #ifdef CONFIG_USERSPACE 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | namespace zpp { 18 | 19 | /// 20 | /// @brief A userspace mutex class. 21 | /// 22 | template 23 | class sys_mutex_base 24 | { 25 | public: 26 | using native_type = struct sys_mutex; 27 | using native_pointer = native_type*; 28 | using native_cont_pointer = native_type const *; 29 | protected: 30 | /// 31 | /// @brief Protected default contructor so only derived objects can be created 32 | /// 33 | constexpr sys_mutex_base() noexcept = default; 34 | 35 | public: 36 | /// 37 | /// @brief Lock the mutex. Wait for ever until it is locked. 38 | /// 39 | /// @return true if successfully locked. 40 | /// 41 | [[nodiscard]] bool lock() noexcept 42 | { 43 | if (sys_mutex_lock(native_handle(), K_FOREVER) == 0) { 44 | return true; 45 | } else { 46 | return false; 47 | } 48 | } 49 | 50 | /// 51 | /// @brief Try locking the mutex without waiting. 52 | /// 53 | /// @return true if successfully locked. 54 | /// 55 | [[nodiscard]] bool try_lock() noexcept 56 | { 57 | if (sys_mutex_lock(native_handle(), K_NO_WAIT) == 0) { 58 | return true; 59 | } else { 60 | return false; 61 | } 62 | } 63 | 64 | /// 65 | /// @brief Try locking the mutex with a timeout. 66 | /// 67 | /// @param timeout The time to wait before returning 68 | /// 69 | /// @return true if successfully locked. 70 | /// 71 | template 72 | [[nodiscard]] bool 73 | try_lock_for(const std::chrono::duration& timeout) noexcept 74 | { 75 | using namespace std::chrono; 76 | 77 | if (sys_mutex_lock(native_handle(), to_timeout(timeout)) == 0) 78 | { 79 | return true; 80 | } else { 81 | return false; 82 | } 83 | } 84 | 85 | /// 86 | /// @brief Unlock the mutex. 87 | /// 88 | [[nodiscard]] bool unlock() noexcept 89 | { 90 | if (sys_mutex_unlock(native_handle()) == 0) { 91 | return true; 92 | } else { 93 | return false; 94 | } 95 | } 96 | 97 | /// 98 | /// @brief get the native zephyr mutex handle. 99 | /// 100 | /// @return A pointer to the zephyr sys_mutex. 101 | /// 102 | auto native_handle() noexcept -> native_pointer 103 | { 104 | return static_cast(this)->native_handle(); 105 | } 106 | 107 | /// 108 | /// @brief get the native zephyr mutex handle. 109 | /// 110 | /// @return A pointer to the zephyr sys_mutex. 111 | /// 112 | auto native_handle() const noexcept -> native_const_pointer 113 | { 114 | return static_cast(this)->native_handle(); 115 | } 116 | public: 117 | sys_mutex_base(const sys_mutex_base&) = delete; 118 | sys_mutex_base(sys_mutex_base&&) = delete; 119 | sys_mutex_base& operator=(const sys_mutex_base&) = delete; 120 | sys_mutex_base& operator=(sys_mutex_base&&) = delete; 121 | }; 122 | 123 | /// 124 | /// @brief A recursive mutex class. 125 | /// 126 | class sys_mutex : public sys_mutex_base { 127 | public: 128 | /// 129 | /// @brief Default constructor 130 | /// 131 | sys_mutex() noexcept 132 | { 133 | sys_mutex_init(&m_mutex); 134 | } 135 | 136 | /// 137 | /// @brief get the native zephyr mutex handle. 138 | /// 139 | /// @return A pointer to the zephyr sys_mutex. 140 | /// 141 | constexpr auto native_handle() noexcept -> native_pointer 142 | { 143 | return &m_mutex; 144 | } 145 | 146 | /// 147 | /// @brief get the native zephyr mutex handle. 148 | /// 149 | /// @return A pointer to the zephyr sys_mutex. 150 | /// 151 | constexpr auto native_handle() const noexcept -> native_const_pointer 152 | { 153 | return &m_mutex; 154 | } 155 | private: 156 | native_type m_mutex; 157 | public: 158 | sys_mutex(const sys_mutex&) = delete; 159 | sys_mutex(sys_mutex&&) = delete; 160 | sys_mutex& operator=(const sys_mutex&) = delete; 161 | sys_mutex& operator=(sys_mutex&&) = delete; 162 | }; 163 | 164 | /// 165 | /// @brief A recursive mutex class borrowing the native mutex. 166 | /// 167 | class sys_mutex_ref : public sys_mutex_base { 168 | public: 169 | /// 170 | /// @brief Construct a mutex using a native sys_mutex* 171 | /// 172 | /// @param m The sys_mutex to use. @a m must already be 173 | /// initialized and will not be freed. 174 | /// 175 | explicit constexpr sys_mutex_ref(native_pointer m) noexcept 176 | : m_mutex_ptr(m) 177 | { 178 | __ASSERT_NO_MSG(m_mutex_ptr != nullptr); 179 | } 180 | 181 | /// 182 | /// @brief Construct a mutex using a native sys_mutex* 183 | /// 184 | /// @param m The sys_mutex to use. @a m must already be 185 | /// initialized and will not be freed. 186 | /// 187 | template 188 | explicit constexpr sys_mutex_ref(T_Mutex& m) noexcept 189 | : m_mutex_ptr(m.native_handle()) 190 | { 191 | __ASSERT_NO_MSG(m_mutex_ptr != nullptr); 192 | } 193 | 194 | /// 195 | /// @brief Construct a mutex using a native sys_mutex* 196 | /// 197 | /// @param m The sys_mutex to use. @a m must already be 198 | /// initialized and will not be freed. 199 | /// 200 | constexpr sys_mutex_ref& operator=(native_pointer m) noexcept 201 | { 202 | m_mutex_ptr = m; 203 | __ASSERT_NO_MSG(m_mutex_ptr != nullptr); 204 | return *this; 205 | } 206 | 207 | /// 208 | /// @brief Construct a mutex using a native sys_mutex* 209 | /// 210 | /// @param m The sys_mutex to use. @a m must already be 211 | /// initialized and will not be freed. 212 | /// 213 | template 214 | constexpr sys_mutex_ref& operator=(T_Mutex& m) noexcept 215 | { 216 | m_mutex_ptr = m.native_handle(); 217 | __ASSERT_NO_MSG(m_mutex_ptr != nullptr); 218 | return *this; 219 | } 220 | 221 | /// 222 | /// @brief get the native zephyr mutex handle. 223 | /// 224 | /// @return A pointer to the zephyr sys_mutex. 225 | /// 226 | constexpr auto native_handle() noexcept -> native_pointer 227 | { 228 | return m_mutex_ptr; 229 | } 230 | 231 | /// 232 | /// @brief get the native zephyr mutex handle. 233 | /// 234 | /// @return A pointer to the zephyr sys_mutex. 235 | /// 236 | constexpr auto native_handle() const noexcept -> native_const_pointer 237 | { 238 | return m_mutex_ptr; 239 | } 240 | private: 241 | native_pointer m_mutex_ptr{ nullptr }; 242 | public: 243 | sys_mutex_ref() = delete; 244 | }; 245 | 246 | } // namespace zpp 247 | 248 | #endif // CONFIG_USERSPACE 249 | 250 | #endif // ZPP_INCLUDE_ZPP_SYS_MUTEX_HPP 251 | -------------------------------------------------------------------------------- /include/zpp/thread_attr.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019 Erwin Rol 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | 7 | #ifndef ZPP_INCLUDE_ZPP_THREAD_ATTR_HPP 8 | #define ZPP_INCLUDE_ZPP_THREAD_ATTR_HPP 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | namespace zpp { 19 | 20 | enum class thread_suspend { yes, no }; 21 | enum class thread_essential { yes, no }; 22 | enum class thread_user { yes, no }; 23 | enum class thread_inherit_perms { yes, no }; 24 | enum class thread_fp_regs { yes, no }; 25 | enum class thread_sse_regs { yes, no }; 26 | 27 | template 28 | struct thread_start_delay { 29 | std::chrono::duration t; 30 | }; 31 | 32 | /// 33 | /// @brief Thread creation attributes. 34 | /// 35 | class thread_attr { 36 | public: 37 | thread_attr(const thread_attr&) noexcept = default; 38 | thread_attr(thread_attr&&) noexcept = default; 39 | thread_attr& operator=(const thread_attr&) noexcept = default; 40 | thread_attr& operator=(thread_attr&&) noexcept = default; 41 | 42 | /// 43 | /// @brief Constructor taking a variable number of attributes 44 | /// 45 | /// Contructor that initializes the thread creation attributes 46 | /// based on the @a args arguments being passed. The order of 47 | /// the arguments does not matter. Arguments must be of a Type 48 | /// that has a coresponding set(Type) function. 49 | /// 50 | /// @param args The attributes to set. 51 | /// 52 | template 53 | constexpr explicit thread_attr(T_Args&&... args) noexcept 54 | { 55 | set(std::forward(args)...); 56 | } 57 | 58 | template 59 | constexpr void set(T_FirstArg&& first, T_Args&&... rest) noexcept 60 | { 61 | set(std::forward(first)); 62 | set(std::forward(rest)...); 63 | } 64 | 65 | constexpr void set() const noexcept 66 | { 67 | } 68 | 69 | /// 70 | /// @brief Set the thread priority 71 | /// 72 | /// @param prio The thread priority 73 | /// 74 | constexpr void set(thread_prio prio) noexcept 75 | { 76 | m_prio = prio; 77 | } 78 | 79 | /// 80 | /// @brief Set the thread start delay 81 | /// 82 | /// @param delay The thread start delay 83 | /// 84 | template 85 | constexpr void 86 | set(const thread_start_delay& delay) noexcept 87 | { 88 | using namespace std::chrono; 89 | 90 | //auto ms = duration_cast(delay.t); 91 | 92 | if (delay.t <= decltype(delay.t)::zero()) { 93 | m_delay = K_NO_WAIT; 94 | } else { 95 | m_delay = to_tick(delay.t); 96 | } 97 | } 98 | 99 | /// 100 | /// @brief Set the thread start suspended flag 101 | /// 102 | /// @param v The thread start suspended flag 103 | /// 104 | constexpr void set(thread_suspend v) noexcept 105 | { 106 | if (v == thread_suspend::yes) { 107 | m_delay = K_FOREVER; 108 | } else { 109 | if (K_TIMEOUT_EQ(m_delay, K_FOREVER)) { 110 | m_delay = K_NO_WAIT; 111 | } 112 | } 113 | } 114 | 115 | /// 116 | /// @brief Set the thread essential flag 117 | /// 118 | /// @param v The thread essential flag 119 | /// 120 | constexpr void set(thread_essential v) noexcept 121 | { 122 | if (v == thread_essential::yes) { 123 | m_options |= K_ESSENTIAL; 124 | } else { 125 | m_options &= ~K_ESSENTIAL; 126 | } 127 | } 128 | 129 | /// 130 | /// @brief Set the thread user flag 131 | /// 132 | /// @param v The thread user flag 133 | /// 134 | constexpr void set(thread_user v) noexcept 135 | { 136 | if (v == thread_user::yes) { 137 | m_options |= K_USER; 138 | } else { 139 | m_options &= ~K_USER; 140 | } 141 | } 142 | 143 | /// 144 | /// @brief Set the thread inherit permisions flag 145 | /// 146 | /// @param v The thread inherit permissions flag 147 | /// 148 | constexpr void set(thread_inherit_perms v) noexcept 149 | { 150 | if (v == thread_inherit_perms::yes) { 151 | m_options |= K_INHERIT_PERMS; 152 | } else { 153 | m_options &= ~K_INHERIT_PERMS; 154 | } 155 | } 156 | 157 | /// 158 | /// @brief Set the thread FP regs flag 159 | /// 160 | /// @param v The thread FP regs flag 161 | /// 162 | constexpr void set(thread_fp_regs v) noexcept 163 | { 164 | #ifdef K_FP_REGS 165 | if (v == thread_fp_regs::yes) { 166 | m_options |= K_FP_REGS; 167 | } else { 168 | m_options &= ~K_FP_REGS; 169 | } 170 | #endif 171 | } 172 | 173 | /// 174 | /// @brief Set the thread SSE regs flag 175 | /// 176 | /// @param v The thread SSE regs flag 177 | /// 178 | constexpr void set(thread_sse_regs v) noexcept 179 | { 180 | #ifdef K_SSE_REGS 181 | if (v == thread_sse_regs::yes) { 182 | m_options |= K_SSE_REGS; 183 | } else { 184 | m_options &= ~K_SSE_REGS; 185 | } 186 | #endif 187 | } 188 | 189 | /// 190 | /// @brief get the Zephyr native delay value 191 | /// 192 | /// @return The native delay value 193 | /// 194 | constexpr auto native_delay() const noexcept 195 | { 196 | return m_delay; 197 | } 198 | 199 | /// 200 | /// @brief get the Zephyr native priority value 201 | /// 202 | /// @return The native priority value 203 | /// 204 | constexpr auto native_prio() const noexcept 205 | { 206 | return m_prio.native_value(); 207 | } 208 | 209 | /// 210 | /// @brief get the Zephyr native options value 211 | /// 212 | /// @return The native options value 213 | /// 214 | constexpr auto native_options() const noexcept 215 | { 216 | return m_options; 217 | } 218 | private: 219 | thread_prio m_prio{ }; 220 | uint32_t m_options{ 0 }; 221 | k_timeout_t m_delay{ K_NO_WAIT }; 222 | }; 223 | 224 | } // namespace zpp 225 | 226 | #endif // ZPP_INCLUDE_ZPP_THREAD_ATTR_HPP 227 | -------------------------------------------------------------------------------- /include/zpp/thread_data.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019 Erwin Rol 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | 7 | #ifndef ZPP_INCLUDE_ZPP_THREAD_DATA_HPP 8 | #define ZPP_INCLUDE_ZPP_THREAD_DATA_HPP 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace zpp { 15 | 16 | /// 17 | /// @brief thread_data holds the stack and thread control block memory 18 | /// 19 | class thread_data { 20 | public: 21 | // 22 | // @brief Default constructor 23 | // 24 | constexpr thread_data() noexcept = default; 25 | 26 | constexpr auto native_handle() noexcept -> struct k_thread* 27 | { 28 | return &m_thread_data; 29 | } 30 | private: 31 | struct k_thread m_thread_data; 32 | public: 33 | thread_data(const thread_data&) = delete; 34 | thread_data(thread_data&&) = delete; 35 | thread_data& operator=(const thread_data&) = delete; 36 | thread_data& operator=(thread_data&&) = delete; 37 | }; 38 | 39 | } // namespace zpp 40 | 41 | #endif // ZPP_INCLUDE_ZPP_THREAD_DATA_HPP 42 | -------------------------------------------------------------------------------- /include/zpp/thread_id.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019 Erwin Rol 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | 7 | #ifndef ZPP_INCLUDE_ZPP_THREAD_ID_HPP 8 | #define ZPP_INCLUDE_ZPP_THREAD_ID_HPP 9 | 10 | #include 11 | #include 12 | 13 | namespace zpp { 14 | 15 | /// 16 | /// @brief Thead ID 17 | /// 18 | class thread_id { 19 | public: 20 | thread_id(const thread_id&) noexcept = default; 21 | thread_id(thread_id&&) noexcept = default; 22 | thread_id& operator=(const thread_id&) noexcept = default; 23 | thread_id& operator=(thread_id&&) noexcept = default; 24 | 25 | /// 26 | /// @brief Default constructor inializing ID to K_ANY 27 | /// 28 | constexpr thread_id() noexcept 29 | { 30 | } 31 | 32 | /// 33 | /// @brief Constructor inializing ID to @a tid 34 | /// 35 | /// @param tid The ID to use for inialization 36 | /// 37 | constexpr explicit thread_id(k_tid_t tid) noexcept 38 | : m_tid(tid) 39 | { 40 | } 41 | 42 | /// 43 | /// @brief test if the ID is valid 44 | /// 45 | /// @return false if the ID equals K_ANY 46 | /// 47 | constexpr explicit operator bool() const noexcept 48 | { 49 | return m_tid != K_ANY; 50 | } 51 | 52 | /// 53 | /// @brief Create an ID with value K_ANY 54 | /// 55 | /// @return An ID with value K_ANY 56 | /// 57 | constexpr static thread_id any() noexcept 58 | { 59 | return thread_id(K_ANY); 60 | } 61 | 62 | /// 63 | /// @brief Get the Zephyr native ID value. 64 | /// 65 | /// @return The native ID value 66 | /// 67 | constexpr auto native_handle() const noexcept 68 | { 69 | return m_tid; 70 | } 71 | private: 72 | k_tid_t m_tid { K_ANY }; 73 | }; 74 | 75 | /// 76 | /// @brief Compare if two ID are equal 77 | /// 78 | /// @param lhs Left hand side for comparison 79 | /// @param rhs Right hand side for comparison 80 | /// 81 | /// @return true is @a lhs and @a rhs are equal 82 | /// 83 | constexpr bool 84 | operator==(const thread_id& lhs, const thread_id& rhs) noexcept 85 | { 86 | return (lhs.native_handle() == rhs.native_handle()); 87 | } 88 | 89 | /// 90 | /// @brief Compare if two ID are not equal 91 | /// 92 | /// @param lhs Left hand side for comparison 93 | /// @param rhs Right hand side for comparison 94 | /// 95 | /// @return true is @a lhs and @a rhs are not equal 96 | /// 97 | constexpr bool 98 | operator!=(const thread_id& lhs, const thread_id& rhs) noexcept 99 | { 100 | return (lhs.native_handle() != rhs.native_handle()); 101 | } 102 | 103 | /// 104 | /// @brief Helper to output the ID with zpp::print("{}", id) 105 | /// 106 | /// @param id The ID to print 107 | /// 108 | inline void 109 | print_arg(thread_id id) noexcept 110 | { 111 | printk("%p", id.native_handle()); 112 | } 113 | 114 | } // namespace zpp 115 | 116 | #endif // ZPP_INCLUDE_ZPP_THREAD_ID_HPP 117 | -------------------------------------------------------------------------------- /include/zpp/thread_prio.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019 Erwin Rol 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | 7 | #ifndef ZPP_INCLUDE_ZPP_THREAD_PRIO_HPP 8 | #define ZPP_INCLUDE_ZPP_THREAD_PRIO_HPP 9 | 10 | #include 11 | #include 12 | 13 | namespace zpp { 14 | 15 | /// 16 | /// @brief Thread priority 17 | /// 18 | class thread_prio { 19 | public: 20 | /// 21 | /// @brief Default constructor initializing priority to zero 22 | /// 23 | constexpr thread_prio() noexcept 24 | { 25 | } 26 | 27 | /// 28 | /// @brief Constructor initializing priority to @a prio 29 | /// 30 | /// @param prio The priority value to use for initialization 31 | /// 32 | constexpr explicit thread_prio(int prio) noexcept 33 | : m_prio(prio) 34 | { 35 | if (m_prio < -CONFIG_NUM_COOP_PRIORITIES) { 36 | m_prio = -CONFIG_NUM_COOP_PRIORITIES; 37 | } else if (m_prio > (CONFIG_NUM_PREEMPT_PRIORITIES - 1)) { 38 | m_prio = CONFIG_NUM_PREEMPT_PRIORITIES - 1; 39 | } 40 | 41 | __ASSERT_NO_MSG(m_prio == prio); 42 | } 43 | 44 | /// 45 | /// @brief Get the Zephyr native priority value 46 | /// 47 | /// @return the Zephyr native priority value 48 | /// 49 | constexpr int native_value() const noexcept 50 | { 51 | return m_prio; 52 | } 53 | 54 | /// 55 | /// @brief Get the most prior cooperative priority 56 | /// 57 | /// @return The most prior cooperative priority 58 | /// 59 | static constexpr thread_prio highest_coop() noexcept 60 | { 61 | return thread_prio(-CONFIG_NUM_COOP_PRIORITIES); 62 | } 63 | 64 | /// 65 | /// @brief Get the least prior cooperative priority 66 | /// 67 | /// @return The least prior cooperative priority 68 | /// 69 | static constexpr thread_prio lowest_coop() noexcept 70 | { 71 | return thread_prio(-1); 72 | } 73 | 74 | /// 75 | /// @brief Get the most prior preemptive priority 76 | /// 77 | /// @return The most prior preemptive priority 78 | /// 79 | static constexpr thread_prio highest_preempt() noexcept 80 | { 81 | return thread_prio(0); 82 | } 83 | 84 | /// 85 | /// @brief Get the least prior preemptive priority 86 | /// 87 | /// @return The least prior preemptive priority 88 | /// 89 | static constexpr thread_prio lowest_preempt() noexcept 90 | { 91 | return thread_prio(CONFIG_NUM_PREEMPT_PRIORITIES - 1); 92 | } 93 | 94 | /// 95 | /// @brief Get the minium coop numeric value 96 | /// 97 | /// The minium coop numric value is the highest 98 | /// thread priority 99 | /// 100 | /// @return The smallest numeric value 101 | /// 102 | static constexpr thread_prio min_coop_numeric() noexcept 103 | { 104 | return highest_coop(); 105 | } 106 | 107 | /// 108 | /// @brief Get the minium coop numeric value 109 | /// 110 | /// The maxium coop numric value is the lowest 111 | /// coop thread priority 112 | /// 113 | /// @return The smallest numeric value 114 | /// 115 | static constexpr thread_prio max_coop_numeric() noexcept 116 | { 117 | return lowest_coop(); 118 | } 119 | 120 | /// 121 | /// @brief Get the minium preempt numeric value 122 | /// 123 | /// The minium preempt numric value is the highest 124 | /// preempt thread priority 125 | /// 126 | /// @return The smallest numeric value 127 | /// 128 | static constexpr thread_prio min_preempt_numeric() noexcept 129 | { 130 | return highest_preempt(); 131 | } 132 | 133 | /// 134 | /// @brief Get the minium preempt numeric value 135 | /// 136 | /// The maxium coop numric value is the lowest 137 | /// thread priority 138 | /// 139 | /// @return The largest numeric value 140 | /// 141 | static constexpr thread_prio max_preempt_numeric() noexcept 142 | { 143 | return lowest_preempt(); 144 | } 145 | 146 | /// 147 | /// @brief Get the minium numeric value 148 | /// 149 | /// @return The smallest numeric value 150 | /// 151 | static constexpr thread_prio min_numeric() noexcept 152 | { 153 | return min_coop_numeric(); 154 | } 155 | 156 | /// 157 | /// @brief Get the maxium numeric value 158 | /// 159 | /// @return The highest numeric value 160 | /// 161 | static constexpr thread_prio max_numeric() noexcept 162 | { 163 | return max_preempt_numeric(); 164 | } 165 | 166 | 167 | /// 168 | /// @brief Create a cooperative priority value 169 | /// 170 | /// @param prio the value, from 0 to highest_coop 171 | /// 172 | /// @return The priority value 173 | /// 174 | static constexpr thread_prio coop(int prio) noexcept 175 | { 176 | return thread_prio( lowest_coop().native_value() - prio ); 177 | } 178 | 179 | /// 180 | /// @brief Create a preemptive priority value 181 | /// 182 | /// @param prio the value, from 0 to highest_preempt 183 | /// 184 | /// @return The priority value 185 | /// 186 | static constexpr thread_prio preempt(int prio) noexcept 187 | { 188 | return (prio >= CONFIG_NUM_PREEMPT_PRIORITIES) ? 189 | highest_preempt() : 190 | thread_prio( lowest_preempt().native_value() - prio); 191 | } 192 | private: 193 | int m_prio { 0 }; 194 | }; 195 | 196 | /// 197 | /// @brief Compare if two priorities are equal 198 | /// 199 | /// @param lhs Left hand side for comparison 200 | /// @param rhs Right hand side for comparison 201 | /// 202 | /// @return true is @a lhs and @a rhs are equal 203 | /// 204 | constexpr bool 205 | operator==(const thread_prio& lhs, const thread_prio& rhs) noexcept 206 | { 207 | return (lhs.native_value() == rhs.native_value()); 208 | } 209 | 210 | /// 211 | /// @brief Compare if two priorities are not equal 212 | /// 213 | /// @param lhs Left hand side for comparison 214 | /// @param rhs Right hand side for comparison 215 | /// 216 | /// @return true is @a lhs and @a rhs are not equal 217 | /// 218 | constexpr bool 219 | operator!=(const thread_prio& lhs, const thread_prio& rhs) noexcept 220 | { 221 | return (lhs.native_value() != rhs.native_value()); 222 | } 223 | 224 | /// 225 | /// @brief Reduce priority by @a rhs 226 | /// 227 | /// @param lhs Left hand side for the operation 228 | /// @param rhs Right hand side for the operation 229 | /// 230 | /// @return A priority value that is @a rhs less prior than @a lhs 231 | /// 232 | constexpr thread_prio 233 | operator-(thread_prio lhs, int rhs) noexcept 234 | { 235 | return thread_prio(lhs.native_value() + rhs); 236 | } 237 | 238 | /// 239 | /// @brief Increase priority by @a rhs 240 | /// 241 | /// @param lhs Left hand side for the operation 242 | /// @param rhs Right hand side for the operation 243 | /// 244 | /// @return A priority value that is @a rhs more prior than @a lhs 245 | /// 246 | constexpr thread_prio 247 | operator+(thread_prio lhs, int rhs) noexcept 248 | { 249 | return thread_prio(lhs.native_value() - rhs); 250 | } 251 | 252 | /// 253 | /// @brief Helper to output the priority with zpp::print("{}", prio) 254 | /// 255 | /// @param prio The priority to print 256 | /// 257 | inline void print_arg(thread_prio prio) noexcept 258 | { 259 | printk("%d", prio.native_value()); 260 | } 261 | 262 | } // namespace zpp 263 | 264 | #endif // ZPP_INCLUDE_ZPP_THREAD_PRIO_HPP 265 | -------------------------------------------------------------------------------- /include/zpp/thread_stack.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2021 Erwin Rol 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | 7 | #ifndef ZPP_INCLUDE_ZPP_THREAD_STACK_HPP 8 | #define ZPP_INCLUDE_ZPP_THREAD_STACK_HPP 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace zpp { 15 | 16 | /// 17 | /// @brief thread_stack holds the stack and thread control block memory 18 | /// 19 | /// @param StackSize defines the stacksize in bytes 20 | /// 21 | class thread_stack { 22 | public: 23 | constexpr thread_stack(const thread_stack&) noexcept = default; 24 | constexpr thread_stack& operator=(const thread_stack&) noexcept = default; 25 | 26 | constexpr thread_stack(k_thread_stack_t* data, size_t size) noexcept 27 | : m_data(data) 28 | , m_size(size) 29 | { 30 | __ASSERT_NO_MSG(m_data != nullptr); 31 | } 32 | 33 | constexpr auto size() const noexcept 34 | { 35 | return m_size; 36 | } 37 | 38 | constexpr auto data() const noexcept 39 | { 40 | return m_data; 41 | } 42 | private: 43 | k_thread_stack_t* m_data; 44 | size_t m_size; 45 | public: 46 | thread_stack() = delete; 47 | }; 48 | 49 | #define ZPP_THREAD_STACK_DEFINE(sym, size) \ 50 | K_THREAD_STACK_DEFINE(sym##_native,(size)); \ 51 | consteval auto sym() noexcept { \ 52 | return zpp::thread_stack(sym##_native, size); \ 53 | } 54 | 55 | #define ZPP_THREAD_PINNED_STACK_DEFINE(sym, size) \ 56 | K_THREAD_PINNED_STACK_DEFINE(sym##_native,(size)); \ 57 | consteval auto sym() noexcept { \ 58 | return zpp::thread_stack(sym##_native, size); \ 59 | } 60 | 61 | #define ZPP_THREAD_STACK_ARRAY_DEFINE(sym, nmemb, size) \ 62 | K_THREAD_STACK_ARRAY_DEFINE(sym##_native, nmemb, size); \ 63 | constexpr auto sym(size_t n) noexcept { \ 64 | return zpp::thread_stack(sym##_native[n], size); \ 65 | } 66 | 67 | #define ZPP_THREAD_PINNED_STACK_ARRAY_DEFINE(sym, nmemb, size) \ 68 | K_THREAD_PINNED_STACK_ARRAY_DEFINE(sym##_native, nmemb, size); \ 69 | constexpr auto sym(size_t n) noexcept { \ 70 | return zpp::thread_stack(sym##_native[n], size); \ 71 | } 72 | 73 | 74 | #define ZPP_KERNEL_STACK_DEFINE(sym, size) \ 75 | K_KERNEL_STACK_DEFINE(sym##_native,(size)); \ 76 | consteval auto sym() noexcept { \ 77 | return zpp::thread_stack(sym##_native, size); \ 78 | } 79 | 80 | #define ZPP_KERNEL_PINNED_STACK_DEFINE(sym, size) \ 81 | K_KERNEL_PINNED_STACK_DEFINE(sym##_native,(size)); \ 82 | consteval auto sym() noexcept { \ 83 | return zpp::thread_stack(sym##_native, size); \ 84 | } 85 | 86 | #define ZPP_KERNEL_STACK_ARRAY_DEFINE(sym, nmemb, size) \ 87 | K_KERNEL_STACK_ARRAY_DEFINE(sym##_native, nmemb, size); \ 88 | constexpr auto sym(size_t n) noexcept { \ 89 | return zpp::thread_stack(sym##_native[n], size); \ 90 | } 91 | 92 | #define ZPP_KERNEL_PINNED_STACK_ARRAY_DEFINE(sym, nmemb, size) \ 93 | K_KERNEL_PINNED_STACK_ARRAY_DEFINE(sym##_native, nmemb, size); \ 94 | constexpr auto sym(size_t n) noexcept { \ 95 | return zpp::thread_stack(sym##_native[n], size); \ 96 | } 97 | 98 | } // namespace zpp 99 | 100 | #endif // ZPP_INCLUDE_ZPP_THREAD_STACK_HPP 101 | -------------------------------------------------------------------------------- /include/zpp/timer.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019 Erwin Rol 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | 7 | #ifndef ZPP_INCLUDE_ZPP_TIMER_HPP 8 | #define ZPP_INCLUDE_ZPP_TIMER_HPP 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | 19 | namespace zpp { 20 | 21 | /// 22 | /// @brief base class for the timer class 23 | /// 24 | class timer_base { 25 | protected: 26 | timer_base() noexcept 27 | { 28 | } 29 | public: 30 | /// 31 | /// @brief Destructor that stops the timer 32 | /// 33 | ~timer_base() 34 | { 35 | stop(); 36 | } 37 | 38 | /// 39 | /// @brief Start a timer with @a duration and @a period. 40 | /// 41 | /// @param duration The first time out 42 | /// @param period the time of the repeat period 43 | /// 44 | template 45 | void start(const std::chrono::duration& duration, 46 | const std::chrono::duration& period) noexcept 47 | { 48 | using namespace std::chrono; 49 | 50 | k_timer_start(&m_timer, to_timeout(duration), to_timeout(period)); 51 | } 52 | 53 | /// 54 | /// @brief Start a single shot timer with @a duration 55 | /// 56 | /// @param duration The timeout 57 | /// 58 | template 59 | void start(const std::chrono::duration& duration) noexcept 60 | { 61 | using namespace std::chrono; 62 | 63 | k_timer_start(&m_timer, to_timeout(duration), K_NO_WAIT); 64 | } 65 | 66 | /// 67 | /// @brief Stop the timer 68 | /// 69 | void stop () noexcept 70 | { 71 | k_timer_stop(&m_timer); 72 | } 73 | 74 | /// 75 | /// @brief get the timer status 76 | /// 77 | /// @return the timer status 78 | /// 79 | auto status() noexcept 80 | { 81 | return k_timer_status_get(&m_timer); 82 | } 83 | 84 | /// 85 | /// @brief sync with the timer 86 | /// 87 | auto sync() noexcept 88 | { 89 | return k_timer_status_sync(&m_timer); 90 | } 91 | 92 | /// 93 | /// @brief Get remaining time 94 | /// 95 | /// @return the remaining time 96 | /// 97 | std::chrono::nanoseconds remaining_time() noexcept 98 | { 99 | auto t = k_timer_remaining_ticks(&m_timer); 100 | return std::chrono::nanoseconds(k_ticks_to_ns_floor64(t)); 101 | } 102 | 103 | /// 104 | /// @brief Zephyr native handle. 105 | /// 106 | /// @return pointer to the k_timer 107 | /// 108 | auto native_handle() noexcept 109 | { 110 | return &m_timer; 111 | } 112 | private: 113 | struct k_timer m_timer { }; 114 | public: 115 | timer_base(const timer_base&) = delete; 116 | timer_base(timer_base&&) = delete; 117 | timer_base& operator=(const timer_base&) = delete; 118 | timer_base& operator=(timer_base&&) = delete; 119 | }; 120 | 121 | /// 122 | /// @brief timer class with expire and stop callbacks 123 | /// 124 | /// @param ExpireCallback Type of the expire callback 125 | /// @param StopCallback Type of the stop callback 126 | /// 127 | template 128 | class timer : public timer_base 129 | { 130 | public: 131 | timer() = delete; 132 | 133 | /// 134 | /// @brief construct timer with expire and stop callback 135 | /// 136 | /// @param ecb the expire callback 137 | /// @param scb the stop callbacl 138 | /// 139 | explicit timer(T_ExpireCallback ecb, T_StopCallback scb) noexcept 140 | : timer_base() 141 | , m_expire_callback(ecb) 142 | , m_stop_callback(scb) 143 | { 144 | k_timer_expiry_t ecb_func = [](struct k_timer* t) noexcept { 145 | auto self = get_user_data(t); 146 | if (self != nullptr) { 147 | std::invoke(self->m_expire_callback, self); 148 | } 149 | }; 150 | 151 | k_timer_stop_t scb_func = [](struct k_timer* t) noexcept { 152 | auto self = get_user_data(t); 153 | if (self != nullptr) { 154 | std::invoke(self->m_stop_callback, self); 155 | } 156 | }; 157 | 158 | k_timer_init( native_handle(), ecb_func, scb_func); 159 | k_timer_user_data_set( native_handle(), this); 160 | } 161 | private: 162 | static timer* get_user_data(struct k_timer* t) noexcept 163 | { 164 | return static_cast(k_timer_user_data_get(t)); 165 | } 166 | private: 167 | T_ExpireCallback m_expire_callback; 168 | T_StopCallback m_stop_callback; 169 | }; 170 | 171 | 172 | /// 173 | /// @brief timer class with only an expire callback 174 | /// 175 | /// @param ExpireCallback Type of the expire callback 176 | /// 177 | template 178 | class basic_timer : public timer_base 179 | { 180 | public: 181 | basic_timer() = delete; 182 | 183 | /// 184 | /// @brief construct timer with an expire callback 185 | /// 186 | /// @param ecb the expire callback 187 | /// 188 | explicit basic_timer(T_ExpireCallback ecb) noexcept 189 | : timer_base() 190 | , m_expire_callback(ecb) 191 | { 192 | k_timer_expiry_t ecb_func = [](struct k_timer* t) noexcept { 193 | auto self = get_user_data(t); 194 | if (self != nullptr) { 195 | std::invoke(self->m_expire_callback, self); 196 | } 197 | }; 198 | 199 | k_timer_init( native_handle(), ecb_func, nullptr); 200 | k_timer_user_data_set( native_handle(), this); 201 | } 202 | private: 203 | static basic_timer* get_user_data(struct k_timer* t) noexcept 204 | { 205 | return static_cast(k_timer_user_data_get(t)); 206 | } 207 | private: 208 | T_ExpireCallback m_expire_callback; 209 | }; 210 | 211 | 212 | /// 213 | /// @brief timer class with no callbacks used for syncing only 214 | /// 215 | class sync_timer : public timer_base 216 | { 217 | public: 218 | /// 219 | /// @brief constuctor for the sync timer 220 | /// 221 | sync_timer() noexcept 222 | : timer_base() 223 | { 224 | k_timer_init(native_handle(), nullptr, nullptr); 225 | } 226 | }; 227 | 228 | /// 229 | /// @brief create sync_timer object 230 | /// 231 | /// @return sync_timer object 232 | /// 233 | inline auto make_timer() noexcept 234 | { 235 | return sync_timer(); 236 | } 237 | 238 | /// 239 | /// @brief create basic_timer object 240 | /// 241 | /// @param ecb the expire callback 242 | /// 243 | /// @return basic_timer object 244 | /// 245 | template 246 | inline auto make_timer(T_ExpireCallback&& ecb) noexcept 247 | { 248 | return basic_timer(std::forward(ecb)); 249 | } 250 | 251 | /// 252 | /// @brief create timer object 253 | /// 254 | /// @param ecb the expire callback 255 | /// @param scb the stop callback 256 | /// 257 | /// @return timer object 258 | /// 259 | template 260 | inline auto make_timer(T_ExpireCallback&& ecb, T_StopCallback&& scb) noexcept 261 | { 262 | return timer(std::forward(ecb), std::forward(scb)); 263 | } 264 | 265 | } // namespace zpp 266 | 267 | #endif // ZPP_INCLUDE_ZPP_TIMER_HPP 268 | -------------------------------------------------------------------------------- /include/zpp/unique_lock.hpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (c) 2021 Erwin Rol 3 | /// 4 | /// SPDX-License-Identifier: Apache-2.0 5 | /// 6 | 7 | #ifndef ZPP_INCLUDE_ZPP_UNIQUE_LOCK_HPP 8 | #define ZPP_INCLUDE_ZPP_UNIQUE_LOCK_HPP 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | namespace zpp { 19 | 20 | /// 21 | /// @brief zpp::unique_lock using zpp::mutex as a lock. 22 | /// 23 | template 24 | class unique_lock { 25 | public: 26 | using native_pointer = T_Mutex::native_pointer; 27 | using native_const_pointer = T_Mutex::native_const_pointer; 28 | public: 29 | /// 30 | /// @brief Try locking the mutex without waiting. 31 | /// 32 | unique_lock() noexcept = default; 33 | 34 | /// 35 | /// @brief Try locking the mutex without waiting. 36 | /// 37 | explicit unique_lock(T_Mutex& lock) noexcept 38 | : m_lock(&lock) 39 | { 40 | __ASSERT_NO_MSG(m_lock != nullptr); 41 | auto res = m_lock->lock(); 42 | __ASSERT_NO_MSG(res != false); 43 | m_is_owner = true; 44 | } 45 | 46 | /// 47 | /// @brief Try locking the mutex without waiting. 48 | /// 49 | unique_lock(unique_lock&& src) noexcept 50 | : m_lock(src.m_lock) 51 | , m_is_owner(src.m_is_owner) 52 | { 53 | src.m_lock = nullptr; 54 | src.m_is_owner = false; 55 | } 56 | 57 | /// 58 | /// @brief Try locking the mutex without waiting. 59 | /// 60 | unique_lock& operator=(unique_lock&& src) noexcept 61 | { 62 | if (m_lock != nullptr && m_is_owner) { 63 | auto res = m_lock->unlock(); 64 | __ASSERT_NO_MSG(res != false); 65 | } 66 | 67 | m_lock = src.m_lock; 68 | m_is_owner = src.m_is_owner; 69 | 70 | src.m_lock = nullptr; 71 | src.m_is_owner = false; 72 | 73 | return *this; 74 | } 75 | 76 | /// 77 | /// @brief Try locking the mutex without waiting. 78 | /// 79 | ~unique_lock() noexcept 80 | { 81 | if (m_lock != nullptr && m_is_owner) { 82 | auto res = m_lock->unlock(); 83 | __ASSERT_NO_MSG(res != false); 84 | } 85 | } 86 | 87 | /// 88 | /// @brief Lock the mutex. Wait for ever until it is locked. 89 | /// 90 | /// @return true if successfully locked. 91 | /// 92 | [[nodiscard]] auto lock() noexcept 93 | { 94 | result res; 95 | 96 | if (m_lock == nullptr) { 97 | res.assign_error(error_code::k_inval); 98 | } else if (m_is_owner == true) { 99 | res.assign_error(error_code::k_deadlk); 100 | } else { 101 | res = m_lock->lock(); 102 | m_is_owner = (bool)res; 103 | } 104 | 105 | return res; 106 | } 107 | 108 | /// 109 | /// @brief Try locking the mutex without waiting. 110 | /// 111 | /// @return true if successfully locked. 112 | /// 113 | [[nodiscard]] auto try_lock() noexcept 114 | { 115 | result res; 116 | 117 | if (m_lock == nullptr) { 118 | res.assign_error(error_code::k_inval); 119 | } else if (m_is_owner == true) { 120 | res.assign_error(error_code::k_deadlk); 121 | } else { 122 | res = m_lock->try_lock(); 123 | m_is_owner = (bool)res; 124 | } 125 | 126 | return res; 127 | } 128 | 129 | /// 130 | /// @brief Try locking the mutex with a timeout. 131 | /// 132 | /// @param timeout The time to wait before returning 133 | /// 134 | /// @return true if successfully locked. 135 | /// 136 | template 137 | [[nodiscard]] auto 138 | try_lock_for(const std::chrono::duration& timeout) noexcept 139 | { 140 | result res; 141 | 142 | if (m_lock == nullptr) { 143 | res.assign_error(error_code::k_inval); 144 | } else if (m_is_owner == true) { 145 | res.assign_error(error_code::k_deadlk); 146 | } else { 147 | res = m_lock->try_lock_for(timeout); 148 | m_is_owner = (bool)res; 149 | } 150 | 151 | return res; 152 | } 153 | 154 | /// 155 | /// @brief Unlock the mutex. 156 | /// 157 | [[nodiscard]] auto unlock() noexcept 158 | { 159 | result res; 160 | 161 | if (m_is_owner == false) { 162 | res.assign_error(error_code::k_perm); 163 | } else if (m_lock == nullptr) { 164 | res.assign_error(error_code::k_inval); 165 | } else { 166 | res = m_lock->unlock(); 167 | m_is_owner = false; 168 | } 169 | 170 | return res; 171 | } 172 | 173 | /// 174 | /// @brief Try locking the mutex without waiting. 175 | /// 176 | constexpr T_Mutex* release() noexcept 177 | { 178 | auto ret = m_lock; 179 | m_lock = nullptr; 180 | m_is_owner = false; 181 | return ret; 182 | } 183 | 184 | /// 185 | /// @brief Try locking the mutex without waiting. 186 | /// 187 | constexpr bool owns_lock() const noexcept 188 | { 189 | return m_is_owner; 190 | } 191 | 192 | /// 193 | /// @brief Try locking the mutex without waiting. 194 | /// 195 | explicit constexpr operator bool() const noexcept 196 | { 197 | return owns_lock(); 198 | } 199 | 200 | /// 201 | /// @brief Try locking the mutex without waiting. 202 | /// 203 | constexpr T_Mutex* mutex() const noexcept 204 | { 205 | return m_lock; 206 | } 207 | 208 | /// 209 | /// @brief get the native zephyr mutex handle. 210 | /// 211 | /// @return A pointer to the zephyr k_mutex. 212 | /// 213 | constexpr auto native_handle() noexcept -> native_pointer 214 | { 215 | if (m_lock != nullptr) 216 | return m_lock->native_handle(); 217 | else 218 | return nullptr; 219 | } 220 | 221 | /// 222 | /// @brief get the native zephyr mutex handle. 223 | /// 224 | /// @return A pointer to the zephyr k_mutex. 225 | /// 226 | constexpr auto native_handle() const noexcept -> native_const_pointer 227 | { 228 | if (m_lock != nullptr) 229 | return m_lock->native_handle(); 230 | else 231 | return nullptr; 232 | } 233 | private: 234 | T_Mutex* m_lock{nullptr}; 235 | bool m_is_owner{false}; 236 | public: 237 | unique_lock(const unique_lock&) = delete; 238 | unique_lock& operator=(const unique_lock&) = delete; 239 | }; 240 | 241 | } // namespace zpp 242 | 243 | #endif // ZPP_INCLUDE_ZPP_UNIQUE_LOCK_HPP 244 | -------------------------------------------------------------------------------- /include/zpp/utils.hpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (c) 2021 Erwin Rol 3 | /// 4 | /// SPDX-License-Identifier: Apache-2.0 5 | /// 6 | 7 | #ifndef ZPP_INCLUDE_ZPP_UTILS_HPP 8 | #define ZPP_INCLUDE_ZPP_UTILS_HPP 9 | 10 | #include 11 | 12 | namespace zpp { 13 | 14 | /// 15 | /// @brief check if the instances refere to the same native zephyr 16 | /// object handle. 17 | /// 18 | /// @return true if they refer to the same native zephyr object. 19 | /// 20 | template 21 | constexpr bool operator==(const T_LHS& lhs, const T_RHS& rhs) noexcept 22 | { 23 | if constexpr (std::is_pointer_v && std::is_pointer_v) { 24 | return lhs == rhs; 25 | } 26 | 27 | if constexpr (std::is_pointer_v && !std::is_pointer_v) { 28 | return lhs == rhs.native_handle(); 29 | } 30 | 31 | if constexpr (!std::is_pointer_v && std::is_pointer_v) { 32 | return lhs.native_handle() == rhs; 33 | } 34 | 35 | if constexpr (!std::is_pointer_v && !std::is_pointer_v) { 36 | return lhs.native_handle() == rhs.native_handle(); 37 | } 38 | 39 | static_assert(true, "should never be reached"); 40 | return true; 41 | } 42 | 43 | /// 44 | /// @brief check if the arguments refere to different native zephyr 45 | /// object handles. 46 | /// 47 | /// @return true if they refer to different native zephyr objects. 48 | /// 49 | template 50 | constexpr bool operator!=(const T_LHS& lhs, const T_RHS& rhs) noexcept 51 | { 52 | if constexpr (std::is_pointer_v && std::is_pointer_v) { 53 | return lhs != rhs; 54 | } 55 | 56 | if constexpr (std::is_pointer_v && !std::is_pointer_v) { 57 | return lhs != rhs.native_handle(); 58 | } 59 | 60 | if constexpr (!std::is_pointer_v && std::is_pointer_v) { 61 | return lhs.native_handle() != rhs; 62 | } 63 | 64 | if constexpr (!std::is_pointer_v && !std::is_pointer_v) { 65 | return lhs.native_handle() != rhs.native_handle(); 66 | } 67 | 68 | static_assert(true, "should never be reached"); 69 | return false; 70 | } 71 | 72 | /// 73 | /// @brief calculate a power of 2 74 | /// 75 | /// @param power the power of 2 to calculate 76 | /// 77 | /// @return the power of 2 78 | /// 79 | consteval uint32_t power_of_two(uint32_t power) noexcept 80 | { 81 | uint32_t res = 1; 82 | 83 | for (uint32_t i = 1; i <= power; ++i) { 84 | res *= 2; 85 | } 86 | 87 | return res; 88 | } 89 | 90 | /// 91 | /// @brief check if a value is a power of two 92 | /// 93 | /// @param value the value to check 94 | /// 95 | /// @return true if @a value is a power of two 96 | /// 97 | consteval bool is_power_of_two(uint32_t value) noexcept 98 | { 99 | uint32_t power {0}; 100 | uint32_t calc_val; 101 | 102 | do { 103 | calc_val = power_of_two(power++); 104 | } while (calc_val < value); 105 | 106 | return calc_val == value; 107 | } 108 | 109 | /// 110 | /// @brief Check if a value is a multiple of another value 111 | /// 112 | /// @param value the value to check 113 | /// @param base the base the @a value should be a multiple of 114 | /// 115 | /// @return true if @a value is a multiple of @a base 116 | /// 117 | consteval bool is_multiple_of(uint32_t value, uint32_t base) 118 | { 119 | if (value == 0 || base == 0) { 120 | return false; 121 | } else { 122 | return (value % base) == 0; 123 | } 124 | } 125 | 126 | } // namespace zpp 127 | 128 | #endif // ZPP_INCLUDE_ZPP_UTILS_HPP 129 | -------------------------------------------------------------------------------- /samples/hello_world/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.20.0) 4 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 5 | project(zpp_hello_world) 6 | 7 | target_sources(app PRIVATE src/main.cpp) 8 | -------------------------------------------------------------------------------- /samples/hello_world/README.md: -------------------------------------------------------------------------------- 1 | # Title: ZPP Hello World 2 | 3 | ## Description: 4 | The sample starts a thread that endlessly prints out a Hello World message. The 5 | main thread will do the same thing. The prints are guarded by a mutex to prevent 6 | console messages getting messed up. 7 | 8 | ## Example output: 9 | 10 | ``` 11 | ***** Booting Zephyr OS build v1.7.99-21379-g8ec0c692022e ***** 12 | Hello World from main tid=0x20000620 13 | Hello World from thread tid=0x20000000 14 | Hello World from thread tid=0x20000000 15 | Hello World from main tid=0x20000620 16 | Hello World from thread tid=0x20000000 17 | Hello World from thread tid=0x20000000 18 | Hello World from main tid=0x20000620 19 | ``` 20 | -------------------------------------------------------------------------------- /samples/hello_world/hello_world.yaml: -------------------------------------------------------------------------------- 1 | sample: 2 | description: ZPP Hello World 3 | name: zpp_hello_world 4 | tests: 5 | sample.zpp.hello_world: 6 | tags: cpp zpp 7 | -------------------------------------------------------------------------------- /samples/hello_world/prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_CPLUSPLUS=y 2 | CONFIG_STD_CPP20=y 3 | CONFIG_NEWLIB_LIBC=y 4 | CONFIG_NEWLIB_LIBC_NANO=y 5 | CONFIG_SPEED_OPTIMIZATIONS=y 6 | CONFIG_LIB_CPLUSPLUS=y 7 | CONFIG_COMPILER_OPT="-Wall -Wextra -Werror -Wno-error=empty-body -Wno-error=unused-parameter -Wno-error=type-limits -Wno-error=missing-field-initializers -Wno-error=sign-compare -Wno-error=ignored-qualifiers -Wno-error=old-style-declaration -Wno-error=cast-function-type" 8 | -------------------------------------------------------------------------------- /samples/hello_world/src/main.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019 Erwin Rol 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | 7 | #include 8 | 9 | #include 10 | 11 | // 12 | // using a anonymous namespace for file local variables and functions 13 | // 14 | namespace { 15 | 16 | // 17 | // Define the Thread Control Block for the thread, using a stack of 1024 bytes 18 | // 19 | ZPP_THREAD_STACK_DEFINE(my_thread_tstack, 1024); 20 | zpp::thread_data my_thread_tcb; 21 | 22 | zpp::heap<128> my_heap; 23 | 24 | } // namespace 25 | 26 | int main(int argc, char *argv[]) 27 | { 28 | // 29 | // use zpp and std::chrono namespaces in the function 30 | // 31 | using namespace zpp; 32 | using namespace std::chrono; 33 | 34 | mutex print_lock; 35 | 36 | // 37 | // Create thread attributes used for thread creation 38 | // 39 | const thread_attr my_thread_attr( 40 | thread_prio::preempt(0), 41 | thread_inherit_perms::no, 42 | thread_suspend::no 43 | ); 44 | 45 | // 46 | // Create the first thread, using a lambda passing a const char* as 47 | // argument that is used as "template" for the print out. 48 | // 49 | // The lock used for making sure the prints don't get messed up 50 | // is captured by reference 51 | // 52 | const char* string_arg = "Hello World from thread tid={}\n"; 53 | 54 | auto my_thread = thread( 55 | my_thread_tcb, my_thread_tstack(), my_thread_attr, &my_heap, 56 | [&print_lock](const char* t) noexcept 57 | { 58 | while (true) { 59 | // 60 | // Use a lock_guard in a scope to automatically 61 | // do the unlocking when leaving the scope 62 | // 63 | { 64 | lock_guard lg(print_lock); 65 | 66 | // 67 | // print the thread ID of this thread 68 | // 69 | print(t, this_thread::get_id()); 70 | } 71 | 72 | // 73 | // let this thread sleep for 500 ms without 74 | // holding the lock 75 | // 76 | this_thread::sleep_for(500ms); 77 | } 78 | }, string_arg); 79 | 80 | // 81 | // Loop forever, because ending main would not only end the 82 | // program, my_thread would also go out of scope aborting the thread. 83 | // 84 | while (true) { 85 | // Use a lock_guard in a scope to automatically 86 | // do the unlocking when leaving the scope 87 | // 88 | { 89 | lock_guard lg(print_lock); 90 | 91 | // 92 | // print the thread ID of the main thread 93 | // 94 | print("Hello World from main tid={}\n", 95 | this_thread::get_id()); 96 | } 97 | 98 | // 99 | // let main thread sleep for 1 s without holding the lock 100 | // 101 | this_thread::sleep_for(1s); 102 | } 103 | 104 | return 0; 105 | } 106 | -------------------------------------------------------------------------------- /samples/kernel/condition_variables/condvar/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.20.0) 4 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 5 | project(condvar) 6 | 7 | FILE(GLOB app_sources src/main.cpp) 8 | target_sources(app PRIVATE ${app_sources}) 9 | -------------------------------------------------------------------------------- /samples/kernel/condition_variables/condvar/prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_TEST=y 2 | CONFIG_CPLUSPLUS=y 3 | CONFIG_STD_CPP20=y 4 | CONFIG_NEWLIB_LIBC=y 5 | CONFIG_NEWLIB_LIBC_NANO=y 6 | CONFIG_SIZE_OPTIMIZATIONS=y 7 | CONFIG_LIB_CPLUSPLUS=y 8 | -------------------------------------------------------------------------------- /samples/kernel/condition_variables/condvar/sample.yaml: -------------------------------------------------------------------------------- 1 | tests: 2 | zpp.sample.kernel.cond_var: 3 | arch_exclude: posix 4 | platform_exclude: qemu_x86_coverage 5 | tags: zpp kernel condition_variables 6 | harness: console 7 | harness_config: 8 | type: one_line 9 | regex: 10 | - ".*Waited and joined with 3 threads" 11 | -------------------------------------------------------------------------------- /samples/kernel/condition_variables/condvar/src/main.cpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (c) 2021 Erwin Rol 3 | /// Copyright (c) 2020 Intel Corporation 4 | /// 5 | /// SPDX-License-Identifier: Apache-2.0 6 | /// 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #define NUM_THREADS 3 16 | #define TCOUNT 10 17 | #define COUNT_LIMIT 12 18 | 19 | #define STACK_SIZE (1024 + CONFIG_TEST_EXTRA_STACK_SIZE) 20 | 21 | namespace { 22 | 23 | int count{}; 24 | 25 | zpp::mutex count_mutex; 26 | zpp::condition_variable count_threshold_cv; 27 | 28 | ZPP_THREAD_STACK_ARRAY_DEFINE(tstack, NUM_THREADS, STACK_SIZE); 29 | zpp::thread_data tcb[NUM_THREADS]; 30 | zpp::thread t[NUM_THREADS]; 31 | 32 | } // anonimouse namespace 33 | 34 | void inc_count(int my_id) noexcept 35 | { 36 | for (int i = 0; i < TCOUNT; i++) { 37 | { 38 | zpp::lock_guard lg(count_mutex); 39 | count++; 40 | 41 | // 42 | // Check the value of count and signal waiting thread when 43 | // condition is reached. Note that this occurs while mutex is 44 | // locked. 45 | // 46 | 47 | if (count == COUNT_LIMIT) { 48 | printk("%s: thread %d, count = %d Threshold reached.", 49 | __func__, my_id, count); 50 | count_threshold_cv.notify_one(); 51 | printk("Just sent signal.\n"); 52 | } 53 | 54 | printk("%s: thread %d, count = %d, unlocking mutex\n", 55 | __func__, my_id, count); 56 | } 57 | 58 | // Sleep so threads can alternate on mutex lock 59 | zpp::this_thread::sleep_for(std::chrono::milliseconds(500)); 60 | } 61 | } 62 | 63 | void watch_count(int my_id) noexcept 64 | { 65 | printk("Starting %s: thread %d\n", __func__, my_id); 66 | 67 | zpp::unique_lock lk(count_mutex); 68 | 69 | while (count < COUNT_LIMIT) { 70 | printk("%s: thread %d Count= %d. Going into wait...\n", 71 | __func__, my_id, count); 72 | 73 | count_threshold_cv.wait(lk); 74 | 75 | printk("%s: thread %d Condition signal received. Count= %d\n", 76 | __func__, my_id, count); 77 | } 78 | 79 | printk("%s: thread %d Updating the value of count...\n", 80 | __func__, my_id); 81 | count += 125; 82 | printk("%s: thread %d count now = %d.\n", __func__, my_id, count); 83 | printk("%s: thread %d Unlocking mutex.\n", __func__, my_id); 84 | } 85 | 86 | int main(void) 87 | { 88 | const zpp::thread_attr attrs( 89 | zpp::thread_prio::preempt(10), 90 | zpp::thread_inherit_perms::no, 91 | zpp::thread_suspend::no 92 | ); 93 | 94 | t[0] = zpp::thread(tcb[0], tstack(0), attrs, watch_count, 1); 95 | 96 | t[1] = zpp::thread(tcb[1], tstack(1), attrs, inc_count, 2); 97 | t[2] = zpp::thread(tcb[2], tstack(2), attrs, inc_count, 3); 98 | 99 | // Wait for all threads to complete 100 | for (int i = 0; i < NUM_THREADS; i++) { 101 | t[i].join(); 102 | } 103 | 104 | printk("Main(): Waited and joined with %d threads. Final value of count = %d. Done.\n", 105 | NUM_THREADS, count); 106 | 107 | return 0; 108 | } 109 | -------------------------------------------------------------------------------- /samples/kernel/condition_variables/simple/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.20.0) 4 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 5 | project(condvar) 6 | 7 | FILE(GLOB app_sources src/main.cpp) 8 | target_sources(app PRIVATE ${app_sources}) 9 | -------------------------------------------------------------------------------- /samples/kernel/condition_variables/simple/prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_TEST=y 2 | CONFIG_CPLUSPLUS=y 3 | CONFIG_STD_CPP20=y 4 | CONFIG_NEWLIB_LIBC=y 5 | CONFIG_NEWLIB_LIBC_NANO=y 6 | CONFIG_SIZE_OPTIMIZATIONS=y 7 | CONFIG_LIB_CPLUSPLUS=y 8 | -------------------------------------------------------------------------------- /samples/kernel/condition_variables/simple/sample.yaml: -------------------------------------------------------------------------------- 1 | tests: 2 | zpp.sample.kernel.cond_var.simple: 3 | arch_exclude: posix 4 | platform_exclude: qemu_x86_coverage qemu_x86_tiny 5 | tags: zpp kernel condition_variables 6 | harness: console 7 | harness_config: 8 | type: one_line 9 | regex: 10 | - ".*done == 20 so everyone is done" 11 | -------------------------------------------------------------------------------- /samples/kernel/condition_variables/simple/src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Intel Corporation 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | #define NUM_THREADS 20 15 | #define STACK_SIZE (1024 + CONFIG_TEST_EXTRA_STACK_SIZE) 16 | 17 | namespace { 18 | 19 | zpp::mutex m; 20 | zpp::condition_variable cv; 21 | 22 | 23 | ZPP_THREAD_STACK_ARRAY_DEFINE(tstack, NUM_THREADS, STACK_SIZE); 24 | zpp::thread_data tcb[NUM_THREADS]; 25 | zpp::thread t[NUM_THREADS]; 26 | 27 | int done{}; 28 | 29 | void worker_thread(int myid) noexcept 30 | { 31 | const int workloops = 5; 32 | 33 | for (int i = 0; i < workloops; i++) { 34 | printk("[thread %d] working (%d/%d)\n", myid, i, workloops); 35 | 36 | zpp::this_thread::sleep_for(std::chrono::milliseconds(500)); 37 | } 38 | 39 | // 40 | // we're going to manipulate done and use the cond, so we need the mutex 41 | // 42 | zpp::lock_guard lg(m); 43 | 44 | // 45 | // increase the count of threads that have finished their work. 46 | // 47 | done++; 48 | printk("[thread %d] done is now %d. Signalling cond.\n", myid, done); 49 | 50 | auto res = cv.notify_one(); 51 | __ASSERT_NO_MSG(res == true); 52 | } 53 | 54 | } // anonimouse namespace 55 | 56 | int main(void) 57 | { 58 | const zpp::thread_attr attrs( 59 | zpp::thread_prio::preempt(10), 60 | zpp::thread_inherit_perms::no, 61 | zpp::thread_suspend::no 62 | ); 63 | 64 | for (int i = 0; i < NUM_THREADS; i++) { 65 | t[i] = zpp::thread(tcb[i], tstack(i), attrs, &worker_thread, i); 66 | } 67 | 68 | //zpp::this_thread::sleep_for(std::chrono::seconds(1)); 69 | 70 | printk("[thread %s] all threads started\n", __func__); 71 | 72 | { 73 | zpp::lock_guard lg(m); 74 | 75 | // 76 | // are the other threads still busy? 77 | // 78 | while (done < NUM_THREADS) { 79 | printk("[thread %s] done is %d which is < %d so waiting on cond\n", 80 | __func__, done, (int)NUM_THREADS); 81 | 82 | // block this thread until another thread signals cond. While 83 | // blocked, the mutex is released, then re-acquired before this 84 | // thread is woken up and the call returns. 85 | auto res = cv.wait(m); 86 | __ASSERT_NO_MSG(res == true); 87 | 88 | printk("[thread %s] wake - cond was signalled.\n", __func__); 89 | 90 | // we go around the loop with the lock held 91 | } 92 | 93 | } // zpp::lock_guard scope 94 | 95 | for (int i = 0; i < NUM_THREADS; i++) { 96 | auto res = t[i].join(); 97 | __ASSERT_NO_MSG(res == true); 98 | } 99 | 100 | printk("[thread %s] done == %d so everyone is done\n", 101 | __func__, (int)NUM_THREADS); 102 | 103 | return 0; 104 | } 105 | -------------------------------------------------------------------------------- /tests/atomic/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.20.0) 4 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 5 | project(zpp_atomic) 6 | 7 | FILE(GLOB app_sources src/*.cpp) 8 | target_sources(app PRIVATE ${app_sources}) 9 | -------------------------------------------------------------------------------- /tests/atomic/prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_CPLUSPLUS=y 2 | CONFIG_STD_CPP20=y 3 | CONFIG_NEWLIB_LIBC=y 4 | CONFIG_ASSERT=y 5 | CONFIG_ZTEST=y 6 | CONFIG_ZTEST_NEW_API=y 7 | CONFIG_ZTEST_FATAL_HOOK=y 8 | CONFIG_SPEED_OPTIMIZATIONS=y 9 | CONFIG_LIB_CPLUSPLUS=y 10 | CONFIG_COMPILER_OPT="-Wall -Wextra -Werror -Wno-error=empty-body -Wno-error=unused-parameter -Wno-error=type-limits -Wno-error=missing-field-initializers -Wno-error=sign-compare -Wno-error=ignored-qualifiers -Wno-error=old-style-declaration -Wno-error=cast-function-type" 11 | -------------------------------------------------------------------------------- /tests/atomic/src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Erwin Rol 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | 15 | ZTEST_SUITE(zpp_atomic_tests, NULL, NULL, NULL, NULL, NULL); 16 | 17 | namespace { 18 | 19 | zpp::atomic_bitset<320> g_bitset; 20 | 21 | } // namespace 22 | 23 | ZTEST(zpp_atomic_tests, test_atomic_bitset) 24 | { 25 | g_bitset.store(0, true); 26 | zassert_true(g_bitset.load(0) == true, "load(0) failed"); 27 | 28 | g_bitset.store(319, true); 29 | zassert_true(g_bitset.load(319) == true, "load(319) failed"); 30 | } 31 | -------------------------------------------------------------------------------- /tests/atomic/testcase.yaml: -------------------------------------------------------------------------------- 1 | tests: 2 | zpp.atomic: 3 | arch_exclude: posix 4 | platform_exclude: qemu_x86_coverage 5 | tags: cpp zpp 6 | -------------------------------------------------------------------------------- /tests/clock/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.20.0) 4 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 5 | project(zpp_clock) 6 | 7 | FILE(GLOB app_sources src/*.cpp) 8 | target_sources(app PRIVATE ${app_sources}) 9 | -------------------------------------------------------------------------------- /tests/clock/prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_CPLUSPLUS=y 2 | CONFIG_STD_CPP20=y 3 | CONFIG_NEWLIB_LIBC=y 4 | CONFIG_ASSERT=y 5 | CONFIG_ZTEST=y 6 | CONFIG_ZTEST_NEW_API=y 7 | CONFIG_ZTEST_FATAL_HOOK=y 8 | CONFIG_SPEED_OPTIMIZATIONS=y 9 | CONFIG_LIB_CPLUSPLUS=y 10 | CONFIG_COMPILER_OPT="-Wall -Wextra -Werror -Wno-error=empty-body -Wno-error=unused-parameter -Wno-error=type-limits -Wno-error=missing-field-initializers -Wno-error=sign-compare -Wno-error=ignored-qualifiers -Wno-error=old-style-declaration -Wno-error=cast-function-type" 11 | -------------------------------------------------------------------------------- /tests/clock/src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Erwin Rol 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | ZTEST_SUITE(zpp_clock_tests, NULL, NULL, NULL, NULL, NULL); 15 | 16 | ZTEST(zpp_clock_tests, test_clock_uptime) 17 | { 18 | using namespace std::chrono; 19 | 20 | auto start = zpp::uptime_clock::now(); 21 | 22 | zpp::this_thread::sleep_for(2s); 23 | 24 | auto end = zpp::uptime_clock::now(); 25 | 26 | zassert_true(end > start, "end time not later than start time"); 27 | } 28 | -------------------------------------------------------------------------------- /tests/clock/testcase.yaml: -------------------------------------------------------------------------------- 1 | tests: 2 | zpp.clock: 3 | arch_exclude: posix 4 | platform_exclude: qemu_x86_coverage 5 | tags: cpp zpp 6 | -------------------------------------------------------------------------------- /tests/compile/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.20.0) 4 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 5 | project(zpp_compile) 6 | 7 | FILE(GLOB app_sources src/*.cpp) 8 | target_sources(app PRIVATE ${app_sources}) 9 | -------------------------------------------------------------------------------- /tests/compile/prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_CPLUSPLUS=y 2 | CONFIG_STD_CPP20=y 3 | CONFIG_NEWLIB_LIBC=y 4 | CONFIG_ASSERT=y 5 | CONFIG_ZTEST=y 6 | CONFIG_ZTEST_NEW_API=y 7 | CONFIG_ZTEST_FATAL_HOOK=y 8 | CONFIG_SPEED_OPTIMIZATIONS=y 9 | CONFIG_LIB_CPLUSPLUS=y 10 | CONFIG_COMPILER_OPT="-Wall -Wextra -Werror -Wno-error=empty-body -Wno-error=unused-parameter -Wno-error=type-limits -Wno-error=missing-field-initializers -Wno-error=sign-compare -Wno-error=ignored-qualifiers -Wno-error=old-style-declaration -Wno-error=cast-function-type" 11 | -------------------------------------------------------------------------------- /tests/compile/src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Erwin Rol 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | /* 8 | * Simple test to check if all zpp headers are error free 9 | */ 10 | 11 | #include 12 | 13 | #include 14 | 15 | #include 16 | 17 | ZTEST_SUITE(zpp_compile_tests, NULL, NULL, NULL, NULL, NULL); 18 | 19 | // 20 | // check compile time power_of_two function 21 | // 22 | static_assert(zpp::power_of_two(0) == 1); 23 | static_assert(zpp::power_of_two(1) == 2); 24 | static_assert(zpp::power_of_two(2) == 4); 25 | static_assert(zpp::power_of_two(3) == 8); 26 | static_assert(zpp::power_of_two(4) == 16); 27 | static_assert(zpp::power_of_two(10) == 1024); 28 | static_assert(zpp::power_of_two(20) == 1048576); 29 | 30 | // 31 | // check compile time is_power_of_two function 32 | // 33 | static_assert(zpp::is_power_of_two(1) == true); 34 | static_assert(zpp::is_power_of_two(2) == true); 35 | static_assert(zpp::is_power_of_two(4) == true); 36 | static_assert(zpp::is_power_of_two(8) == true); 37 | static_assert(zpp::is_power_of_two(16) == true); 38 | static_assert(zpp::is_power_of_two(3) == false); 39 | static_assert(zpp::is_power_of_two(100) == false); 40 | 41 | // 42 | // check compile time is_multiple_of function 43 | // 44 | static_assert(zpp::is_multiple_of(0, 0) == false); 45 | static_assert(zpp::is_multiple_of(4, 4) == true); 46 | static_assert(zpp::is_multiple_of(6, 3) == true); 47 | static_assert(zpp::is_multiple_of(10, 3) == false); 48 | -------------------------------------------------------------------------------- /tests/compile/testcase.yaml: -------------------------------------------------------------------------------- 1 | tests: 2 | zpp.compile: 3 | arch_exclude: posix 4 | platform_exclude: qemu_x86_coverage 5 | build_only: true 6 | tags: cpp zpp 7 | -------------------------------------------------------------------------------- /tests/condition_variable/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.20.0) 4 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 5 | project(zpp_condition_variable) 6 | 7 | FILE(GLOB app_sources src/*.cpp) 8 | target_sources(app PRIVATE ${app_sources}) 9 | -------------------------------------------------------------------------------- /tests/condition_variable/prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_CPLUSPLUS=y 2 | CONFIG_STD_CPP20=y 3 | CONFIG_NEWLIB_LIBC=y 4 | CONFIG_ASSERT=y 5 | CONFIG_ZTEST=y 6 | CONFIG_ZTEST_NEW_API=y 7 | CONFIG_ZTEST_FATAL_HOOK=y 8 | CONFIG_SPEED_OPTIMIZATIONS=y 9 | CONFIG_LIB_CPLUSPLUS=y 10 | CONFIG_COMPILER_OPT="-Wall -Wextra -Werror -Wno-error=empty-body -Wno-error=unused-parameter -Wno-error=type-limits -Wno-error=missing-field-initializers -Wno-error=sign-compare -Wno-error=ignored-qualifiers -Wno-error=old-style-declaration -Wno-error=cast-function-type" 11 | -------------------------------------------------------------------------------- /tests/condition_variable/src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Erwin Rol 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | 16 | ZTEST_SUITE(test_zpp_condition_variable, NULL, NULL, NULL, NULL, NULL); 17 | 18 | namespace { 19 | 20 | ZPP_THREAD_STACK_DEFINE(tstack, 1024); 21 | zpp::thread_data tcb; 22 | 23 | 24 | bool ready = false; 25 | bool processed = false; 26 | 27 | char data[128] = {}; 28 | 29 | zpp::mutex m; 30 | 31 | K_MUTEX_DEFINE(g_mutex); 32 | 33 | zpp::mutex_ref m_ref(&g_mutex); 34 | 35 | zpp::condition_variable cv; 36 | 37 | K_CONDVAR_DEFINE(g_condvar); 38 | 39 | zpp::condition_variable_ref cv_ref(&g_condvar); 40 | 41 | } // namespace 42 | 43 | ZTEST(test_zpp_condition_variable, test_condition_variable_cmp) 44 | { 45 | bool res; 46 | 47 | res = cv == cv_ref; 48 | zassert_false(res, "unable to compare condition_variable == condition_variable_ref\n"); 49 | 50 | res = cv != cv_ref; 51 | zassert_true(res, "unable to compare condition_variable != condition_variable_ref\n"); 52 | 53 | res = cv_ref == &g_condvar; 54 | zassert_true(res, "unable to compare condition_variable_ref == k_condvar*\n"); 55 | 56 | res = cv_ref != &g_condvar; 57 | zassert_false(res, "unable to compare condition_variable_ref != k_condvar*\n"); 58 | 59 | res = cv == &g_condvar; 60 | zassert_false(res, "unable to compare condition_variable == k_condvar*\n"); 61 | 62 | res = cv != &g_condvar; 63 | zassert_true(res, "unable to compare condition_variable != k_condvar*\n"); 64 | } 65 | 66 | ZTEST(test_zpp_condition_variable, test_condition_variable) 67 | { 68 | using namespace zpp; 69 | using namespace std::chrono; 70 | 71 | const thread_attr attr( 72 | thread_prio::preempt(0), 73 | thread_inherit_perms::no, 74 | thread_essential::no, 75 | thread_suspend::no 76 | ); 77 | 78 | auto t = thread( 79 | tcb, tstack(), attr, 80 | []() noexcept { 81 | // Wait until main() sends data 82 | { 83 | zpp::lock_guard lg(m); 84 | 85 | auto rc = cv.wait(m, []{return ready;}); 86 | __ASSERT_NO_MSG(rc == true); 87 | 88 | // after the wait, we own the lock. 89 | print("Worker thread is processing data\n"); 90 | 91 | strcat(data, " after processing"); 92 | 93 | // Send data back to main() 94 | processed = true; 95 | print("Worker thread signals data processing completed\n"); 96 | } 97 | 98 | auto rc = cv.notify_one(); 99 | __ASSERT_NO_MSG(rc == true); 100 | }); 101 | 102 | strcpy(data, "Example data"); 103 | // send data to the worker thread 104 | { 105 | zpp::lock_guard lg(m); 106 | ready = true; 107 | print("main() signals data ready for processing\n"); 108 | } 109 | auto rc = cv.notify_one(); 110 | __ASSERT_NO_MSG(rc == true); 111 | 112 | // wait for the worker 113 | { 114 | zpp::lock_guard lg(m); 115 | rc = cv.wait(m, []{return processed;}); 116 | __ASSERT_NO_MSG(rc == true); 117 | } 118 | print("Back in main(), data = {}\n", data); 119 | 120 | rc = t.join(); 121 | __ASSERT_NO_MSG(rc == true); 122 | } 123 | -------------------------------------------------------------------------------- /tests/condition_variable/testcase.yaml: -------------------------------------------------------------------------------- 1 | tests: 2 | zpp.condition_variable: 3 | arch_exclude: posix 4 | platform_exclude: qemu_x86_coverage 5 | tags: cpp zpp 6 | -------------------------------------------------------------------------------- /tests/fifo/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.20.0) 4 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 5 | project(zpp_fifo) 6 | 7 | FILE(GLOB app_sources src/*.cpp) 8 | target_sources(app PRIVATE ${app_sources}) 9 | -------------------------------------------------------------------------------- /tests/fifo/prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_CPLUSPLUS=y 2 | CONFIG_STD_CPP20=y 3 | CONFIG_NEWLIB_LIBC=y 4 | CONFIG_ASSERT=y 5 | CONFIG_ZTEST=y 6 | CONFIG_ZTEST_NEW_API=y 7 | CONFIG_ZTEST_FATAL_HOOK=y 8 | CONFIG_SPEED_OPTIMIZATIONS=y 9 | CONFIG_LIB_CPLUSPLUS=y 10 | CONFIG_COMPILER_OPT="-Wall -Wextra -Werror -Wno-error=empty-body -Wno-error=unused-parameter -Wno-error=type-limits -Wno-error=missing-field-initializers -Wno-error=sign-compare -Wno-error=ignored-qualifiers -Wno-error=old-style-declaration -Wno-error=cast-function-type" 11 | -------------------------------------------------------------------------------- /tests/fifo/src/main.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019 Erwin Rol 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | 7 | #include 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | ZTEST_SUITE(test_zpp_fifo, NULL, NULL, NULL, NULL, NULL); 18 | 19 | namespace { 20 | 21 | ZPP_THREAD_STACK_DEFINE(tstack, 1024); 22 | zpp::thread_data tcb; 23 | 24 | struct item { 25 | void* fifo_reserved{}; 26 | uint32_t data{}; 27 | uint32_t more_data{}; 28 | }; 29 | 30 | std::array g_item_array; 31 | 32 | zpp::fifo g_fifo; 33 | 34 | } // namespace 35 | 36 | ZTEST(test_zpp_fifo, test_fifo) 37 | { 38 | using namespace zpp; 39 | using namespace std::chrono; 40 | 41 | const thread_attr attr( 42 | thread_prio::preempt(0), 43 | thread_inherit_perms::yes, 44 | thread_essential::no, 45 | thread_suspend::no 46 | ); 47 | 48 | // 49 | // Put items into fifo 50 | // 51 | for (auto& item: g_item_array) { 52 | item.data = 0x1234; 53 | item.more_data = 0x5678; 54 | g_fifo.push_back(&item); 55 | } 56 | 57 | auto t = thread( 58 | tcb, tstack(), attr, 59 | []() noexcept { 60 | // 61 | // Get items from fifo 62 | // 63 | for (auto& item: g_item_array) { 64 | auto res = g_fifo.try_pop_front(); 65 | zassert_equal(res->data, 0x1234, nullptr); 66 | zassert_equal(res->more_data, 0x5678, nullptr); 67 | zassert_equal(res, &item, nullptr); 68 | } 69 | 70 | // 71 | // Put items into fifo 72 | // 73 | for (auto& item: g_item_array) { 74 | g_fifo.push_back(&item); 75 | } 76 | }); 77 | 78 | // 79 | // Let the child thread run 80 | // 81 | auto res = t.join(); 82 | zassert_equal(!!res, true, ""); 83 | 84 | // 85 | // Get items from fifo 86 | // 87 | for (auto& item: g_item_array) { 88 | auto res = g_fifo.try_pop_front(); 89 | zassert_equal(res->data, 0x1234, nullptr); 90 | zassert_equal(res->more_data, 0x5678, nullptr); 91 | zassert_equal(res, &item, nullptr); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /tests/fifo/testcase.yaml: -------------------------------------------------------------------------------- 1 | tests: 2 | zpp.fifo: 3 | arch_exclude: posix 4 | platform_exclude: qemu_x86_coverage 5 | tags: cpp zpp 6 | -------------------------------------------------------------------------------- /tests/heap/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.20.0) 4 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 5 | project(zpp_heap) 6 | 7 | FILE(GLOB app_sources src/*.cpp) 8 | target_sources(app PRIVATE ${app_sources}) 9 | -------------------------------------------------------------------------------- /tests/heap/prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_CPLUSPLUS=y 2 | CONFIG_STD_CPP20=y 3 | CONFIG_NEWLIB_LIBC=y 4 | CONFIG_ASSERT=y 5 | CONFIG_ZTEST=y 6 | CONFIG_ZTEST_NEW_API=y 7 | CONFIG_ZTEST_FATAL_HOOK=y 8 | CONFIG_SPEED_OPTIMIZATIONS=y 9 | CONFIG_LIB_CPLUSPLUS=y 10 | CONFIG_COMPILER_OPT="-Wall -Wextra -Werror -Wno-error=empty-body -Wno-error=unused-parameter -Wno-error=type-limits -Wno-error=missing-field-initializers -Wno-error=sign-compare -Wno-error=ignored-qualifiers -Wno-error=old-style-declaration -Wno-error=cast-function-type" 11 | -------------------------------------------------------------------------------- /tests/heap/src/main.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019 Erwin Rol 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | 7 | #include 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | 15 | ZTEST_SUITE(zpp_heap_tests, NULL, NULL, NULL, NULL, NULL); 16 | 17 | namespace { 18 | 19 | zpp::heap<1024> g_heap; 20 | 21 | } // namespace 22 | 23 | ZTEST(zpp_heap_tests, test_heap) 24 | { 25 | auto p = g_heap.allocate(1); 26 | 27 | zassert_not_null(p, ""); 28 | 29 | g_heap.deallocate(p); 30 | 31 | p = g_heap.allocate(128); 32 | 33 | zassert_not_null(p, ""); 34 | 35 | g_heap.deallocate(p); 36 | } 37 | -------------------------------------------------------------------------------- /tests/heap/testcase.yaml: -------------------------------------------------------------------------------- 1 | tests: 2 | zpp.heap: 3 | arch_exclude: posix 4 | platform_exclude: qemu_x86_coverage 5 | tags: cpp zpp 6 | -------------------------------------------------------------------------------- /tests/mem_slab/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.20.0) 4 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 5 | project(zpp_mem_slab) 6 | 7 | FILE(GLOB app_sources src/*.cpp) 8 | target_sources(app PRIVATE ${app_sources}) 9 | -------------------------------------------------------------------------------- /tests/mem_slab/prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_CPLUSPLUS=y 2 | CONFIG_STD_CPP20=y 3 | CONFIG_NEWLIB_LIBC=y 4 | CONFIG_ASSERT=y 5 | CONFIG_ZTEST=y 6 | CONFIG_ZTEST_NEW_API=y 7 | CONFIG_ZTEST_FATAL_HOOK=y 8 | CONFIG_SPEED_OPTIMIZATIONS=y 9 | CONFIG_LIB_CPLUSPLUS=y 10 | CONFIG_COMPILER_OPT="-Wall -Wextra -Werror -Wno-error=empty-body -Wno-error=unused-parameter -Wno-error=type-limits -Wno-error=missing-field-initializers -Wno-error=sign-compare -Wno-error=ignored-qualifiers -Wno-error=old-style-declaration -Wno-error=cast-function-type" 11 | -------------------------------------------------------------------------------- /tests/mem_slab/src/main.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019 Erwin Rol 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | 7 | #include 8 | 9 | #include 10 | 11 | #include 12 | 13 | 14 | ZTEST_SUITE(zpp_mem_slab_tests, NULL, NULL, NULL, NULL, NULL); 15 | 16 | namespace { 17 | 18 | zpp::mem_slab<8, 64, 8> g_mem_slab; 19 | 20 | } // namespace 21 | 22 | ZTEST(zpp_mem_slab_tests, test_mem_slab) 23 | { 24 | const auto total = g_mem_slab.total_block_count(); 25 | 26 | zassert_equal(g_mem_slab.free_block_count(), total, ""); 27 | zassert_equal(g_mem_slab.used_block_count(), 0, ""); 28 | 29 | auto p = g_mem_slab.allocate(); 30 | 31 | zassert_not_null(p, ""); 32 | 33 | zassert_equal(g_mem_slab.free_block_count(), total - 1, ""); 34 | zassert_equal(g_mem_slab.used_block_count(), 1, ""); 35 | 36 | g_mem_slab.deallocate(p); 37 | 38 | zassert_equal(g_mem_slab.free_block_count(), total, ""); 39 | zassert_equal(g_mem_slab.used_block_count(), 0, ""); 40 | } 41 | -------------------------------------------------------------------------------- /tests/mem_slab/testcase.yaml: -------------------------------------------------------------------------------- 1 | tests: 2 | zpp.mem_slab: 3 | arch_exclude: posix 4 | platform_exclude: qemu_x86_coverage 5 | tags: cpp zpp 6 | -------------------------------------------------------------------------------- /tests/mutex/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.20.0) 4 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 5 | project(zpp_mutex) 6 | 7 | FILE(GLOB app_sources src/*.cpp) 8 | target_sources(app PRIVATE ${app_sources}) 9 | -------------------------------------------------------------------------------- /tests/mutex/prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_CPLUSPLUS=y 2 | CONFIG_STD_CPP20=y 3 | CONFIG_NEWLIB_LIBC=y 4 | CONFIG_ASSERT=y 5 | CONFIG_ZTEST=y 6 | CONFIG_ZTEST_NEW_API=y 7 | CONFIG_ZTEST_FATAL_HOOK=y 8 | CONFIG_SPEED_OPTIMIZATIONS=y 9 | CONFIG_LIB_CPLUSPLUS=y 10 | CONFIG_COMPILER_OPT="-Wall -Wextra -Werror -Wno-error=empty-body -Wno-error=unused-parameter -Wno-error=type-limits -Wno-error=missing-field-initializers -Wno-error=sign-compare -Wno-error=ignored-qualifiers -Wno-error=old-style-declaration -Wno-error=cast-function-type" 11 | -------------------------------------------------------------------------------- /tests/mutex/src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Erwin Rol 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | 17 | ZTEST_SUITE(test_zpp_mutex, NULL, NULL, NULL, NULL, NULL); 18 | 19 | namespace { 20 | 21 | zpp::mutex m; 22 | 23 | K_MUTEX_DEFINE(g_mutex); 24 | 25 | zpp::mutex_ref m_ref(&g_mutex); 26 | 27 | } // namespace 28 | 29 | ZTEST(test_zpp_mutex, test_mutex_cmp) 30 | { 31 | bool res; 32 | 33 | res = m == m_ref; 34 | zassert_false(res, "unable to compare mutex == mutex_ref\n"); 35 | 36 | res = m != m_ref; 37 | zassert_true(res, "unable to compare mutex != mutex_ref\n"); 38 | 39 | res = m_ref == m; 40 | zassert_false(res, "unable to compare mutex_ref == mutex\n"); 41 | 42 | res = m_ref != m; 43 | zassert_true(res, "unable to compare mutex_ref != mutex\n"); 44 | 45 | res = m_ref == &g_mutex; 46 | zassert_true(res, "unable to compare mutex_ref == k_condvar*\n"); 47 | 48 | res = m_ref != &g_mutex; 49 | zassert_false(res, "unable to compare mutex_ref != k_condvar*\n"); 50 | 51 | res = m == &g_mutex; 52 | zassert_false(res, "unable to compare mutex == k_condvar*\n"); 53 | 54 | res = m != &g_mutex; 55 | zassert_true(res, "unable to compare mutex != k_mutex*\n"); 56 | 57 | res = &g_mutex == m_ref; 58 | zassert_true(res, "unable to compare k_condvar* == mutex_ref\n"); 59 | 60 | res = &g_mutex != m_ref; 61 | zassert_false(res, "unable to compare k_condvar* != mutex_ref\n"); 62 | 63 | res = &g_mutex == m; 64 | zassert_false(res, "unable to compare mutex == k_condvar* == mutex\n"); 65 | 66 | res = &g_mutex != m; 67 | zassert_true(res, "unable to compare k_mutex* != mutex\n"); 68 | 69 | } 70 | 71 | ZTEST(test_zpp_mutex, test_mutex) 72 | { 73 | auto rc = m.lock(); 74 | 75 | zassert_true(!!rc, "Failed to lock mutex: %d\n", rc.error()); 76 | 77 | rc = m.unlock(); 78 | 79 | zassert_true(!!rc, "Failed to unlock mutex: %d\n", rc.error()); 80 | } 81 | 82 | ZTEST(test_zpp_mutex, test_mutex_ref) 83 | { 84 | auto rc = m_ref.lock(); 85 | 86 | zassert_true(!!rc, "Failed to lock mutex_ref: %d\n", rc.error()); 87 | 88 | rc = m_ref.unlock(); 89 | 90 | zassert_true(!!rc, "Failed to unlock mutex_ref: %d\n", rc.error()); 91 | } 92 | 93 | ZTEST(test_zpp_mutex, test_lock_guard) 94 | { 95 | zpp::lock_guard g(m); 96 | zpp::lock_guard g_ref(m_ref); 97 | } 98 | -------------------------------------------------------------------------------- /tests/mutex/testcase.yaml: -------------------------------------------------------------------------------- 1 | tests: 2 | zpp.mutex: 3 | arch_exclude: posix 4 | platform_exclude: qemu_x86_coverage 5 | tags: cpp zpp 6 | -------------------------------------------------------------------------------- /tests/poll/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.20.0) 4 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 5 | project(zpp_poll) 6 | 7 | FILE(GLOB app_sources src/*.cpp) 8 | target_sources(app PRIVATE ${app_sources}) 9 | -------------------------------------------------------------------------------- /tests/poll/prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_CPLUSPLUS=y 2 | CONFIG_STD_CPP20=y 3 | CONFIG_NEWLIB_LIBC=y 4 | CONFIG_ASSERT=y 5 | CONFIG_ZTEST=y 6 | CONFIG_ZTEST_NEW_API=y 7 | CONFIG_ZTEST_FATAL_HOOK=y 8 | CONFIG_POLL=y 9 | CONFIG_MP_NUM_CPUS=1 10 | CONFIG_SPEED_OPTIMIZATIONS=y 11 | CONFIG_LIB_CPLUSPLUS=y 12 | CONFIG_COMPILER_OPT="-Wall -Wextra -Werror -Wno-error=empty-body -Wno-error=unused-parameter -Wno-error=type-limits -Wno-error=missing-field-initializers -Wno-error=sign-compare -Wno-error=ignored-qualifiers -Wno-error=old-style-declaration -Wno-error=cast-function-type" 13 | -------------------------------------------------------------------------------- /tests/poll/src/main.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2017 Wind River Systems, Inc. 3 | // Copyright (c) 2019 Erwin Rol 4 | // 5 | // SPDX-License-Identifier: Apache-2.0 6 | // 7 | 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | 17 | ZTEST_SUITE(zpp_poll_tests, NULL, NULL, NULL, NULL, NULL); 18 | 19 | namespace { 20 | 21 | #define SIGNAL_RESULT 0x1ee7d00d 22 | #define FIFO_MSG_VALUE 0xdeadbeef 23 | 24 | ZPP_THREAD_STACK_DEFINE(test_thread_stack, 1024); 25 | zpp::thread_data test_thread; 26 | 27 | 28 | struct fifo_msg { 29 | void* fifo_reserved{}; 30 | uint32_t msg { FIFO_MSG_VALUE }; 31 | }; 32 | 33 | fifo_msg wait_msg; 34 | 35 | zpp::sem wait_sem; 36 | zpp::fifo wait_fifo; 37 | zpp::poll_signal wait_signal; 38 | 39 | zpp::poll_event_set wait_events { 40 | wait_sem, 41 | wait_fifo, 42 | wait_signal, 43 | nullptr 44 | }; 45 | 46 | } // namespace 47 | 48 | ZTEST(zpp_poll_tests, test_poll_wait) 49 | { 50 | using namespace std::chrono; 51 | 52 | const zpp::thread_prio main_low_prio{ 10 }; 53 | 54 | auto old_prio = zpp::this_thread::get_priority(); 55 | 56 | // 57 | // Wait for 3 non-ready events to become ready from a higher priority 58 | // thread. 59 | // 60 | zpp::this_thread::set_priority(main_low_prio); 61 | 62 | zpp::thread_attr attr( 63 | main_low_prio + 1, 64 | zpp::thread_inherit_perms::yes, 65 | zpp::thread_essential::no, 66 | zpp::thread_suspend::no ); 67 | 68 | auto poll_helper = [](bool do_fifo) noexcept { 69 | zpp::this_thread::sleep_for(250ms); 70 | 71 | wait_sem++; 72 | 73 | if (do_fifo) { 74 | wait_fifo.push_back(&wait_msg); 75 | } 76 | 77 | wait_signal.raise(SIGNAL_RESULT); 78 | }; 79 | 80 | auto t = zpp::thread(test_thread, test_thread_stack(), attr, poll_helper, true); 81 | 82 | auto rc = wait_events.try_poll_for(1s); 83 | 84 | zpp::this_thread::set_priority(old_prio); 85 | 86 | zassert_equal(rc, true, ""); 87 | 88 | zassert_equal(wait_events[0].is_ready(), true, ""); 89 | zassert_equal(wait_sem.try_take(), true, ""); 90 | 91 | zassert_equal(wait_events[1].is_ready(), true, ""); 92 | auto msg_ptr = wait_fifo.try_pop_front(); 93 | zassert_not_null(msg_ptr, ""); 94 | zassert_equal(msg_ptr, &wait_msg, ""); 95 | zassert_equal(msg_ptr->msg, FIFO_MSG_VALUE, ""); 96 | 97 | zassert_equal(wait_events[2].is_ready(), true, ""); 98 | zassert_equal(wait_signal.check().value_or(-1), SIGNAL_RESULT, ""); 99 | 100 | zassert_equal(wait_events[3].is_ready(), false, ""); 101 | 102 | // 103 | // verify events are not ready anymore 104 | // 105 | wait_events[0].reset(); 106 | wait_events[1].reset(); 107 | wait_events[2].reset(); 108 | wait_events[3].reset(); 109 | wait_signal.reset(); 110 | 111 | zassert_equal(wait_events.try_poll_for(1s), false, ""); 112 | 113 | zassert_equal(wait_events[0].is_ready(), false, ""); 114 | zassert_equal(wait_events[1].is_ready(), false, ""); 115 | zassert_equal(wait_events[2].is_ready(), false, ""); 116 | zassert_equal(wait_events[3].is_ready(), false, ""); 117 | 118 | // 119 | // Wait for 2 out of 3 non-ready events to become ready from a higher 120 | // priority thread. 121 | // 122 | zpp::this_thread::set_priority(main_low_prio); 123 | 124 | attr.set(old_prio + 1); 125 | t = zpp::thread(test_thread, test_thread_stack(), attr, poll_helper, false); 126 | 127 | rc = wait_events.try_poll_for(1s); 128 | 129 | zpp::this_thread::set_priority(old_prio); 130 | 131 | zassert_equal(rc, true, ""); 132 | 133 | zassert_equal(wait_events[0].is_ready(), true, ""); 134 | zassert_equal(wait_sem.try_take(), true, ""); 135 | 136 | zassert_equal(wait_events[1].is_ready(), false, ""); 137 | msg_ptr = wait_fifo.try_pop_front(); 138 | zassert_is_null(msg_ptr, ""); 139 | 140 | zassert_equal(wait_events[2].is_ready(), true, ""); 141 | zassert_equal(wait_signal.check().value_or(-1), SIGNAL_RESULT, ""); 142 | 143 | zassert_equal(wait_events[3].is_ready(), false, ""); 144 | 145 | 146 | // 147 | // Wait for each event to be ready from a lower priority thread, one at 148 | // a time. 149 | // 150 | wait_events[0].reset(); 151 | wait_events[1].reset(); 152 | wait_events[2].reset(); 153 | wait_events[3].reset(); 154 | wait_signal.reset(); 155 | 156 | attr.set(old_prio - 1); 157 | t = zpp::thread(test_thread, test_thread_stack(), attr, poll_helper, true); 158 | 159 | // 160 | // semaphore 161 | // 162 | rc = wait_events.try_poll_for(1s); 163 | 164 | zassert_equal(rc, true, ""); 165 | 166 | zassert_equal(wait_events[0].is_ready(), true, ""); 167 | zassert_equal(wait_sem.try_take(), true, ""); 168 | 169 | zassert_equal(wait_events[1].is_ready(), false, ""); 170 | msg_ptr = wait_fifo.try_pop_front(); 171 | zassert_is_null(msg_ptr, ""); 172 | 173 | zassert_equal(wait_events[2].is_ready(), false, ""); 174 | 175 | wait_events[0].reset(); 176 | 177 | // 178 | // fifo 179 | // 180 | rc = wait_events.try_poll_for(1s); 181 | 182 | zassert_equal(rc, true, ""); 183 | 184 | zassert_equal(wait_events[0].is_ready(), false, ""); 185 | zassert_equal(wait_sem.try_take(), false, ""); 186 | 187 | zassert_equal(wait_events[1].is_ready(), true, ""); 188 | msg_ptr = wait_fifo.try_pop_front(); 189 | zassert_not_null(msg_ptr, ""); 190 | 191 | zassert_equal(wait_events[2].is_ready(), false, ""); 192 | 193 | wait_events[1].reset(); 194 | 195 | // 196 | // poll signal 197 | // 198 | rc = wait_events.try_poll_for(1s); 199 | 200 | zassert_equal(rc, true, ""); 201 | 202 | zassert_equal(wait_events[0].is_ready(), false, ""); 203 | zassert_equal(wait_sem.try_take(), false, ""); 204 | 205 | zassert_equal(wait_events[1].is_ready(), false, ""); 206 | msg_ptr = wait_fifo.try_pop_front(); 207 | zassert_is_null(msg_ptr, ""); 208 | 209 | zassert_equal(wait_events[2].is_ready(), true, ""); 210 | zassert_equal(wait_signal.check().value_or(-1), SIGNAL_RESULT, ""); 211 | 212 | wait_events[2].reset(); 213 | wait_signal.reset(); 214 | } 215 | -------------------------------------------------------------------------------- /tests/poll/testcase.yaml: -------------------------------------------------------------------------------- 1 | tests: 2 | zpp.poll: 3 | arch_exclude: posix 4 | platform_exclude: qemu_x86_coverage 5 | tags: cpp zpp 6 | -------------------------------------------------------------------------------- /tests/print/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.20.0) 4 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 5 | project(zpp_print) 6 | 7 | FILE(GLOB app_sources src/*.cpp) 8 | target_sources(app PRIVATE ${app_sources}) 9 | -------------------------------------------------------------------------------- /tests/print/prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_CPLUSPLUS=y 2 | CONFIG_STD_CPP20=y 3 | CONFIG_NEWLIB_LIBC=y 4 | CONFIG_ASSERT=y 5 | CONFIG_ZTEST=y 6 | CONFIG_ZTEST_NEW_API=y 7 | CONFIG_ZTEST_FATAL_HOOK=y 8 | CONFIG_SPEED_OPTIMIZATIONS=y 9 | CONFIG_LIB_CPLUSPLUS=y 10 | CONFIG_COMPILER_OPT="-Wall -Wextra -Werror -Wno-error=empty-body -Wno-error=unused-parameter -Wno-error=type-limits -Wno-error=missing-field-initializers -Wno-error=sign-compare -Wno-error=ignored-qualifiers -Wno-error=old-style-declaration -Wno-error=cast-function-type" 11 | -------------------------------------------------------------------------------- /tests/print/src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Erwin Rol 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include 8 | 9 | #include 10 | 11 | ZTEST_SUITE(zpp_print_tests, NULL, NULL, NULL, NULL, NULL); 12 | 13 | ZTEST(zpp_print_tests, test_print_uint8_t) 14 | { 15 | uint8_t v{ 12 }; 16 | zpp::print("uint8_t {} == 12\n", v); 17 | } 18 | 19 | ZTEST(zpp_print_tests, test_print_int8_t) 20 | { 21 | int8_t v{ -12 }; 22 | zpp::print("int8_t {} == -12\n", v); 23 | } 24 | 25 | ZTEST(zpp_print_tests, test_print_uint16_t) 26 | { 27 | uint16_t v{ 1234 }; 28 | zpp::print("uint16_t {} == 1234\n", v); 29 | } 30 | 31 | ZTEST(zpp_print_tests, test_print_int16_t) 32 | { 33 | int16_t v{ -1234 }; 34 | zpp::print("int16_t {} == -1234\n", v); 35 | } 36 | 37 | ZTEST(zpp_print_tests, test_print_uint32_t) 38 | { 39 | uint32_t v{ 12345678 }; 40 | zpp::print("uint32_t {} == 12345678\n", v); 41 | } 42 | 43 | ZTEST(zpp_print_tests, test_print_int32_t) 44 | { 45 | int32_t v{ -12345678 }; 46 | zpp::print("int32_t {} == -12345678\n", v); 47 | } 48 | 49 | ZTEST(zpp_print_tests, test_print_uint64_t) 50 | { 51 | uint64_t v{ 12345678901011 }; 52 | zpp::print("uint64_t {} == 12345678901011\n", v); 53 | } 54 | 55 | ZTEST(zpp_print_tests, test_print_int64_t) 56 | { 57 | int64_t v{ -12345678901011 }; 58 | zpp::print("int64_t {} == -12345678901011\n", v); 59 | } 60 | 61 | ZTEST(zpp_print_tests, test_print_char) 62 | { 63 | char v{ 'c' }; 64 | zpp::print("char {} == c\n", v); 65 | } 66 | 67 | ZTEST(zpp_print_tests, test_print_string) 68 | { 69 | const char* v{ "string" }; 70 | zpp::print("const char* {} == string\n", v); 71 | } 72 | 73 | ZTEST(zpp_print_tests, test_print_void_ptr) 74 | { 75 | void* v{ (void*)0x12345678 }; 76 | zpp::print("void* {} == 0x12345678\n", v); 77 | } 78 | -------------------------------------------------------------------------------- /tests/print/testcase.yaml: -------------------------------------------------------------------------------- 1 | tests: 2 | zpp.print: 3 | arch_exclude: posix 4 | platform_exclude: qemu_x86_coverage 5 | tags: cpp zpp 6 | -------------------------------------------------------------------------------- /tests/result/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.20.0) 4 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 5 | project(zpp_result) 6 | 7 | FILE(GLOB app_sources src/*.cpp) 8 | target_sources(app PRIVATE ${app_sources}) 9 | -------------------------------------------------------------------------------- /tests/result/prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_CPLUSPLUS=y 2 | CONFIG_STD_CPP20=y 3 | CONFIG_NEWLIB_LIBC=y 4 | CONFIG_ASSERT=y 5 | CONFIG_ZTEST=y 6 | CONFIG_ZTEST_NEW_API=y 7 | CONFIG_ZTEST_FATAL_HOOK=y 8 | CONFIG_SPEED_OPTIMIZATIONS=y 9 | CONFIG_LIB_CPLUSPLUS=y 10 | CONFIG_COMPILER_OPT="-Wall -Wextra -Werror -Wno-error=empty-body -Wno-error=unused-parameter -Wno-error=type-limits -Wno-error=missing-field-initializers -Wno-error=sign-compare -Wno-error=ignored-qualifiers -Wno-error=old-style-declaration -Wno-error=cast-function-type" 11 | -------------------------------------------------------------------------------- /tests/result/src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Erwin Rol 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | 16 | 17 | ZTEST_SUITE(test_zpp_result, NULL, NULL, NULL, NULL, NULL); 18 | 19 | namespace { 20 | 21 | class ResultData { 22 | public: 23 | ResultData() = delete; 24 | ResultData(int v) noexcept : m_data(v) {} 25 | private: 26 | int m_data{42}; 27 | }; 28 | 29 | class ErrorData { 30 | public: 31 | ErrorData() = delete; 32 | ErrorData(int v) noexcept : m_data(v) {} 33 | private: 34 | int m_data{42}; 35 | }; 36 | 37 | } // namespace 38 | 39 | ZTEST(test_zpp_result, test_result) 40 | { 41 | zpp::result res_a; 42 | zpp::result res_b; 43 | zpp::result res_c; 44 | 45 | zassert_true(!res_a, "res_a should be false\n"); 46 | zassert_false(res_b, "res_b should be false\n"); 47 | zassert_true(res_c == false, "res_c should be false\n"); 48 | 49 | res_a = zpp::error_result(zpp::error_code::k_inval); 50 | 51 | zassert_true(res_a == false, "res_a should be false\n"); 52 | 53 | res_a = 12345; 54 | 55 | zassert_true(res_a == true, "res_a should be true\n"); 56 | zassert_true(res_a.value() == 12345, "res_a.value() should be 12345\n"); 57 | 58 | auto res_d = res_a; 59 | zassert_true(res_d == true, "res_d should be true\n"); 60 | zassert_true(res_d.value() == 12345, "res_d.value() should be 12345\n"); 61 | 62 | res_d.assign_error(zpp::error_code::k_already); 63 | zassert_false(res_d, "res_d should be false\n"); 64 | zassert_true(res_d.error() == zpp::error_code::k_already, "res_d should hold zpp::error_code::k_already"); 65 | 66 | zpp::result res_e; 67 | zassert_false(res_e, "res_d should be true\n"); 68 | 69 | res_e.assign_value(); 70 | zassert_true(!!res_e, "res_d should be true\n"); 71 | 72 | res_e = zpp::error_result(0); 73 | zassert_true(res_e.error() == 0, "res_d should hold 0"); 74 | 75 | zpp::result res_f; 76 | zassert_false(res_f, "res_f should be false\n"); 77 | 78 | zpp::result res_g(zpp::error_result(ErrorData(13))); 79 | zassert_false(res_g, "res_g should be false\n"); 80 | 81 | zpp::result res_h(zpp::error_result(ErrorData(13))); 82 | zassert_false(res_h, "res_h should be false\n"); 83 | 84 | } 85 | -------------------------------------------------------------------------------- /tests/result/testcase.yaml: -------------------------------------------------------------------------------- 1 | tests: 2 | zpp.result: 3 | arch_exclude: posix 4 | platform_exclude: qemu_x86_coverage 5 | tags: cpp zpp 6 | -------------------------------------------------------------------------------- /tests/sem/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.20.0) 4 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 5 | project(zpp_sem) 6 | 7 | FILE(GLOB app_sources src/*.cpp) 8 | target_sources(app PRIVATE ${app_sources}) 9 | -------------------------------------------------------------------------------- /tests/sem/prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_CPLUSPLUS=y 2 | CONFIG_STD_CPP20=y 3 | CONFIG_NEWLIB_LIBC=y 4 | CONFIG_ZTEST=y 5 | CONFIG_ZTEST_NEW_API=y 6 | CONFIG_ZTEST_FATAL_HOOK=y 7 | CONFIG_ASSERT=y 8 | CONFIG_TEST_USERSPACE=y 9 | CONFIG_MP_NUM_CPUS=1 10 | CONFIG_SPEED_OPTIMIZATIONS=y 11 | CONFIG_LIB_CPLUSPLUS=y 12 | CONFIG_COMPILER_OPT="-Wall -Wextra -Werror -Wno-error=empty-body -Wno-error=unused-parameter -Wno-error=type-limits -Wno-error=missing-field-initializers -Wno-error=sign-compare -Wno-error=ignored-qualifiers -Wno-error=old-style-declaration -Wno-error=cast-function-type" 13 | -------------------------------------------------------------------------------- /tests/sem/src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Erwin Rol 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | ZTEST_SUITE(test_zpp_sem, NULL, NULL, NULL, NULL, NULL); 16 | 17 | namespace { 18 | 19 | K_SEM_DEFINE(g_sem, 0, 10); 20 | 21 | zpp::sem_ref simple_ref_sem(&g_sem); 22 | 23 | zpp::sem simple_sem(0, 10); 24 | 25 | } // namespace 26 | 27 | ZTEST(test_zpp_sem, test_sem_cmp) 28 | { 29 | bool res; 30 | 31 | res = simple_sem == simple_ref_sem; 32 | zassert_false(res, "unable to compare sem == sem_ref\n"); 33 | 34 | res = simple_sem != simple_ref_sem; 35 | zassert_true(res, "unable to compare sem != sem_ref\n"); 36 | 37 | res = simple_ref_sem == simple_sem; 38 | zassert_false(res, "unable to compare sem_ref == sem\n"); 39 | 40 | res = simple_ref_sem != simple_sem; 41 | zassert_true(res, "unable to compare sem_ref != sem\n"); 42 | 43 | res = simple_ref_sem == &g_sem; 44 | zassert_true(res, "unable to compare sem_ref == k_sem*\n"); 45 | 46 | res = simple_ref_sem != &g_sem; 47 | zassert_false(res, "unable to compare sem_ref != k_sem*\n"); 48 | 49 | res = simple_sem == &g_sem; 50 | zassert_false(res, "unable to compare sem == k_sem*\n"); 51 | 52 | res = simple_sem != &g_sem; 53 | zassert_true(res, "unable to compare sem != k_sem*\n"); 54 | 55 | res = &g_sem == simple_ref_sem; 56 | zassert_true(res, "unable to compare k_sem* == sem_ref\n"); 57 | 58 | res = &g_sem != simple_ref_sem; 59 | zassert_false(res, "unable to compare k_sem* != sem_ref\n"); 60 | 61 | res = &g_sem == simple_sem; 62 | zassert_false(res, "unable to compare k_sem* == sem\n"); 63 | 64 | res = &g_sem != simple_sem; 65 | zassert_true(res, "unable to compare k_sem* != sem\n"); 66 | 67 | } 68 | 69 | ZTEST(test_zpp_sem, test_sem_try_take) 70 | { 71 | simple_sem.reset(); 72 | 73 | for (int i = 0; i < 5; i++) { 74 | simple_sem++; 75 | 76 | auto signal_count = simple_sem.count(); 77 | zassert_true(signal_count == (i + 1), 78 | "signal count missmatch Expected %d, got %d\n", 79 | (i + 1), signal_count); 80 | } 81 | 82 | for (int i = 4; i >= 0; i--) { 83 | auto ret_value = simple_sem.try_take(); 84 | zassert_true(ret_value == true, 85 | "unable to do k_sem_take which returned %d\n", 86 | ret_value); 87 | 88 | auto signal_count = simple_sem.count(); 89 | zassert_true(signal_count == i, 90 | "signal count missmatch Expected %d, got %d\n", 91 | i, signal_count); 92 | } 93 | } 94 | 95 | ZTEST(test_zpp_sem, test_sem_try_take_fails) 96 | { 97 | simple_sem.reset(); 98 | 99 | for (int i = 4; i >= 0; i--) { 100 | auto ret_value = simple_sem.try_take(); 101 | zassert_true(ret_value == false, 102 | "k_sem_take returned when not possible"); 103 | 104 | auto signal_count = simple_sem.count(); 105 | zassert_true(signal_count == 0U, 106 | "signal count missmatch Expected 0, got %d\n", 107 | signal_count); 108 | } 109 | } 110 | 111 | ZTEST(test_zpp_sem, test_sem_try_take_for_fails) 112 | { 113 | using namespace std::chrono; 114 | 115 | simple_sem.reset(); 116 | 117 | for (int i = 4; i >= 0; i--) { 118 | auto ret_value = simple_sem.try_take_for(100ms); 119 | zassert_true(ret_value == false, 120 | "k_sem_take succeeded when its not possible"); 121 | } 122 | } 123 | 124 | ZTEST(test_zpp_sem, test_sem_try_take_ref) 125 | { 126 | simple_ref_sem.reset(); 127 | 128 | for (int i = 0; i < 5; i++) { 129 | simple_ref_sem++; 130 | 131 | auto signal_count = simple_ref_sem.count(); 132 | zassert_true(signal_count == (i + 1), 133 | "signal count missmatch Expected %d, got %d\n", 134 | (i + 1), signal_count); 135 | } 136 | 137 | for (int i = 4; i >= 0; i--) { 138 | auto ret_value = simple_ref_sem.try_take(); 139 | zassert_true(ret_value == true, 140 | "unable to do k_sem_take which returned %d\n", 141 | ret_value); 142 | 143 | auto signal_count = simple_ref_sem.count(); 144 | zassert_true(signal_count == i, 145 | "signal count missmatch Expected %d, got %d\n", 146 | i, signal_count); 147 | } 148 | } 149 | 150 | ZTEST(test_zpp_sem, test_sem_try_take_fails_ref) 151 | { 152 | simple_ref_sem.reset(); 153 | 154 | for (int i = 4; i >= 0; i--) { 155 | auto ret_value = simple_ref_sem.try_take(); 156 | zassert_true(ret_value == false, 157 | "k_sem_take returned when not possible"); 158 | 159 | auto signal_count = simple_ref_sem.count(); 160 | zassert_true(signal_count == 0U, 161 | "signal count missmatch Expected 0, got %d\n", 162 | signal_count); 163 | } 164 | } 165 | 166 | ZTEST(test_zpp_sem, test_sem_try_take_for_fails_ref) 167 | { 168 | using namespace std::chrono; 169 | 170 | simple_ref_sem.reset(); 171 | 172 | for (int i = 4; i >= 0; i--) { 173 | auto ret_value = simple_ref_sem.try_take_for(100ms); 174 | zassert_true(ret_value == false, 175 | "k_sem_take succeeded when its not possible"); 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /tests/sem/testcase.yaml: -------------------------------------------------------------------------------- 1 | tests: 2 | zpp.sem: 3 | arch_exclude: posix 4 | platform_exclude: qemu_x86_coverage 5 | tags: cpp zpp 6 | -------------------------------------------------------------------------------- /tests/thread/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.20.0) 4 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 5 | project(zpp_thread) 6 | 7 | FILE(GLOB app_sources src/*.cpp) 8 | target_sources(app PRIVATE ${app_sources}) 9 | -------------------------------------------------------------------------------- /tests/thread/prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_CPLUSPLUS=y 2 | CONFIG_STD_CPP20=y 3 | CONFIG_NEWLIB_LIBC=y 4 | CONFIG_ASSERT=y 5 | CONFIG_ZTEST=y 6 | CONFIG_ZTEST_NEW_API=y 7 | CONFIG_ZTEST_FATAL_HOOK=y 8 | CONFIG_INIT_STACKS=y 9 | CONFIG_SPEED_OPTIMIZATIONS=y 10 | CONFIG_LIB_CPLUSPLUS=y 11 | CONFIG_COMPILER_OPT="-Wall -Wextra -Werror -Wno-error=empty-body -Wno-error=unused-parameter -Wno-error=type-limits -Wno-error=missing-field-initializers -Wno-error=sign-compare -Wno-error=ignored-qualifiers -Wno-error=old-style-declaration -Wno-error=cast-function-type" 12 | -------------------------------------------------------------------------------- /tests/thread/src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Erwin Rol 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | 16 | ZTEST_SUITE(zpp_thread_tests, NULL, NULL, NULL, NULL, NULL); 17 | 18 | namespace { 19 | 20 | ZPP_THREAD_STACK_DEFINE(tstack, 1024); 21 | zpp::thread_data tcb; 22 | 23 | zpp::heap<1024> theap; 24 | 25 | } // namespace 26 | 27 | ZTEST(zpp_thread_tests, test_thread_creation) 28 | { 29 | using namespace zpp; 30 | using namespace std::chrono; 31 | 32 | const thread_attr attr( 33 | thread_prio::preempt(0), 34 | thread_inherit_perms::no, 35 | thread_essential::no, 36 | thread_suspend::no 37 | ); 38 | 39 | int dummy=42; 40 | sem done; 41 | 42 | auto t = thread( 43 | tcb, tstack(), attr, &theap, 44 | [&dummy, &done]() noexcept { 45 | print("Hello from thread tid={}\n", 46 | this_thread::get_id()); 47 | 48 | print("dummy = {}\n", (void*)&dummy); 49 | print("done = {}\n", (void*)&done); 50 | 51 | zassert_true(dummy == 42, "dummy not 42\n"); 52 | 53 | done++; 54 | }); 55 | 56 | // wait until the thread does done++ 57 | done--; 58 | 59 | auto rc = t.join(); 60 | zassert_true(rc == true, "join failed"); 61 | 62 | print("Hello from main tid={}\n", this_thread::get_id()); 63 | } 64 | 65 | ZTEST(zpp_thread_tests, test_thread_creation_void) 66 | { 67 | using namespace zpp; 68 | using namespace std::chrono; 69 | 70 | const thread_attr attr( 71 | thread_prio::preempt(0), 72 | thread_inherit_perms::no, 73 | thread_essential::no, 74 | thread_suspend::no 75 | ); 76 | 77 | auto t = thread( 78 | tcb, tstack(), attr, 79 | []() noexcept { 80 | print("Hello from thread tid={}\n", 81 | this_thread::get_id()); 82 | }); 83 | 84 | auto rc = t.join(); 85 | zassert_true(rc == true, "join failed"); 86 | 87 | print("Hello from main tid={}\n", this_thread::get_id()); 88 | } 89 | 90 | ZTEST(zpp_thread_tests, test_thread_creation_pointer) 91 | { 92 | using namespace zpp; 93 | using namespace std::chrono; 94 | 95 | const thread_attr attr( 96 | thread_prio::preempt(0), 97 | thread_inherit_perms::no, 98 | thread_essential::no, 99 | thread_suspend::no 100 | ); 101 | 102 | struct S { 103 | S() noexcept { 104 | print("S() {} {} {}", 105 | (void*)this, a, b); 106 | } 107 | 108 | S(const S& other) noexcept : a(other.a), b(other.b) { 109 | print("S(&{} {} {}) {} {} {}", 110 | (void*)&other, other.a, other.b, 111 | (void*)this, a, b); 112 | } 113 | ~S() noexcept { 114 | print("~S() {} {} {}", 115 | (void*)this, a, b); 116 | } 117 | 118 | int a{}; 119 | int b{}; 120 | }; 121 | 122 | S s; 123 | 124 | auto t = thread( 125 | tcb, tstack(), attr, 126 | [](S* s) noexcept { 127 | print("Hello from thread tid={} s->a={} s->b={}\n", 128 | this_thread::get_id(), 129 | s->a, s->b); 130 | 131 | s->a = 21; 132 | s->b = 43; 133 | 134 | }, &s); 135 | 136 | auto rc = t.join(); 137 | zassert_true(rc == true, "join failed"); 138 | 139 | zassert_true(s.a == 21, "s.a != 21\n"); 140 | zassert_true(s.b == 43, "s.a != 43\n"); 141 | 142 | print("Hello from main tid={}\n", this_thread::get_id()); 143 | } 144 | 145 | 146 | ZTEST(zpp_thread_tests, test_thread_creation_params) 147 | { 148 | using namespace zpp; 149 | using namespace std::chrono; 150 | 151 | const thread_attr attr( 152 | thread_prio::preempt(0), 153 | thread_inherit_perms::no, 154 | thread_essential::no, 155 | thread_suspend::no 156 | ); 157 | 158 | struct S { 159 | S() noexcept { 160 | print("S() {} {} {}", 161 | (void*)this, a, b); 162 | } 163 | 164 | S(const S& other) noexcept : a(other.a), b(other.b) { 165 | print("S(&{} {} {}) {} {} {}", 166 | (void*)&other, other.a, other.b, 167 | (void*)this, a, b); 168 | } 169 | ~S() noexcept { 170 | print("~S() {} {} {}", 171 | (void*)this, a, b); 172 | } 173 | 174 | int a{}; 175 | int b{}; 176 | }; 177 | 178 | sem done; 179 | 180 | S s; 181 | int a = 12; 182 | int b = 34; 183 | 184 | auto t = thread( 185 | tcb, tstack(), attr, &theap, 186 | [&done](S s, int a, int b) noexcept { 187 | print("Hello from thread tid={} s.a={} s.b={} a={} b={}\n", 188 | this_thread::get_id(), 189 | s.a, s.b, a, b); 190 | 191 | s.a = a; 192 | s.b = b; 193 | 194 | done++; 195 | }, s, a, b); 196 | 197 | // wait until the thread does done++ 198 | done--; 199 | 200 | auto rc = t.join(); 201 | zassert_true(rc == true, "join failed"); 202 | 203 | print("Hello from main tid={}\n", this_thread::get_id()); 204 | } 205 | -------------------------------------------------------------------------------- /tests/thread/testcase.yaml: -------------------------------------------------------------------------------- 1 | tests: 2 | zpp.thread: 3 | arch_exclude: posix 4 | platform_exclude: qemu_x86_coverage 5 | tags: cpp zpp 6 | -------------------------------------------------------------------------------- /tests/timer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | 3 | cmake_minimum_required(VERSION 3.20.0) 4 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 5 | project(zpp_timer) 6 | 7 | FILE(GLOB app_sources src/*.cpp) 8 | target_sources(app PRIVATE ${app_sources}) 9 | -------------------------------------------------------------------------------- /tests/timer/prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_CPLUSPLUS=y 2 | CONFIG_STD_CPP20=y 3 | CONFIG_NEWLIB_LIBC=y 4 | CONFIG_ZTEST=y 5 | CONFIG_ZTEST_NEW_API=y 6 | CONFIG_ZTEST_FATAL_HOOK=y 7 | CONFIG_ASSERT=y 8 | CONFIG_SPEED_OPTIMIZATIONS=y 9 | CONFIG_LIB_CPLUSPLUS=y 10 | CONFIG_COMPILER_OPT="-Wall -Wextra -Werror -Wno-error=empty-body -Wno-error=unused-parameter -Wno-error=type-limits -Wno-error=missing-field-initializers -Wno-error=sign-compare -Wno-error=ignored-qualifiers -Wno-error=old-style-declaration -Wno-error=cast-function-type" 11 | -------------------------------------------------------------------------------- /tests/timer/src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Erwin Rol 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | ZTEST_SUITE(zpp_timer_tests, NULL, NULL, NULL, NULL, NULL); 16 | 17 | namespace { 18 | 19 | auto g_t = zpp::make_timer(); 20 | 21 | void timer_callback(zpp::timer_base* t) noexcept 22 | { 23 | zpp::print("Hello from timer tid={}\n", zpp::this_thread::get_id()); 24 | } 25 | 26 | } // namespace 27 | 28 | ZTEST(zpp_timer_tests, test_timer_creation_function) 29 | { 30 | using namespace zpp; 31 | using namespace std::chrono; 32 | 33 | auto t = make_timer(timer_callback); 34 | t.start(100ms, 1s); 35 | 36 | this_thread::sleep_for(5s); 37 | } 38 | 39 | ZTEST(zpp_timer_tests, test_timer_creation_lambda) 40 | { 41 | using namespace zpp; 42 | using namespace std::chrono; 43 | 44 | auto t = make_timer( 45 | [] (auto t) { 46 | print("Hello from timer tid={}\n", 47 | this_thread::get_id()); 48 | } ); 49 | 50 | t.start(100ms, 1s); 51 | 52 | this_thread::sleep_for(5s); 53 | } 54 | -------------------------------------------------------------------------------- /tests/timer/testcase.yaml: -------------------------------------------------------------------------------- 1 | tests: 2 | zpp.timer: 3 | slow: true 4 | arch_exclude: posix 5 | platform_exclude: qemu_x86_coverage 6 | tags: cpp zpp 7 | -------------------------------------------------------------------------------- /zephyr/module.yml: -------------------------------------------------------------------------------- 1 | build: 2 | cmake: . 3 | samples: 4 | - samples 5 | tests: 6 | - tests 7 | --------------------------------------------------------------------------------