├── .clang-format ├── .gitignore ├── LICENSE ├── README.md ├── include ├── Chrono.h ├── ConditionVariable.h ├── EventFlag.h ├── Memory.h ├── MessageQueue.h ├── Mutex.h ├── OS.h ├── OSException.h ├── Semaphore.h ├── Thread.h ├── ThreadFlag.h ├── Threads.h ├── Timer.h └── WaitFlag.h └── src ├── Chrono.cpp ├── ConditionVariable.cpp ├── EventFlag.cpp ├── Memory.cpp ├── MessageQueue.cpp ├── Mutex.cpp ├── OS.cpp ├── OSException.cpp ├── Semaphore.cpp ├── Thread.cpp ├── ThreadFlag.cpp ├── Threads.cpp ├── Timer.cpp └── rtx_os.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | # See https://clang.llvm.org/docs/ClangFormatStyleOptions.html 2 | 3 | BasedOnStyle: LLVM 4 | AccessModifierOffset: -4 5 | AlignAfterOpenBracket: AlwaysBreak 6 | AlignArrayOfStructures: Left 7 | AlignConsecutiveBitFields: AcrossEmptyLinesAndComments 8 | AlignConsecutiveMacros: true 9 | AlignConsecutiveAssignments: false 10 | AlignConsecutiveDeclarations: false 11 | AlignEscapedNewlines: DontAlign 12 | AlignOperands: AlignAfterOperator 13 | AlignTrailingComments: true 14 | AllowAllArgumentsOnNextLine: false 15 | AllowAllConstructorInitializersOnNextLine: true 16 | AllowAllParametersOfDeclarationOnNextLine: false 17 | AllowShortBlocksOnASingleLine: Never 18 | AllowShortCaseLabelsOnASingleLine: false 19 | AllowShortEnumsOnASingleLine: true 20 | AllowShortFunctionsOnASingleLine: InlineOnly 21 | AllowShortIfStatementsOnASingleLine: Never 22 | AllowShortLambdasOnASingleLine: Empty 23 | AllowShortLoopsOnASingleLine: false 24 | AlwaysBreakAfterReturnType: None 25 | AlwaysBreakTemplateDeclarations: MultiLine 26 | BinPackArguments: false 27 | BinPackParameters: false 28 | BitFieldColonSpacing: After 29 | BraceWrapping: 30 | AfterCaseLabel: true 31 | AfterClass: true 32 | AfterControlStatement: true 33 | AfterEnum: true 34 | AfterFunction: true 35 | AfterNamespace: true 36 | AfterObjCDeclaration: true 37 | AfterStruct: true 38 | AfterUnion: true 39 | AfterExternBlock: true 40 | BeforeCatch: true 41 | BeforeElse: true 42 | BeforeLambdaBody: true 43 | BeforeWhile: true 44 | IndentBraces: false 45 | SplitEmptyFunction: false 46 | SplitEmptyRecord: false 47 | SplitEmptyNamespace: false 48 | BreakBeforeBinaryOperators: None 49 | BreakBeforeBraces: Custom 50 | BreakBeforeTernaryOperators: true 51 | BreakConstructorInitializers: AfterColon 52 | BreakInheritanceList: AfterColon 53 | BreakStringLiterals: true 54 | ColumnLimit: 120 55 | CompactNamespaces: true 56 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 57 | ConstructorInitializerIndentWidth: 4 58 | ContinuationIndentWidth: 4 59 | Cpp11BracedListStyle: true 60 | DerivePointerAlignment: false 61 | EmptyLineAfterAccessModifier: Never 62 | EmptyLineBeforeAccessModifier: Always 63 | FixNamespaceComments: true 64 | IncludeBlocks: Preserve 65 | IndentCaseLabels: false 66 | IndentExternBlock: Indent 67 | IndentPPDirectives: AfterHash 68 | IndentWidth: 4 69 | IndentPPDirectives: None 70 | KeepEmptyLinesAtTheStartOfBlocks: false 71 | LambdaBodyIndentation: Signature 72 | Language: Cpp 73 | MaxEmptyLinesToKeep: 1 74 | NamespaceIndentation: All 75 | PackConstructorInitializers: Never 76 | # PenaltyBreakAssignment: 77 | # PenaltyBreakBeforeFirstCallParameter: 600 78 | # PenaltyBreakComment: 300 79 | # PenaltyBreakFirstLessLess: 120 80 | # PenaltyBreakString: 1000 81 | # PenaltyBreakTemplateDeclaration: 82 | # PenaltyExcessCharacter: 1000000 83 | # PenaltyReturnTypeOnItsOwnLine: 60 84 | PointerAlignment: Left 85 | ReferenceAlignment: Pointer 86 | ReflowComments: true 87 | SortIncludes: true 88 | SortUsingDeclarations: true 89 | SpaceAfterLogicalNot: false 90 | SpaceAfterTemplateKeyword: true 91 | SpaceBeforeAssignmentOperators: true 92 | SpaceBeforeCaseColon: false 93 | SpaceBeforeCtorInitializerColon: true 94 | SpaceBeforeInheritanceColon: true 95 | SpaceBeforeParens: ControlStatements 96 | SpaceBeforeRangeBasedForLoopColon: true 97 | SpaceBeforeSquareBrackets: false 98 | SpaceInEmptyParentheses: false 99 | SpacesInConditionalStatement: false 100 | SpacesInContainerLiterals: false 101 | SpacesInParentheses: false 102 | SpacesInSquareBrackets: false 103 | Standard: c++17 104 | TabWidth: 4 105 | UseTab: AlignWithSpaces 106 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # Visual Studio Code 35 | .vscode 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2017, Benichou 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CMSIS C++ 2 | A C++11/C++14 interface for CMSIS-RTOS API Version 2. 3 | 4 | This source code implements some classes of the STL, based on [CMSIS-RTOS API Version 2](https://arm-software.github.io/CMSIS_5/RTOS2/html/index.html) interface. 5 | You must use a C++ compiler that supports the C++11/C++14 standard, like [GNU ARM Embedded Toolchain](https://developer.arm.com/open-source/gnu-toolchain/gnu-rm). 6 | 7 | ## C++ Standard 8 | ### Thread 9 | Defined in header "Thread.h" 10 | 11 | This header is part of the [concurrency support](http://en.cppreference.com/w/cpp/thread) library. It provides a full implementation of STL [](http://en.cppreference.com/w/cpp/header/thread) interfaces. 12 | You can directly use [std::thread](http://en.cppreference.com/w/cpp/thread/thread) and [std::thread​::id](http://en.cppreference.com/w/cpp/thread/thread/id) classes, and std::this_thread namespace. 13 | 14 | Threads are created in a join-able state, with default thread priority (osPriorityNormal) and default stack size from the [Global Memory Pool](https://arm-software.github.io/CMSIS_5/RTOS2/html/theory_of_operation.html#GlobalMemoryPool). See [Thread Management](https://arm-software.github.io/CMSIS_5/RTOS2/html/group__CMSIS__RTOS__ThreadMgmt.html) for more details. 15 | 16 | ### Mutex 17 | Defined in header "Mutex.h" 18 | 19 | This header is part of the [concurrency support](http://en.cppreference.com/w/cpp/thread) library. It provides a partial implementation of STL [](http://en.cppreference.com/w/cpp/header/mutex) interfaces. 20 | You can directly use [std::mutex](http://en.cppreference.com/w/cpp/thread/thread), [std::timed_mutex](http://en.cppreference.com/w/cpp/thread/timed_mutex), [std::recursive_mutex](http://en.cppreference.com/w/cpp/thread/recursive_mutex) and [std::recursive_timed_mutex](http://en.cppreference.com/w/cpp/thread/recursive_timed_mutex) classes. 21 | [once_flag](http://en.cppreference.com/w/cpp/thread/once_flag) and [call_once](http://en.cppreference.com/w/cpp/thread/call_once) are not implemented yet. 22 | 23 | Mutexes are created with Priority inheritance protocol (osMutexPrioInherit flag). While a thread owns this mutex it cannot be preempted by a higher priority thread to avoid starvation. See [Mutex Management](https://arm-software.github.io/CMSIS_5/RTOS2/html/group__CMSIS__RTOS__MutexMgmt.html) for more details. 24 | 25 | Mutex management functions cannot be called from [Interrupt Service Routines](https://arm-software.github.io/CMSIS_5/RTOS2/html/theory_of_operation.html#CMSIS_RTOS_ISR_Calls) (ISR), unlike a binary semaphore that can be released from an ISR. 26 | 27 | ### Semaphore 28 | Defined in header "Semaphore.h" 29 | 30 | This header is part of the [concurrency support](http://en.cppreference.com/w/cpp/thread) library. It provides a full implementation of STL [](https://en.cppreference.com/w/cpp/thread/counting_semaphore) interfaces. 31 | You can directly use [std::counting_semaphore](https://en.cppreference.com/w/cpp/thread/counting_semaphore) and [std::binary_semaphore](https://en.cppreference.com/w/cpp/thread/counting_semaphore) classes. 32 | 33 | [Semaphores](https://arm-software.github.io/CMSIS_5/RTOS2/html/group__CMSIS__RTOS__SemaphoreMgmt.html) are used to manage and protect access to shared resources. 34 | 35 | ### Chrono 36 | Defined in header "Chrono.h" 37 | 38 | This header is part of the [date and time](http://en.cppreference.com/w/cpp/chrono) library. It provides a full implementation of STL [](http://en.cppreference.com/w/cpp/header/chrono) interfaces. [std::chrono::system_clock](http://en.cppreference.com/w/cpp/chrono/system_clock) and [std::chrono::high_resolution_clock](http://en.cppreference.com/w/cpp/chrono/high_resolution_clock) are implemented using the osKernelGetTickCount() function. 39 | If you need more precision, you can use sys::chrono::high\_resolution\_clock that is implemented with osKernelGetSysTimerCount() function. 40 | 41 | ### Dynamic memory managment (new, delete) 42 | Globals operators [new](http://en.cppreference.com/w/cpp/memory/new/operator_new) and [delete](http://en.cppreference.com/w/cpp/memory/new/operator_delete) are overridden for using the [Global Memory Pool](https://arm-software.github.io/CMSIS_5/RTOS2/html/theory_of_operation.html#GlobalMemoryPool). For now, this part is specific to [RTX5](https://github.com/ARM-software/CMSIS_5) implementation, and need to be ported for other RTOS (like [FreeRTOS](http://www.freertos.org)). 43 | 44 | ### Exceptions 45 | Defined in header "OSException.h" 46 | 47 | In case of failure, methods throws a [std::system_error](http://en.cppreference.com/w/cpp/error/system_error) exception. [std::error_code::value](http://en.cppreference.com/w/cpp/error/error_code/value) contains the [CMSIS error code](https://arm-software.github.io/CMSIS_5/RTOS2/html/group__CMSIS__RTOS__Definitions.html#ga6c0dbe6069e4e7f47bb4cd32ae2b813e). 48 | 49 | ## CMSIS Specific 50 | This part is a group of some CMSIS specific classes, but as close as possible of the "STL spirit". 51 | 52 | ### Kernel Information and Control 53 | Defined in header "OS.h" 54 | 55 | #### std::string sys::kernel::version() 56 | Get RTOS Kernel version. Returns a string that contains version information. In case of failure, throws a std::system_error exception. 57 | 58 | #### uint32_t sys::kernel::tick_frequency(); 59 | Get RTOS Kernel tick frequency in Hz. Returns the frequency of the current RTOS kernel tick. In case of failure, throws a std::system_error exception. 60 | 61 | #### void sys::kernel::initialize() 62 | Initialize the RTOS Kernel. In case of failure, throws a std::system_error exception. 63 | 64 | If you want to use static C++ objects, the RTOS must be initialized before main(). In that case, call osKernelInitialize() at the end of [SystemInit()](https://arm-software.github.io/CMSIS_5/Core/html/group__system__init__gr.html) function. 65 | 66 | #### void sys::kernel::start() 67 | Start the RTOS Kernel scheduler. In case of success, this function will never returns. In case of failure, throws a std::system_error exception. 68 | 69 | #### uint32_t sys::kernel::suspend() noexcept 70 | Suspends the RTOS kernel scheduler and thus enables sleep modes. 71 | 72 | #### void sys::kernel::resume(uint32_t sleep_ticks) noexcept 73 | Enables the RTOS kernel scheduler and thus wakes up the system from sleep mode. 74 | 75 | #### uint32_t sys::core::clock_frequency(); 76 | Get system core clock frequency in Hz. Returns the frequency of the current system core clock. In case of failure, throws a std::system_error exception. 77 | 78 | ### Event Flags 79 | Defined in header "EventFlag.h" 80 | 81 | The [event flags management](https://arm-software.github.io/CMSIS_5/RTOS2/html/group__CMSIS__RTOS__EventFlags.html) allow you to control or wait for event flags. Each signal has up to 31 event flags. 82 | 83 | Class sys::event. 84 | 85 | ### Timer 86 | Defined in header "Timer.h" 87 | 88 | Timer Management, class sys::timer. 89 | 90 | ### Message Queue 91 | Defined in header "MessageQueue.h" 92 | 93 | [Message Queue](https://arm-software.github.io/CMSIS_5/RTOS2/html/group__CMSIS__RTOS__Message.html) exchange messages between threads in a FIFO-like operation. 94 | 95 | class sys::message_queue. 96 | 97 | ### Memory Pool 98 | Defined in header "Memory.h" 99 | 100 | [Memory Pools](https://arm-software.github.io/CMSIS_5/RTOS2/html/group__CMSIS__RTOS__PoolMgmt.html) are fixed-size blocks of memory that are thread-safe. 101 | 102 | class sys::memory\_pool satisfies [allocator completeness requirements](https://en.cppreference.com/w/cpp/named_req/Allocator) and provides a compatible interface with [std::allocator](https://en.cppreference.com/w/cpp/named_req/Allocator) but is not [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible). In consequence, don't try to use this class with STL containers, because this ones aren't designed to works with fixed size allocators. 103 | 104 | class sys::memory\_pool\_delete is a Deleter (like [std::default_delete](http://en.cppreference.com/w/cpp/memory/default_delete)) associated to an memory pool. 105 | 106 | Be carreful with memory pools and smart pointers. Don't delete a memory pool with living associated smart pointers. 107 | 108 | ## Exemple 109 | ``` 110 | #include 111 | #include "OS.h" 112 | #include "Thread.h" 113 | #include "Timer.h" 114 | #include "Chrono.h" 115 | 116 | int main() 117 | { 118 | cmsis::kernel::initialize(); // Or call osKernelInitialize() at the end of SystemInit() function 119 | 120 | std::thread main_thread([] 121 | { 122 | std::cout << cmsis::kernel::version() << std::endl; 123 | std::cout << "Core Clock: " << sys::core::clock_frequency() << "Hz" << std::endl; 124 | 125 | try 126 | { 127 | std::chrono::system_clock::time_point tp0 = std::chrono::system_clock::now(); 128 | 129 | sys::timer ledTimer(std::chrono::seconds(1), [&] 130 | { 131 | std::cout << "now: " << (std::chrono::system_clock::now() - tp0).count() << std::endl; 132 | return true; 133 | }); 134 | ledTimer.start(); 135 | 136 | sys::chrono::high_resolution_clock::time_point tp1 = sys::chrono::high_resolution_clock::now(); 137 | 138 | for (;;) 139 | { 140 | std::this_thread::sleep_for(std::chrono::milliseconds(900)); 141 | 142 | std::cout << "hrc: " << (sys::chrono::high_resolution_clock::now() - tp1).count() << std::endl; 143 | } 144 | } 145 | catch(std::exception& e) 146 | { 147 | std::cout << "ERROR: " << e.what() << std::endl; 148 | } 149 | }); 150 | 151 | cmsis::kernel::start(); 152 | return 0; 153 | } 154 | ``` 155 | -------------------------------------------------------------------------------- /include/Chrono.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, B. Leforestier 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the author nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef CMSIS_CHRONO_H_ 29 | #define CMSIS_CHRONO_H_ 30 | 31 | #include 32 | 33 | namespace cmsis 34 | { 35 | namespace chrono 36 | { 37 | struct system_clock 38 | { 39 | typedef std::chrono::microseconds duration; 40 | typedef duration::rep rep; 41 | typedef duration::period period; 42 | typedef std::chrono::time_point time_point; 43 | static constexpr bool is_steady = true; 44 | 45 | static_assert( 46 | system_clock::duration::min() < system_clock::duration::zero(), 47 | "a clock's minimum duration cannot be less than its epoch"); 48 | 49 | static time_point now() noexcept; 50 | static std::time_t to_time_t(const time_point& t); 51 | static time_point from_time_t(std::time_t t); 52 | }; 53 | 54 | struct high_resolution_clock 55 | { 56 | typedef std::chrono::nanoseconds duration; 57 | typedef duration::rep rep; 58 | typedef duration::period period; 59 | typedef std::chrono::time_point time_point; 60 | static constexpr bool is_steady = true; 61 | 62 | static time_point now() noexcept; 63 | }; 64 | 65 | using steady_clock = high_resolution_clock; 66 | } // namespace chrono 67 | } // namespace cmsis 68 | 69 | namespace sys 70 | { 71 | namespace chrono = cmsis::chrono; 72 | } 73 | 74 | #endif // CMSIS_CHRONO_H_ 75 | -------------------------------------------------------------------------------- /include/ConditionVariable.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, B. Leforestier 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the author nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef CMSIS_CONDITION_VARIABLE_H_ 29 | #define CMSIS_CONDITION_VARIABLE_H_ 30 | 31 | #include "Mutex.h" 32 | #include "Semaphore.h" 33 | #include 34 | #include 35 | 36 | namespace cmsis 37 | { 38 | // cv_status 39 | enum class cv_status 40 | { 41 | no_timeout, 42 | timeout 43 | }; 44 | 45 | // STL like implementation 46 | class condition_variable 47 | { 48 | public: 49 | typedef void* native_handle_type; 50 | typedef std::chrono::system_clock clock_t; 51 | 52 | condition_variable() = default; 53 | ~condition_variable() = default; 54 | 55 | void notify_one() noexcept; 56 | void notify_all() noexcept; 57 | void wait(std::unique_lock& lock); 58 | 59 | template void wait(std::unique_lock& lock, Predicate pred) 60 | { 61 | while (!pred()) 62 | wait(lock); 63 | } 64 | 65 | template 66 | cv_status 67 | wait_until(std::unique_lock& lock, const std::chrono::time_point& abs_time) 68 | { 69 | auto rel_time = abs_time - Clock::now(); 70 | if (rel_time < std::chrono::microseconds::zero()) 71 | return cv_status::timeout; 72 | 73 | return wait_for(lock, rel_time); 74 | } 75 | 76 | template 77 | bool wait_until( 78 | std::unique_lock& lock, 79 | const std::chrono::time_point& abs_time, 80 | Predicate pred) 81 | { 82 | while (!pred()) 83 | { 84 | if (wait_until(lock, abs_time) == cv_status::timeout) 85 | return pred(); 86 | } 87 | return true; 88 | } 89 | 90 | template 91 | cv_status wait_for(std::unique_lock& lock, const std::chrono::duration& rel_time) 92 | { 93 | return wait_for_usec(lock, std::chrono::duration_cast(rel_time)); 94 | } 95 | 96 | template 97 | bool wait_for( 98 | std::unique_lock& lock, 99 | const std::chrono::duration& rel_time, 100 | Predicate pred) 101 | { 102 | clock_t::time_point abs_time = clock_t::now() + rel_time; 103 | 104 | while (!pred()) 105 | { 106 | if (wait_until(lock, abs_time) == cv_status::timeout) 107 | return pred(); 108 | } 109 | return true; 110 | } 111 | 112 | native_handle_type native_handle() noexcept { return nullptr; } 113 | 114 | condition_variable(const condition_variable&) = delete; 115 | condition_variable& operator=(const condition_variable&) = delete; 116 | 117 | private: 118 | cv_status wait_for_usec(std::unique_lock& lock, std::chrono::microseconds usec); 119 | 120 | private: 121 | cmsis::mutex m_mutex; 122 | std::list m_wait; 123 | }; 124 | } // namespace cmsis 125 | 126 | #if !defined(GLIBCXX_HAS_GTHREADS) && !defined(_GLIBCXX_HAS_GTHREADS) 127 | namespace std 128 | { 129 | using cv_status = cmsis::cv_status; 130 | using condition_variable = cmsis::condition_variable; 131 | } // namespace std 132 | #endif 133 | 134 | #endif // CMSIS_CONDITION_VARIABLE_H_ 135 | -------------------------------------------------------------------------------- /include/EventFlag.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, B. Leforestier 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the author nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef CMSIS_EVENTFLAG_H_ 29 | #define CMSIS_EVENTFLAG_H_ 30 | 31 | #include "WaitFlag.h" 32 | #include 33 | 34 | namespace cmsis 35 | { 36 | class event 37 | { 38 | public: 39 | typedef void* native_handle_type; 40 | typedef uint32_t mask_type; 41 | 42 | enum class status 43 | { 44 | no_timeout, 45 | timeout 46 | }; 47 | 48 | event(mask_type mask = 0); 49 | event(const event&) = delete; 50 | event(event&& evt) noexcept; 51 | ~event() noexcept(false); 52 | 53 | event& operator=(const event&) = delete; 54 | event& operator=(event&& evt) noexcept; 55 | 56 | void swap(event& evt) noexcept; 57 | 58 | mask_type get() const; 59 | 60 | mask_type set(mask_type mask); 61 | mask_type clear(mask_type mask = static_cast(0x7FFFFFFF)); 62 | mask_type wait(mask_type mask, wait_flag flg = wait_flag::any); 63 | 64 | template 65 | status wait_for( 66 | mask_type mask, 67 | wait_flag flg, 68 | const std::chrono::duration& rel_time, 69 | mask_type& flagValue) 70 | { 71 | return wait_for_usec(mask, flg, rel_time, flagValue); 72 | } 73 | 74 | template 75 | status wait_for(mask_type mask, const std::chrono::duration& rel_time, mask_type& flagValue) 76 | { 77 | return wait_for(mask, wait_flag::any, rel_time, flagValue); 78 | } 79 | 80 | template 81 | status wait_until( 82 | mask_type mask, 83 | wait_flag flg, 84 | const std::chrono::time_point& abs_time, 85 | mask_type& flagValue) 86 | { 87 | auto rel_time = abs_time - Clock::now(); 88 | if (rel_time < std::chrono::microseconds::zero()) 89 | return status::timeout; 90 | 91 | return wait_for(mask, flg, rel_time, flagValue); 92 | } 93 | 94 | template 95 | status 96 | wait_until(mask_type mask, const std::chrono::time_point& abs_time, mask_type& flagValue) 97 | { 98 | return wait_until(mask, wait_flag::any, abs_time, flagValue); 99 | } 100 | 101 | native_handle_type native_handle() noexcept { return m_id; } 102 | 103 | private: 104 | status wait_for_usec(mask_type mask, wait_flag flg, std::chrono::microseconds usec, mask_type& flagValue); 105 | 106 | private: 107 | native_handle_type m_id; // event flag identifier 108 | }; 109 | 110 | inline void swap(event& __x, event& __y) noexcept 111 | { 112 | __x.swap(__y); 113 | } 114 | } // namespace cmsis 115 | 116 | namespace sys 117 | { 118 | using event = cmsis::event; 119 | } 120 | 121 | #endif // CMSIS_EVENTFLAG_H_ 122 | -------------------------------------------------------------------------------- /include/Memory.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, B. Leforestier 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the author nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef CMSIS_MEMORY_H_ 29 | #define CMSIS_MEMORY_H_ 30 | 31 | #include 32 | 33 | namespace cmsis 34 | { 35 | namespace internal 36 | { 37 | class base_memory_pool 38 | { 39 | protected: 40 | typedef void* native_handle_type; 41 | 42 | base_memory_pool(size_t count, size_t n); 43 | base_memory_pool(base_memory_pool&& other); 44 | ~base_memory_pool() noexcept(false); 45 | 46 | base_memory_pool& operator=(base_memory_pool&& other); 47 | 48 | void* allocate(size_t n); 49 | void deallocate(void* p); 50 | size_t max_size() const noexcept; 51 | size_t size() const noexcept; 52 | 53 | native_handle_type native_handle() noexcept { return m_id; } 54 | 55 | base_memory_pool(const base_memory_pool&) = delete; 56 | base_memory_pool& operator=(const base_memory_pool&) = delete; 57 | 58 | private: 59 | native_handle_type m_id; 60 | }; 61 | } // namespace internal 62 | 63 | template class memory_pool_delete; 64 | 65 | // This class satisfies allocator completeness requirements. 66 | template class memory_pool : private internal::base_memory_pool 67 | { 68 | public: 69 | typedef internal::base_memory_pool Base; 70 | typedef typename Base::native_handle_type native_handle_type; 71 | 72 | typedef size_t size_type; 73 | typedef ptrdiff_t difference_type; 74 | typedef T* pointer; 75 | typedef const T* const_pointer; 76 | typedef T& reference; 77 | typedef const T& const_reference; 78 | typedef T value_type; 79 | typedef memory_pool_delete deleter_type; 80 | 81 | memory_pool(size_type count) : 82 | Base(count, sizeof(T)) 83 | {} 84 | memory_pool(memory_pool&& other) : 85 | Base(std::move(other)) 86 | {} 87 | ~memory_pool() noexcept(false) = default; 88 | 89 | memory_pool& operator=(memory_pool&& other) 90 | { 91 | Base::operator=(std::move(other)); 92 | return *this; 93 | } 94 | 95 | pointer address(reference x) const noexcept { return std::addressof(x); } 96 | const_pointer address(const_reference x) const noexcept { return std::addressof(x); } 97 | 98 | pointer allocate(size_type n = 1, const void* = 0) { return static_cast(Base::allocate(n)); } 99 | void deallocate(pointer p, size_type) { Base::deallocate(p); } 100 | size_type max_size() const noexcept { return Base::max_size(); } 101 | size_type size() const noexcept { return Base::size(); } 102 | 103 | template void construct(U* p, _Args&&... args) 104 | { 105 | ::new ((void*)p) U(std::forward<_Args>(args)...); 106 | } 107 | 108 | template void destroy(U* p) { p->~U(); } 109 | 110 | deleter_type get_deleter() noexcept { return deleter_type(*this); } 111 | 112 | template std::unique_ptr make_unique(Args&&... args) 113 | { 114 | std::unique_ptr ptr(allocate(), get_deleter()); 115 | construct(ptr.get(), std::forward(args)...); 116 | return ptr; 117 | } 118 | 119 | template std::shared_ptr make_shared(Args&&... args) 120 | { 121 | std::shared_ptr ptr(allocate(), get_deleter()); 122 | construct(ptr.get(), std::forward(args)...); 123 | return ptr; 124 | } 125 | 126 | native_handle_type native_handle() noexcept { return Base::native_handle(); } 127 | 128 | memory_pool(const memory_pool&) = delete; 129 | memory_pool& operator=(const memory_pool&) = delete; 130 | }; 131 | 132 | template class memory_pool_delete 133 | { 134 | public: 135 | memory_pool_delete(memory_pool& mempool) : 136 | m_mempool(mempool) 137 | {} 138 | memory_pool_delete(const memory_pool_delete& m) : 139 | m_mempool(m.m_mempool) 140 | {} 141 | ~memory_pool_delete() = default; 142 | 143 | void operator()(void* p) const 144 | { 145 | if (p) 146 | { 147 | m_mempool.destroy(static_cast(p)); 148 | m_mempool.deallocate(static_cast(p), 1); 149 | } 150 | } 151 | 152 | memory_pool_delete& operator=(const memory_pool_delete&) = delete; 153 | 154 | private: 155 | memory_pool& m_mempool; 156 | }; 157 | 158 | template bool operator==(const memory_pool& lhs, const memory_pool& rhs) 159 | { 160 | return lhs.native_handle() == rhs.native_handle(); 161 | } 162 | 163 | template bool operator!=(const memory_pool& lhs, const memory_pool& rhs) 164 | { 165 | return lhs.native_handle() != rhs.native_handle(); 166 | } 167 | 168 | template bool operator==(const memory_pool& lhs, const memory_pool& rhs) 169 | { 170 | return lhs.native_handle() == rhs.native_handle(); 171 | } 172 | 173 | template bool operator!=(const memory_pool& lhs, const memory_pool& rhs) 174 | { 175 | return lhs.native_handle() != rhs.native_handle(); 176 | } 177 | } // namespace cmsis 178 | 179 | namespace sys 180 | { 181 | template using memory_pool = cmsis::memory_pool; 182 | template using memory_pool_delete = cmsis::memory_pool_delete; 183 | } // namespace sys 184 | 185 | #endif // CMSIS_MEMORY_H_ 186 | -------------------------------------------------------------------------------- /include/MessageQueue.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, B. Leforestier 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the author nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef CPP_CMSIS_MESSAGE_QUEUE_H_INCLUDED 29 | #define CPP_CMSIS_MESSAGE_QUEUE_H_INCLUDED 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | namespace cmsis 36 | { 37 | // mq_status 38 | enum class mq_status 39 | { 40 | no_timeout, 41 | timeout, 42 | full, 43 | empty 44 | }; 45 | 46 | namespace internal 47 | { 48 | class message_queue_impl 49 | { 50 | public: 51 | message_queue_impl(size_t max_len, size_t ele_len); 52 | message_queue_impl(const message_queue_impl&) = delete; 53 | message_queue_impl(message_queue_impl&& t); 54 | ~message_queue_impl() noexcept(false); 55 | 56 | void swap(message_queue_impl& t); 57 | 58 | message_queue_impl& operator=(const message_queue_impl&) = delete; 59 | message_queue_impl& operator=(message_queue_impl&& t); 60 | 61 | void put(const void* data, uint8_t priority); 62 | mq_status put(const void* data, uint8_t priority, std::chrono::microseconds usec); 63 | 64 | void get(void* data); 65 | mq_status get(void* data, std::chrono::microseconds usec); 66 | 67 | size_t size() const; 68 | size_t capacity() const; 69 | 70 | void clear(); 71 | 72 | private: 73 | void* m_id; 74 | }; 75 | } // namespace internal 76 | 77 | template // Default implementation 78 | class message_queue : private internal::message_queue_impl 79 | { 80 | static_assert(std::is_standard_layout::value && std::is_trivial::value, "Only support POD type"); 81 | 82 | public: 83 | typedef T element_type; 84 | 85 | message_queue(size_t max_len) : 86 | internal::message_queue_impl(max_len, sizeof(T)) 87 | {} 88 | message_queue(const message_queue&) = delete; 89 | message_queue(message_queue&& t) : 90 | internal::message_queue_impl(std::move(t)) 91 | {} 92 | ~message_queue() = default; 93 | 94 | void swap(message_queue& t) noexcept { internal::message_queue_impl::swap(t); } 95 | 96 | message_queue& operator=(const message_queue&) = delete; 97 | message_queue& operator=(message_queue&& t) 98 | { 99 | internal::message_queue_impl::operator=(std::move(t)); 100 | return *this; 101 | } 102 | 103 | void put(const element_type& data, uint8_t priority = 0) { internal::message_queue_impl::put(&data, priority); } 104 | 105 | template 106 | mq_status put(const element_type& data, uint8_t priority, const std::chrono::duration& wait_time) 107 | { 108 | return internal::message_queue_impl::put(&data, priority, wait_time); 109 | } 110 | 111 | template 112 | mq_status put(const element_type& data, const std::chrono::duration& wait_time) 113 | { 114 | return internal::message_queue_impl::put(&data, 0, wait_time); 115 | } 116 | 117 | element_type get() 118 | { 119 | element_type data; 120 | internal::message_queue_impl::get(&data); 121 | return data; 122 | } 123 | 124 | void get(element_type& data) { internal::message_queue_impl::get(&data); } 125 | 126 | template 127 | mq_status get(element_type& data, const std::chrono::duration& wait_time) 128 | { 129 | return internal::message_queue_impl::get(&data, wait_time); 130 | } 131 | 132 | bool empty() const { return size() == 0; } 133 | size_t size() const { return internal::message_queue_impl::size(); } 134 | size_t capacity() const { return internal::message_queue_impl::capacity(); } 135 | 136 | void clear() { internal::message_queue_impl::clear(); } 137 | }; 138 | 139 | template // Specialization for unique_pointer 140 | class message_queue> : private internal::message_queue_impl 141 | { 142 | public: 143 | typedef typename std::unique_ptr::element_type element_type; 144 | typedef typename std::unique_ptr::pointer pointer; 145 | 146 | message_queue(size_t max_len) : 147 | internal::message_queue_impl(max_len, sizeof(pointer)) 148 | {} 149 | message_queue(const message_queue&) = delete; 150 | message_queue(message_queue&& t) : 151 | internal::message_queue_impl(std::move(t)) 152 | {} 153 | ~message_queue() = default; 154 | 155 | void swap(message_queue& t) noexcept { internal::message_queue_impl::swap(t); } 156 | 157 | message_queue& operator=(const message_queue&) = delete; 158 | message_queue& operator=(message_queue&& t) 159 | { 160 | internal::message_queue_impl::operator=(std::move(t)); 161 | return *this; 162 | } 163 | 164 | void put(std::unique_ptr&& data, uint8_t priority = 0) 165 | { 166 | pointer ptr = data.release(); 167 | internal::message_queue_impl::put(&ptr, priority); 168 | } 169 | 170 | template 171 | mq_status put(std::unique_ptr&& data, uint8_t priority, const std::chrono::duration& wait_time) 172 | { 173 | pointer ptr = data.release(); 174 | return internal::message_queue_impl::put(&ptr, priority, wait_time); 175 | } 176 | 177 | template 178 | mq_status put(std::unique_ptr&& data, const std::chrono::duration& wait_time) 179 | { 180 | pointer ptr = data.release(); 181 | return internal::message_queue_impl::put(&ptr, 0, wait_time); 182 | } 183 | 184 | std::unique_ptr get() 185 | { 186 | void* ptr = nullptr; 187 | internal::message_queue_impl::get(&ptr); 188 | return std::unique_ptr(static_cast(ptr)); 189 | } 190 | 191 | void get(std::unique_ptr& data) 192 | { 193 | void* ptr = nullptr; 194 | bool ret = internal::message_queue_impl::get(&ptr); 195 | data.reset(static_cast(ptr)); 196 | } 197 | 198 | template 199 | mq_status get(std::unique_ptr& data, const std::chrono::duration& wait_time) 200 | { 201 | void* ptr = nullptr; 202 | mq_status ret = internal::message_queue_impl::get(&ptr, wait_time); 203 | data.reset(static_cast(ptr)); 204 | return ret; 205 | } 206 | 207 | bool empty() const { return size() == 0; } 208 | size_t size() const { return internal::message_queue_impl::size(); } 209 | size_t capacity() const { return internal::message_queue_impl::capacity(); } 210 | 211 | void clear() 212 | { 213 | // Avoid memory leak 214 | while (!empty()) 215 | get(); 216 | 217 | internal::message_queue_impl::clear(); 218 | } 219 | }; 220 | 221 | template // Specialization for pointer 222 | class message_queue : private internal::message_queue_impl 223 | { 224 | public: 225 | typedef T element_type; 226 | typedef typename std::add_pointer::type pointer; 227 | 228 | message_queue(size_t max_len) : 229 | internal::message_queue_impl(max_len, sizeof(pointer)) 230 | {} 231 | message_queue(const message_queue&) = delete; 232 | message_queue(message_queue&& t) : 233 | internal::message_queue_impl(std::move(t)) 234 | {} 235 | ~message_queue() = default; 236 | 237 | void swap(message_queue& t) noexcept { internal::message_queue_impl::swap(t); } 238 | 239 | message_queue& operator=(const message_queue&) = delete; 240 | message_queue& operator=(message_queue&& t) 241 | { 242 | internal::message_queue_impl::operator=(std::move(t)); 243 | return *this; 244 | } 245 | 246 | void put(const pointer& ptr, uint8_t priority = 0) { internal::message_queue_impl::put(&ptr, priority); } 247 | 248 | template 249 | mq_status put(const pointer& ptr, uint8_t priority, const std::chrono::duration& wait_time) 250 | { 251 | return internal::message_queue_impl::put(&ptr, priority, wait_time); 252 | } 253 | 254 | template 255 | mq_status put(const pointer& ptr, const std::chrono::duration& wait_time) 256 | { 257 | return internal::message_queue_impl::put(&ptr, 0, wait_time); 258 | } 259 | 260 | pointer get() 261 | { 262 | void* ptr = nullptr; 263 | internal::message_queue_impl::get(&ptr); 264 | return static_cast(ptr); 265 | } 266 | 267 | void get(pointer& data) 268 | { 269 | void* ptr = nullptr; 270 | bool ret = internal::message_queue_impl::get(&ptr); 271 | data = static_cast(ptr); 272 | } 273 | 274 | template 275 | mq_status get(pointer& data, const std::chrono::duration& wait_time) 276 | { 277 | void* ptr = nullptr; 278 | mq_status ret = internal::message_queue_impl::get(&ptr, wait_time); 279 | data = static_cast(ptr); 280 | return ret; 281 | } 282 | 283 | bool empty() const { return size() == 0; } 284 | size_t size() const { return internal::message_queue_impl::size(); } 285 | size_t capacity() const { return internal::message_queue_impl::capacity(); } 286 | 287 | void clear() { internal::message_queue_impl::clear(); } 288 | }; 289 | 290 | template inline void swap(message_queue& __x, message_queue& __y) noexcept 291 | { 292 | __x.swap(__y); 293 | } 294 | } // namespace cmsis 295 | 296 | namespace sys 297 | { 298 | using mq_status = cmsis::mq_status; 299 | template using message_queue = cmsis::message_queue; 300 | } // namespace sys 301 | 302 | #endif // CPP_CMSIS_MESSAGE_QUEUE_H_INCLUDED 303 | -------------------------------------------------------------------------------- /include/Mutex.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, B. Leforestier 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the author nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef CMSIS_MUTEX_H_ 29 | #define CMSIS_MUTEX_H_ 30 | 31 | #include 32 | 33 | namespace cmsis 34 | { 35 | namespace internal 36 | { 37 | class base_timed_mutex 38 | { 39 | protected: 40 | typedef void* native_handle_type; 41 | 42 | base_timed_mutex(const char* name, bool recursive); 43 | ~base_timed_mutex() noexcept(false); 44 | 45 | void lock(); 46 | void unlock(); 47 | bool try_lock(); 48 | 49 | template bool try_lock_for(const std::chrono::duration& rel_time) 50 | { 51 | return try_lock_for_usec(rel_time); 52 | } 53 | 54 | template 55 | bool try_lock_until(const std::chrono::time_point& abs_time) 56 | { 57 | auto rel_time = abs_time - Clock::now(); 58 | if (rel_time < std::chrono::microseconds::zero()) 59 | return false; 60 | 61 | return try_lock_for(rel_time); 62 | } 63 | 64 | native_handle_type native_handle() noexcept { return m_id; } 65 | 66 | base_timed_mutex(const base_timed_mutex&) = delete; 67 | base_timed_mutex& operator=(const base_timed_mutex&) = delete; 68 | 69 | private: 70 | bool try_lock_for_usec(std::chrono::microseconds usec); 71 | 72 | private: 73 | native_handle_type m_id; ///< mutex identifier 74 | }; 75 | } // namespace internal 76 | 77 | // STL like implementation 78 | class mutex : private internal::base_timed_mutex 79 | { 80 | public: 81 | typedef internal::base_timed_mutex::native_handle_type native_handle_type; 82 | 83 | mutex() : 84 | internal::base_timed_mutex("mutex", false) 85 | {} 86 | ~mutex() = default; 87 | 88 | void lock() { internal::base_timed_mutex::lock(); } 89 | void unlock() { internal::base_timed_mutex::unlock(); } 90 | bool try_lock() { return internal::base_timed_mutex::try_lock(); } 91 | 92 | native_handle_type native_handle() noexcept { return internal::base_timed_mutex::native_handle(); } 93 | 94 | mutex(const mutex&) = delete; 95 | mutex& operator=(const mutex&) = delete; 96 | }; 97 | 98 | class recursive_mutex : private internal::base_timed_mutex 99 | { 100 | public: 101 | typedef internal::base_timed_mutex::native_handle_type native_handle_type; 102 | 103 | recursive_mutex() : 104 | internal::base_timed_mutex("recursive_mutex", true) 105 | {} 106 | ~recursive_mutex() = default; 107 | 108 | void lock() { internal::base_timed_mutex::lock(); } 109 | void unlock() { internal::base_timed_mutex::unlock(); } 110 | bool try_lock() { return internal::base_timed_mutex::try_lock(); } 111 | 112 | native_handle_type native_handle() noexcept { return internal::base_timed_mutex::native_handle(); } 113 | 114 | recursive_mutex(const recursive_mutex&) = delete; 115 | recursive_mutex& operator=(const recursive_mutex&) = delete; 116 | }; 117 | 118 | class timed_mutex : private internal::base_timed_mutex 119 | { 120 | public: 121 | typedef internal::base_timed_mutex::native_handle_type native_handle_type; 122 | 123 | timed_mutex() : 124 | internal::base_timed_mutex("timed_mutex", false) 125 | {} 126 | ~timed_mutex() = default; 127 | 128 | void lock() { internal::base_timed_mutex::lock(); } 129 | void unlock() { internal::base_timed_mutex::unlock(); } 130 | bool try_lock() { return internal::base_timed_mutex::try_lock(); } 131 | 132 | template bool try_lock_for(const std::chrono::duration& rel_time) 133 | { 134 | return internal::base_timed_mutex::try_lock_for(rel_time); 135 | } 136 | 137 | template 138 | bool try_lock_until(const std::chrono::time_point& abs_time) 139 | { 140 | return internal::base_timed_mutex::try_lock_until(abs_time); 141 | } 142 | 143 | native_handle_type native_handle() noexcept { return internal::base_timed_mutex::native_handle(); } 144 | 145 | timed_mutex(const timed_mutex&) = delete; 146 | timed_mutex& operator=(const timed_mutex&) = delete; 147 | }; 148 | 149 | class recursive_timed_mutex : private internal::base_timed_mutex 150 | { 151 | public: 152 | typedef internal::base_timed_mutex::native_handle_type native_handle_type; 153 | 154 | recursive_timed_mutex() : 155 | internal::base_timed_mutex("recursive_timed_mutex", true) 156 | {} 157 | ~recursive_timed_mutex() = default; 158 | 159 | void lock() { internal::base_timed_mutex::lock(); } 160 | void unlock() { internal::base_timed_mutex::unlock(); } 161 | bool try_lock() { return internal::base_timed_mutex::try_lock(); } 162 | 163 | template bool try_lock_for(const std::chrono::duration& rel_time) 164 | { 165 | return internal::base_timed_mutex::try_lock_for(rel_time); 166 | } 167 | 168 | template 169 | bool try_lock_until(const std::chrono::time_point& abs_time) 170 | { 171 | return internal::base_timed_mutex::try_lock_until(abs_time); 172 | } 173 | 174 | native_handle_type native_handle() noexcept { return internal::base_timed_mutex::native_handle(); } 175 | 176 | recursive_timed_mutex(const recursive_timed_mutex&) = delete; 177 | recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete; 178 | }; 179 | } // namespace cmsis 180 | 181 | #if !defined(GLIBCXX_HAS_GTHREADS) && !defined(_GLIBCXX_HAS_GTHREADS) 182 | namespace std 183 | { 184 | using mutex = cmsis::mutex; 185 | using recursive_mutex = cmsis::recursive_mutex; 186 | using timed_mutex = cmsis::timed_mutex; 187 | using recursive_timed_mutex = cmsis::recursive_timed_mutex; 188 | } // namespace std 189 | #endif 190 | 191 | #endif // CMSIS_MUTEX_H_ 192 | -------------------------------------------------------------------------------- /include/OS.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, B. Leforestier 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the author nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef CPP_CMSIS_OS_H_ 29 | #define CPP_CMSIS_OS_H_ 30 | 31 | #include 32 | #include 33 | 34 | namespace cmsis 35 | { 36 | /// Kernel Information and Control. 37 | namespace kernel 38 | { 39 | /// Get RTOS Kernel version. 40 | /// \return string that contains version information. 41 | /// \exception In case of failure, throws a std::system_error exception. 42 | const char* version(); 43 | 44 | /// Get RTOS Kernel tick frequency in Hz. 45 | /// \return the frequency of the current RTOS kernel tick. 46 | /// \exception In case of failure, throws a std::system_error exception. 47 | uint32_t tick_frequency(); 48 | 49 | /// Initialize the RTOS Kernel. 50 | /// \exception In case of failure, throws a std::system_error exception. 51 | void initialize(); 52 | 53 | /// Start the RTOS Kernel scheduler. 54 | /// In case of success, this function will never returns. 55 | /// \exception In case of failure, throws a std::system_error exception. 56 | void start(); 57 | 58 | /// Suspends the RTOS kernel scheduler and thus enables sleep modes. 59 | uint32_t suspend() noexcept; 60 | 61 | /// Enables the RTOS kernel scheduler and thus wakes up the system from sleep mode. 62 | void resume(uint32_t sleep_ticks) noexcept; 63 | 64 | /// Start the idle handler called by the idle thread. 65 | /// \exception In case of failure, throws a std::system_error exception. 66 | void set_idle_handler(std::function&& handler); 67 | } // namespace kernel 68 | 69 | namespace core 70 | { 71 | /// Get system core clock frequency in Hz. 72 | /// \return the frequency of the current system core clock. 73 | /// \exception In case of failure, throws a std::system_error exception. 74 | uint32_t clock_frequency(); 75 | } // namespace core 76 | 77 | /// Management of the RTOS Kernel scheduler. 78 | /// This class is conform to the C++ BasicLockable concept, and can be used by std::lock_guard. 79 | class dispatch 80 | { 81 | public: 82 | dispatch(); 83 | ~dispatch() = default; 84 | 85 | dispatch(const dispatch&) = delete; 86 | dispatch& operator=(const dispatch&) = delete; 87 | 88 | void lock(); 89 | void unlock(); 90 | 91 | static bool locked(); 92 | 93 | private: 94 | int32_t m_previous_lock_state; 95 | }; 96 | } // namespace cmsis 97 | 98 | namespace sys 99 | { 100 | namespace kernel = cmsis::kernel; 101 | namespace core = cmsis::core; 102 | using dispatch = cmsis::dispatch; 103 | } // namespace sys 104 | 105 | #endif // CPP_CMSIS_OS_H_ 106 | -------------------------------------------------------------------------------- /include/OSException.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, B. Leforestier 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the author nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef CMSIS_OSEXCEPTION_H_ 29 | #define CMSIS_OSEXCEPTION_H_ 30 | 31 | #include 32 | 33 | #ifdef __cpp_exceptions 34 | #include 35 | 36 | namespace cmsis 37 | { 38 | const std::error_category& os_category(); 39 | const std::error_category& flags_category(); 40 | 41 | namespace internal 42 | { 43 | std::string str_error(const std::string& func, const void* id); 44 | } 45 | } // namespace cmsis 46 | 47 | #endif // __cpp_exceptions 48 | #endif // CMSIS_OSEXCEPTION_H_ 49 | -------------------------------------------------------------------------------- /include/Semaphore.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, B. Leforestier 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the author nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef CPP_CMSIS_SEMAPHORE_H_ 29 | #define CPP_CMSIS_SEMAPHORE_H_ 30 | 31 | #include 32 | 33 | namespace cmsis 34 | { 35 | namespace internal 36 | { 37 | class base_semaphore 38 | { 39 | public: 40 | typedef void* native_handle_type; 41 | 42 | base_semaphore(std::ptrdiff_t max, std::ptrdiff_t desired); 43 | ~base_semaphore() noexcept(false); 44 | 45 | void release(std::ptrdiff_t update = 1); 46 | void acquire(); 47 | bool try_acquire() noexcept; 48 | 49 | template bool try_acquire_for(const std::chrono::duration& rel_time) 50 | { 51 | return try_acquire_for_usec(std::chrono::duration_cast(rel_time)); 52 | } 53 | 54 | template 55 | bool try_acquire_until(const std::chrono::time_point& abs_time) 56 | { 57 | auto rel_time = abs_time - Clock::now(); 58 | if (rel_time < std::chrono::microseconds::zero()) 59 | return false; 60 | 61 | return try_acquire_for(rel_time); 62 | } 63 | 64 | native_handle_type native_handle() noexcept { return m_id; } 65 | 66 | base_semaphore(const base_semaphore&) = delete; 67 | base_semaphore& operator=(const base_semaphore&) = delete; 68 | 69 | private: 70 | bool try_acquire_for_usec(std::chrono::microseconds usec); 71 | 72 | private: 73 | native_handle_type m_id; ///< sempahore identifier 74 | }; 75 | } // namespace internal 76 | 77 | template class counting_semaphore : private internal::base_semaphore 78 | { 79 | public: 80 | typedef internal::base_semaphore::native_handle_type native_handle_type; 81 | 82 | constexpr explicit counting_semaphore(std::ptrdiff_t desired) : 83 | internal::base_semaphore(max(), desired) 84 | {} 85 | ~counting_semaphore() = default; 86 | 87 | void release(std::ptrdiff_t update = 1) { internal::base_semaphore::release(update); } 88 | void acquire() { internal::base_semaphore::acquire(); } 89 | bool try_acquire() noexcept { return internal::base_semaphore::try_acquire(); } 90 | 91 | template bool try_acquire_for(const std::chrono::duration& rel_time) 92 | { 93 | return internal::base_semaphore::try_acquire_for(rel_time); 94 | } 95 | 96 | template 97 | bool try_acquire_until(const std::chrono::time_point& abs_time) 98 | { 99 | return internal::base_semaphore::try_acquire_until(abs_time); 100 | } 101 | 102 | static constexpr std::ptrdiff_t max() noexcept { return LeastMaxValue; } 103 | 104 | native_handle_type native_handle() noexcept { return internal::base_semaphore::native_handle(); } 105 | 106 | counting_semaphore(const counting_semaphore&) = delete; 107 | counting_semaphore& operator=(const counting_semaphore&) = delete; 108 | }; 109 | 110 | using binary_semaphore = counting_semaphore<1>; 111 | } // namespace cmsis 112 | 113 | #if !defined(GLIBCXX_HAS_GTHREADS) && !defined(_GLIBCXX_HAS_GTHREADS) 114 | namespace std 115 | { 116 | template 117 | using counting_semaphore = cmsis::counting_semaphore; 118 | using binary_semaphore = cmsis::binary_semaphore; 119 | } // namespace std 120 | #endif 121 | 122 | #endif // CPP_CMSIS_SEMAPHORE_H_ 123 | -------------------------------------------------------------------------------- /include/Thread.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, B. Leforestier 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the author nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef CPP_CMSIS_THREAD_H_ 29 | #define CPP_CMSIS_THREAD_H_ 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | namespace cmsis 36 | { 37 | class thread_impl; 38 | 39 | // STL like implementation 40 | class thread 41 | { 42 | public: 43 | typedef void* native_handle_type; 44 | 45 | class id 46 | { 47 | public: 48 | id() noexcept : 49 | m_tid(0) 50 | {} 51 | explicit id(native_handle_type __id) : 52 | m_tid(__id) 53 | {} 54 | 55 | private: 56 | friend class thread; 57 | friend class std::hash; 58 | 59 | friend bool operator==(thread::id __x, thread::id __y) noexcept { return __x.m_tid == __y.m_tid; } 60 | friend bool operator<(thread::id __x, thread::id __y) noexcept { return __x.m_tid < __y.m_tid; } 61 | 62 | template 63 | friend std::basic_ostream<_CharT, _Traits>& 64 | operator<<(std::basic_ostream<_CharT, _Traits>& __out, thread::id __id); 65 | 66 | private: 67 | native_handle_type m_tid; 68 | }; 69 | 70 | // Specific structure for embedded system 71 | struct attributes 72 | { 73 | void* stack_mem; // memory for stack (NULL to allocate stack from a fixed-size memory) 74 | size_t stack_size; // size of stack (0 as the default is no memory provided) 75 | size_t priority; // initial thread priority (default: osPriorityNormal) 76 | const char* name; // name of the thread 77 | }; 78 | 79 | thread() noexcept; 80 | thread(const thread&) = delete; 81 | thread(thread&& __t) noexcept; 82 | 83 | template 84 | thread(const attributes& attr, _Callable&& __f, _Args&&... __args) : 85 | thread(attr, make_routine(std::bind(std::forward<_Callable>(__f), std::forward<_Args>(__args)...))) 86 | {} 87 | 88 | ~thread(); 89 | 90 | thread& operator=(const thread&) = delete; 91 | thread& operator=(thread&& __t); 92 | 93 | void join(); 94 | 95 | void detach(); 96 | 97 | bool joinable() const; // checks whether the thread is joinable 98 | 99 | id get_id() const; 100 | 101 | native_handle_type native_handle(); 102 | 103 | void swap(thread& __t); 104 | 105 | // Returns a value that hints at the number of hardware thread contexts. 106 | static unsigned int hardware_concurrency() noexcept; 107 | 108 | // CMSIS specific methods 109 | void suspend(); 110 | void resume(); 111 | 112 | void priority(size_t prio); 113 | size_t priority() const; 114 | 115 | const char* name() const noexcept; 116 | bool is_blocked() const; 117 | 118 | size_t stack_size() const noexcept; 119 | size_t stack_space() const noexcept; 120 | 121 | // Simple base type that the templatized, derived class containing an arbitrary functor can be converted to and 122 | // called. 123 | struct CallableBase 124 | { 125 | virtual ~CallableBase() = default; 126 | virtual void run() = 0; 127 | }; 128 | 129 | private: 130 | template struct CallableImpl : public CallableBase 131 | { 132 | explicit CallableImpl(_Callable&& __f) : 133 | m_func(std::forward<_Callable>(__f)) 134 | {} 135 | virtual void run() override { m_func(); } 136 | _Callable m_func; 137 | }; 138 | 139 | template std::unique_ptr make_routine(_Callable&& __f) 140 | { 141 | // Create and allocate full data structure, not base. 142 | return std::unique_ptr(new CallableImpl<_Callable>(std::forward<_Callable>(__f))); 143 | } 144 | 145 | thread(const attributes& attr, std::unique_ptr base); 146 | 147 | private: 148 | std::unique_ptr m_pThread; 149 | }; 150 | 151 | inline void swap(thread& __x, thread& __y) noexcept 152 | { 153 | __x.swap(__y); 154 | } 155 | 156 | inline bool operator!=(thread::id __x, thread::id __y) noexcept 157 | { 158 | return !(__x == __y); 159 | } 160 | 161 | inline bool operator<=(thread::id __x, thread::id __y) noexcept 162 | { 163 | return !(__y < __x); 164 | } 165 | 166 | inline bool operator>(thread::id __x, thread::id __y) noexcept 167 | { 168 | return __y < __x; 169 | } 170 | 171 | inline bool operator>=(thread::id __x, thread::id __y) noexcept 172 | { 173 | return !(__x < __y); 174 | } 175 | 176 | template 177 | inline std::basic_ostream<_CharT, _Traits>& operator<<(std::basic_ostream<_CharT, _Traits>& __out, thread::id __id) 178 | { 179 | if (__id == thread::id()) 180 | return __out << "task::id of a non-executing thread"; 181 | else 182 | return __out << __id.m_tid; 183 | } 184 | 185 | namespace this_thread 186 | { 187 | namespace internal 188 | { 189 | void sleep_for_usec(std::chrono::microseconds usec); 190 | } 191 | 192 | /// Provides a hint to the implementation to reschedule the execution of threads, allowing other threads to run. 193 | void yield(); 194 | 195 | /// Returns the id of the current thread. 196 | thread::id get_id(); 197 | 198 | /// sleep_for 199 | template void sleep_for(const std::chrono::duration& sleep_duration) 200 | { 201 | internal::sleep_for_usec(std::chrono::duration_cast(sleep_duration)); 202 | } 203 | 204 | /// sleep_until 205 | template 206 | void sleep_until(const std::chrono::time_point& sleep_time) 207 | { 208 | auto now = Clock::now(); 209 | if (Clock::is_steady) 210 | { 211 | if (now < sleep_time) 212 | sleep_for(sleep_time - now); 213 | return; 214 | } 215 | 216 | while (now < sleep_time) 217 | { 218 | sleep_for(sleep_time - now); 219 | now = Clock::now(); 220 | } 221 | } 222 | } // namespace this_thread 223 | } // namespace cmsis 224 | 225 | namespace sys 226 | { 227 | using thread = cmsis::thread; 228 | namespace this_thread = cmsis::this_thread; 229 | } // namespace sys 230 | 231 | namespace std 232 | { 233 | /// std::hash specialization for thread::id. 234 | template <> struct hash : public __hash_base 235 | { 236 | size_t operator()(const cmsis::thread::id& __id) const noexcept 237 | { 238 | return std::hash()(__id.m_tid); 239 | } 240 | }; 241 | 242 | #if !defined(GLIBCXX_HAS_GTHREADS) && !defined(_GLIBCXX_HAS_GTHREADS) && !defined(_GLIBCXX_THREAD_H) 243 | class thread : public cmsis::thread 244 | { 245 | public: 246 | thread() noexcept = default; 247 | thread(const thread&) = delete; 248 | thread(thread&&) noexcept = default; 249 | 250 | template 251 | explicit thread(_Callable&& __f, _Args&&... __args) : 252 | cmsis::thread({}, std::forward<_Callable>(__f), std::forward<_Args>(__args)...) 253 | {} 254 | 255 | ~thread() = default; 256 | 257 | thread& operator=(const thread&) = delete; 258 | thread& operator=(thread&&) = default; 259 | }; 260 | 261 | namespace this_thread = cmsis::this_thread; 262 | #endif 263 | } // namespace std 264 | 265 | #endif // CPP_CMSIS_THREAD_H_ 266 | -------------------------------------------------------------------------------- /include/ThreadFlag.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, B. Leforestier 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the author nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef CPP_CMSIS_THREADFLAG_H_ 29 | #define CPP_CMSIS_THREADFLAG_H_ 30 | 31 | #include "Thread.h" 32 | #include "WaitFlag.h" 33 | 34 | namespace cmsis 35 | { 36 | struct thread_flags 37 | { 38 | typedef uint32_t mask_type; 39 | 40 | static mask_type set(thread& t, mask_type mask); 41 | }; 42 | 43 | namespace this_thread 44 | { 45 | class flags 46 | { 47 | public: 48 | typedef uint32_t mask_type; 49 | 50 | enum class status 51 | { 52 | no_timeout, 53 | timeout 54 | }; 55 | 56 | static mask_type set(mask_type mask); 57 | static mask_type get(); 58 | 59 | static mask_type clear(mask_type mask = static_cast(0x7FFFFFFF)); 60 | static mask_type wait(mask_type mask, wait_flag flg = wait_flag::any); 61 | 62 | template 63 | static status wait_for( 64 | mask_type mask, 65 | wait_flag flg, 66 | const std::chrono::duration& rel_time, 67 | mask_type& flagValue) 68 | { 69 | return wait_for_usec(mask, flg, rel_time, flagValue); 70 | } 71 | 72 | template 73 | static status 74 | wait_for(mask_type mask, const std::chrono::duration& rel_time, mask_type& flagValue) 75 | { 76 | return wait_for(mask, wait_flag::any, rel_time, flagValue); 77 | } 78 | 79 | template 80 | static status wait_until( 81 | mask_type mask, 82 | wait_flag flg, 83 | const std::chrono::time_point& abs_time, 84 | mask_type& flagValue) 85 | { 86 | auto rel_time = abs_time - Clock::now(); 87 | if (rel_time < std::chrono::microseconds::zero()) 88 | return status::timeout; 89 | 90 | return wait_for(mask, flg, rel_time, flagValue); 91 | } 92 | 93 | template 94 | static status 95 | wait_until(mask_type mask, const std::chrono::time_point& abs_time, mask_type& flagValue) 96 | { 97 | return wait_until(mask, wait_flag::any, abs_time, flagValue); 98 | } 99 | 100 | private: 101 | static status 102 | wait_for_usec(mask_type mask, wait_flag flg, std::chrono::microseconds usec, mask_type& flagValue); 103 | }; 104 | } // namespace this_thread 105 | } // namespace cmsis 106 | 107 | namespace sys 108 | { 109 | using thread_flags = cmsis::thread_flags; 110 | namespace this_thread = cmsis::this_thread; 111 | } // namespace sys 112 | 113 | #endif // CPP_CMSIS_THREADFLAG_H_ 114 | -------------------------------------------------------------------------------- /include/Threads.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, B. Leforestier 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the author nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef CPP_CMSIS_THREADS_H_ 29 | #define CPP_CMSIS_THREADS_H_ 30 | 31 | #include "Thread.h" 32 | #include 33 | 34 | namespace cmsis 35 | { 36 | class threads 37 | { 38 | public: 39 | struct info 40 | { 41 | thread::native_handle_type handle; 42 | const char* name; 43 | size_t state; 44 | size_t priority; 45 | size_t stack_size; 46 | size_t stack_space; 47 | }; 48 | 49 | static size_t count() noexcept; 50 | static std::vector enumerate() noexcept; 51 | }; 52 | } // namespace cmsis 53 | 54 | namespace sys 55 | { 56 | using threads = cmsis::threads; 57 | } 58 | 59 | #endif // CPP_CMSIS_THREADS_H_ 60 | -------------------------------------------------------------------------------- /include/Timer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, B. Leforestier 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the author nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef CPP_CMSIS_TIMER_H_INCLUDED 29 | #define CPP_CMSIS_TIMER_H_INCLUDED 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | namespace cmsis 36 | { 37 | class cmsis_timer; 38 | 39 | class timer 40 | { 41 | public: 42 | typedef std::function callback_t; // If callback return false, the timer is stopped 43 | enum class timer_type_t 44 | { 45 | once, 46 | periodic 47 | }; 48 | 49 | timer(); 50 | timer(std::chrono::microseconds usec, callback_t&& function, timer_type_t type = timer_type_t::periodic); 51 | timer(const timer&) = delete; 52 | timer(timer&& t); 53 | ~timer(); 54 | 55 | void swap(timer& t) noexcept; 56 | 57 | timer& operator=(const timer&) = delete; 58 | timer& operator=(timer&& t); 59 | 60 | void start(); 61 | void stop(); 62 | bool running() const; 63 | 64 | private: 65 | std::unique_ptr m_pImplTimer; 66 | }; 67 | 68 | inline void swap(timer& __x, timer& __y) noexcept 69 | { 70 | __x.swap(__y); 71 | } 72 | } // namespace cmsis 73 | 74 | namespace sys 75 | { 76 | using timer = cmsis::timer; 77 | } 78 | 79 | #endif // CPP_CMSIS_TIMER_H_INCLUDED 80 | -------------------------------------------------------------------------------- /include/WaitFlag.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, B. Leforestier 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the author nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef CMSIS_WAITFLAG_H_ 29 | #define CMSIS_WAITFLAG_H_ 30 | 31 | #include 32 | 33 | namespace cmsis 34 | { 35 | enum class wait_flag : uint32_t 36 | { 37 | any = 0, // Wait for any flag 38 | all = 1, // Wait for all flags 39 | no_clear = 2 // Do not clear flags which have been specified to wait for 40 | }; 41 | } 42 | 43 | inline cmsis::wait_flag operator|(cmsis::wait_flag left, cmsis::wait_flag right) 44 | { 45 | return static_cast(static_cast(left) | static_cast(right)); 46 | } 47 | 48 | inline cmsis::wait_flag operator|=(cmsis::wait_flag left, cmsis::wait_flag right) 49 | { 50 | left = left | right; 51 | return left; 52 | } 53 | 54 | inline cmsis::wait_flag operator&(cmsis::wait_flag left, cmsis::wait_flag right) 55 | { 56 | return static_cast(static_cast(left) & static_cast(right)); 57 | } 58 | 59 | inline cmsis::wait_flag operator&=(cmsis::wait_flag left, cmsis::wait_flag right) 60 | { 61 | left = left & right; 62 | return left; 63 | } 64 | 65 | namespace sys 66 | { 67 | using wait_flag = cmsis::wait_flag; 68 | } 69 | 70 | #endif // CMSIS_WAITFLAG_H_ 71 | -------------------------------------------------------------------------------- /src/Chrono.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, B. Leforestier 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the author nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "Chrono.h" 29 | #include "cmsis_os2.h" 30 | #include 31 | 32 | namespace 33 | { 34 | template D convertDuration(uint64_t count, uint32_t freq) 35 | { 36 | return D((count * D::period::den) / (freq * D::period::num)); 37 | } 38 | } // namespace 39 | 40 | namespace cmsis 41 | { 42 | namespace chrono 43 | { 44 | system_clock::time_point system_clock::now() noexcept 45 | { 46 | return time_point(convertDuration(osKernelGetTickCount(), osKernelGetTickFreq())); 47 | } 48 | 49 | std::time_t system_clock::to_time_t(const time_point& __t) 50 | { 51 | return std::time_t(std::chrono::duration_cast(__t.time_since_epoch()).count()); 52 | } 53 | 54 | system_clock::time_point system_clock::from_time_t(std::time_t __t) 55 | { 56 | typedef std::chrono::time_point __from; 57 | return std::chrono::time_point_cast(__from(std::chrono::seconds(__t))); 58 | } 59 | 60 | high_resolution_clock::time_point high_resolution_clock::now() noexcept 61 | { 62 | return time_point(convertDuration( 63 | osKernelGetSysTimerCount(), 64 | osKernelGetSysTimerFreq())); 65 | } 66 | } // namespace chrono 67 | } // namespace cmsis 68 | 69 | #if !defined(OS_USE_SEMIHOSTING) 70 | #ifdef __cplusplus 71 | extern "C" 72 | { 73 | #endif 74 | 75 | #include 76 | 77 | int _gettimeofday(struct timeval*, void*); 78 | 79 | int _gettimeofday(struct timeval* tp, void* tzvp) 80 | { 81 | if (tp != NULL) 82 | { 83 | uint64_t now = 84 | convertDuration(osKernelGetTickCount(), osKernelGetTickFreq()).count(); 85 | tp->tv_sec = static_cast(now / 1000000); 86 | tp->tv_usec = static_cast(now % 1000000); 87 | } 88 | 89 | if (tzvp != NULL) 90 | { 91 | struct timezone* tzp = static_cast(tzvp); 92 | tzp->tz_minuteswest = 0; 93 | tzp->tz_dsttime = 0; 94 | } 95 | 96 | return 0; 97 | } 98 | #ifdef __cplusplus 99 | } 100 | #endif 101 | #endif // !OS_USE_SEMIHOSTING 102 | -------------------------------------------------------------------------------- /src/ConditionVariable.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, B. Leforestier 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the author nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "ConditionVariable.h" 29 | #include "OSException.h" 30 | #include "Semaphore.h" 31 | #include "cmsis_os2.h" 32 | 33 | namespace cmsis 34 | { 35 | void condition_variable::notify_one() noexcept 36 | { 37 | std::lock_guard lg(m_mutex); 38 | if (!m_wait.empty()) 39 | { 40 | m_wait.front()->release(); 41 | m_wait.pop_front(); 42 | } 43 | } 44 | 45 | void condition_variable::notify_all() noexcept 46 | { 47 | std::lock_guard lg(m_mutex); 48 | for (auto psema : m_wait) 49 | psema->release(); 50 | 51 | m_wait.clear(); 52 | } 53 | 54 | void condition_variable::wait(std::unique_lock& lock) 55 | { 56 | wait_for(lock, std::chrono::microseconds::max()); 57 | } 58 | 59 | cmsis::cv_status 60 | condition_variable::wait_for_usec(std::unique_lock& lock, std::chrono::microseconds usec) 61 | { 62 | if (!lock.owns_lock()) 63 | std::terminate(); 64 | 65 | cmsis::binary_semaphore sema(0); 66 | std::list::iterator it; 67 | { 68 | std::lock_guard lg(m_mutex); 69 | it = m_wait.insert(m_wait.end(), &sema); 70 | } 71 | 72 | lock.unlock(); 73 | bool st = sema.try_acquire_for(usec); 74 | lock.lock(); 75 | 76 | if (!st) 77 | { 78 | std::lock_guard lg(m_mutex); 79 | m_wait.erase(it); 80 | return cmsis::cv_status::timeout; 81 | } 82 | 83 | return cmsis::cv_status::no_timeout; 84 | } 85 | } // namespace cmsis 86 | -------------------------------------------------------------------------------- /src/EventFlag.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, B. Leforestier 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the author nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "EventFlag.h" 29 | #include "OSException.h" 30 | #include "cmsis_os2.h" 31 | 32 | namespace cmsis 33 | { 34 | /** 35 | * Event flag constructor 36 | * @throw std::system_error if an error occurs 37 | */ 38 | event::event(mask_type mask) : 39 | m_id(0) 40 | { 41 | m_id = osEventFlagsNew(NULL); 42 | if (m_id == 0) 43 | #ifdef __cpp_exceptions 44 | throw std::system_error(osError, os_category(), "osEventFlagsNew"); 45 | #else 46 | std::terminate(); 47 | #endif 48 | 49 | if (mask != 0) 50 | set(mask); 51 | } 52 | 53 | event::event(event&& evt) noexcept : 54 | m_id(0) 55 | { 56 | swap(evt); 57 | } 58 | 59 | /** 60 | * Event flag destructor 61 | */ 62 | event::~event() noexcept(false) 63 | { 64 | if (m_id) 65 | { 66 | osStatus_t sta = osEventFlagsDelete(m_id); 67 | if (sta != osOK) 68 | #ifdef __cpp_exceptions 69 | throw std::system_error(sta, os_category(), internal::str_error("osEventFlagsDelete", m_id)); 70 | #else 71 | std::terminate(); 72 | #endif 73 | } 74 | } 75 | 76 | void event::swap(event& evt) noexcept 77 | { 78 | std::swap(m_id, evt.m_id); 79 | } 80 | 81 | event& event::operator=(event&& evt) noexcept 82 | { 83 | swap(evt); 84 | return *this; 85 | } 86 | 87 | /** 88 | * Get current event flag pattern. 89 | * @throw std::system_error if an error occurs 90 | */ 91 | event::mask_type event::get() const 92 | { 93 | int32_t flags = osEventFlagsGet(m_id); 94 | if (flags < 0) 95 | #ifdef __cpp_exceptions 96 | throw std::system_error(flags, os_category(), internal::str_error("osEventFlagsGet", m_id)); 97 | #else 98 | std::terminate(); 99 | #endif 100 | 101 | return flags; 102 | } 103 | 104 | /** 105 | * Sets an event flag. 106 | * @throw std::system_error if an error occurs 107 | */ 108 | event::mask_type event::set(mask_type mask) 109 | { 110 | int32_t flags = osEventFlagsSet(m_id, mask); 111 | if (flags < 0) 112 | #ifdef __cpp_exceptions 113 | throw std::system_error(flags, flags_category(), internal::str_error("osEventFlagsSet", m_id)); 114 | #else 115 | std::terminate(); 116 | #endif 117 | 118 | return flags; 119 | } 120 | 121 | /** 122 | * Clears an event flag. 123 | * @throw std::system_error if an error occurs 124 | */ 125 | event::mask_type event::clear(mask_type mask) 126 | { 127 | int32_t flags = osEventFlagsClear(m_id, mask); 128 | if (flags < 0) 129 | #ifdef __cpp_exceptions 130 | throw std::system_error(flags, flags_category(), internal::str_error("osEventFlagsClear", m_id)); 131 | #else 132 | std::terminate(); 133 | #endif 134 | 135 | return flags; 136 | } 137 | 138 | /** 139 | * Wait until an event flag is set 140 | * @param mask 141 | * @return the event flag value 142 | * @throw std::system_error if an error occurs 143 | */ 144 | event::mask_type event::wait(mask_type mask, wait_flag flg) 145 | { 146 | uint32_t option = ((flg & wait_flag::all) == wait_flag::all) ? osFlagsWaitAll : osFlagsWaitAny; 147 | if ((flg & wait_flag::no_clear) == wait_flag::no_clear) 148 | option |= osFlagsNoClear; 149 | 150 | int32_t flags = osEventFlagsWait(m_id, mask, option, osWaitForever); 151 | if (flags < 0) 152 | #ifdef __cpp_exceptions 153 | throw std::system_error(flags, flags_category(), internal::str_error("osEventFlagsWait", m_id)); 154 | #else 155 | std::terminate(); 156 | #endif 157 | 158 | return flags; 159 | } 160 | 161 | /** 162 | * Wait until an event flag is set or a timeout occurs 163 | * @param mask 164 | * @return the event flag value 165 | * @throw std::system_error if an error occurs 166 | */ 167 | event::status 168 | event::wait_for_usec(mask_type mask, wait_flag flg, std::chrono::microseconds usec, mask_type& flagValue) 169 | { 170 | if (usec < std::chrono::microseconds::zero()) 171 | #ifdef __cpp_exceptions 172 | throw std::system_error(osErrorParameter, os_category(), "event: negative timer"); 173 | #else 174 | std::terminate(); 175 | #endif 176 | 177 | uint32_t timeout = static_cast( 178 | (usec.count() * osKernelGetTickFreq() * std::chrono::microseconds::period::num) / 179 | std::chrono::microseconds::period::den); 180 | if (timeout > std::numeric_limits::max()) 181 | timeout = osWaitForever; 182 | 183 | uint32_t option = ((flg & wait_flag::all) == wait_flag::all) ? osFlagsWaitAll : osFlagsWaitAny; 184 | if ((flg & wait_flag::no_clear) == wait_flag::no_clear) 185 | option |= osFlagsNoClear; 186 | 187 | flagValue = osEventFlagsWait(m_id, mask, option, timeout); 188 | if (timeout == 0 && flagValue == osFlagsErrorResource) 189 | return status::timeout; 190 | 191 | if ((flagValue & osFlagsError) && flagValue != osFlagsErrorTimeout) 192 | #ifdef __cpp_exceptions 193 | throw std::system_error(flagValue, flags_category(), internal::str_error("osEventFlagsWait", m_id)); 194 | #else 195 | std::terminate(); 196 | #endif 197 | 198 | return (flagValue == osFlagsErrorTimeout ? status::timeout : status::no_timeout); 199 | } 200 | } // namespace cmsis 201 | -------------------------------------------------------------------------------- /src/Memory.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, B. Leforestier 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the author nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "Memory.h" 29 | #include "OSException.h" 30 | #include "cmsis_os2.h" 31 | 32 | namespace cmsis 33 | { 34 | namespace internal 35 | { 36 | base_memory_pool::base_memory_pool(size_t count, size_t n) : 37 | m_id(0) 38 | { 39 | m_id = osMemoryPoolNew(static_cast(count), static_cast(n), NULL); 40 | if (!m_id) 41 | #ifdef __cpp_exceptions 42 | throw std::system_error(osError, os_category(), "osMemoryPoolNew"); 43 | #else 44 | std::terminate(); 45 | #endif 46 | } 47 | 48 | base_memory_pool::base_memory_pool(base_memory_pool&& other) : 49 | m_id(other.m_id) 50 | { 51 | other.m_id = 0; 52 | } 53 | 54 | base_memory_pool::~base_memory_pool() noexcept(false) 55 | { 56 | if (m_id) 57 | { 58 | osStatus_t sta = osMemoryPoolDelete(m_id); 59 | if (sta != osOK) 60 | #ifdef __cpp_exceptions 61 | throw std::system_error(sta, os_category(), internal::str_error("osMemoryPoolDelete", m_id)); 62 | #else 63 | std::terminate(); 64 | #endif 65 | } 66 | } 67 | 68 | base_memory_pool& base_memory_pool::operator=(base_memory_pool&& other) 69 | { 70 | if (this != &other) 71 | { 72 | if (m_id) 73 | { 74 | osStatus_t sta = osMemoryPoolDelete(m_id); 75 | if (sta != osOK) 76 | #ifdef __cpp_exceptions 77 | throw std::system_error(sta, os_category(), internal::str_error("osMemoryPoolDelete", m_id)); 78 | #else 79 | std::terminate(); 80 | #endif 81 | m_id = 0; 82 | } 83 | 84 | std::swap(m_id, other.m_id); 85 | } 86 | 87 | return *this; 88 | } 89 | 90 | void* base_memory_pool::allocate(size_t n) 91 | { 92 | if (n != 1) 93 | #ifdef __cpp_exceptions 94 | throw std::bad_alloc(); 95 | #else 96 | return nullptr; 97 | #endif 98 | 99 | void* p = osMemoryPoolAlloc(m_id, osWaitForever); 100 | #ifdef __cpp_exceptions 101 | if (!p) 102 | throw std::bad_alloc(); 103 | #endif 104 | 105 | return p; 106 | } 107 | 108 | void base_memory_pool::deallocate(void* p) 109 | { 110 | osStatus_t sta = osMemoryPoolFree(m_id, p); 111 | if (sta != osOK) 112 | #ifdef __cpp_exceptions 113 | throw std::system_error(sta, os_category(), internal::str_error("osMemoryPoolFree", m_id)); 114 | #else 115 | std::terminate(); 116 | #endif 117 | } 118 | 119 | size_t base_memory_pool::max_size() const noexcept 120 | { 121 | return osMemoryPoolGetCapacity(m_id); 122 | } 123 | 124 | size_t base_memory_pool::size() const noexcept 125 | { 126 | return osMemoryPoolGetCount(m_id); 127 | } 128 | } // namespace internal 129 | } // namespace cmsis 130 | -------------------------------------------------------------------------------- /src/MessageQueue.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, B. Leforestier 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the author nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "OSException.h" 29 | #include "cmsis_os2.h" 30 | #include 31 | 32 | namespace cmsis 33 | { 34 | namespace internal 35 | { 36 | message_queue_impl::message_queue_impl(size_t max_len, size_t ele_len) : 37 | m_id(0) 38 | { 39 | m_id = osMessageQueueNew(max_len, ele_len, NULL); 40 | if (m_id == 0) 41 | { 42 | #ifdef __cpp_exceptions 43 | throw std::system_error(osError, os_category(), "osMessageQueueNew"); 44 | #else 45 | std::terminate(); 46 | #endif 47 | } 48 | } 49 | 50 | message_queue_impl::message_queue_impl(message_queue_impl&& t) : 51 | m_id(t.m_id) 52 | { 53 | t.m_id = 0; 54 | } 55 | 56 | message_queue_impl::~message_queue_impl() noexcept(false) 57 | { 58 | osStatus_t sta = osMessageQueueDelete(m_id); 59 | if (sta != osOK) 60 | { 61 | #ifdef __cpp_exceptions 62 | throw std::system_error(sta, os_category(), internal::str_error("osMessageQueueDelete", m_id)); 63 | #else 64 | std::terminate(); 65 | #endif 66 | } 67 | } 68 | 69 | void message_queue_impl::swap(message_queue_impl& t) 70 | { 71 | std::swap(m_id, t.m_id); 72 | } 73 | 74 | message_queue_impl& message_queue_impl::operator=(message_queue_impl&& t) 75 | { 76 | if (&t != this) 77 | std::swap(m_id, t.m_id); 78 | 79 | return *this; 80 | } 81 | 82 | void message_queue_impl::put(const void* data, uint8_t priority) 83 | { 84 | osStatus_t sta = osMessageQueuePut(m_id, data, priority, osWaitForever); 85 | if (sta != osOK) 86 | { 87 | #ifdef __cpp_exceptions 88 | throw std::system_error(sta, os_category(), internal::str_error("osMessageQueuePut", m_id)); 89 | #else 90 | std::terminate(); 91 | #endif 92 | } 93 | } 94 | 95 | mq_status message_queue_impl::put(const void* data, uint8_t priority, std::chrono::microseconds usec) 96 | { 97 | if (usec < std::chrono::microseconds::zero()) 98 | { 99 | #ifdef __cpp_exceptions 100 | throw std::system_error(osErrorParameter, os_category(), "Data queue: negative timer"); 101 | #else 102 | std::terminate(); 103 | #endif 104 | } 105 | 106 | uint32_t timeout = static_cast( 107 | (usec.count() * osKernelGetTickFreq() * std::chrono::microseconds::period::num) / 108 | std::chrono::microseconds::period::den); 109 | if (timeout > std::numeric_limits::max()) 110 | timeout = osWaitForever; 111 | 112 | osStatus_t sta = osMessageQueuePut(m_id, data, priority, timeout); 113 | if (timeout == 0 && sta == osErrorResource) 114 | return mq_status::full; 115 | 116 | if (sta != osOK && sta != osErrorTimeout) 117 | { 118 | #ifdef __cpp_exceptions 119 | throw std::system_error(sta, os_category(), internal::str_error("osMessageQueuePut", m_id)); 120 | #else 121 | std::terminate(); 122 | #endif 123 | } 124 | 125 | return (sta == osOK) ? mq_status::no_timeout : mq_status::timeout; 126 | } 127 | 128 | void message_queue_impl::get(void* data) 129 | { 130 | osStatus_t sta = osMessageQueueGet(m_id, data, 0, osWaitForever); // wait for message 131 | if (sta != osOK) 132 | { 133 | #ifdef __cpp_exceptions 134 | throw std::system_error(sta, os_category(), internal::str_error("osMessageQueueGet", m_id)); 135 | #else 136 | std::terminate(); 137 | #endif 138 | } 139 | } 140 | 141 | mq_status message_queue_impl::get(void* data, std::chrono::microseconds usec) 142 | { 143 | if (usec < std::chrono::microseconds::zero()) 144 | { 145 | #ifdef __cpp_exceptions 146 | throw std::system_error(osErrorParameter, os_category(), "Data queue: negative timer"); 147 | #else 148 | std::terminate(); 149 | #endif 150 | } 151 | 152 | uint32_t timeout = static_cast( 153 | (usec.count() * osKernelGetTickFreq() * std::chrono::microseconds::period::num) / 154 | std::chrono::microseconds::period::den); 155 | if (timeout > std::numeric_limits::max()) 156 | timeout = osWaitForever; 157 | 158 | osStatus_t sta = osMessageQueueGet(m_id, data, 0, timeout); // wait for message 159 | if (timeout == 0 && sta == osErrorResource) 160 | return mq_status::empty; 161 | 162 | if (sta != osOK && sta != osErrorTimeout) 163 | { 164 | #ifdef __cpp_exceptions 165 | throw std::system_error(sta, os_category(), internal::str_error("osMessageQueueGet", m_id)); 166 | #else 167 | std::terminate(); 168 | #endif 169 | } 170 | 171 | return (sta == osOK) ? mq_status::no_timeout : mq_status::timeout; 172 | } 173 | 174 | size_t message_queue_impl::size() const 175 | { 176 | return osMessageQueueGetCount(m_id); 177 | } 178 | 179 | size_t message_queue_impl::capacity() const 180 | { 181 | return osMessageQueueGetCapacity(m_id); 182 | } 183 | 184 | void message_queue_impl::clear() 185 | { 186 | osStatus_t sta = osMessageQueueReset(m_id); 187 | if (sta != osOK) 188 | { 189 | #ifdef __cpp_exceptions 190 | throw std::system_error(sta, os_category(), internal::str_error("osMessageQueueReset", m_id)); 191 | #else 192 | std::terminate(); 193 | #endif 194 | } 195 | } 196 | } // namespace internal 197 | } // namespace cmsis 198 | -------------------------------------------------------------------------------- /src/Mutex.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, B. Leforestier 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the author nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "Mutex.h" 29 | #include "OSException.h" 30 | #include "cmsis_os2.h" 31 | 32 | namespace cmsis 33 | { 34 | namespace internal 35 | { 36 | base_timed_mutex::base_timed_mutex(const char* name, bool recursive) : 37 | m_id(0) 38 | { 39 | osMutexAttr_t Mutex_attr = {name, osMutexPrioInherit, NULL, 0}; 40 | if (recursive) 41 | Mutex_attr.attr_bits |= osMutexRecursive; 42 | 43 | m_id = osMutexNew(&Mutex_attr); 44 | if (m_id == 0) 45 | #ifdef __cpp_exceptions 46 | throw std::system_error(osError, os_category(), "osMutexNew"); 47 | #else 48 | std::terminate(); 49 | #endif 50 | } 51 | 52 | base_timed_mutex::~base_timed_mutex() noexcept(false) 53 | { 54 | osStatus_t sta = osMutexDelete(m_id); 55 | if (sta != osOK) 56 | #ifdef __cpp_exceptions 57 | throw std::system_error(sta, os_category(), internal::str_error("osMutexDelete", m_id)); 58 | #else 59 | std::terminate(); 60 | #endif 61 | } 62 | 63 | void base_timed_mutex::lock() 64 | { 65 | osStatus_t sta = osMutexAcquire(m_id, osWaitForever); 66 | if (sta != osOK) 67 | #ifdef __cpp_exceptions 68 | throw std::system_error(sta, os_category(), internal::str_error("osMutexAcquire", m_id)); 69 | #else 70 | std::terminate(); 71 | #endif 72 | } 73 | 74 | void base_timed_mutex::unlock() 75 | { 76 | osStatus_t sta = osMutexRelease(m_id); 77 | if (sta != osOK) 78 | #ifdef __cpp_exceptions 79 | throw std::system_error(sta, os_category(), internal::str_error("osMutexRelease", m_id)); 80 | #else 81 | std::terminate(); 82 | #endif 83 | } 84 | 85 | bool base_timed_mutex::try_lock() 86 | { 87 | osStatus_t sta = osMutexAcquire(m_id, 0); 88 | if (sta != osOK && sta != osErrorTimeout) 89 | #ifdef __cpp_exceptions 90 | throw std::system_error(sta, os_category(), internal::str_error("osMutexAcquire", m_id)); 91 | #else 92 | std::terminate(); 93 | #endif 94 | 95 | return (sta != osErrorTimeout); 96 | } 97 | 98 | bool base_timed_mutex::try_lock_for_usec(std::chrono::microseconds usec) 99 | { 100 | if (usec < std::chrono::microseconds::zero()) 101 | #ifdef __cpp_exceptions 102 | throw std::system_error(osErrorParameter, os_category(), "base_timed_mutex: negative timer"); 103 | #else 104 | std::terminate(); 105 | #endif 106 | 107 | uint32_t timeout = static_cast( 108 | (usec.count() * osKernelGetTickFreq() * std::chrono::microseconds::period::num) / 109 | std::chrono::microseconds::period::den); 110 | if (timeout > std::numeric_limits::max()) 111 | timeout = osWaitForever; 112 | 113 | osStatus_t sta = osMutexAcquire(m_id, timeout); 114 | if (timeout == 0 && sta == osErrorResource) 115 | return false; 116 | 117 | if (sta != osOK && sta != osErrorTimeout) 118 | #ifdef __cpp_exceptions 119 | throw std::system_error(sta, os_category(), internal::str_error("osMutexAcquire", m_id)); 120 | #else 121 | std::terminate(); 122 | #endif 123 | 124 | return (sta != osErrorTimeout); 125 | } 126 | } // namespace internal 127 | } // namespace cmsis 128 | -------------------------------------------------------------------------------- /src/OS.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, B. Leforestier 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the author nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "OS.h" 29 | #include "OSException.h" 30 | #include "cmsis_os2.h" 31 | #include 32 | 33 | extern "C" uint32_t SystemCoreClock; /**< System Clock Frequency (Core Clock) */ 34 | extern "C" void SystemCoreClockUpdate(void); /**< Updates the variable SystemCoreClock */ 35 | 36 | std::function idleHandler; 37 | 38 | namespace cmsis 39 | { 40 | namespace kernel 41 | { 42 | const char* version() 43 | { 44 | static char infobuf[100]; 45 | osVersion_t osv; 46 | 47 | osStatus_t sta = osKernelGetInfo(&osv, infobuf, sizeof(infobuf)); 48 | if (sta != osOK) 49 | { 50 | #ifdef __cpp_exceptions 51 | throw std::system_error(sta, os_category(), "osKernelGetInfo"); 52 | #else 53 | std::terminate(); 54 | #endif 55 | } 56 | 57 | return infobuf; 58 | } 59 | 60 | uint32_t tick_frequency() 61 | { 62 | uint32_t tick = osKernelGetTickFreq(); 63 | if (!tick) 64 | { 65 | #ifdef __cpp_exceptions 66 | throw std::system_error(osError, os_category(), "osKernelGetTickFreq"); 67 | #else 68 | std::terminate(); 69 | #endif 70 | } 71 | 72 | return tick; 73 | } 74 | 75 | /** 76 | * Initialize the RTOS Kernel. 77 | * @throw std::system_error if an error occurs 78 | */ 79 | void initialize() 80 | { 81 | if (osKernelGetState() == osKernelInactive) 82 | { 83 | osStatus_t sta = osKernelInitialize(); 84 | if (sta != osOK) 85 | { 86 | #ifdef __cpp_exceptions 87 | throw std::system_error(sta, os_category(), "osKernelInitialize"); 88 | #else 89 | std::terminate(); 90 | #endif 91 | } 92 | } 93 | } 94 | 95 | /** 96 | * Start the RTOS Kernel scheduler. In case of success, this function never returns. 97 | * @throw std::system_error if an error occurs 98 | */ 99 | void start() 100 | { 101 | osStatus_t sta = osKernelStart(); 102 | if (sta != osOK) 103 | { 104 | #ifdef __cpp_exceptions 105 | throw std::system_error(sta, os_category(), "osKernelStart"); 106 | #else 107 | std::terminate(); 108 | #endif 109 | } 110 | } 111 | 112 | /** 113 | * Suspends the RTOS kernel scheduler and thus enables sleep modes. 114 | * Returns time in ticks, for how long the system can sleep or power-down. 115 | */ 116 | uint32_t suspend() noexcept 117 | { 118 | return osKernelSuspend(); 119 | } 120 | 121 | /** 122 | * Enables the RTOS kernel scheduler and thus wakes up the system from sleep mode. 123 | * sleep_ticks: time in ticks for how long the system was in sleep or power-down mode. 124 | */ 125 | void resume(uint32_t sleep_ticks) noexcept 126 | { 127 | return osKernelResume(sleep_ticks); 128 | } 129 | 130 | /** 131 | * Start the idle handler called by the idle thread. 132 | * @throw std::system_error if an error occurs 133 | */ 134 | void set_idle_handler(std::function&& handler) 135 | { 136 | idleHandler = std::move(handler); 137 | } 138 | } // namespace kernel 139 | 140 | namespace core 141 | { 142 | uint32_t clock_frequency() 143 | { 144 | SystemCoreClockUpdate(); 145 | if (!SystemCoreClock) 146 | { 147 | #ifdef __cpp_exceptions 148 | throw std::system_error(osError, os_category(), "SystemCoreClock"); 149 | #else 150 | std::terminate(); 151 | #endif 152 | } 153 | 154 | return SystemCoreClock; 155 | } 156 | } // namespace core 157 | 158 | /** 159 | * Lock / unlock Dispatching. 160 | * @throw std::system_error if an error occurs 161 | */ 162 | dispatch::dispatch() : 163 | m_previous_lock_state(osError) 164 | {} 165 | 166 | void dispatch::lock() 167 | { 168 | m_previous_lock_state = osKernelLock(); 169 | if (m_previous_lock_state < 0) 170 | { 171 | #ifdef __cpp_exceptions 172 | throw std::system_error(m_previous_lock_state, os_category(), "osKernelLock"); 173 | #else 174 | std::terminate(); 175 | #endif 176 | } 177 | } 178 | 179 | void dispatch::unlock() 180 | { 181 | if (m_previous_lock_state < 0) 182 | { 183 | #ifdef __cpp_exceptions 184 | throw std::system_error(m_previous_lock_state, os_category(), "Bad kernel previous state"); 185 | #else 186 | std::terminate(); 187 | #endif 188 | } 189 | 190 | m_previous_lock_state = osKernelRestoreLock(m_previous_lock_state); 191 | if (m_previous_lock_state < 0) 192 | { 193 | #ifdef __cpp_exceptions 194 | throw std::system_error(m_previous_lock_state, os_category(), "osKernelRestoreLock"); 195 | #else 196 | std::terminate(); 197 | #endif 198 | } 199 | } 200 | 201 | bool dispatch::locked() 202 | { 203 | return (osKernelGetState() == osKernelLocked); 204 | } 205 | } // namespace cmsis 206 | -------------------------------------------------------------------------------- /src/OSException.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, B. Leforestier 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the author nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "OSException.h" 29 | #include "cmsis_os2.h" 30 | 31 | #ifdef __cpp_exceptions 32 | 33 | #ifdef RTE_CMSIS_RTOS2_RTX5 34 | #include "rtx_os.h" 35 | #endif 36 | 37 | namespace 38 | { 39 | class cmsis_os_error_category : public std::error_category 40 | { 41 | public: 42 | cmsis_os_error_category(const cmsis_os_error_category&) = delete; 43 | constexpr cmsis_os_error_category() = default; 44 | virtual ~cmsis_os_error_category() = default; 45 | 46 | virtual const char* name() const noexcept override { return "cmsis os"; } 47 | 48 | virtual std::string message(int condition) const noexcept override 49 | { 50 | switch (condition) 51 | { 52 | case osOK: 53 | return "Operation completed successfully"; 54 | case osError: 55 | return "Unspecified RTOS error: run-time error but no other error message fits"; 56 | case osErrorTimeout: 57 | return "Operation not completed within the timeout period"; 58 | case osErrorResource: 59 | return "Resource not available"; 60 | case osErrorParameter: 61 | return "Parameter error"; 62 | case osErrorNoMemory: 63 | return "System is out of memory: it was impossible to allocate or reserve memory for the operation"; 64 | case osErrorISR: 65 | return "Not allowed in ISR context: the function cannot be called from interrupt service routines"; 66 | case osStatusReserved: 67 | return "Prevents enum down-size compiler optimization"; 68 | #ifdef RTE_CMSIS_RTOS2_RTX5 69 | case osRtxErrorStackUnderflow: 70 | return "Stack underflow detected for thread"; 71 | case osRtxErrorISRQueueOverflow: 72 | return "ISR Queue overflow detected when inserting object"; 73 | case osRtxErrorTimerQueueOverflow: 74 | return "User Timer Callback Queue overflow detected for timer"; 75 | case osRtxErrorClibSpace: 76 | return "Standard C/C++ library libspace not available: increase OS_THREAD_LIBSPACE_NUM"; 77 | case osRtxErrorClibMutex: 78 | return "Standard C/C++ library mutex initialization failed"; 79 | #endif 80 | 81 | default: 82 | return "Unknown error"; 83 | } 84 | } 85 | }; 86 | 87 | class cmsis_flag_error_category : public std::error_category 88 | { 89 | public: 90 | cmsis_flag_error_category(const cmsis_flag_error_category&) = delete; 91 | constexpr cmsis_flag_error_category() = default; 92 | virtual ~cmsis_flag_error_category() = default; 93 | 94 | virtual const char* name() const noexcept override { return "cmsis flag"; } 95 | 96 | virtual std::string message(int condition) const noexcept override 97 | { 98 | switch (condition) 99 | { 100 | case static_cast(osFlagsErrorUnknown): 101 | return "Generic error"; 102 | case static_cast(osFlagsErrorTimeout): 103 | return "A timeout was specified and the specified flags were not set, when the timeout occurred"; 104 | case static_cast(osFlagsErrorResource): 105 | return "Try to get a flag that was not set and timeout 0 was specified, or the specified object " 106 | "identifier is corrupt or invalid"; 107 | case static_cast(osFlagsErrorParameter): 108 | return "A given parameter is wrong"; 109 | case static_cast(osFlagsErrorISR): 110 | return "Not allowed in ISR context: the function cannot be called from interrupt service routines"; 111 | 112 | default: 113 | return "Unknown error"; 114 | } 115 | } 116 | }; 117 | } // namespace 118 | 119 | namespace cmsis 120 | { 121 | const std::error_category& os_category() 122 | { 123 | static cmsis_os_error_category osErrorCategory; 124 | return osErrorCategory; 125 | } 126 | 127 | const std::error_category& flags_category() 128 | { 129 | static cmsis_flag_error_category osErrorCategory; 130 | return osErrorCategory; 131 | } 132 | 133 | namespace internal 134 | { 135 | std::string str_error(const std::string& func, const void* id) 136 | { 137 | std::string str = func + '(' + std::to_string(reinterpret_cast(id)) + ')'; 138 | return str; 139 | } 140 | } // namespace internal 141 | } // namespace cmsis 142 | #endif // __cpp_exceptions 143 | -------------------------------------------------------------------------------- /src/Semaphore.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, B. Leforestier 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the author nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "Semaphore.h" 29 | #include "OSException.h" 30 | #include "cmsis_os2.h" 31 | 32 | namespace cmsis 33 | { 34 | namespace internal 35 | { 36 | base_semaphore::base_semaphore(std::ptrdiff_t max, std::ptrdiff_t desired) : 37 | m_id(0) 38 | { 39 | m_id = osSemaphoreNew(static_cast(max), static_cast(desired), NULL); 40 | if (m_id == 0) 41 | { 42 | #ifdef __cpp_exceptions 43 | throw std::system_error(osError, os_category(), "osSemaphoreNew"); 44 | #else 45 | std::terminate(); 46 | #endif 47 | } 48 | } 49 | 50 | base_semaphore::~base_semaphore() noexcept(false) 51 | { 52 | osStatus_t sta = osSemaphoreDelete(m_id); 53 | if (sta != osOK) 54 | { 55 | #ifdef __cpp_exceptions 56 | throw std::system_error(sta, os_category(), internal::str_error("osSemaphoreDelete", m_id)); 57 | #else 58 | std::terminate(); 59 | #endif 60 | } 61 | } 62 | 63 | void base_semaphore::release(std::ptrdiff_t update) 64 | { 65 | while (update--) 66 | { 67 | osStatus_t sta = osSemaphoreRelease(m_id); 68 | if (sta != osOK) 69 | { 70 | #ifdef __cpp_exceptions 71 | throw std::system_error(sta, os_category(), internal::str_error("osSemaphoreRelease", m_id)); 72 | #else 73 | std::terminate(); 74 | #endif 75 | } 76 | } 77 | } 78 | 79 | void base_semaphore::acquire() 80 | { 81 | osStatus_t sta = osSemaphoreAcquire(m_id, osWaitForever); 82 | if (sta != osOK) 83 | { 84 | #ifdef __cpp_exceptions 85 | throw std::system_error(sta, os_category(), internal::str_error("osSemaphoreAcquire", m_id)); 86 | #else 87 | std::terminate(); 88 | #endif 89 | } 90 | } 91 | 92 | bool base_semaphore::try_acquire() noexcept 93 | { 94 | return (osSemaphoreAcquire(m_id, 0) == osOK); 95 | } 96 | 97 | bool base_semaphore::try_acquire_for_usec(std::chrono::microseconds usec) 98 | { 99 | if (usec < std::chrono::microseconds::zero()) 100 | { 101 | #ifdef __cpp_exceptions 102 | throw std::system_error(osErrorParameter, os_category(), "semaphore: negative timer"); 103 | #else 104 | std::terminate(); 105 | #endif 106 | } 107 | 108 | uint32_t timeout = static_cast( 109 | (usec.count() * osKernelGetTickFreq() * std::chrono::microseconds::period::num) / 110 | std::chrono::microseconds::period::den); 111 | if (timeout > std::numeric_limits::max()) 112 | timeout = osWaitForever; 113 | 114 | osStatus_t sta = osSemaphoreAcquire(m_id, timeout); 115 | if (timeout == 0 && sta == osErrorResource) 116 | return false; 117 | 118 | if (sta != osOK && sta != osErrorTimeout) 119 | { 120 | #ifdef __cpp_exceptions 121 | throw std::system_error(sta, os_category(), internal::str_error("osSemaphoreAcquire", m_id)); 122 | #else 123 | std::terminate(); 124 | #endif 125 | } 126 | 127 | return (sta == osOK); 128 | } 129 | } // namespace internal 130 | } // namespace cmsis 131 | -------------------------------------------------------------------------------- /src/Thread.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, B. Leforestier 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the author nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "Thread.h" 29 | #include "OSException.h" 30 | #include "cmsis_os2.h" 31 | #include 32 | #ifdef __GNUC__ 33 | #include 34 | #endif 35 | 36 | namespace cmsis 37 | { 38 | class thread_impl 39 | { 40 | public: 41 | thread_impl(const thread::attributes& attr, std::unique_ptr targetfunc) : 42 | m_id(0), 43 | m_function(std::move(targetfunc)), 44 | m_detached(false) 45 | { 46 | osThreadAttr_t osAttr = {}; 47 | osAttr.attr_bits = osThreadJoinable; 48 | osAttr.name = attr.name; 49 | osAttr.stack_mem = attr.stack_mem; 50 | osAttr.stack_size = attr.stack_size; 51 | osAttr.priority = static_cast(attr.priority); 52 | 53 | if (osAttr.priority == osPriorityNone) 54 | osAttr.priority = osPriorityNormal; 55 | 56 | m_id = osThreadNew(runnableMethodStatic, this, &osAttr); 57 | if (m_id == 0) 58 | { 59 | #ifdef __cpp_exceptions 60 | throw std::system_error(osError, os_category(), "osThreadNew"); 61 | #else 62 | std::terminate(); 63 | #endif 64 | } 65 | } 66 | 67 | thread_impl(const thread_impl&) = delete; 68 | thread_impl& operator=(const thread_impl&) = delete; 69 | 70 | ~thread_impl() { osThreadTerminate(m_id); } 71 | 72 | void join() 73 | { 74 | osStatus_t sta = osThreadJoin(m_id); 75 | if (sta != osOK) 76 | { 77 | #ifdef __cpp_exceptions 78 | throw std::system_error(sta, os_category(), internal::str_error("osThreadJoin", m_id)); 79 | #else 80 | std::terminate(); 81 | #endif 82 | } 83 | 84 | m_detached.store(true); 85 | } 86 | 87 | void detach() 88 | { 89 | osStatus_t sta = osThreadDetach(m_id); 90 | if (sta != osOK) 91 | { 92 | #ifdef __cpp_exceptions 93 | throw std::system_error(sta, os_category(), internal::str_error("osThreadDetach", m_id)); 94 | #else 95 | std::terminate(); 96 | #endif 97 | } 98 | 99 | m_detached.store(true); 100 | } 101 | 102 | bool joinable() const { return !m_detached.load(); } 103 | 104 | osThreadId_t get_id() const noexcept { return m_id; } 105 | 106 | private: 107 | static void runnableMethodStatic(void* pVThread) 108 | { 109 | #ifdef __cpp_exceptions 110 | try 111 | { 112 | #endif // __cpp_exceptions 113 | thread_impl* pThreadImpl = reinterpret_cast(pVThread); 114 | pThreadImpl->m_function->run(); 115 | #ifdef __cpp_exceptions 116 | } 117 | #ifdef __GNUC__ 118 | catch (const abi::__forced_unwind&) 119 | { 120 | throw; 121 | } 122 | #endif // __GNUC__ 123 | catch (...) 124 | { 125 | std::terminate(); 126 | } 127 | #endif // __cpp_exceptions 128 | 129 | osThreadExit(); 130 | } 131 | 132 | private: 133 | osThreadId_t m_id; // task identifier 134 | std::unique_ptr m_function; 135 | std::atomic_bool m_detached; 136 | }; 137 | 138 | thread::thread() noexcept : 139 | m_pThread(nullptr) 140 | {} 141 | 142 | thread::thread(const attributes& attr, std::unique_ptr base) : 143 | m_pThread(std::make_unique(attr, std::move(base))) 144 | {} 145 | 146 | thread::thread(thread&& __t) noexcept : 147 | m_pThread(std::move(__t.m_pThread)) 148 | {} 149 | 150 | thread::~thread() 151 | { 152 | if (joinable()) 153 | std::terminate(); 154 | } 155 | 156 | thread& thread::operator=(thread&& __t) 157 | { 158 | if (joinable()) 159 | std::terminate(); 160 | 161 | swap(__t); 162 | return *this; 163 | } 164 | 165 | void thread::join() 166 | { 167 | if (!joinable()) 168 | { 169 | #ifdef __cpp_exceptions 170 | throw std::system_error( 171 | std::make_error_code(std::errc::invalid_argument), 172 | "thread::join"); // task is detached (aka auto-delete) 173 | #else 174 | std::terminate(); 175 | #endif 176 | } 177 | 178 | if (thread::id(m_pThread->get_id()) == cmsis::this_thread::get_id()) 179 | { 180 | #ifdef __cpp_exceptions 181 | throw std::system_error(std::make_error_code(std::errc::resource_deadlock_would_occur), "thread::join"); 182 | #else 183 | std::terminate(); 184 | #endif 185 | } 186 | 187 | m_pThread->join(); 188 | } 189 | 190 | bool thread::joinable() const 191 | { 192 | return m_pThread && m_pThread->joinable(); 193 | } 194 | 195 | void thread::detach() 196 | { 197 | if (!joinable()) 198 | { 199 | #ifdef __cpp_exceptions 200 | throw std::system_error( 201 | std::make_error_code(std::errc::invalid_argument), 202 | "thread::detach"); // task is detached (aka auto-delete) 203 | #else 204 | std::terminate(); 205 | #endif 206 | } 207 | 208 | m_pThread->detach(); 209 | } 210 | 211 | thread::id thread::get_id() const 212 | { 213 | return m_pThread ? thread::id(m_pThread->get_id()) : thread::id(); 214 | } 215 | 216 | thread::native_handle_type thread::native_handle() 217 | { 218 | return get_id().m_tid; 219 | } 220 | 221 | unsigned int thread::hardware_concurrency() noexcept 222 | { 223 | return 255; 224 | } 225 | 226 | void thread::swap(thread& __t) 227 | { 228 | m_pThread.swap(__t.m_pThread); 229 | } 230 | 231 | void thread::suspend() 232 | { 233 | osStatus_t sta = osThreadSuspend(get_id().m_tid); 234 | if (sta != osOK) 235 | { 236 | #ifdef __cpp_exceptions 237 | throw std::system_error(sta, os_category(), internal::str_error("osThreadSuspend", get_id().m_tid)); 238 | #else 239 | std::terminate(); 240 | #endif 241 | } 242 | } 243 | 244 | void thread::resume() 245 | { 246 | osStatus_t sta = osThreadResume(get_id().m_tid); 247 | if (sta != osOK) 248 | { 249 | #ifdef __cpp_exceptions 250 | throw std::system_error(sta, os_category(), internal::str_error("osThreadResume", get_id().m_tid)); 251 | #else 252 | std::terminate(); 253 | #endif 254 | } 255 | } 256 | 257 | void thread::priority(size_t prio) 258 | { 259 | osStatus_t sta = osThreadSetPriority(get_id().m_tid, static_cast(prio)); 260 | if (sta != osOK) 261 | { 262 | #ifdef __cpp_exceptions 263 | throw std::system_error(sta, os_category(), internal::str_error("osThreadSetPriority", get_id().m_tid)); 264 | #else 265 | std::terminate(); 266 | #endif 267 | } 268 | } 269 | 270 | size_t thread::priority() const 271 | { 272 | osPriority_t prio = osThreadGetPriority(get_id().m_tid); 273 | if (prio == osPriorityError) 274 | { 275 | #ifdef __cpp_exceptions 276 | throw std::system_error(osError, os_category(), internal::str_error("osThreadGetPriority", get_id().m_tid)); 277 | #else 278 | std::terminate(); 279 | #endif 280 | } 281 | 282 | return static_cast(prio); 283 | } 284 | 285 | const char* thread::name() const noexcept 286 | { 287 | return osThreadGetName(get_id().m_tid); 288 | } 289 | 290 | bool thread::is_blocked() const 291 | { 292 | osThreadState_t state = osThreadGetState(get_id().m_tid); 293 | if (state == osThreadError) 294 | { 295 | #ifdef __cpp_exceptions 296 | throw std::system_error(osError, os_category(), internal::str_error("osThreadGetState", get_id().m_tid)); 297 | #else 298 | std::terminate(); 299 | #endif 300 | } 301 | 302 | return (state == osThreadBlocked); 303 | } 304 | 305 | size_t thread::stack_size() const noexcept 306 | { 307 | return static_cast(osThreadGetStackSize(get_id().m_tid)); 308 | } 309 | 310 | size_t thread::stack_space() const noexcept 311 | { 312 | return static_cast(osThreadGetStackSpace(get_id().m_tid)); 313 | } 314 | 315 | namespace this_thread 316 | { 317 | void yield() 318 | { 319 | osStatus_t sta = osThreadYield(); 320 | if (sta != osOK) 321 | { 322 | #ifdef __cpp_exceptions 323 | throw std::system_error(sta, os_category(), "osThreadYield"); 324 | #else 325 | std::terminate(); 326 | #endif 327 | } 328 | } 329 | 330 | thread::id get_id() 331 | { 332 | osThreadId_t tid = osThreadGetId(); 333 | #ifdef __cpp_exceptions 334 | if (tid == NULL) 335 | throw std::system_error(osErrorResource, os_category(), "osThreadGetId"); 336 | #endif 337 | return thread::id(tid); 338 | } 339 | 340 | namespace internal 341 | { 342 | void sleep_for_usec(std::chrono::microseconds usec) 343 | { 344 | if (usec > std::chrono::microseconds::zero()) 345 | { 346 | uint32_t ticks = static_cast( 347 | (usec.count() * osKernelGetTickFreq() * std::chrono::microseconds::period::num) / 348 | std::chrono::microseconds::period::den); 349 | if (ticks > std::numeric_limits::max()) 350 | ticks = osWaitForever; 351 | 352 | osStatus_t sta = osDelay(ticks); 353 | if (sta != osOK) 354 | { 355 | #ifdef __cpp_exceptions 356 | throw std::system_error(sta, os_category(), "osDelay"); 357 | #else 358 | std::terminate(); 359 | #endif 360 | } 361 | } 362 | } 363 | } // namespace internal 364 | } // namespace this_thread 365 | } // namespace cmsis 366 | 367 | #if !defined(OS_USE_SEMIHOSTING) 368 | 369 | extern "C" int _getpid(void) 370 | { 371 | return reinterpret_cast(osThreadGetId()); 372 | } 373 | 374 | #endif // !OS_USE_SEMIHOSTING 375 | -------------------------------------------------------------------------------- /src/ThreadFlag.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, B. Leforestier 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the author nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "ThreadFlag.h" 29 | #include "OSException.h" 30 | #include "cmsis_os2.h" 31 | 32 | namespace cmsis 33 | { 34 | /** 35 | * Sets a thread flag. 36 | * @throw std::system_error if an error occurs 37 | */ 38 | thread_flags::mask_type thread_flags::set(thread& t, mask_type mask) 39 | { 40 | int32_t flags = osThreadFlagsSet(t.native_handle(), mask); 41 | if (flags < 0) 42 | #ifdef __cpp_exceptions 43 | throw std::system_error(flags, os_category(), internal::str_error("osThreadFlagsSet", t.native_handle())); 44 | #else 45 | std::terminate(); 46 | #endif 47 | 48 | return flags; 49 | } 50 | 51 | namespace this_thread 52 | { 53 | flags::mask_type flags::set(mask_type mask) 54 | { 55 | osThreadId_t tid = osThreadGetId(); 56 | if (tid == NULL) 57 | #ifdef __cpp_exceptions 58 | throw std::system_error(osErrorResource, os_category(), "osThreadGetId"); 59 | #else 60 | std::terminate(); 61 | #endif 62 | 63 | int32_t flags = osThreadFlagsSet(tid, mask); 64 | if (flags < 0) 65 | #ifdef __cpp_exceptions 66 | throw std::system_error(flags, os_category(), cmsis::internal::str_error("osThreadFlagsSet", tid)); 67 | #else 68 | std::terminate(); 69 | #endif 70 | 71 | return flags; 72 | } 73 | 74 | flags::mask_type flags::get() 75 | { 76 | int32_t flags = osThreadFlagsGet(); 77 | if (flags < 0) 78 | #ifdef __cpp_exceptions 79 | throw std::system_error(flags, flags_category(), "osThreadFlagsGet"); 80 | #else 81 | std::terminate(); 82 | #endif 83 | 84 | return flags; 85 | } 86 | 87 | /** 88 | * Clears a thread flag. 89 | * @param mask 90 | * @return the thread flag value 91 | * @throw std::system_error if an error occurs 92 | */ 93 | flags::mask_type flags::clear(mask_type mask) 94 | { 95 | int32_t flags = osThreadFlagsClear(mask); 96 | if (flags < 0) 97 | #ifdef __cpp_exceptions 98 | throw std::system_error(flags, flags_category(), "osThreadFlagsClear"); 99 | #else 100 | std::terminate(); 101 | #endif 102 | 103 | return flags; 104 | } 105 | 106 | /** 107 | * Wait until a thread flag is set 108 | * @param mask 109 | * @return the thread flag value 110 | * @throw std::system_error if an error occurs 111 | */ 112 | flags::mask_type flags::wait(mask_type mask, wait_flag flg) 113 | { 114 | uint32_t option = ((flg & wait_flag::all) == wait_flag::all) ? osFlagsWaitAll : osFlagsWaitAny; 115 | if ((flg & wait_flag::no_clear) == wait_flag::no_clear) 116 | option |= osFlagsNoClear; 117 | 118 | int32_t flags = osThreadFlagsWait(mask, option, osWaitForever); 119 | if (flags < 0) 120 | #ifdef __cpp_exceptions 121 | throw std::system_error(flags, flags_category(), "osThreadFlagsWait"); 122 | #else 123 | std::terminate(); 124 | #endif 125 | 126 | return flags; 127 | } 128 | 129 | /** 130 | * Wait until a thread flag is set or a timeout occurs 131 | * @param mask 132 | * @return the thread flag value 133 | * @throw std::system_error if an error occurs 134 | */ 135 | flags::status 136 | flags::wait_for_usec(mask_type mask, wait_flag flg, std::chrono::microseconds usec, mask_type& flagValue) 137 | { 138 | if (usec < std::chrono::microseconds::zero()) 139 | #ifdef __cpp_exceptions 140 | throw std::system_error(osErrorParameter, os_category(), "thread_flag: negative timer"); 141 | #else 142 | std::terminate(); 143 | #endif 144 | 145 | uint32_t timeout = static_cast( 146 | (usec.count() * osKernelGetTickFreq() * std::chrono::microseconds::period::num) / 147 | std::chrono::microseconds::period::den); 148 | if (timeout > std::numeric_limits::max()) 149 | timeout = osWaitForever; 150 | 151 | uint32_t option = ((flg & wait_flag::all) == wait_flag::all) ? osFlagsWaitAll : osFlagsWaitAny; 152 | if ((flg & wait_flag::no_clear) == wait_flag::no_clear) 153 | option |= osFlagsNoClear; 154 | 155 | flagValue = osThreadFlagsWait(mask, option, timeout); 156 | if (timeout == 0 && flagValue == osFlagsErrorResource) 157 | return status::timeout; 158 | 159 | if ((flagValue & osFlagsError) && flagValue != osFlagsErrorTimeout) 160 | #ifdef __cpp_exceptions 161 | throw std::system_error(flagValue, flags_category(), "osThreadFlagsWait"); 162 | #else 163 | std::terminate(); 164 | #endif 165 | 166 | return (flagValue == osFlagsErrorTimeout ? status::timeout : status::no_timeout); 167 | } 168 | } // namespace this_thread 169 | } // namespace cmsis 170 | -------------------------------------------------------------------------------- /src/Threads.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, B. Leforestier 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the author nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "Threads.h" 29 | #include "OS.h" 30 | #include "cmsis_os2.h" 31 | #include 32 | 33 | namespace cmsis 34 | { 35 | size_t threads::count() noexcept 36 | { 37 | return static_cast(osThreadGetCount()); 38 | } 39 | 40 | std::vector threads::enumerate() noexcept 41 | { 42 | cmsis::dispatch dptch; 43 | std::lock_guard lg(dptch); 44 | 45 | std::vector thread_array(count()); 46 | uint32_t nb = osThreadEnumerate(thread_array.data(), thread_array.size()); 47 | 48 | std::vector infos(nb); 49 | for (size_t i = 0; i < infos.size(); ++i) 50 | { 51 | osThreadId_t tid = thread_array[i]; 52 | infos[i].handle = tid; 53 | infos[i].name = osThreadGetName(tid); 54 | infos[i].state = static_cast(osThreadGetState(tid)); 55 | infos[i].priority = static_cast(osThreadGetPriority(tid)); 56 | infos[i].stack_size = static_cast(osThreadGetStackSize(tid)); 57 | infos[i].stack_space = static_cast(osThreadGetStackSpace(tid)); 58 | } 59 | 60 | return infos; 61 | } 62 | } // namespace cmsis 63 | -------------------------------------------------------------------------------- /src/Timer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, B. Leforestier 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the author nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "Timer.h" 29 | #include "OSException.h" 30 | #include "cmsis_os2.h" 31 | 32 | namespace cmsis 33 | { 34 | class cmsis_timer 35 | { 36 | public: 37 | typedef std::function callback_t; 38 | 39 | cmsis_timer(std::chrono::microseconds usec, callback_t&& function, bool bOnce) : 40 | m_Callback(std::move(function)), 41 | m_id(0), 42 | m_usec(usec) 43 | { 44 | if (!m_Callback) 45 | { 46 | #ifdef __cpp_exceptions 47 | throw std::system_error(osErrorParameter, os_category(), "timer: missing callback"); 48 | #else 49 | std::terminate(); 50 | #endif 51 | } 52 | 53 | if (m_usec < std::chrono::microseconds::zero()) 54 | { 55 | #ifdef __cpp_exceptions 56 | throw std::system_error(osErrorParameter, os_category(), "base_timed_mutex: negative timer"); 57 | #else 58 | std::terminate(); 59 | #endif 60 | } 61 | 62 | m_id = osTimerNew(handler, bOnce ? osTimerOnce : osTimerPeriodic, this, NULL); 63 | if (m_id == 0) 64 | { 65 | #ifdef __cpp_exceptions 66 | throw std::system_error(osError, os_category(), "osTimerNew"); 67 | #else 68 | std::terminate(); 69 | #endif 70 | } 71 | } 72 | 73 | ~cmsis_timer() noexcept(false) 74 | { 75 | osStatus_t sta = osTimerDelete(m_id); 76 | if (sta != osOK) 77 | { 78 | #ifdef __cpp_exceptions 79 | throw std::system_error(sta, os_category(), internal::str_error("osTimerDelete", m_id)); 80 | #else 81 | std::terminate(); 82 | #endif 83 | } 84 | } 85 | 86 | void start() 87 | { 88 | uint32_t ticks = static_cast( 89 | (m_usec.count() * osKernelGetTickFreq() * std::chrono::microseconds::period::num) / 90 | std::chrono::microseconds::period::den); 91 | if (ticks > std::numeric_limits::max()) 92 | ticks = osWaitForever; 93 | 94 | osStatus_t sta = osTimerStart(m_id, ticks); 95 | if (sta != osOK) 96 | { 97 | #ifdef __cpp_exceptions 98 | throw std::system_error(sta, os_category(), internal::str_error("osTimerStart", m_id)); 99 | #else 100 | std::terminate(); 101 | #endif 102 | } 103 | } 104 | 105 | void stop() 106 | { 107 | osStatus_t sta = osTimerStop(m_id); 108 | if (sta != osOK) 109 | { 110 | #ifdef __cpp_exceptions 111 | throw std::system_error(sta, os_category(), internal::str_error("osTimerStop", m_id)); 112 | #else 113 | std::terminate(); 114 | #endif 115 | } 116 | } 117 | 118 | bool running() const { return osTimerIsRunning(m_id) != 0; } 119 | 120 | cmsis_timer(const cmsis_timer&) = delete; 121 | cmsis_timer& operator=(const cmsis_timer&) = delete; 122 | 123 | private: 124 | static void handler(void* argument) 125 | { 126 | cmsis_timer* pTimer = static_cast(argument); 127 | 128 | if (!pTimer->running()) 129 | return; 130 | 131 | if (!pTimer->m_Callback()) 132 | pTimer->stop(); 133 | } 134 | 135 | private: 136 | callback_t m_Callback; 137 | osTimerId_t m_id; 138 | std::chrono::microseconds m_usec; 139 | }; 140 | 141 | timer::timer() : 142 | m_pImplTimer() 143 | {} 144 | 145 | timer::timer(std::chrono::microseconds usec, callback_t&& function, timer_type_t type) : 146 | m_pImplTimer(std::make_unique(usec, std::move(function), type == timer_type_t::once)) 147 | {} 148 | 149 | timer::timer(timer&& t) : 150 | m_pImplTimer(std::move(t.m_pImplTimer)) 151 | {} 152 | 153 | timer& timer::operator=(timer&& t) 154 | { 155 | if (&t != this) 156 | m_pImplTimer = std::move(t.m_pImplTimer); 157 | 158 | return *this; 159 | } 160 | 161 | timer::~timer() 162 | {} 163 | 164 | void timer::swap(timer& t) noexcept 165 | { 166 | std::swap(m_pImplTimer, t.m_pImplTimer); 167 | } 168 | 169 | void timer::start() 170 | { 171 | if (!m_pImplTimer) 172 | { 173 | #ifdef __cpp_exceptions 174 | throw std::system_error(osErrorResource, os_category(), "timer::start"); 175 | #else 176 | std::terminate(); 177 | #endif 178 | } 179 | 180 | m_pImplTimer->start(); 181 | } 182 | 183 | void timer::stop() 184 | { 185 | if (!m_pImplTimer) 186 | { 187 | #ifdef __cpp_exceptions 188 | throw std::system_error(osErrorResource, os_category(), "timer::stop"); 189 | #else 190 | std::terminate(); 191 | #endif 192 | } 193 | 194 | m_pImplTimer->stop(); 195 | } 196 | 197 | bool timer::running() const 198 | { 199 | if (!m_pImplTimer) 200 | return false; 201 | 202 | return m_pImplTimer->running(); 203 | } 204 | } // namespace cmsis 205 | -------------------------------------------------------------------------------- /src/rtx_os.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, B. Leforestier 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the author nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | // This following part is specific to CMSIS-RTOS RTX implementation 29 | #include "rtx_os.h" 30 | #include "OSException.h" 31 | #include 32 | 33 | extern std::function idleHandler; 34 | 35 | // OS Idle Thread 36 | extern "C" __attribute__((weak)) void osRtxIdleThread(void* argument) 37 | { 38 | (void)argument; 39 | for (;;) 40 | { 41 | if (idleHandler) 42 | idleHandler(); 43 | } 44 | } 45 | 46 | // OS Error Callback function 47 | extern "C" __attribute__((weak)) uint32_t osRtxErrorNotify(uint32_t code, void* object_id) 48 | { 49 | #ifdef __cpp_exceptions 50 | try 51 | { 52 | throw std::system_error(code, cmsis::os_category(), cmsis::internal::str_error("osRtxErrorNotify", object_id)); 53 | } 54 | catch (std::exception& e) 55 | { 56 | for (;;) 57 | { 58 | } 59 | } 60 | #else 61 | (void)object_id; 62 | switch (code) 63 | { 64 | case osRtxErrorStackOverflow: 65 | // Stack overflow detected for thread (thread_id=object_id) 66 | break; 67 | case osRtxErrorISRQueueOverflow: 68 | // ISR Queue overflow detected when inserting object (object_id) 69 | break; 70 | case osRtxErrorTimerQueueOverflow: 71 | // User Timer Callback Queue overflow detected for timer (timer_id=object_id) 72 | break; 73 | case osRtxErrorClibSpace: 74 | // Standard C/C++ library libspace not available: increase OS_THREAD_LIBSPACE_NUM 75 | break; 76 | case osRtxErrorClibMutex: 77 | // Standard C/C++ library mutex initialization failed 78 | break; 79 | default: 80 | // Reserved 81 | break; 82 | } 83 | 84 | for (;;) 85 | { 86 | } 87 | #endif 88 | return code; 89 | } 90 | --------------------------------------------------------------------------------