├── .gitmodules ├── library.json ├── CMakeLists.txt ├── library.properties ├── LICENSE ├── src ├── include │ ├── prioqueue.hpp │ ├── macro_overload.hpp │ ├── response.hpp │ ├── types.hpp │ ├── bytebuffer.hpp │ ├── clock.hpp │ ├── critical.hpp │ ├── memory.hpp │ ├── queue.hpp │ ├── timer.hpp │ ├── helper.hpp │ ├── util.hpp │ ├── list.hpp │ └── logger.hpp ├── clock.cpp ├── coroutine.cpp ├── CMakeLists.txt ├── critical.cpp ├── response.cpp ├── bytebuffer.cpp ├── prioqueue.cpp ├── timer.cpp ├── config │ └── config.h ├── queue.cpp ├── QuarkTS.h ├── task.cpp ├── memory.cpp ├── list.cpp └── input.cpp ├── examples ├── Simple_Example │ └── Simple_Example.ino └── LED_Blink_Flat_State_Machine │ └── LED_Blink_Flat_State_Machine.ino └── keywords.txt /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "doc/stylesheet"] 2 | path = doc/stylesheet 3 | url = https://github.com/jothepro/doxygen-awesome-css.git 4 | -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "QuarkTS", 3 | "keywords": "os, multitasking, cooperative, event, task, scheduler, state-machine, scheduling", 4 | "description": "An open-source OS for small embedded applications", 5 | "repository": 6 | { 7 | "type": "git", 8 | "url": "https://github.com/kmilo17pet/QuarkTS-cpp" 9 | }, 10 | "authors": 11 | [ 12 | { 13 | "name": "J. Camilo Gomez C.", 14 | "email": "kmilo17pet@gmail.com", 15 | "url": "https://github.com/kmilo17pet", 16 | "maintainer": true 17 | } 18 | ], 19 | "version": "1.8.0", 20 | "license": "MIT", 21 | "frameworks": "arduino", 22 | "platforms": "*" 23 | } 24 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2) 2 | 3 | project(simple_dry_test) 4 | 5 | add_subdirectory( src ) 6 | include_directories( src ) 7 | 8 | set(CMAKE_VERBOSE_MAKEFILE ON) 9 | set(CMAKE_CXX_STANDARD 11) 10 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 11 | set(CMAKE_CXX_EXTENSIONS OFF) 12 | 13 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/build/lib) 14 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/build/lib) 15 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/build/bin) 16 | 17 | add_executable ( drytest check/simple_dry_test.cpp ) 18 | target_include_directories( drytest PUBLIC ${PROJECT_SOURCE_DIR}/src ) 19 | target_link_libraries( drytest quarkts-cpp ) 20 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=QuarkTS 2 | version=1.8.0 3 | license=MIT 4 | author=J. Camilo Gomez C. 5 | maintainer=J. Camilo Gomez C. 6 | sentence=An open-source OS for embedded applications that supports prioritized cooperative scheduling, time control, inter-task communications primitives, hierarchical state machines and CoRoutines. 7 | paragraph=QuarkTS++ is an operating system that provides a modern environment to build stable and predictable event-driven multitasking embedded software. The OS is built on top of a cooperative quasi-static scheduler and its simplified kernel implements a specialized round-robin scheme using a linked-chain approach and an event-queue to provide true FIFO priority-scheduling.. 8 | category=Timing 9 | url=https://github.com/kmilo17pet/QuarkTS-cpp 10 | repository=https://github.com/kmilo17pet/QuarkTS-cpp 11 | architectures=* 12 | includes=QuarkTS.h 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 J. Camilo G.C. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/include/prioqueue.hpp: -------------------------------------------------------------------------------- 1 | #ifndef QOS_CPP_PRIO_QUEUE 2 | #define QOS_CPP_PRIO_QUEUE 3 | 4 | #include "include/types.hpp" 5 | #include "include/task.hpp" 6 | 7 | /*! @cond */ 8 | 9 | namespace qOS { 10 | 11 | namespace pq { 12 | struct queueStack_t { 13 | task *pTask{ nullptr }; 14 | void *qData{ nullptr }; 15 | }; 16 | } 17 | 18 | class prioQueue : private nonCopyable { 19 | private: 20 | volatile base_t index{ -1 }; 21 | void *data{ nullptr }; 22 | pq::queueStack_t *stack{ nullptr }; 23 | size_t size{ 0U }; 24 | void clearIndex( const index_t indexToClear ) noexcept; 25 | prioQueue( prioQueue const& ) = delete; 26 | void operator=( prioQueue const& ) = delete; 27 | protected: 28 | prioQueue() = delete; 29 | virtual ~prioQueue() {} 30 | prioQueue( pq::queueStack_t *area, const size_t pq_size ) noexcept; 31 | size_t count( void ) const noexcept; 32 | task* get( void ) noexcept; 33 | bool isTaskInside( const task &Task ) const noexcept; 34 | bool insert( task &Task, void *pData ) noexcept; 35 | void cleanUp( const task &Task ) noexcept; 36 | inline bool hasElements( void ) const noexcept 37 | { 38 | return ( index >= 0 ); 39 | } 40 | friend class core; /*only core can use this class*/ 41 | }; 42 | 43 | } 44 | 45 | /*! @endcond */ 46 | 47 | #endif /*QOS_CPP_PRIO_QUEUE*/ 48 | -------------------------------------------------------------------------------- /src/clock.cpp: -------------------------------------------------------------------------------- 1 | #include "include/clock.hpp" 2 | 3 | using namespace qOS; 4 | 5 | volatile qOS::clock_t clock::sysTick_Epochs = 0U; // skipcq: CXX-W2009 6 | qOS::getTickFcn_t clock::getTick = &internalTick; // skipcq: CXX-W2009 7 | /*cstat -MISRAC++2008-2-13-3*/ 8 | const qOS::duration_t clock::NONE = 0_ms; 9 | const qOS::duration_t clock::IMMEDIATE = 0_ms; 10 | /*cstat +MISRAC++2008-2-13-3*/ 11 | /*============================================================================*/ 12 | void clock::sysTick( void ) noexcept 13 | { 14 | sysTick_Epochs = sysTick_Epochs + 1U; /* ++sysTick_Epochs */ 15 | } 16 | /*============================================================================*/ 17 | bool clock::timeDeadLineCheck( const qOS::clock_t ti, const qOS::clock_t td ) noexcept 18 | { 19 | return ( clock::getTick() - ti >= td ); 20 | } 21 | /*============================================================================*/ 22 | qOS::clock_t clock::internalTick( void ) noexcept 23 | { 24 | return sysTick_Epochs; 25 | } 26 | /*============================================================================*/ 27 | bool clock::setTickProvider( const getTickFcn_t provider ) noexcept 28 | { 29 | bool retValue = false; 30 | 31 | if ( nullptr != clock::getTick ) { 32 | if ( nullptr != provider ) { 33 | clock::getTick = provider; 34 | } 35 | else { 36 | clock::getTick = &internalTick; 37 | } 38 | retValue = true; 39 | } 40 | 41 | return retValue; 42 | } 43 | /*============================================================================*/ 44 | -------------------------------------------------------------------------------- /examples/Simple_Example/Simple_Example.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace qOS; 4 | task demoTask1, blinkTask; 5 | 6 | void blinkTask_callback( event_t e ) { 7 | if ( e.firstCall() ) { 8 | logger::out() << e.thisTask() << " Launched!"; 9 | } 10 | co::reenter() { 11 | for(;;) { 12 | digitalWrite( LED_BUILTIN, HIGH ); 13 | logger::out() << e.thisTask(); 14 | co::delay( 500_ms ); 15 | digitalWrite( LED_BUILTIN, LOW ); 16 | logger::out() << e.thisTask(); 17 | co::delay( 500_ms ); 18 | } 19 | } 20 | } 21 | 22 | void demoTask1_Callback( event_t e ) { 23 | if ( e.firstCall() ) { 24 | logger::out() << e.thisTask() << " Launched!"; 25 | } 26 | logger::out() << e.thisTask(); 27 | } 28 | 29 | void idleTask_callback( event_t e ) { 30 | if ( e.firstCall() ) { 31 | logger::out() << e.thisTask() << " Launched!"; 32 | } 33 | co::reenter() { 34 | for(;;) { 35 | co::delay( 500_ms ); 36 | logger::out() << e.thisTask(); 37 | } 38 | } 39 | } 40 | 41 | /* hardware-OS wrappers*/ 42 | void tracePutcWrapper( void *arg, const char c ) { 43 | Serial.write( c ); 44 | (void)arg; 45 | } 46 | 47 | void setup() { 48 | pinMode(LED_BUILTIN, OUTPUT); 49 | Serial.begin(115200); 50 | 51 | logger::setOutputFcn( tracePutcWrapper ); 52 | os.init( millis, idleTask_callback ); 53 | os.add( demoTask1, demoTask1_Callback, core::MEDIUM_PRIORITY, 250_ms, task::PERIODIC ); 54 | os.add( blinkTask, blinkTask_callback, core::LOWEST_PRIORITY, 10_ms, task::PERIODIC ); 55 | demoTask1.setName("demoTask1"); 56 | blinkTask.setName("blinkTask"); 57 | } 58 | 59 | void loop() { 60 | os.run(); 61 | } 62 | -------------------------------------------------------------------------------- /src/coroutine.cpp: -------------------------------------------------------------------------------- 1 | #include "include/coroutine.hpp" 2 | 3 | using namespace qOS; 4 | 5 | /*============================================================================*/ 6 | void co::handle::try_restart( void ) noexcept 7 | { 8 | try_set( co::BEGINNING ); 9 | } 10 | /*============================================================================*/ 11 | void co::handle::try_suspend( void ) noexcept 12 | { 13 | if ( prev != ctx->label ) { 14 | prev = ctx->label; 15 | try_set( co::SUSPENDED ); 16 | } 17 | } 18 | /*============================================================================*/ 19 | void co::handle::try_resume( void ) noexcept 20 | { 21 | if ( co::SUSPENDED == prev ) { 22 | try_restart(); 23 | } 24 | else { 25 | try_set( prev ); 26 | } 27 | prev = co::UNDEFINED; 28 | } 29 | /*============================================================================*/ 30 | void co::handle::try_set( co::state p ) noexcept 31 | { 32 | ctx->label = p; 33 | } 34 | /*============================================================================*/ 35 | void co::semaphore::signal( void ) noexcept 36 | { 37 | ++count; 38 | } 39 | /*============================================================================*/ 40 | bool co::semaphore::tryLock( void ) noexcept 41 | { 42 | bool retValue = false; 43 | 44 | if ( count > static_cast( 0U ) ) { 45 | retValue = true; /*break the Wait operation*/ 46 | --count; 47 | } 48 | 49 | return retValue; 50 | } 51 | /*============================================================================*/ 52 | void co::semaphore::set( size_t val ) noexcept 53 | { 54 | count = val; 55 | } 56 | /*============================================================================*/ 57 | -------------------------------------------------------------------------------- /src/include/macro_overload.hpp: -------------------------------------------------------------------------------- 1 | #ifndef QOS_CPP_MACRO_OVERLOAD 2 | #define QOS_CPP_MACRO_OVERLOAD 3 | 4 | #define QOS_MO_CAT(a, ...) QOS_MO_PRIMITIVE_CAT( a, __VA_ARGS__ ) 5 | #define QOS_MO_PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__ 6 | #define QOS_MO_SPLIT(i, ...) QOS_MO_PRIMITIVE_CAT( QOS_MO_SPLIT_, i )( __VA_ARGS__ ) 7 | #define QOS_MO_SPLIT_0(a, ...) a 8 | #define QOS_MO_SPLIT_1(a, ...) __VA_ARGS__ 9 | #define QOS_IS_VARIADIC(...) QOS_MO_SPLIT( 0, QOS_MO_CAT( QOS_IS_VARIADIC_R_, QOS_IS_VARIADIC_C __VA_ARGS__ ) ) 10 | #define QOS_IS_VARIADIC_C(...) 1 11 | #define QOS_IS_VARIADIC_R_1 1, 12 | #define QOS_IS_VARIADIC_R_QOS_IS_VARIADIC_C 0, 13 | #define QOS_MO_IIF(bit) QOS_MO_PRIMITIVE_CAT( QOS_MO_IIF_, bit ) 14 | #define QOS_MO_IIF_0(t, ...) __VA_ARGS__ 15 | #define QOS_MO_IIF_1(t, ...) t 16 | #define QOS_MO_IS_EMPTY_NON_FUNCTION(...) QOS_MO_IIF( QOS_IS_VARIADIC( __VA_ARGS__ ) )( 0, QOS_IS_VARIADIC( QOS_MO_IS_EMPTY_NON_FUNCTION_C __VA_ARGS__ () ) ) 17 | #define QOS_MO_IS_EMPTY_NON_FUNCTION_C() () 18 | #define QOS_MO_COMMA() , 19 | #define QOS_MO_REM(...) __VA_ARGS__ 20 | #define QOS_MO_SIZE(...) QOS_MO_SPLIT( 0, QOS_MO_SPLIT( 1, QOS_MO_SIZE_A( QOS_MO_COMMA, QOS_MO_REM( __VA_ARGS__ ) ),, ) ) 21 | #define QOS_MO_SIZE_A(_, im) QOS_MO_SIZE_B( im, _() 5, _() 4, _() 3, _() 2, _() 1,) 22 | #define QOS_MO_SIZE_B(a, b, c, d, e, _, ...) _ 23 | #define QOS_MO_GTZ_OVERLOAD(prefix, ...) QOS_MO_CAT( prefix, QOS_MO_SIZE( __VA_ARGS__) ) 24 | #define QOS_MO_SELECT(bit, t, f) QOS_MO_SELECT_I( bit, t, f ) 25 | #define QOS_MO_SELECT_I(bit, t, f) QOS_MO_SELECT_ ## bit( t, f ) 26 | #define QOS_MO_SELECT_0(t, f) f 27 | #define QOS_MO_SELECT_1(t, f) t 28 | 29 | #define MACRO_OVERLOAD( prefix, ... ) \ 30 | QOS_MO_SELECT( QOS_MO_IS_EMPTY_NON_FUNCTION( __VA_ARGS__ ), QOS_MO_CAT( prefix , 0() ), QOS_MO_GTZ_OVERLOAD( prefix , __VA_ARGS__ )( __VA_ARGS__ ) ) 31 | 32 | #endif -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required( VERSION 3.2 ) 2 | project( quarkts-cpp 3 | VERSION 1.8.0 4 | DESCRIPTION "An open-source OS for small embedded applications" 5 | LANGUAGES CXX ) 6 | 7 | add_library( ${PROJECT_NAME} INTERFACE ) 8 | 9 | target_sources( ${PROJECT_NAME} INTERFACE 10 | "${CMAKE_CURRENT_LIST_DIR}/critical.cpp" 11 | "${CMAKE_CURRENT_LIST_DIR}/list.cpp" 12 | "${CMAKE_CURRENT_LIST_DIR}/clock.cpp" 13 | "${CMAKE_CURRENT_LIST_DIR}/timer.cpp" 14 | "${CMAKE_CURRENT_LIST_DIR}/queue.cpp" 15 | "${CMAKE_CURRENT_LIST_DIR}/task.cpp" 16 | "${CMAKE_CURRENT_LIST_DIR}/prioqueue.cpp" 17 | "${CMAKE_CURRENT_LIST_DIR}/kernel.cpp" 18 | "${CMAKE_CURRENT_LIST_DIR}/fsm.cpp" 19 | "${CMAKE_CURRENT_LIST_DIR}/coroutine.cpp" 20 | "${CMAKE_CURRENT_LIST_DIR}/util.cpp" 21 | "${CMAKE_CURRENT_LIST_DIR}/cli.cpp" 22 | "${CMAKE_CURRENT_LIST_DIR}/memory.cpp" 23 | "${CMAKE_CURRENT_LIST_DIR}/bytebuffer.cpp" 24 | "${CMAKE_CURRENT_LIST_DIR}/response.cpp" 25 | "${CMAKE_CURRENT_LIST_DIR}/input.cpp" 26 | "${CMAKE_CURRENT_LIST_DIR}/logger.cpp" 27 | ) 28 | 29 | target_compile_options( ${PROJECT_NAME} INTERFACE 30 | $<$: 31 | -std=c++11 -Wall -Wextra -Wpedantic -Wconversion 32 | -flto -Wimplicit-fallthrough=0 -Wformat-security 33 | -Wduplicated-cond -Wfloat-equal -Wshadow -Wsign-conversion 34 | -Wlogical-not-parentheses -Wnull-dereference -Wstringop-overflow 35 | -fdump-rtl-expand -fstrict-aliasing -Wstrict-aliasing 36 | -Wparentheses -Wsequence-point -Wreturn-type -Wswitch -Wtrigraphs 37 | -Wunused -Wuninitialized -Wunknown-pragmas -Wfloat-equal -Wshadow 38 | -Wwrite-strings -Wsign-compare -Wmissing-declarations -Wformat 39 | -Wmissing-format-attribute -Wno-deprecated-declarations -Wpacked 40 | -Wredundant-decls -Wunreachable-code 41 | > 42 | ) 43 | set_target_properties( ${PROJECT_NAME} PROPERTIES CXX_EXTENSIONS OFF) 44 | target_include_directories( ${PROJECT_NAME} INTERFACE ${PROJECT_SOURCE_DIR} ) 45 | 46 | -------------------------------------------------------------------------------- /src/critical.cpp: -------------------------------------------------------------------------------- 1 | #include "include/critical.hpp" 2 | 3 | using namespace qOS; 4 | 5 | /*! @cond */ 6 | int_disabler_t critical::lock::disable = nullptr; // skipcq: CXX-W2009 /*< Point to the user-supplied function used to disable the hardware interrupts. */ 7 | int_restorer_t critical::lock::restore = nullptr; // skipcq: CXX-W2009 /*< Point to the user-supplied function used to restore the hardware interrupts. */ 8 | volatile uint32_t critical::lock::flags = 0UL; // skipcq: CXX-W2009 /*< To save the current interrupt flags before the disable action is performed. */ 9 | volatile int critical::lock::nestingLevel = 0; // skipcq: CXX-W2009 10 | /*! @endcond */ 11 | 12 | /*============================================================================*/ 13 | void critical::lock::enter( void ) noexcept 14 | { 15 | if ( ( 0 == nestingLevel ) && ( nullptr != disable ) ) { 16 | const int_disabler_t xDisabler = disable; 17 | flags = xDisabler(); 18 | } 19 | ++nestingLevel; 20 | } 21 | /*============================================================================*/ 22 | void critical::lock::exit( void ) noexcept 23 | { 24 | if ( nestingLevel > 0 ) { 25 | --nestingLevel; 26 | if ( ( 0 == nestingLevel ) && ( nullptr != restore ) ) { 27 | const int_restorer_t xRestorer = restore; 28 | xRestorer( flags ); 29 | } 30 | } 31 | } 32 | /*============================================================================*/ 33 | critical::lock::lock() noexcept 34 | { 35 | enter(); 36 | } 37 | /*============================================================================*/ 38 | critical::lock::~lock() noexcept 39 | { 40 | exit(); 41 | } 42 | /*============================================================================*/ 43 | critical::lock::operator bool() noexcept 44 | { 45 | const bool ret = entered; 46 | entered = false; 47 | return ret; 48 | } 49 | /*============================================================================*/ 50 | bool critical::setInterruptsED( const int_restorer_t rFcn, const int_disabler_t dFcn ) noexcept 51 | { 52 | bool retValue = false; 53 | 54 | if ( ( rFcn != critical::lock::restore ) || ( dFcn != critical::lock::disable ) ) { 55 | critical::lock::restore = rFcn; 56 | critical::lock::disable = dFcn; 57 | retValue = true; 58 | } 59 | 60 | return retValue; 61 | } 62 | /*============================================================================*/ 63 | -------------------------------------------------------------------------------- /src/response.cpp: -------------------------------------------------------------------------------- 1 | #include "include/response.hpp" 2 | #include "include/util.hpp" 3 | #include "include/helper.hpp" 4 | 5 | using namespace qOS; 6 | 7 | /*============================================================================*/ 8 | bool response::setup( char *xLocBuff, const size_t nMax ) noexcept 9 | { 10 | bool retValue = false; 11 | 12 | if ( ( nullptr != xLocBuff ) && ( nMax > 0U ) ) { 13 | pattern2Match = xLocBuff; 14 | maxStrLength = nMax; 15 | reset(); 16 | retValue = true; 17 | } 18 | 19 | return retValue; 20 | } 21 | /*============================================================================*/ 22 | void response::reset( void ) noexcept 23 | { 24 | patternLength = 0U; 25 | matchedCount = 0U; 26 | responseReceived = false; 27 | timeout.disarm(); 28 | } 29 | /*============================================================================*/ 30 | responseStatus response::received( const char *pattern, const size_t n, const qOS::duration_t t ) noexcept 31 | { 32 | responseStatus retValue = responseStatus::MISSING; 33 | 34 | if ( ( !responseReceived ) && ( 0U == patternLength ) ) { 35 | (void)util::strcpy( pattern2Match, pattern, maxStrLength ); 36 | patternLength = ( 0U == n ) ? util::strlen( pattern, maxStrLength ) : n; 37 | matchedCount = 0U; 38 | responseReceived = false; 39 | if ( t > clock::IMMEDIATE ) { 40 | (void)timeout.set( t ); 41 | } 42 | } 43 | else if ( timeout.expired() ) { 44 | reset(); 45 | retValue = responseStatus::TIMEOUT; 46 | } 47 | else if ( responseReceived ) { 48 | reset(); 49 | retValue = responseStatus::SUCCESS; 50 | } 51 | else { 52 | /*nothing to do*/ 53 | } 54 | 55 | return retValue; 56 | } 57 | /*============================================================================*/ 58 | bool response::isrHandler( const char rxChar ) noexcept 59 | { 60 | bool retValue = false; 61 | 62 | if ( ( !responseReceived ) && ( patternLength > 0U ) ) { 63 | if ( pattern2Match[ matchedCount ] == rxChar ) { 64 | matchedCount = matchedCount + 1U; /* ++matchedCount */ 65 | if ( matchedCount == patternLength ) { 66 | responseReceived = true; 67 | retValue = responseReceived; 68 | } 69 | } 70 | } 71 | 72 | return retValue; 73 | } 74 | /*============================================================================*/ 75 | bool response::isInitialized( void ) const noexcept 76 | { 77 | return ( maxStrLength > 0U ); 78 | } 79 | /*============================================================================*/ 80 | -------------------------------------------------------------------------------- /src/include/response.hpp: -------------------------------------------------------------------------------- 1 | #ifndef QOS_RESPONSE 2 | #define QOS_RESPONSE 3 | 4 | #include "include/types.hpp" 5 | #include "include/timer.hpp" 6 | 7 | namespace qOS { 8 | 9 | /** @addtogroup qresponse Response handler 10 | * @brief API to simplify the handling of requested responses from terminal 11 | * interfaces. 12 | * @{ 13 | */ 14 | 15 | /** 16 | * @brief A enum with the possible return status of a qOS::response object. 17 | */ 18 | enum class responseStatus { 19 | MISSING = 0, 20 | SUCCESS, 21 | TIMEOUT, 22 | }; 23 | 24 | /** 25 | * @brief A Response Handler object. 26 | */ 27 | class response : private nonCopyable { 28 | private: 29 | char *pattern2Match{ nullptr }; 30 | timer timeout; 31 | size_t maxStrLength{ 0U }; 32 | size_t patternLength{ 0U }; 33 | volatile size_t matchedCount{ 0U }; 34 | volatile bool responseReceived{ false }; 35 | public: 36 | response() = default; 37 | /*! @cond */ 38 | virtual ~response() {} 39 | /*! @endcond */ 40 | /** 41 | * @brief Initialize the instance of the response handler object 42 | * @param[in] xLocBuff A pointer to the memory block where the desired 43 | * response will remain. 44 | * @param[in] nMax The size of @a xLocBuff 45 | * @return On success returns @c true, otherwise returns @c false. 46 | */ 47 | bool setup( char *xLocBuff, const size_t nMax ) noexcept; 48 | /** 49 | * @brief Reset the Response Handler 50 | */ 51 | void reset( void ) noexcept; 52 | /** 53 | * @brief Non-Blocking response check 54 | * @param[in] pattern The data checked in the receiver ISR 55 | * @param[in] n The length of the data pointer by @a pattern 56 | * (if @a pattern is string, set @a n to 0 to auto-compute the length) 57 | * @param[in] t The timeout value given in milliseconds. 58 | * @return responseStatus::SUCCESS if there is a response acknowledge, 59 | * responseStatus::TIMEOUT if timeout expires otherwise returns 60 | * responseStatus::MISSING 61 | */ 62 | responseStatus received( const char *pattern, const size_t n, const qOS::duration_t t = clock::IMMEDIATE ) noexcept; 63 | /** 64 | * @brief ISR receiver for the response handler 65 | * @param[in] rxChar The byte-data from the receiver 66 | * @return True when the Response handler match the request from 67 | * response::received() 68 | */ 69 | bool isrHandler( const char rxChar ) noexcept; 70 | /** 71 | * @brief Check if the response object is already initialized by 72 | * using response::setup() 73 | * @return @c true if the response object is initialized, @c false if not. 74 | */ 75 | bool isInitialized( void ) const noexcept; 76 | /** 77 | * @brief Check if the response object is already initialized by 78 | * using response::setup() 79 | * @return @c true if the response object is initialized, @c false if not. 80 | */ 81 | explicit operator bool() const noexcept { 82 | return isInitialized(); 83 | } 84 | }; 85 | 86 | /** @}*/ 87 | } 88 | 89 | #endif /*QOS_RESPONSE*/ 90 | -------------------------------------------------------------------------------- /src/bytebuffer.cpp: -------------------------------------------------------------------------------- 1 | #include "include/bytebuffer.hpp" 2 | 3 | using namespace qOS; 4 | 5 | /*============================================================================*/ 6 | size_t byteBuffer::checkValidPowerOfTwo( size_t k ) noexcept 7 | { 8 | const size_t r = k; 9 | 10 | if ( 0U != ( ( k - 1U ) & k ) ) { 11 | k--; 12 | /*cstat -MISRAC++2008-6-5-4 -CERT-INT34-C_a*/ 13 | for ( index_t i = 1U ; i < ( sizeof(index_t)*8U ) ; i = static_cast( i * 2U ) ) { 14 | k = k | static_cast( k >> i ); 15 | } 16 | /*cstat +MISRAC++2008-6-5-4 +CERT-INT34-C_a*/ 17 | k = static_cast( ( k + 1U ) >> 1U ); 18 | } 19 | 20 | return ( k < r ) ? ( k * 2U ) : k; 21 | } 22 | /*============================================================================*/ 23 | bool byteBuffer::setup( volatile byte_t *pBuffer, const size_t bLength ) noexcept 24 | { 25 | bool retValue = false; 26 | 27 | if ( ( nullptr != pBuffer ) && ( length > 0U ) ) { 28 | head = 0U; 29 | tail = 0U; 30 | buffer = pBuffer; 31 | length = checkValidPowerOfTwo( bLength ); 32 | retValue = true; 33 | } 34 | 35 | return retValue; 36 | } 37 | /*============================================================================*/ 38 | bool byteBuffer::put( const byte_t bData ) noexcept 39 | { 40 | bool retValue = false; 41 | 42 | if ( !isFull() ) { 43 | buffer[ head % length ] = bData; 44 | head = head + 1U; /* ++head */ 45 | retValue = true; 46 | } 47 | 48 | return retValue; 49 | } 50 | /*============================================================================*/ 51 | bool byteBuffer::read( void *dst, const size_t n ) noexcept 52 | { 53 | bool retValue = false; 54 | 55 | if ( n > 0U ) { 56 | /*cstat -CERT-EXP36-C_b*/ 57 | byte_t * const pData = static_cast( dst ); 58 | /*cstat +CERT-EXP36-C_b*/ 59 | for ( size_t i = 0U ; i < n ; ++i ) { 60 | (void)get( &pData[ i ] ); 61 | } 62 | retValue = true; 63 | } 64 | 65 | return retValue; 66 | } 67 | /*============================================================================*/ 68 | bool byteBuffer::get( byte_t *dst ) noexcept 69 | { 70 | bool retValue = false; 71 | 72 | if ( !isEmpty() ) { 73 | const index_t vTail = static_cast( tail ); 74 | *dst = buffer[ vTail % length ]; 75 | tail = tail + 1U; /* ++tail */ 76 | retValue = true; 77 | } 78 | 79 | return retValue; 80 | } 81 | /*============================================================================*/ 82 | byte_t byteBuffer::peek( void ) const noexcept 83 | { 84 | const index_t vTail = static_cast( tail ); 85 | return static_cast( buffer[ vTail % length ] ); 86 | } 87 | /*============================================================================*/ 88 | bool byteBuffer::isEmpty( void ) const noexcept 89 | { 90 | return ( 0U == count() ); 91 | } 92 | /*============================================================================*/ 93 | bool byteBuffer::isFull( void ) const noexcept 94 | { 95 | return ( length == count() ); 96 | } 97 | /*============================================================================*/ 98 | size_t byteBuffer::count( void ) const noexcept 99 | { 100 | const index_t vHead = static_cast( head ); 101 | const index_t vTail = static_cast( tail ); 102 | return static_cast( vHead - vTail ); 103 | } 104 | /*============================================================================*/ 105 | -------------------------------------------------------------------------------- /src/prioqueue.cpp: -------------------------------------------------------------------------------- 1 | #include "include/prioqueue.hpp" 2 | #include "include/critical.hpp" 3 | 4 | using namespace qOS; 5 | 6 | /*============================================================================*/ 7 | prioQueue::prioQueue( pq::queueStack_t *area, const size_t pq_size ) noexcept 8 | { 9 | critical::scope { 10 | stack = area; 11 | size = pq_size; 12 | for ( size_t i = 0U ; i < size ; ++i ) { 13 | stack[ i ].pTask = nullptr; 14 | } 15 | index = -1; 16 | } 17 | } 18 | /*============================================================================*/ 19 | size_t prioQueue::count( void ) const noexcept 20 | { 21 | size_t retValue = 0U; 22 | 23 | if ( hasElements() ) { 24 | retValue = static_cast( index ) + 1U; 25 | } 26 | 27 | return retValue; 28 | } 29 | /*============================================================================*/ 30 | task* prioQueue::get( void ) noexcept 31 | { 32 | task *xTask = nullptr; 33 | 34 | if ( hasElements() ) { 35 | critical::scope { 36 | priority_t maxPriority; 37 | index_t indexTaskToExtract = 0U; 38 | 39 | maxPriority = stack[ 0 ].pTask->getPriority(); 40 | for ( index_t i = 1U ; ( i < size ) && ( nullptr != stack[ i ].pTask ) ; ++i ) { 41 | const priority_t iPriorityValue = stack[ i ].pTask->getPriority(); 42 | if ( iPriorityValue > maxPriority ) { 43 | maxPriority = iPriorityValue; 44 | indexTaskToExtract = i; 45 | } 46 | } 47 | data = stack[ indexTaskToExtract ].qData; 48 | xTask = stack[ indexTaskToExtract ].pTask; 49 | clearIndex( indexTaskToExtract ); 50 | } 51 | } 52 | 53 | return xTask; 54 | } 55 | /*============================================================================*/ 56 | bool prioQueue::isTaskInside( const task &Task ) const noexcept 57 | { 58 | bool retValue = false; 59 | const base_t currentQueueIndex = index + 1; 60 | 61 | if ( currentQueueIndex > 0 ) { 62 | critical::scope { 63 | for ( base_t i = 0 ; i < currentQueueIndex ; ++i ) { 64 | if ( &Task == stack[ i ].pTask ) { 65 | retValue = true; 66 | break; 67 | } 68 | } 69 | } 70 | } 71 | 72 | return retValue; 73 | } 74 | /*============================================================================*/ 75 | /*cstat -MISRAC++2008-7-1-2*/ 76 | bool prioQueue::insert( task &Task, void *pData ) noexcept 77 | { 78 | bool retValue = false; 79 | const base_t queueMaxIndex = static_cast( size ) - 1; 80 | 81 | if ( index < queueMaxIndex ) { 82 | pq::queueStack_t tmp; 83 | 84 | tmp.pTask = &Task; 85 | tmp.qData = pData; 86 | index = index + 1; /* ++index */ 87 | stack[ index ] = tmp; /*stack[ ++index ] = tmp*/ 88 | retValue = true; 89 | } 90 | return retValue; 91 | } 92 | /*cstat +MISRAC++2008-7-1-2*/ 93 | /*============================================================================*/ 94 | void prioQueue::clearIndex( const index_t indexToClear ) noexcept 95 | { 96 | const base_t queueIndex = static_cast( index ); 97 | 98 | stack[ indexToClear ].pTask = nullptr; 99 | for ( index_t j = indexToClear ; static_cast( j ) < queueIndex ; ++j ) { 100 | stack[ j ] = stack[ j + 1U ]; 101 | } 102 | index = index - 1; /* --index */ 103 | } 104 | /*============================================================================*/ 105 | void prioQueue::cleanUp( const task &Task ) noexcept 106 | { 107 | for ( index_t i = 1U ; i < size ; ++i ) { 108 | if ( stack[ i ].pTask == &Task ) { 109 | clearIndex( i ); 110 | } 111 | } 112 | } 113 | /*============================================================================*/ 114 | -------------------------------------------------------------------------------- /src/timer.cpp: -------------------------------------------------------------------------------- 1 | #include "include/timer.hpp" 2 | 3 | using namespace qOS; 4 | 5 | const bool timer::ARMED = true; 6 | const bool timer::DISARMED = false; 7 | const qOS::clock_t timer::DISARM_VALUE = 0UL ; 8 | const qOS::clock_t timer::REMAINING_IN_DISARMED_STATE = 0xFFFFFFFFUL; 9 | 10 | /*============================================================================*/ 11 | timer::timer() noexcept 12 | { 13 | disarm(); 14 | } 15 | /*============================================================================*/ 16 | void timer::reload( void ) noexcept 17 | { 18 | tStart = clock::getTick(); 19 | } 20 | /*============================================================================*/ 21 | bool timer::set( const qOS::duration_t tTime ) noexcept 22 | { 23 | bool retValue = false; 24 | /*cstat -CERT-FLP36-C*/ 25 | if ( tTime > static_cast( 0 ) ) { 26 | reload(); 27 | tv = static_cast( tTime ); 28 | retValue = true; 29 | } 30 | /*cstat +CERT-FLP36-C*/ 31 | return retValue; 32 | } 33 | /*============================================================================*/ 34 | timer& timer::operator=( const qOS::duration_t tTime ) 35 | { 36 | /*cstat -CERT-FLP36-C*/ 37 | if( tTime > static_cast( 0 ) ) { 38 | (void)set( tTime ); 39 | } 40 | /*cstat +CERT-FLP36-C*/ 41 | else { 42 | disarm(); 43 | } 44 | return *this; 45 | } 46 | /*============================================================================*/ 47 | timer& timer::operator=( const bool en ) 48 | { 49 | ( en ) ? reload() : disarm(); 50 | return *this; 51 | } 52 | /*============================================================================*/ 53 | bool timer::operator()( void ) const 54 | { 55 | return expired(); 56 | } 57 | /*============================================================================*/ 58 | void timer::disarm( void ) noexcept 59 | { 60 | tv = timer::DISARM_VALUE; 61 | tStart = timer::DISARM_VALUE; 62 | } 63 | /*============================================================================*/ 64 | bool timer::reloadIfExpired( const qOS::duration_t tTime ) noexcept 65 | { 66 | bool retValue = false; 67 | 68 | if ( timer::ARMED == status() ) { 69 | if ( expired() ) { 70 | reload(); 71 | retValue = true; 72 | } 73 | } 74 | else { 75 | (void)set( tTime ); 76 | } 77 | 78 | return retValue; 79 | } 80 | /*============================================================================*/ 81 | bool timer::reloadIfExpired( void ) noexcept 82 | { 83 | bool retValue = false; 84 | 85 | if ( timer::ARMED == status() ) { 86 | if ( expired() ) { 87 | reload(); 88 | retValue = true; 89 | } 90 | } 91 | 92 | return retValue; 93 | } 94 | /*============================================================================*/ 95 | bool timer::operator()( const qOS::duration_t tTime ) 96 | { 97 | return set( tTime ); 98 | } 99 | /*============================================================================*/ 100 | void timer::operator()( const bool en ) 101 | { 102 | ( en )? reload() : disarm(); 103 | } 104 | /*============================================================================*/ 105 | qOS::clock_t timer::elapsed( void ) const noexcept 106 | { 107 | return ( timer::ARMED == status() ) ? clock::getTick() - tStart : 0U; 108 | } 109 | /*============================================================================*/ 110 | qOS::clock_t timer::remaining( void ) const noexcept 111 | { 112 | return ( timer::DISARM_VALUE != status() ) ? ( tv - elapsed() ) : timer::REMAINING_IN_DISARMED_STATE; // skipcq: CXX-W2065 113 | } 114 | /*============================================================================*/ 115 | bool timer::expired( void ) const noexcept 116 | { 117 | bool retValue = false; 118 | 119 | if ( timer::ARMED == status() ) { 120 | retValue = deadLineCheck(); 121 | } 122 | 123 | return retValue; 124 | } 125 | /*============================================================================*/ 126 | bool timer::status( void ) const noexcept 127 | { 128 | return ( tv != 0U ); 129 | } 130 | /*============================================================================*/ 131 | bool timer::deadLineCheck( void ) const noexcept 132 | { 133 | return ( ( clock::getTick() - tStart ) >= tv ); 134 | } 135 | /*============================================================================*/ 136 | qOS::clock_t timer::getInterval( void ) const noexcept 137 | { 138 | return tv; 139 | } 140 | /*============================================================================*/ 141 | -------------------------------------------------------------------------------- /examples/LED_Blink_Flat_State_Machine/LED_Blink_Flat_State_Machine.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace qOS; 4 | 5 | /* 6 | This example uses a push button (tact switch) attached to digital pin 2 and GND, 7 | using an internal pull-up resistor so pin 2 is HIGH when the button is not pressed. 8 | */ 9 | input::digitalChannel button( 2, true ); /* Pin D2 -> invert value = true (due internal pull-up)*/ 10 | input::watcher inWatcher( digitalRead, nullptr, 50_ms ); /*inWatcher will use digitalRead to read the channel using a debounce time of 50_ms*/ 11 | 12 | /*define the FSM application event-signals*/ 13 | enum : sm::signalIDType { 14 | SIGNAL_BUTTON_PRESSED = sm::SIGNAL_USER( 1 ), 15 | SIGNAL_DELAY = sm::SIGNAL_TIMEOUT( 0 ), 16 | SIGNAL_BLINK = sm::SIGNAL_TIMEOUT( 1 ), 17 | }; 18 | 19 | task LED_Task; /*The task node*/ 20 | stateMachine LED_FSM; /*The state-machine handler*/ 21 | sm::state State_LEDOff, State_LEDOn, State_LEDBlink; 22 | sm::signalQueue<5> LEDsigqueue; /*The signal queue for the state machine*/ 23 | sm::timeoutSpec TimeoutSpecs; /*The timeout specification to handle timers within states*/ 24 | 25 | /*create the transition tables for every state*/ 26 | sm::transition LEDOff_transitions[] = { 27 | { SIGNAL_BUTTON_PRESSED, State_LEDOn } 28 | }; 29 | 30 | sm::transition LEDOn_transitions[] = { 31 | { SIGNAL_DELAY, State_LEDOff }, 32 | { SIGNAL_BUTTON_PRESSED, State_LEDBlink } 33 | }; 34 | 35 | sm::transition LEDBlink_transitions[] = { 36 | { SIGNAL_DELAY, State_LEDOff }, 37 | { SIGNAL_BUTTON_PRESSED, State_LEDOff } 38 | }; 39 | 40 | /*define the timeout specifications */ 41 | sm::timeoutStateDefinition LedOn_Timeouts[] = { 42 | { 10_sec, sm::TIMEOUT_USE_SIGNAL( 0 ) | sm::TIMEOUT_SET_ENTRY | sm::TIMEOUT_RST_EXIT }, 43 | }; 44 | 45 | sm::timeoutStateDefinition LEDBlink_timeouts[] = { 46 | { 10_sec, sm::TIMEOUT_USE_SIGNAL( 0 ) | sm::TIMEOUT_SET_ENTRY | sm::TIMEOUT_RST_EXIT }, 47 | { 0.25_sec, sm::TIMEOUT_USE_SIGNAL( 1 ) | sm::TIMEOUT_SET_ENTRY | sm::TIMEOUT_RST_EXIT | sm::TIMEOUT_PERIODIC } 48 | }; 49 | 50 | sm::status State_LEDOff_Callback( sm::handler_t h ) { 51 | switch ( h.signal() ) { 52 | case sm::signalID::SIGNAL_ENTRY: 53 | logger::out() << "LED Off state"; 54 | digitalWrite( LED_BUILTIN, LOW ); 55 | break; 56 | default: 57 | break; 58 | } 59 | return sm::status::SUCCESS; 60 | } 61 | 62 | sm::status State_LEDOn_Callback( sm::handler_t h ) { 63 | switch ( h.signal() ) { 64 | case sm::signalID::SIGNAL_ENTRY: 65 | logger::out() << "LED On state"; 66 | digitalWrite( LED_BUILTIN, HIGH ); 67 | break; 68 | default: 69 | break; 70 | } 71 | return sm::status::SUCCESS; 72 | } 73 | 74 | sm::status State_LEDBlink_Callback( sm::handler_t h ) { 75 | switch ( h.signal() ) { 76 | case sm::signalID::SIGNAL_ENTRY: 77 | logger::out() << "LED blink state"; 78 | break; 79 | case SIGNAL_BLINK: 80 | digitalWrite( LED_BUILTIN, !digitalRead(LED_BUILTIN) ); 81 | break; 82 | default: 83 | break; 84 | } 85 | return sm::status::SUCCESS; 86 | } 87 | 88 | /* hardware-OS wrappers*/ 89 | void tracePutcWrapper( void *arg, const char c ) { 90 | Serial.write( c ); 91 | (void)arg; 92 | } 93 | 94 | void idleTaskCallback( event_t e ) { 95 | if ( e.firstCall() ) { 96 | logger::out() << QUARKTS_CPP_CAPTION; 97 | } 98 | } 99 | 100 | void buttonEvent( input::channel& c ) { 101 | if ( input::event::RISING_EDGE == c.getEvent() ) { 102 | LED_FSM.sendSignal( SIGNAL_BUTTON_PRESSED ); 103 | } 104 | } 105 | 106 | void setup() { 107 | pinMode( LED_BUILTIN, OUTPUT ); 108 | pinMode( 2, INPUT_PULLUP ); 109 | Serial.begin(115200); 110 | logger::setOutputFcn( tracePutcWrapper ); 111 | os.init( millis, idleTaskCallback ); 112 | inWatcher.add( button, buttonEvent ); 113 | os.add( inWatcher ); //let the os handle the input-watcher 114 | 115 | LED_FSM.setup( nullptr, State_LEDOff ); 116 | LED_FSM.add( State_LEDOff, State_LEDOff_Callback ); 117 | LED_FSM.add( State_LEDOn, State_LEDOn_Callback ); 118 | LED_FSM.add( State_LEDBlink, State_LEDBlink_Callback ); 119 | 120 | LED_FSM.install( LEDsigqueue ); 121 | LED_FSM.install( TimeoutSpecs ); 122 | State_LEDOff.install( LEDOff_transitions ); 123 | State_LEDOn.install( LEDOn_transitions, LedOn_Timeouts ); 124 | State_LEDBlink.install( LEDBlink_transitions, LEDBlink_timeouts ); 125 | 126 | os.add( LED_Task, LED_FSM, core::MEDIUM_PRIORITY, 100_ms ); 127 | LED_Task.setName("LEDFSM_Task1"); 128 | } 129 | 130 | void loop() { 131 | os.run(); 132 | } 133 | -------------------------------------------------------------------------------- /src/config/config.h: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file config.h 3 | * @author J. Camilo Gomez C. 4 | * @version 1.10 5 | * @note This file is part of the QuarkTS distribution. 6 | * @brief OS Configuration file 7 | **/ 8 | 9 | #ifndef QCONFIG_H 10 | #define QCONFIG_H 11 | 12 | /** @addtogroup qconfiguration 13 | * @brief Some OS features can be customized using a set of macros located 14 | * in the header file @c config.h. 15 | * @{ 16 | */ 17 | 18 | /*================================================== CONFIGURATION FLAGS =======================================================*/ 19 | /** 20 | * @brief Number of priority levels. 21 | * @details The number of priorities available to the application tasks 22 | * @note Default value @c 3 23 | */ 24 | #define Q_PRIORITY_LEVELS ( 3 ) /**< The number of priorities available to the application tasks*/ 25 | /** 26 | * @brief The size of the priority queue. 27 | * @details The size of the priority FIFO queue for notifications (use a 0(zero) value to disable it) 28 | * @note Default value @c 10 29 | */ 30 | #define Q_PRIO_QUEUE_SIZE ( 10 ) 31 | /** 32 | * @brief Allow scheduler release action. 33 | * @details Used to enable or disable the release of the scheduling. 34 | * @note Default value @c 1 @a enabled 35 | */ 36 | #define Q_ALLOW_SCHEDULER_RELEASE ( 1 ) 37 | /** 38 | * @brief Preserve task entry order. 39 | * @details If enabled, kernel will preserve the tasks entry order every OS scheduling cycle. 40 | * @note Default value @c 1 @a enabled 41 | */ 42 | #define Q_PRESERVE_TASK_ENTRY_ORDER ( 1 ) 43 | /** 44 | * @brief Byte alignment used by the memory manager. 45 | * @details Use a number in power of two for this configuration. 46 | * @note Default value @c 8 47 | */ 48 | #define Q_BYTE_ALIGNMENT ( 8 ) 49 | /** 50 | * @brief Heap size fo the default memory pool. 51 | * @details This also will enable @c new and @c delete operators if not available 52 | * in the target compiler. 53 | * @note Default value @c 0 @a disabled 54 | */ 55 | #define Q_DEFAULT_HEAP_SIZE ( 0 ) 56 | /** 57 | * @brief Finite State Machine enabler. 58 | * @details Used to enable or disable the Finite State Machine (FSM) module 59 | * @note Default value @c 1 @a enabled 60 | */ 61 | #define Q_FSM ( 1 ) 62 | /** 63 | * @brief Finite State Machine : nest depth 64 | * @details The max depth of nesting for the Finite State Machines (FSM) module. 65 | * This setting its required to allow hierarchical state machines. Use a value 66 | * greater than 1 67 | * @note Default value @c 5 68 | */ 69 | #define Q_FSM_MAX_NEST_DEPTH ( 5 ) 70 | /** 71 | * @brief Finite State Machine : number of timeouts. 72 | * @details Max number of timeouts inside a timeout specification for the 73 | * Finite State machine (FSM) module 74 | * @note Default value @c 3 75 | */ 76 | #define Q_FSM_MAX_TIMEOUTS ( 3 ) 77 | /** 78 | * @brief Finite State Machine : number of signals to subscribe. 79 | * @details Max number of signals to subscribe for a single FSM object. 80 | * @note Default value @c 8 81 | */ 82 | #define Q_FSM_PS_SIGNALS_MAX ( 8 ) 83 | /** 84 | * @brief Finite State Machine : subscribers per signal. 85 | * @details Max number of FSM subscribers per signal. 86 | * @note Default value @c 4 87 | */ 88 | #define Q_FSM_PS_SUB_PER_SIGNAL_MAX ( 4 ) 89 | /** 90 | * @brief Size for the trace internal buffer 91 | * @details The trace object requires an internal buffer for standard integer 92 | * conversions. This macro defines its size. 36 bytes should be enough 93 | * @note Default value @c 36 94 | */ 95 | #define Q_TRACE_BUFSIZE ( 36 ) 96 | /** 97 | * @brief AT Command Line Interface enabler 98 | * @details Used to enable or disable the AT Command Line Interface(CLI) 99 | * @note Default value @c 1 @a enabled 100 | */ 101 | #define Q_CLI ( 1 ) 102 | /** 103 | * @brief Queues enabler 104 | * @details Used to enable or disable OS queues 105 | * @note Default value @c 1 @a enabled 106 | */ 107 | #define Q_QUEUES ( 1 ) 108 | /** 109 | * @brief Colored output in logger 110 | * @details Used to enable colored output in supported terminals when using 111 | * logger 112 | * @note Default value @c 0 @a disabled 113 | */ 114 | #define Q_LOGGER_COLORED ( 0 ) 115 | /*================================================================================================================================*/ 116 | 117 | /** @}*/ 118 | #endif 119 | -------------------------------------------------------------------------------- /src/include/types.hpp: -------------------------------------------------------------------------------- 1 | #ifndef QOS_CPP_TYPES 2 | #define QOS_CPP_TYPES 3 | 4 | #if defined( ARDUINO ) || defined( ARDUINO_ARCH_AVR) || defined( ARDUINO_ARCH_SAMD ) || defined( ENERGIA_ARCH_MSP430ELF ) 5 | #define ARDUINO_PLATFORM 6 | #endif 7 | 8 | #if ( __cplusplus < 201103L || defined ( __AVR_ARCH__ ) || defined( ARDUINO_PLATFORM ) || defined ( STM8Sxx ) ) 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #define STD_TYPE_UINT8_T uint8_t 16 | #define STD_TYPE_UINT16_T uint16_t 17 | #define STD_TYPE_UINT32_T uint32_t 18 | #define STD_TYPE_INT8_T int8_t 19 | #define STD_TYPE_INT16_T int16_t 20 | #define STD_TYPE_INT32_T int32_t 21 | #define STD_TYPE_UINTPTR_T uintptr_t 22 | #define STD_TYPE_SIZE_T size_t 23 | #else 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #define STD_TYPE_UINT8_T std::uint8_t 31 | #define STD_TYPE_UINT16_T std::uint16_t 32 | #define STD_TYPE_UINT32_T std::uint32_t 33 | #define STD_TYPE_INT8_T std::int8_t 34 | #define STD_TYPE_INT16_T std::int16_t 35 | #define STD_TYPE_INT32_T std::int32_t 36 | #define STD_TYPE_UINTPTR_T std::uintptr_t 37 | #define STD_TYPE_SIZE_T std::size_t 38 | #endif 39 | 40 | #if defined( ARDUINO_PLATFORM ) 41 | #include 42 | #else 43 | #include 44 | #endif 45 | 46 | #ifndef SIZE_MAX 47 | #define SIZE_MAX ( ~static_cast( 0 ) ) 48 | #endif 49 | 50 | namespace qOS { 51 | /** @addtogroup qtypes 52 | * @brief Sets of types having specified widths used to design the entire OS. 53 | * It also define macros directives to perform specific actions and options 54 | * for some OS APIs. 55 | * @{ 56 | */ 57 | 58 | /** 59 | * @brief A type to instantiate a integer-base variable. This size of this type is 60 | * implementation-defined. 61 | */ 62 | using base_t = int; 63 | 64 | /** 65 | * @brief A type to instantiate a byte variable 66 | */ 67 | using byte_t = STD_TYPE_UINT8_T; 68 | 69 | /** 70 | * @brief A type to instantiate an unsigned variable 71 | */ 72 | using unsigned_t = unsigned long; 73 | 74 | /** 75 | * @brief A type to instantiate an signed variable 76 | */ 77 | using signed_t = long int; 78 | 79 | /** 80 | * @brief A type to instantiate a single-precision variable of 32-bits IEEE 754. 81 | */ 82 | using float32_t = float; /*this is not always true in some compilers*/ 83 | 84 | /** 85 | * @brief A type to instantiate a single-precision variable of 64-bits IEEE 754. 86 | */ 87 | using float64_t = double; /*this is not always true in some compilers*/ 88 | 89 | /** 90 | * @brief A type to instantiate an OS index variable. Can store the maximum 91 | * size of a theoretically possible object of any type (including array). 92 | * Should be used for array indexing and loop counting. 93 | */ 94 | using index_t = STD_TYPE_SIZE_T; 95 | 96 | /** 97 | * @brief A type to instantiate a variable that hold the number of task cycles. 98 | */ 99 | using cycles_t = STD_TYPE_UINT32_T; 100 | 101 | /** 102 | * @brief A type to instantiate a variable that hold the number of task iterations. 103 | */ 104 | using iteration_t = STD_TYPE_INT32_T; 105 | 106 | /** 107 | * @brief A type to instantiate a variable to hold the priority value of a task. 108 | */ 109 | using priority_t = STD_TYPE_UINT8_T; 110 | 111 | /*! @cond */ 112 | using uint8_t = STD_TYPE_UINT8_T; 113 | using uint16_t = STD_TYPE_UINT16_T; 114 | using uint32_t = STD_TYPE_UINT32_T; 115 | using int8_t = STD_TYPE_INT8_T; 116 | using int16_t = STD_TYPE_INT16_T; 117 | using int32_t = STD_TYPE_INT32_T; 118 | using uintptr_t = STD_TYPE_UINTPTR_T; 119 | using size_t = STD_TYPE_SIZE_T; 120 | #if defined( ARDUINO_PLATFORM ) 121 | using string = String; 122 | #else 123 | using string = std::string; 124 | #endif 125 | 126 | class nonCopyable { 127 | protected: 128 | nonCopyable() {} 129 | ~nonCopyable() {} 130 | private: 131 | nonCopyable( const nonCopyable & ); 132 | nonCopyable& operator=( const nonCopyable & ); 133 | }; 134 | 135 | /*! @endcond */ 136 | 137 | /** 138 | * @brief A type to instantiate a variable to hold a time count. 139 | */ 140 | using timeCount_t = unsigned long; 141 | 142 | /** @}*/ 143 | } 144 | 145 | /*! @cond */ 146 | #define Q_UNUSED(arg) (void)(arg) 147 | #define Q_NONE /*EMPTY MACRO*/ 148 | /*! @endcond */ 149 | 150 | #endif /*QOS_CPP_TYPES*/ 151 | -------------------------------------------------------------------------------- /src/include/bytebuffer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef QOS_BYTE_BUFFER 2 | #define QOS_BYTE_BUFFER 3 | 4 | #include "include/types.hpp" 5 | 6 | 7 | namespace qOS { 8 | 9 | /** @addtogroup qbsbuffers Byte-Sized buffers 10 | * @brief An interrupt-safe byte-sized ring buffer interface. 11 | * @{ 12 | */ 13 | 14 | /** 15 | * @brief A Byte-sized buffer object 16 | */ 17 | class byteBuffer : private nonCopyable { 18 | private: 19 | volatile byte_t *buffer{ nullptr }; 20 | volatile index_t tail{ 0U }; 21 | volatile index_t head{ 0U }; 22 | size_t length{ 0U }; 23 | static size_t checkValidPowerOfTwo( size_t k ) noexcept; 24 | byteBuffer( byteBuffer const& ) = delete; 25 | void operator=( byteBuffer const& ) = delete; 26 | public: 27 | /*! @cond */ 28 | virtual ~byteBuffer() {} 29 | /*! @endcond */ 30 | /** 31 | * @brief Initialize the Byte-sized buffer instance 32 | * @param[in] pBuffer Block of memory or array of data 33 | * @param[in] bLength The size of the buffer(Must be a power of two) 34 | */ 35 | byteBuffer( volatile byte_t *pBuffer, const size_t bLength ) 36 | { 37 | (void)setup( pBuffer, bLength ); 38 | } 39 | template 40 | byteBuffer( volatile byte_t (&area)[numberOfBytes] ) noexcept 41 | { 42 | (void)setup( area, numberOfBytes ); 43 | } 44 | /** 45 | * @brief Initialize the Byte-sized buffer 46 | * @param[in] pBuffer Block of memory or array of data 47 | * @param[in] bLength The size of the buffer(Must be a power of two) 48 | * @return @c true on success, otherwise returns @c false. 49 | */ 50 | bool setup( volatile byte_t *pBuffer, const size_t bLength ) noexcept; 51 | template 52 | bool setup( volatile byte_t (&area)[numberOfBytes] ) noexcept // skipcq : CXX-W2066 53 | { 54 | return setup( area, numberOfBytes ); 55 | } 56 | /** 57 | * @brief Adds an element of data to the Byte-sized buffer 58 | * @param[in] bData The data to be added 59 | * @return @c true on success, otherwise returns @c false. 60 | */ 61 | bool put( const byte_t bData ) noexcept; 62 | /** 63 | * @brief Gets n data from the Byte-sized buffer and removes them 64 | * @param[out] dst the location where the data-byte will be written 65 | * @param[in] n The number of bytes to read 66 | * @return @c true on success, otherwise returns @c false 67 | */ 68 | bool read( void *dst, const size_t n ) noexcept; 69 | /** 70 | * @brief Gets one data-byte from the front of the Byte-sized buffer, and 71 | * removes it 72 | * @param[out] dst the location where the data-byte will be written 73 | * @return @c true on success, otherwise returns @c false 74 | */ 75 | bool get( byte_t *dst ) noexcept; 76 | /** 77 | * @brief Looks for one byte from the head of the Byte-sized buffer without 78 | * removing it 79 | * @return byte of data, or zero if nothing in the list 80 | */ 81 | byte_t peek( void ) const noexcept; 82 | /** 83 | * @brief Query the empty status of the Byte-sized buffer 84 | * @return @c true if the Byte-sized buffer is empty, @c false if it 85 | * is not. 86 | */ 87 | bool isEmpty( void ) const noexcept; 88 | /** 89 | * @brief Query the full status of the Byte-sized buffer 90 | * @return @c true if the Byte-sized buffer is empty, @c false if it 91 | * is not. 92 | */ 93 | bool isFull( void ) const noexcept; 94 | /** 95 | * @brief Query the number of elements in the Byte-sized buffer 96 | * @return Number of elements in the byte-sized Buffer. 97 | */ 98 | size_t count( void ) const noexcept; 99 | /** 100 | * @brief Check if the byteBuffer instance has been initialized. 101 | * @return @c true if instance has been initialized 102 | */ 103 | bool isInitialized( void ) const { 104 | return ( nullptr != buffer ); 105 | } 106 | /** 107 | * @brief Check if the byteBuffer instance has been initialized. 108 | * @return @c true if instance has been initialized 109 | */ 110 | explicit operator bool() const noexcept { 111 | return isInitialized(); 112 | } 113 | }; 114 | 115 | /** @}*/ 116 | } 117 | 118 | 119 | #endif /*QOS_BYTE_BUFFER*/ 120 | -------------------------------------------------------------------------------- /src/include/clock.hpp: -------------------------------------------------------------------------------- 1 | #ifndef QOS_CPP_CLOCK 2 | #define QOS_CPP_CLOCK 3 | 4 | #include "include/types.hpp" 5 | #include "config/config.h" 6 | 7 | namespace qOS { 8 | 9 | /** @addtogroup qclock 10 | * @brief Clock and time manipulation interface used by the entire OS. 11 | * @{ 12 | */ 13 | 14 | /** @brief A unsigned integer to hold ticks count. Epochs counter.*/ 15 | using clock_t = timeCount_t; 16 | 17 | /** @brief The typedef that specified an time quantity, usually expressed in milliseconds.*/ 18 | using duration_t = timeCount_t; 19 | 20 | /*! @cond */ 21 | /*cstat -CERT-FLP34-C -MISRAC++2008-5-0-5 -MISRAC++2008-5-0-7*/ 22 | constexpr qOS::duration_t operator "" _ms( unsigned long long int x ) 23 | { 24 | return static_cast( x ); 25 | } 26 | constexpr qOS::duration_t operator "" _sec( unsigned long long int x ) 27 | { 28 | return static_cast( 1000U*x ); 29 | } 30 | constexpr qOS::duration_t operator "" _sec( long double x ) 31 | { 32 | return static_cast( 1000U*x ); 33 | } 34 | constexpr qOS::duration_t operator "" _minutes( unsigned long long int x ) 35 | { 36 | return static_cast( 60000U*x ); 37 | } 38 | constexpr qOS::duration_t operator "" _minutes( long double x ) 39 | { 40 | return static_cast( 60000U*x ); 41 | } 42 | constexpr qOS::duration_t operator "" _hours( unsigned long long int x ) 43 | { 44 | return static_cast( 3600000U*x ); 45 | } 46 | constexpr qOS::duration_t operator "" _hours( long double x ) 47 | { 48 | return static_cast( 3600000U*x ); 49 | } 50 | constexpr qOS::duration_t operator "" _days( unsigned long long int x ) 51 | { 52 | return static_cast( 86400000U*x ); 53 | } 54 | constexpr qOS::duration_t operator "" _days( long double x ) 55 | { 56 | return static_cast( 86400000*x ); 57 | } 58 | /*cstat +CERT-FLP34-C +MISRAC++2008-5-0-5 +MISRAC++2008-5-0-7*/ 59 | /*! @endcond */ 60 | 61 | 62 | /** 63 | * @brief Pointer to a function that gets the current hardware tick value. 64 | * 65 | * @note User should use bare-metal code to implement this function. 66 | * Example : 67 | * @code{.c} 68 | * unsigned long OSInterface_GetTick( void ) { 69 | * return HAL_GetTick(); 70 | * } 71 | * @endcode 72 | * @return The number of ticks provided by the system HAL. 73 | */ 74 | using getTickFcn_t = clock_t (*)( void ); 75 | 76 | /** 77 | * @brief A class to encapsulate the OS clock 78 | */ 79 | class clock final { 80 | protected: 81 | /*! @cond */ 82 | static volatile qOS::clock_t sysTick_Epochs; // skipcq: CXX-W2009 83 | static qOS::clock_t internalTick( void ) noexcept; 84 | clock() = default; 85 | /*! @endcond */ 86 | public: 87 | clock( clock &other ) = delete; 88 | void operator=( const clock & ) = delete; 89 | /** 90 | * @brief Return the current tick used by the OS 91 | * @return time (t) in epochs. 92 | */ 93 | static getTickFcn_t getTick; // skipcq: CXX-W2009 94 | /** 95 | * @brief Feed the system tick. 96 | * @note This call is mandatory and must be called once inside the 97 | * dedicated timer interrupt service routine (ISR). Example 98 | * @code{.c} 99 | * void interrupt xPeriodicTimer_ISR( void ) { 100 | * qOS::clock::sysTick(); 101 | * } 102 | * @endcode 103 | */ 104 | static void sysTick( void ) noexcept; 105 | /** 106 | * @brief Perform a timestamp check. This function computes the amount 107 | * of time elapsed between the current instant and the init timestamp @a ti 108 | * and checks if the result is greater than @a td. 109 | * @param[in] ti Init timestamp in epochs 110 | * @param[in] td Elapsed time to check in epochs 111 | * @return @c true if the elapsed time (t-ti) is greater or equal to td. 112 | * Otherwise returns @c false 113 | */ 114 | static bool timeDeadLineCheck( const qOS::clock_t ti, const qOS::clock_t td ) noexcept; 115 | /** 116 | * @brief Set the clock-tick provider function. 117 | * @param[in] provider A pointer to the tick provider function 118 | * @return @c true on success, otherwise returns @c false. 119 | */ 120 | static bool setTickProvider( const getTickFcn_t provider ) noexcept; 121 | /** @brief To specify a null time value.*/ 122 | static const qOS::duration_t NONE; 123 | /** @brief To specify a non-wait time value.*/ 124 | static const qOS::duration_t IMMEDIATE; 125 | }; 126 | 127 | /** @}*/ 128 | } 129 | 130 | 131 | 132 | #endif /*QOS_CPP_CLOCK*/ 133 | -------------------------------------------------------------------------------- /src/include/critical.hpp: -------------------------------------------------------------------------------- 1 | #ifndef QOS_CPP_CRITICAL 2 | #define QOS_CPP_CRITICAL 3 | 4 | #include "include/types.hpp" 5 | 6 | namespace qOS { 7 | 8 | /** @addtogroup qcritical 9 | * @brief APIs to handle entry/exit actions in @ref q_critical. 10 | * @{ 11 | */ 12 | 13 | /** 14 | * @brief Function called by critical::exit() to restore interrupts. 15 | * 16 | * @note User should use bare-metal code to implement this function. 17 | * @note The kernel passes the previously saved interrupt configuration as 18 | * input argument. The user is responsible for taking this argument to 19 | * restore the saved interrupt setup. 20 | * Example : 21 | * @code{.c} 22 | * void BSP_InterruptRestorer( uint32_t savedMask ) { 23 | * HAL_InterruptSetMask( savedMask ); 24 | * HAL_EnableInterrupts(); 25 | * } 26 | * @endcode 27 | * @param[in] savedMask The interrupt configuration saved by the "Disabler" 28 | * function 29 | */ 30 | using int_restorer_t = void (*)( uint32_t ); 31 | 32 | /** 33 | * @brief Function called by critical::enter() to disable interrupts. 34 | * 35 | * @note User should use bare-metal code to implement this function. 36 | * @note User should return the current interrupt configuration to be saved 37 | * by the kernel. 38 | * Example : 39 | * @code{.c} 40 | * uint32_t BSP_InterruptDisabler( void ) { 41 | * uint32_t currentMask; 42 | * currentMask = HAL_InterruptGetMask( savedMask ); 43 | * HAL_DisableInterrupts(); 44 | * return currentMask; 45 | * } 46 | * @endcode 47 | * @return The current interrupt configuration (mask). The kernel will retain 48 | * this value 49 | * until the critical section is exited 50 | */ 51 | using int_disabler_t = uint32_t (*)( void ); 52 | 53 | /** 54 | * @brief OS Critical interfaces. 55 | */ 56 | namespace critical { 57 | 58 | /** @addtogroup qcritical 59 | * @brief APIs to handle entry/exit actions in @ref q_critical. 60 | * @{ 61 | */ 62 | 63 | /** 64 | * @brief Enables a scoped critical section with minimal syntax overhead. 65 | * 66 | * @code{.cpp} 67 | * void example() { 68 | * // code here : normal section(non-critical) 69 | * critical::scope { 70 | * // Code here runs in a critical section 71 | * } 72 | * // code here, normal section (non-critical) 73 | * } 74 | * @endcode 75 | */ 76 | inline void scope( void ) noexcept {} 77 | 78 | /** 79 | * @brief Scoped critical section lock. 80 | * 81 | * @details 82 | * The `lock` class provides a simple RAII-based mechanism for managing critical 83 | * sections. When an object of this class is created, it automatically enters a 84 | * critical section (disabling interrupts). When the object is destroyed, it exits 85 | * the critical section (restoring interrupts). 86 | * 87 | * @code{.cpp} 88 | * void example() { 89 | * critical::lock l 90 | * // Code that runs in a critical section 91 | * } 92 | * @endcode 93 | */ 94 | class lock final : private nonCopyable { 95 | private: 96 | static void enter( void ) noexcept; 97 | static void exit( void ) noexcept; 98 | static int_disabler_t disable; // skipcq: CXX-W2009 99 | static int_restorer_t restore; // skipcq: CXX-W2009 100 | static volatile uint32_t flags; // skipcq: CXX-W2009 101 | static volatile int nestingLevel; // skipcq: CXX-W2009 102 | bool entered{ true }; 103 | friend bool setInterruptsED( const int_restorer_t rFcn, const int_disabler_t dFcn ) noexcept; 104 | public: 105 | lock() noexcept; 106 | ~lock() noexcept; 107 | explicit operator bool() noexcept; 108 | }; 109 | 110 | /** 111 | * @brief Set the hardware-specific code for global interrupt enable/disable. 112 | * Setting this allows you to communicate safely from Interrupts using 113 | * queued-notifications or queues. 114 | * @param[in] rFcn The function with hardware specific code that enables or 115 | * restores interrupts. 116 | * @param[in] dFcn The function with hardware specific code that disables 117 | * interrupts. 118 | * @return @c true on success. Otherwise return @c false. 119 | */ 120 | bool setInterruptsED( const int_restorer_t rFcn, const int_disabler_t dFcn ) noexcept; 121 | 122 | /** @}*/ 123 | } 124 | /** @}*/ 125 | } 126 | 127 | /*! @cond */ 128 | /*============================================================================*/ 129 | #define scope \ 130 | scope(); \ 131 | for ( critical::lock critical_lock; critical_lock; ) \ 132 | /*============================================================================*/ 133 | /*! @endcond */ 134 | 135 | #endif /*QOS_CPP_CRITICAL*/ 136 | -------------------------------------------------------------------------------- /src/queue.cpp: -------------------------------------------------------------------------------- 1 | #include "include/queue.hpp" 2 | #include "include/critical.hpp" 3 | 4 | using namespace qOS; 5 | 6 | /*============================================================================*/ 7 | bool queue::setup( void *pData, const size_t size, const size_t count ) noexcept 8 | { 9 | bool retValue = false; 10 | 11 | if ( ( nullptr != pData ) && ( size > 0U ) && ( count > 0U ) ) { 12 | itemsCount = count; 13 | itemSize = size; 14 | /*cstat -CERT-EXP36-C_b*/ 15 | head = static_cast( pData ); 16 | /*cstat +CERT-EXP36-C_b*/ 17 | reset(); 18 | retValue = true; 19 | } 20 | 21 | return retValue; 22 | } 23 | /*============================================================================*/ 24 | void queue::reset( void ) noexcept 25 | { 26 | critical::scope { 27 | /*cstat -CERT-INT30-C_a*/ 28 | tail = head + ( itemsCount*itemSize ); 29 | itemsWaiting = 0U; 30 | writer = head; 31 | reader = head + ( ( itemsCount - 1U )*itemSize ); 32 | /*cstat +CERT-INT30-C_a*/ 33 | } 34 | } 35 | /*============================================================================*/ 36 | bool queue::isEmpty( void ) const noexcept 37 | { 38 | return ( 0U == itemsWaiting ); 39 | } 40 | /*============================================================================*/ 41 | bool queue::isFull( void ) const noexcept 42 | { 43 | return ( itemsWaiting == itemsCount ); 44 | } 45 | /*============================================================================*/ 46 | size_t queue::count( void ) const noexcept 47 | { 48 | return itemsWaiting; 49 | } 50 | /*============================================================================*/ 51 | size_t queue::itemsAvailable( void ) const noexcept 52 | { 53 | return itemsCount - itemsWaiting; 54 | } 55 | /*============================================================================*/ 56 | void queue::moveReader( void ) noexcept 57 | { 58 | reader += itemSize; 59 | if ( reader >= tail ) { 60 | reader = head; 61 | } 62 | } 63 | /*============================================================================*/ 64 | bool queue::removeFront( void ) noexcept 65 | { 66 | bool retValue = false; 67 | 68 | critical::scope { 69 | size_t waiting; 70 | 71 | waiting = itemsWaiting; 72 | if ( waiting > 0U ) { 73 | moveReader(); 74 | itemsWaiting = itemsWaiting - 1U; /* --itemsWaiting */ 75 | retValue = true; 76 | } 77 | } 78 | 79 | return retValue; 80 | } 81 | /*============================================================================*/ 82 | void queue::copyDataFromQueue( void * const dst ) noexcept 83 | { 84 | moveReader(); 85 | (void)memcpy( static_cast( dst ), static_cast( reader ), itemSize ); 86 | } 87 | /*============================================================================*/ 88 | bool queue::receive( void *dst ) noexcept 89 | { 90 | bool retValue = false; 91 | 92 | critical::scope { 93 | size_t waiting; 94 | 95 | waiting = itemsWaiting; 96 | if ( waiting > 0U ) { 97 | copyDataFromQueue( dst ); 98 | itemsWaiting = itemsWaiting - 1U; /* --itemsWaiting */ 99 | retValue = true; 100 | } 101 | } 102 | return retValue; 103 | } 104 | /*============================================================================*/ 105 | void queue::copyDataToQueue( const void *itemToQueue, const queueSendMode xPosition ) noexcept 106 | { 107 | if ( queueSendMode::TO_BACK == xPosition ) { 108 | (void)memcpy( static_cast( writer ), itemToQueue, itemSize ); 109 | writer += itemSize; 110 | if ( writer >= tail ) { 111 | writer = head; 112 | } 113 | } 114 | else { 115 | (void)memcpy( static_cast( reader ), itemToQueue, itemSize ); 116 | reader -= itemSize; 117 | if ( reader < head ) { 118 | reader = ( tail - itemSize ); 119 | } 120 | } 121 | itemsWaiting = itemsWaiting + 1U; /* ++itemsWaiting */ 122 | } 123 | /*============================================================================*/ 124 | bool queue::send( void *itemToQueue, const queueSendMode pos ) noexcept 125 | { 126 | bool retValue = false; 127 | 128 | if ( ( queueSendMode::TO_BACK == pos ) || ( queueSendMode::TO_FRONT == pos ) ) { 129 | critical::scope { 130 | if ( itemsWaiting < itemsCount ) { 131 | copyDataToQueue( itemToQueue, pos ); 132 | retValue = true; 133 | } 134 | } 135 | } 136 | 137 | return retValue; 138 | } 139 | /*============================================================================*/ 140 | void* queue::peek( void ) const noexcept 141 | { 142 | uint8_t *retValue = nullptr; 143 | critical::scope { 144 | size_t waiting; 145 | 146 | waiting = itemsWaiting; 147 | if ( waiting > 0U ) { 148 | retValue = static_cast( reader + itemSize ); 149 | if ( retValue >= tail ) { 150 | retValue = head; 151 | } 152 | } 153 | } 154 | return static_cast( retValue ); 155 | } 156 | /*============================================================================*/ 157 | bool queue::isInitialized( void ) const noexcept 158 | { 159 | return ( nullptr != head ); 160 | } 161 | /*============================================================================*/ 162 | size_t queue::getItemSize( void ) const noexcept 163 | { 164 | return itemSize; 165 | } 166 | /*============================================================================*/ 167 | -------------------------------------------------------------------------------- /src/QuarkTS.h: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file QuarkTS.h 3 | * @author J. Camilo Gomez C. 4 | * @version 1.8.0 5 | * @note This file is part of the QuarkTS++ distribution. 6 | * @brief Global inclusion header 7 | **/ 8 | 9 | 10 | /* 11 | QuarkTS++ - An open-source OS for small embedded applications. 12 | MIT License 13 | C++11 and MISRA C++ 2008 / CERT Compliant 14 | 15 | Copyright (C) 2012 Eng. Juan Camilo Gomez Cadavid MSc. All Rights Reserved. 16 | 17 | Permission is hereby granted, free of charge, to any person obtaining a copy of 18 | this software and associated documentation files (the "Software"), to deal in 19 | the Software without restriction, including without limitation the rights to 20 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 21 | the Software, and to permit persons to whom the Software is furnished to do so, 22 | subject to the following conditions: 23 | 24 | The above copyright notice and this permission notice shall be included in all 25 | copies or substantial portions of the Software. 26 | 27 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 28 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 29 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 30 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 31 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 32 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 33 | 34 | VISIT https://github.com/kmilo17pet/QuarkTS-cpp TO ENSURE YOU ARE USING THE LATEST 35 | VERSION. 36 | 37 | 38 | This file is part of the QuarkTS++ OS distribution. 39 | */ 40 | 41 | #ifndef QOS_CPP_H 42 | #define QOS_CPP_H 43 | 44 | #define QUARKTS_CPP_VERSION "1.8.0" 45 | #define QUARKTS_CPP_VERNUM ( 180u ) 46 | #define QUARKTS_CPP_CAPTION "QuarkTS++ OS " QUARKTS_CPP_VERSION 47 | 48 | #include "config/config.h" 49 | #include "include/types.hpp" 50 | #include "include/critical.hpp" 51 | #include "include/clock.hpp" 52 | #include "include/timer.hpp" 53 | #include "include/queue.hpp" 54 | #include "include/fsm.hpp" 55 | #include "include/cli.hpp" 56 | #include "include/kernel.hpp" 57 | #include "include/task.hpp" 58 | #include "include/helper.hpp" 59 | #include "include/coroutine.hpp" 60 | #include "include/memory.hpp" 61 | #include "include/util.hpp" 62 | #include "include/bytebuffer.hpp" 63 | #include "include/input.hpp" 64 | #include "include/response.hpp" 65 | #include "include/logger.hpp" 66 | 67 | namespace qOS { 68 | /*cstat -MISRAC++2008-0-1-4_b*/ 69 | namespace build { 70 | constexpr const uint32_t number = 4367; 71 | constexpr const char* date = __DATE__; 72 | constexpr const char* time = __TIME__; 73 | constexpr const char* std = "c++11"; 74 | } 75 | namespace version { 76 | constexpr const char* str = QUARKTS_CPP_VERSION; 77 | constexpr const uint8_t number = QUARKTS_CPP_VERNUM; 78 | constexpr const uint8_t mayor = 1U; 79 | constexpr const uint8_t minor = 8U; 80 | constexpr const uint8_t rev = 0U; 81 | } 82 | namespace product { 83 | constexpr const char* author = "J. Camilo Gomez C."; 84 | constexpr const char* copyright = "Copyright (C) 2012 J. Camilo Gomez C. All Rights Reserved."; 85 | constexpr const char* name = "QuarkTS++"; 86 | constexpr const char* category = "OS"; 87 | constexpr const char* scheme = "Cooperative"; 88 | constexpr const char* caption = QUARKTS_CPP_CAPTION; 89 | constexpr const char* compliance = "MISRAC++2008,SEI-CERT"; 90 | constexpr const char* license = "MIT"; 91 | constexpr const char* source_model = "Open Source"; 92 | constexpr const char* kernel_type = "Cooperative Real-Time Microkernel"; 93 | } 94 | /*cstat +MISRAC++2008-0-1-4_b*/ 95 | } 96 | 97 | #endif /*QOS_CPP_H*/ 98 | 99 | 100 | /** 101 | * @defgroup qos Operative System 102 | * This section contains the documentation related to all the Interfaces and 103 | * intrinsic definitions of the operating system. 104 | */ 105 | 106 | /** 107 | * @defgroup qtaskcreation Scheduler Interface 108 | * @ingroup qos 109 | */ 110 | 111 | /** 112 | * @defgroup qtaskmanip Managing tasks 113 | * @ingroup qos 114 | */ 115 | 116 | /** 117 | * @defgroup qpriv Inter-Task communication 118 | * @brief Inter-Task communication primitives : Queues, Notifications and Event-flags 119 | * @ingroup qos 120 | */ 121 | 122 | /** 123 | * @defgroup qqueues Queues 124 | * @ingroup qpriv 125 | */ 126 | 127 | /** 128 | * @defgroup qnot Notifications 129 | * @ingroup qpriv 130 | */ 131 | 132 | /** 133 | * @defgroup qeventflags Event Flags 134 | * @ingroup qpriv 135 | */ 136 | 137 | /** 138 | * @defgroup qclock Clock 139 | * @ingroup qos 140 | */ 141 | 142 | /** 143 | * @defgroup qcritical Critical 144 | * @ingroup qos 145 | */ 146 | 147 | /** 148 | * @defgroup qconfiguration Configuration 149 | * @ingroup qos 150 | */ 151 | 152 | /** 153 | * @defgroup qtypes Types and macros 154 | * @ingroup qos 155 | */ 156 | 157 | /** 158 | * @defgroup qmodules Kernel extensions 159 | * This section contains the documentation related to all the extensions that 160 | * adds additional functionality to the operating system. 161 | */ 162 | 163 | /** 164 | * @defgroup qfsm Finite State Machines 165 | * @ingroup qmodules 166 | */ 167 | 168 | /** 169 | * @defgroup qstimers Timers 170 | * @ingroup qmodules 171 | */ 172 | 173 | /** 174 | * @defgroup qcoroutines Co-Routines 175 | * @ingroup qmodules 176 | */ 177 | 178 | /** 179 | * @defgroup qatcli AT Command Line Interface 180 | * @ingroup qmodules 181 | */ 182 | 183 | /** 184 | * @defgroup qmemmang Memory Management 185 | * @ingroup qmodules 186 | */ 187 | 188 | /** 189 | * @defgroup qutility Utilities 190 | * A collection of utility libraries for the QuarkTS OS 191 | */ 192 | 193 | /** 194 | * @defgroup qlists Generic double-linked lists 195 | * @ingroup qutility 196 | */ 197 | 198 | /** 199 | * @defgroup qbsbuffers Byte-Sized buffers 200 | * @ingroup qutility 201 | */ 202 | 203 | /** 204 | * @defgroup qinput Input channel events 205 | * @ingroup qutility 206 | */ 207 | 208 | /** 209 | * @defgroup qioutils I/O Utils 210 | * @ingroup qutility 211 | */ 212 | 213 | /** 214 | * @defgroup qresponse Response handler 215 | * @ingroup qutility 216 | */ 217 | 218 | /** 219 | * @defgroup qflm Helper functions 220 | * @ingroup qutility 221 | */ 222 | -------------------------------------------------------------------------------- /src/include/memory.hpp: -------------------------------------------------------------------------------- 1 | #ifndef QOS_CPP_MEMORY 2 | #define QOS_CPP_MEMORY 3 | 4 | #include "include/types.hpp" 5 | 6 | #ifndef Q_BYTE_ALIGNMENT 7 | #define Q_BYTE_ALIGNMENT ( 8 ) 8 | #endif 9 | 10 | #if ( ( Q_BYTE_ALIGNMENT != 1 ) && ( Q_BYTE_ALIGNMENT != 2 ) && ( Q_BYTE_ALIGNMENT != 4 ) && ( Q_BYTE_ALIGNMENT != 8 ) ) 11 | #error Q_BYTE_ALIGNMENT value not allowed, use only 1,2,4 or 8(default). 12 | #endif 13 | 14 | namespace qOS { 15 | 16 | /** 17 | * @brief Memory management interfaces. 18 | */ 19 | namespace mem { 20 | 21 | /** @addtogroup qmemmang 22 | * @brief API interface for the @ref q_memmang extension. 23 | * @{ 24 | */ 25 | 26 | /*! @cond */ 27 | using address_t = size_t; 28 | struct blockConnect_t { 29 | blockConnect_t *next{ nullptr }; 30 | size_t blockSize{ 0U }; 31 | }; 32 | /*! @endcond */ 33 | 34 | /** 35 | * @brief A Memory Pool object 36 | * @details A memory pool its a special resource that allows memory blocks to 37 | * be dynamically allocated from a user-designated memory region. Instead of 38 | * typical pools with fixed-size block allocation, the pools in QuarkTS++ can 39 | * be of any size, thereby the user is responsible for selecting the 40 | * appropriate memory pool to allocate data with the same size. 41 | */ 42 | class pool { 43 | private: 44 | blockConnect_t *end{ nullptr }; 45 | blockConnect_t start; 46 | uint8_t *poolMemory{ nullptr }; 47 | size_t poolMemSize{ 0U }; 48 | size_t freeBytesRemaining{ 0U }; 49 | void insertBlockIntoFreeList( blockConnect_t *xBlock ) noexcept; 50 | void init( void ) noexcept; 51 | pool( pool const& ) = delete; 52 | void operator=( pool const& ) = delete; 53 | public: 54 | /*! @cond */ 55 | virtual ~pool() {} 56 | /*! @endcond */ 57 | /** 58 | * @brief Initializes a memory pool instance. 59 | * @param[in] pArea A pointer to a memory block @c uint8_t statically 60 | * allocated to act as Heap of the memory pool. The size of this block should 61 | * match the @a pSize argument. 62 | * @param[in] pSize The size of the memory block pointed by @a pArea 63 | */ 64 | inline pool( void *pArea, const size_t pSize ) noexcept { 65 | (void)setup( pArea, pSize ); 66 | } 67 | /** 68 | * @brief Initializes a memory pool instance. This function should be called 69 | * once before any heap memory request. 70 | * @param[in] pArea A pointer to a memory block @c uint8_t statically 71 | * allocated to act as Heap of the memory pool. The size of this block should 72 | * match the @a pSize argument. 73 | * @param[in] pSize The size of the memory block pointed by @a pArea 74 | * @return Returns @c true on success, otherwise, returns @c false. 75 | */ 76 | bool setup( void *pArea, const size_t pSize ) noexcept; 77 | /** 78 | * @brief Deallocates the space previously allocated by mem::pool::alloc(). 79 | * Deallocation will be performed in the selected memory pool. 80 | * If @a ptr is a @c nullptr pointer, the function does nothing. 81 | * The behavior is undefined if selected memory pool has not been initialized. 82 | * The behavior is undefined if the value of @a ptr does not equal a value 83 | * returned earlier by mem::pool::alloc(). 84 | * The behavior is undefined if the memory area referred to by @a ptr has 85 | * already been deallocated, that is, mem::pool::free() has already been called with 86 | * @a ptr as the argument and no calls to mem::pool::alloc() resulted in a pointer 87 | * equal to @a ptr afterwards. The behavior is undefined if after mem::pool::free() 88 | * returns, an access is made through the pointer @a ptr. 89 | * @attention This method is NOT interrupt-safe. 90 | * @param[in] ptr to the memory to deallocate 91 | */ 92 | void free( void *ptr ) noexcept; 93 | /** 94 | * @brief Allocate a block of memory that is @a pSize bytes large. 95 | * If the requested memory can be allocated, a pointer is 96 | * returned to the beginning of the memory block. 97 | * @attention This method is NOT interrupt-safe. 98 | * @param[in] pSize Size of the memory block in bytes. 99 | * @return If the request is successful then a pointer to the memory block is 100 | * returned. If the function failed to allocate the requested block of memory 101 | * , a @c nullptr pointer is returned. 102 | */ 103 | void* alloc( size_t pSize ) noexcept; 104 | /** 105 | * @brief Returns the total amount of heap space that remains unallocated for 106 | * the memory pool. 107 | * @return The size of the unallocated heap. 108 | */ 109 | size_t getFreeSize( void ) const noexcept; 110 | /** 111 | * @brief Returns the total amount of heap space requested for the 112 | * the memory pool. 113 | * @return The size of the pool in bytes. 114 | */ 115 | size_t getTotalSize( void ) const noexcept; 116 | /** 117 | * @brief Returns a pointer to a memory block statically allocated 118 | * to act as Heap of the memory pool 119 | * @return A pointer to the memory block. 120 | */ 121 | void* getPoolArea( void ) const noexcept; 122 | /** 123 | * @brief Check if the memory pool instance has been initialized. 124 | * @return @c true if instance has been initialized 125 | */ 126 | bool isInitialized( void ) const { 127 | return ( nullptr != poolMemory ) && ( poolMemSize > 0U ); 128 | } 129 | /** 130 | * @brief Check if the memory pool instance has been initialized. 131 | * @return @c true if instance has been initialized 132 | */ 133 | explicit operator bool() const noexcept { 134 | return isInitialized(); 135 | } 136 | }; 137 | 138 | /** @}*/ 139 | } 140 | } 141 | 142 | #if ( Q_DEFAULT_HEAP_SIZE >= 64 ) 143 | void * operator new( size_t size); 144 | void * operator new[]( size_t size); 145 | 146 | void operator delete(void * ptr) noexcept; 147 | void operator delete[](void * ptr) noexcept; 148 | 149 | void operator delete(void* ptr, void* place) noexcept; 150 | void operator delete[](void* ptr, void* place) noexcept; 151 | #endif /*Q_USE_MEM_ALLOCATION_SCHEME*/ 152 | 153 | #endif /*QOS_CPP_MEMORY*/ 154 | -------------------------------------------------------------------------------- /src/include/queue.hpp: -------------------------------------------------------------------------------- 1 | #ifndef QOS_CPP_QUEUE 2 | #define QOS_CPP_QUEUE 3 | 4 | #include "include/types.hpp" 5 | 6 | namespace qOS { 7 | 8 | /** @addtogroup qqueues 9 | * @brief API interface to create and handle @ref q_queues. 10 | * @{ 11 | */ 12 | 13 | /** 14 | * @brief An enum that defines the modes in which a item should be inserted 15 | * in to a queue. 16 | */ 17 | enum class queueSendMode { 18 | TO_BACK, /*< to indicate whether the item in the queue should be sent to the back. */ 19 | TO_FRONT /*< to indicate whether the item in the queue should be sent to the front. */ 20 | }; 21 | 22 | /** 23 | * @brief A Queue object 24 | * @details A queue is a linear data structure with simple operations based 25 | * on the FIFO (First In First Out) principle. It is capable to hold a finite 26 | * number of fixed-size data items. The maximum number of items that a queue 27 | * can hold is called its length. Both the length and the size of each data 28 | * item are set when the queue is created. 29 | * 30 | * In general, this kind of data structure is used to serialize data between 31 | * tasks, allowing some elasticity in time. In many cases, the queue is used 32 | * as a data buffer in interrupt service routines. This buffer will collect 33 | * the data so, at some later time, another task can fetch the data for 34 | * further processing. This use case is the single "task to task" buffering 35 | * case. There are also other applications for queues as serializing many 36 | * data streams into one receiving streams (multiple tasks to a single task) 37 | * or vice-versa (single task to multiple tasks). 38 | * 39 | * The queue::setup() method configures the queue and initialize the instance. 40 | * The required RAM for the queue data should be provided by the application 41 | * writer and could be statically allocated at compile time or in run-time 42 | * using the memory management extension. 43 | */ 44 | class queue : private nonCopyable { 45 | private: 46 | uint8_t *head{ nullptr }; 47 | uint8_t *tail{ nullptr }; 48 | uint8_t *writer{ nullptr }; 49 | uint8_t *reader{ nullptr }; 50 | volatile size_t itemsWaiting = 0U; 51 | size_t itemsCount = 0U; 52 | size_t itemSize = 0U; 53 | void moveReader( void ) noexcept; 54 | void copyDataFromQueue( void * const dst ) noexcept; 55 | void copyDataToQueue( const void *itemToQueue, const queueSendMode xPosition ) noexcept; 56 | public: 57 | queue() = default; 58 | /*! @cond */ 59 | virtual ~queue() {} 60 | /*! @endcond */ 61 | /** 62 | * @brief Configures a Queue. Here, the RAM used to hold the queue data 63 | * @a pData is statically allocated at compile time by the application writer. 64 | * @param[in] pData Data block or array of data (Queue storage area). 65 | * @param[in] size The size, in bytes, of one single item in the queue. 66 | * @param[in] count The maximum number of items the queue can hold. 67 | * @return @c true on success, otherwise returns @c false. 68 | */ 69 | bool setup( void *pData, const size_t size, const size_t count ) noexcept; 70 | /** 71 | * @brief Configures a Queue. Here, the RAM used to hold the queue data 72 | * @a pData is statically allocated at compile time by the application writer. 73 | * @tparam T Type of one single item in the queue 74 | * @param[in] pData Data block or array of data (Queue storage area). 75 | * @param[in] count The maximum number of items the queue can hold. 76 | * @return @c true on success, otherwise returns @c false. 77 | */ 78 | template 79 | bool setup( void *pData, const size_t count ) noexcept 80 | { 81 | return setup( pData, sizeof(T), count ); 82 | } 83 | /** 84 | * @brief Resets a queue to its original empty state. 85 | */ 86 | void reset( void ) noexcept; 87 | /** 88 | * @brief Returns the empty status of the Queue 89 | * @return @c true if the Queue is empty, @c false if it is not. 90 | */ 91 | bool isEmpty( void ) const noexcept; 92 | /** 93 | * @brief Returns the full status of the Queue 94 | * @return @c true if the Queue is full, @c false if it is not. 95 | */ 96 | bool isFull( void ) const noexcept; 97 | /** 98 | * @brief Returns the number of items in the Queue 99 | * @return The number of elements in the queue 100 | */ 101 | size_t count( void ) const noexcept; 102 | /** 103 | * @brief Returns the number of available slots to hold items inside 104 | * the queue. 105 | * @return The number of available slots in the queue. 106 | */ 107 | size_t itemsAvailable( void ) const noexcept; 108 | /** 109 | * @brief Remove the data located at the front of the Queue 110 | * @return @c true if data was removed from the Queue, otherwise returns 111 | * @c false 112 | */ 113 | bool removeFront( void ) noexcept; 114 | /** 115 | * @brief Receive an item from a queue (and removes it). The item is 116 | * received by copy so a buffer of adequate size must be provided. 117 | * The number of bytes copied into the buffer was defined when the 118 | * queue was created. 119 | * @param[out] dst Pointer to the buffer into which the received item 120 | * will be copied. 121 | * @return @c true if data was retrieved from the Queue, otherwise returns 122 | * @c false 123 | */ 124 | bool receive( void *dst ) noexcept; 125 | /** 126 | * @brief Post an item to the the queue. The item is queued by copy, 127 | * not by reference 128 | * @param[in] itemToQueue A pointer to the item that is to be placed on the 129 | * queue. The size of the items the queue will hold was defined when the 130 | * queue was created, so this many bytes will be copied from @a itemToQueue 131 | * into the queue storage area. 132 | * @param[in] pos Can take the value @c queueSendMode::TO_BACK (default) 133 | * to place the item at the back of the queue, or @c queueSendMode::TO_FRONT 134 | * to place the item at the front of the queue (for high priority messages). 135 | * @return @c true on successful add, @c false if not added 136 | */ 137 | bool send( void *itemToQueue, const queueSendMode pos = queueSendMode::TO_BACK ) noexcept; 138 | /** 139 | * @brief Looks at the data from the front of the Queue without removing it. 140 | * @return Pointer to the data, or @c nullptr if there is nothing in the queue. 141 | */ 142 | void* peek( void ) const noexcept; 143 | /** 144 | * @brief Check if the queue is already initialized by using queue::setup() 145 | * @return @c true if the queue is initialized, @c false if not. 146 | */ 147 | bool isInitialized( void ) const noexcept; 148 | /** 149 | * @brief Check if the queue is already initialized by using queue::setup() 150 | * @return @c true if the queue is initialized, @c false if not. 151 | */ 152 | explicit operator bool() const noexcept { 153 | return isInitialized(); 154 | } 155 | /** 156 | * @brief Get the size(in bytes) used for every item in the queue. 157 | * @return The item-size in bytes. 158 | */ 159 | size_t getItemSize( void ) const noexcept; 160 | }; 161 | 162 | /** @}*/ 163 | } 164 | 165 | 166 | #endif /*QOS_CPP_QUEUE*/ 167 | -------------------------------------------------------------------------------- /src/include/timer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef QOS_CPP_TIMER 2 | #define QOS_CPP_TIMER 3 | 4 | #include "include/types.hpp" 5 | #include "include/clock.hpp" 6 | 7 | namespace qOS { 8 | 9 | /** @addtogroup qstimers Timers 10 | * @brief API interface for the @ref q_stimers extension. 11 | * @pre This extension requires the operating system is previously initialized 12 | * with core::init() with a functional time-base. Please read @ref q_timmingapproach . 13 | * @{ 14 | */ 15 | 16 | /** 17 | * @brief A non-blocking Timer object 18 | * @details Timers are an essential extension as they allow for accurate and 19 | * efficient timekeeping without blocking tasks. Using timers enables the 20 | * embedded application to perform other critical tasks while the timer is 21 | * running in the background. Timers also provide flexibility in the event 22 | * that the timer needs to be paused, restarted, or adjusted on the fly. 23 | * This can be particularly useful in applications that require dynamic 24 | * timing or have unpredictable event intervals. 25 | */ 26 | class timer { 27 | private: 28 | qOS::clock_t tStart{ 0U }; 29 | qOS::clock_t tv{ 0U }; 30 | public: 31 | timer() noexcept; 32 | /*! @cond */ 33 | virtual ~timer() {} 34 | /*! @endcond */ 35 | /** 36 | * @brief Initializes the instance of the timer with the specified 37 | * expiration time. Timer will start armed. 38 | * @note The OS must be running before using timers. 39 | * @note The expiration time should be at least, two times greater 40 | * than the clock-Tick. 41 | * @param[in] tTime The expiration time given in milliseconds. 42 | */ 43 | explicit timer( const qOS::duration_t tTime ) 44 | { 45 | (void)set( tTime ); 46 | } 47 | /** 48 | * @brief Set the expiration time for a timer. On success, the timer gets 49 | * armed immediately 50 | * @note The OS must be running before using timers. 51 | * @note The expiration time should be at least, two times greater than 52 | * the clock-Tick. 53 | * @param[in] tTime The expiration time given in milliseconds. 54 | * @return Returns @c true on success, otherwise, returns @c false. 55 | */ 56 | bool set( const qOS::duration_t tTime ) noexcept; 57 | /** 58 | * @brief Disarms the timer object 59 | */ 60 | void disarm( void ) noexcept; 61 | /** 62 | * @brief Reload the timer with the previous specified time. 63 | * @note Timer should be armed before this operation 64 | */ 65 | void reload( void ) noexcept; 66 | /** 67 | * @brief Get the current status of the Timer (Armed or Disarmed) 68 | * @return @c true when armed, otherwise @c false when disarmed. 69 | */ 70 | bool status( void ) const noexcept; 71 | /** 72 | * @brief Non-Blocking timer check with automatic arming. 73 | * 74 | * Behavior: 75 | * If disarmed, it gets armed immediately with the specified time. 76 | * 77 | * If armed, the time argument is ignored and the API only checks for 78 | * expiration. When the time expires, the timer gets armed immediately 79 | * taking the specified time. 80 | * @note After the timer expiration, this method re-arms the timer 81 | * @note The OS must be running before using a timer. 82 | * @note The expiration time should be at least, two times greater than 83 | * the clock-Tick. 84 | * @param[in] tTime The expiration time given in milliseconds. 85 | * @return Returns @c true on success, otherwise, returns @c false. 86 | * @note A disarmed timer also returns @c false. 87 | */ 88 | bool reloadIfExpired( const qOS::duration_t tTime ) noexcept; 89 | /** 90 | * @brief Non-Blocking timer check with automatic arming. 91 | * 92 | * Behavior: 93 | * If disarmed, it gets armed immediately with the previous 94 | * specified time. 95 | * 96 | * If armed, the API only checks for expiration. When the time 97 | * expires, the timer gets armed immediately using the previously 98 | * assigned time. 99 | * @note After the timer expiration, this method re-arms the timer 100 | * @note The OS must be running before using a timer. 101 | * @return Returns @c true on success, otherwise, returns @c false. 102 | * @note A disarmed timer also returns @c false. 103 | */ 104 | bool reloadIfExpired( void ) noexcept; 105 | /** 106 | * @brief Retrieve the remaining time in epochs 107 | * @return The remaining time specified in epochs. 108 | */ 109 | qOS::clock_t remaining( void ) const noexcept; 110 | /** 111 | * @brief Retrieve the elapsed time in epochs 112 | * @return The Elapsed time specified in epochs. 113 | */ 114 | qOS::clock_t elapsed( void ) const noexcept; 115 | /** 116 | * @brief Non-Blocking timer check 117 | * @return Returns @c true when timer expires, otherwise, returns @c false. 118 | * @note A disarmed timer also returns @c false. 119 | */ 120 | bool expired( void ) const noexcept; 121 | /** 122 | * @brief Check if the specified deadline for has been reached. 123 | * @return @c true if the deadline has been reached, otherwise, returns @c false. 124 | */ 125 | bool deadLineCheck( void ) const noexcept; 126 | /** 127 | * @brief Retrieve the timer interval value 128 | * @return The interval value in epochs. 129 | */ 130 | qOS::clock_t getInterval( void ) const noexcept; 131 | /** 132 | * @brief Set the expiration time for a timer and gets armed immediately 133 | * @note The OS must be running before using timers. 134 | * @note The expiration time should be at least, two times greater than 135 | * the clock-Tick. 136 | * @param[in] tTime The expiration time given in milliseconds. 137 | */ 138 | timer& operator=( const qOS::duration_t tTime ); 139 | /** 140 | * @brief Disarm or reload the timer 141 | * @note The OS must be running before using timers. 142 | * @note The expiration time should be at least, two times greater than 143 | * the clock-Tick. 144 | * @param[in] en @c true for reload of @c false to disarm. 145 | */ 146 | timer& operator=( const bool en ); 147 | /** 148 | * @brief Non-Blocking timer check 149 | * @return Returns @c true when timer expires, otherwise, returns @c false. 150 | * @note A disarmed timer also returns @c false. 151 | */ 152 | bool operator()( void ) const; 153 | /** 154 | * @brief Set the expiration time for a timer and gets armed immediately 155 | * @note The OS must be running before using timers. 156 | * @note The expiration time should be at least, two times greater than 157 | * the clock-Tick. 158 | * @param[in] tTime The expiration time given in milliseconds. 159 | */ 160 | bool operator()( const qOS::duration_t tTime ); 161 | /** 162 | * @brief Disarm or reload the timer 163 | * @note The OS must be running before using timers. 164 | * @note The expiration time should be at least, two times greater than 165 | * the clock-Tick. 166 | * @param[in] en @c true for reload of @c false to disarm. 167 | */ 168 | void operator()( const bool en ); 169 | /** 170 | * @brief Non-Blocking timer check 171 | * @return Returns @c true when timer expires, otherwise, returns @c false. 172 | * @note A disarmed timer also returns @c false. 173 | */ 174 | explicit operator bool() const noexcept { 175 | return expired(); 176 | } 177 | /** @brief Constant that defines the status of an armed timer*/ 178 | static const bool ARMED; 179 | /** @brief Constant that defines the status of a disarmed timer*/ 180 | static const bool DISARMED; 181 | /** @brief Constant that defines the value of a disarmed timer*/ 182 | static const qOS::clock_t DISARM_VALUE; 183 | /** @brief Constant that defines the value that a disarmed timer 184 | * returns when the remaining time is requested. 185 | */ 186 | static const qOS::clock_t REMAINING_IN_DISARMED_STATE; 187 | }; 188 | 189 | /** @}*/ 190 | } 191 | 192 | bool operator==( const qOS::timer& obj, bool value ); 193 | 194 | #endif /*QOS_CPP_TIMER*/ 195 | 196 | -------------------------------------------------------------------------------- /src/task.cpp: -------------------------------------------------------------------------------- 1 | #include "include/task.hpp" 2 | #include "include/kernel.hpp" 3 | #include "include/helper.hpp" 4 | #include "include/util.hpp" 5 | 6 | using namespace qOS; 7 | 8 | const iteration_t task::PERIODIC = INT32_MIN; 9 | const iteration_t task::INDEFINITE = task::PERIODIC; 10 | const iteration_t task::SINGLE_SHOT = 1; 11 | 12 | const uint32_t task::BIT_INIT = 0x00000001UL; 13 | const uint32_t task::BIT_ENABLED = 0x00000002UL; 14 | const uint32_t task::BIT_QUEUE_RECEIVER = 0x00000004UL; 15 | const uint32_t task::BIT_QUEUE_FULL = 0x00000008UL; 16 | const uint32_t task::BIT_QUEUE_COUNT = 0x00000010UL; 17 | const uint32_t task::BIT_QUEUE_EMPTY = 0x00000020UL; 18 | const uint32_t task::BIT_SHUTDOWN = 0x00000040UL; 19 | const uint32_t task::BIT_REMOVE_REQUEST = 0x00000080UL; 20 | const uint32_t task::EVENT_FLAGS_MASK = 0xFFFFF000UL; 21 | const uint32_t task::QUEUE_FLAGS_MASK = 0x0000003CUL; 22 | 23 | /*============================================================================*/ 24 | constexpr iteration_t TASK_ITER_VALUE( iteration_t x ) 25 | { 26 | return ( ( x < 0 ) && ( x != task::PERIODIC ) ) ? -x : x; 27 | } 28 | /*============================================================================*/ 29 | void task::activities( event_t e ) 30 | { 31 | if ( nullptr != callback ) { 32 | callback( e ); 33 | } 34 | } 35 | /*============================================================================*/ 36 | void task::setFlags( const uint32_t xFlags, const bool value ) noexcept 37 | { 38 | if ( value ) { 39 | bits::multipleSet( this->flags, xFlags ); 40 | } 41 | else { 42 | bits::multipleClear( this->flags, xFlags ); 43 | } 44 | } 45 | /*============================================================================*/ 46 | bool task::getFlag( const uint32_t flag ) const noexcept 47 | { 48 | const uint32_t xBit = this->flags & flag; 49 | return ( 0UL != xBit ); 50 | } 51 | /*============================================================================*/ 52 | priority_t task::getPriority( void ) const noexcept 53 | { 54 | return priority; 55 | } 56 | /*============================================================================*/ 57 | bool task::setPriority( const priority_t pValue ) noexcept 58 | { 59 | bool retValue = false; 60 | 61 | if ( pValue < static_cast( Q_PRIORITY_LEVELS ) ) { 62 | priority = pValue; 63 | retValue = true; 64 | } 65 | 66 | return retValue; 67 | } 68 | /*============================================================================*/ 69 | cycles_t task::getCycles( void ) const noexcept 70 | { 71 | return cycles; 72 | } 73 | /*============================================================================*/ 74 | taskState task::getState( void ) const noexcept 75 | { 76 | taskState retValue; 77 | 78 | retValue = static_cast( getFlag( BIT_SHUTDOWN ) ); 79 | if ( taskState::DISABLED_STATE != retValue ) { /*Task is awaken*/ 80 | retValue = static_cast( getFlag( BIT_ENABLED ) ); 81 | } 82 | 83 | return retValue; 84 | } 85 | /*============================================================================*/ 86 | bool task::deadLineReached( void ) const noexcept 87 | { 88 | bool retValue = false; 89 | 90 | if ( getFlag( BIT_ENABLED ) ) { 91 | const iteration_t iters = iterations; 92 | /*task should be periodic or must have available iters*/ 93 | if ( ( TASK_ITER_VALUE( iters ) > 0 ) || ( PERIODIC == iters ) ) { 94 | /*check the time deadline*/ 95 | const clock_t interval = time.getInterval(); 96 | const bool expired = time.expired(); 97 | 98 | if ( ( 0UL == interval ) || expired ) { 99 | retValue = true; 100 | } 101 | } 102 | } 103 | 104 | return retValue; 105 | } 106 | /*============================================================================*/ 107 | bool task::setState( const taskState s ) noexcept 108 | { 109 | bool retValue = false; 110 | 111 | switch ( s ) { 112 | case taskState::DISABLED_STATE: case taskState::ENABLED_STATE: // skipcq: CXX-C1001 113 | if ( s != static_cast( getFlag( BIT_ENABLED ) ) ) { 114 | setFlags( BIT_ENABLED, static_cast( s ) ); 115 | time.reload(); 116 | } 117 | retValue = true; 118 | break; 119 | case taskState::ASLEEP_STATE: 120 | setFlags( BIT_SHUTDOWN, false ); 121 | retValue = true; 122 | break; 123 | case taskState::AWAKE_STATE: 124 | setFlags( BIT_SHUTDOWN, true ); 125 | retValue = true; 126 | break; 127 | default: 128 | break; 129 | } 130 | 131 | return retValue; 132 | } 133 | /*============================================================================*/ 134 | void task::setIterations( const iteration_t iValue ) noexcept 135 | { 136 | if ( iValue > 0 ) { 137 | iterations = -iValue; 138 | } 139 | else if ( PERIODIC == iValue ) { 140 | iterations = PERIODIC; 141 | } 142 | else { 143 | /*nothing to do, return qFalse*/ 144 | } 145 | } 146 | /*============================================================================*/ 147 | bool task::setTime( const qOS::duration_t tValue ) noexcept 148 | { 149 | return time.set( tValue ); 150 | } 151 | /*============================================================================*/ 152 | bool task::setCallback( const taskFcn_t tCallback ) noexcept 153 | { 154 | bool retValue = false; 155 | 156 | if ( tCallback != callback ) { 157 | callback = tCallback; 158 | #if ( ( Q_FSM == 1 ) || ( Q_CLI == 1 ) ) 159 | aObj = nullptr; 160 | #endif 161 | retValue = true; 162 | } 163 | 164 | return retValue; 165 | } 166 | /*============================================================================*/ 167 | bool task::setData( void *arg ) noexcept 168 | { 169 | bool retValue = false; 170 | 171 | if ( arg != taskData ) { 172 | taskData = arg; 173 | retValue = true; 174 | } 175 | 176 | return retValue; 177 | } 178 | /*============================================================================*/ 179 | bool task::setName( const char *tName ) noexcept 180 | { 181 | bool retValue = false; 182 | const size_t nl = util::strlen( tName , sizeof(name) ); 183 | /*cstat -MISRAC++2008-5-14-1*/ 184 | if ( ( nullptr != getContainer() ) && ( nl > 0U ) && ( nl < sizeof(name) ) ) { 185 | if ( nullptr == os.getTaskByName( tName ) ) { 186 | (void)util::strcpy( name, tName , sizeof( name ) ); // skipcq: CXX-C1000 187 | retValue = true; 188 | } 189 | } 190 | /*cstat +MISRAC++2008-5-14-1*/ 191 | return retValue; 192 | } 193 | /*============================================================================*/ 194 | const char* task::getName( void ) const noexcept 195 | { 196 | return name; // skipcq: CXX-C1000 197 | } 198 | /*============================================================================*/ 199 | trigger task::queueCheckEvents( void ) noexcept 200 | { 201 | trigger retValue = trigger::None; 202 | 203 | if ( nullptr != aQueue ) { 204 | const bool fullFlag = getFlag( BIT_QUEUE_FULL ); 205 | const bool countFlag = getFlag( BIT_QUEUE_COUNT ); 206 | const bool receiverFlag = getFlag( BIT_QUEUE_RECEIVER ); 207 | const bool emptyFlag = getFlag( BIT_QUEUE_EMPTY ); 208 | const size_t qCount = aQueue->count(); /*current queue count*/ 209 | 210 | /*check the queue events in the corresponding precedence order*/ 211 | /*cstat -MISRAC++2008-5-14-1*/ 212 | if ( fullFlag && aQueue->isFull() ) { /*isFull() is known to not have side effects*/ 213 | retValue = trigger::byQueueFull; 214 | } 215 | else if ( ( countFlag ) && ( qCount >= aQueueCount ) ) { 216 | retValue = trigger::byQueueCount; 217 | } 218 | else if ( receiverFlag && ( qCount > 0U ) ) { 219 | retValue = trigger::byQueueReceiver; 220 | } 221 | else if ( emptyFlag && aQueue->isEmpty() ) { /*isEmpty() is known to not have side effects*/ 222 | /*qQueue_IsEmpty is known to not have side effects*/ 223 | retValue = trigger::byQueueEmpty; 224 | } 225 | else { 226 | /*this case does not need to be handled*/ 227 | } 228 | /*cstat +MISRAC++2008-5-14-1*/ 229 | } 230 | 231 | return retValue; 232 | } 233 | /*============================================================================*/ 234 | size_t task::getID( void ) const noexcept 235 | { 236 | return entry; 237 | } 238 | /*============================================================================*/ 239 | bool task::attachQueue( queue &q, const queueLinkMode mode, const size_t arg ) noexcept 240 | { 241 | bool retValue = false; 242 | 243 | if ( q.isInitialized() ) { 244 | setFlags( static_cast( mode ) & QUEUE_FLAGS_MASK, 0U != arg ); 245 | if ( queueLinkMode::QUEUE_COUNT == mode ) { 246 | aQueueCount = arg; 247 | } 248 | aQueue = ( arg > 0U ) ? &q : nullptr; 249 | retValue = true; 250 | } 251 | 252 | return retValue; 253 | } 254 | /*============================================================================*/ 255 | void * const & task::getBindedObject( void ) const noexcept 256 | { 257 | return aObj; 258 | } 259 | /*============================================================================*/ 260 | queue* task::getQueue( void ) noexcept 261 | { 262 | return aQueue; 263 | } 264 | /*============================================================================*/ 265 | 266 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map for QuarkTS++ 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes(KEYWORD1) 7 | ####################################### 8 | 9 | os KEYWORD1 10 | co KEYWORD1 11 | logger KEYWORD1 12 | task KEYWORD1 13 | sm KEYWORD1 14 | bits KEYWORD1 15 | queue KEYWORD1 16 | cli KEYWORD1 17 | timer KEYWORD1 18 | critical KEYWORD1 19 | util KEYWORD1 20 | event_t KEYWORD1 21 | byteBuffer KEYWORD1 22 | response KEYWORD1 23 | commandType KEYWORD1 24 | handler_t KEYWORD1 25 | commandCallback_t KEYWORD1 26 | options_t KEYWORD1 27 | commandLineInterface KEYWORD1 28 | clock KEYWORD1 29 | time_t KEYWORD1 30 | timingBase_t KEYWORD1 31 | handle KEYWORD1 32 | position KEYWORD1 33 | state KEYWORD1 34 | base_t KEYWORD1 35 | semaphore KEYWORD1 36 | reenter KEYWORD1 37 | yield KEYWORD1 38 | delay KEYWORD1 39 | waitUntil KEYWORD1 40 | timeoutExpired KEYWORD1 41 | restart KEYWORD1 42 | semWait KEYWORD1 43 | semSignal KEYWORD1 44 | getPosition KEYWORD1 45 | setPosition KEYWORD1 46 | int_restorer_t KEYWORD1 47 | int_disabler_t KEYWORD1 48 | input KEYWORD1 49 | channel KEYWORD1 50 | digitalChannel KEYWORD1 51 | analogChannel KEYWORD1 52 | node KEYWORD1 53 | pinState KEYWORD1 54 | signalID KEYWORD1 55 | signal_t KEYWORD1 56 | status KEYWORD1 57 | historyMode KEYWORD1 58 | handler_t KEYWORD1 59 | stateCallback_t KEYWORD1 60 | signalQueue KEYWORD1 61 | surroundingCallback_t KEYWORD1 62 | signalAction_t KEYWORD1 63 | timeoutSpecOption_t KEYWORD1 64 | timeoutStateDefinition KEYWORD1 65 | transition KEYWORD1 66 | timeoutSpec KEYWORD1 67 | psReqStatus KEYWORD1 68 | psIndex_t KEYWORD1 69 | stateMachine KEYWORD1 70 | coreFlags_t KEYWORD1 71 | notificationSpreader_t KEYWORD1 72 | notifyMode KEYWORD1 73 | list KEYWORD1 74 | listIterator KEYWORD1 75 | listCompareFcn_t KEYWORD1 76 | listCompareHandle_t KEYWORD1 77 | listPosition KEYWORD1 78 | listDirection KEYWORD1 79 | address_t KEYWORD1 80 | mem KEYWORD1 81 | pool KEYWORD1 82 | queueSendMode KEYWORD1 83 | responseStatus KEYWORD1 84 | queueLinkMode KEYWORD1 85 | taskFcn_t KEYWORD1 86 | notifier_t KEYWORD1 87 | taskFlag_t KEYWORD1 88 | globalState KEYWORD1 89 | trigger KEYWORD1 90 | clock_t KEYWORD1 91 | cycles_t KEYWORD1 92 | priority_t KEYWORD1 93 | iteration_t KEYWORD1 94 | index_t KEYWORD1 95 | byte_t KEYWORD1 96 | putChar_t KEYWORD1 97 | ioFcn_t KEYWORD1 98 | input KEYWORD1 99 | channel KEYWORD1 100 | digitalChannel KEYWORD1 101 | analogChannel KEYWORD1 102 | watcher KEYWORD1 103 | digitalValue_t KEYWORD1 104 | analogValue_t KEYWORD1 105 | eventCallback_t KEYWORD1 106 | digitalReaderFcn_t KEYWORD1 107 | analogReaderFcn_t KEYWORD1 108 | 109 | ####################################### 110 | # Methods and Functions(KEYWORD2) 111 | ####################################### 112 | 113 | setup KEYWORD2 114 | put KEYWORD2 115 | read KEYWORD2 116 | get KEYWORD2 117 | peek KEYWORD2 118 | isEmpty KEYWORD2 119 | isFull KEYWORD2 120 | count KEYWORD2 121 | add KEYWORD2 122 | isrHandler KEYWORD2 123 | raise KEYWORD2 124 | inputFlush KEYWORD2 125 | exec KEYWORD2 126 | run KEYWORD2 127 | getOwner KEYWORD2 128 | setData KEYWORD2 129 | getTick KEYWORD2 130 | convert2Clock KEYWORD2 131 | convert2Time KEYWORD2 132 | sysTick KEYWORD2 133 | timeDeadLineCheck KEYWORD2 134 | setTimeBase KEYWORD2 135 | setTickProvider KEYWORD2 136 | try_restart KEYWORD2 137 | try_suspend KEYWORD2 138 | try_resume KEYWORD2 139 | try_set KEYWORD2 140 | set KEYWORD2 141 | perform KEYWORD2 142 | until KEYWORD2 143 | critical KEYWORD2 144 | enter KEYWORD2 145 | exit KEYWORD2 146 | setInterruptsED KEYWORD2 147 | selectPin KEYWORD2 148 | getStatus KEYWORD2 149 | update KEYWORD2 150 | install KEYWORD2 151 | sendSignal KEYWORD2 152 | sendSignalToSubscriber KEYWORD2s 153 | timeoutSet KEYWORD2 154 | timeoutStop KEYWORD2 155 | getTop KEYWORD2 156 | getCurrent KEYWORD2 157 | getQueue KEYWORD2 158 | getTimeSpec KEYWORD2 159 | setSurrounding KEYWORD2 160 | subscribeToSignal KEYWORD2 161 | unsubscribeFromSignal KEYWORD2 162 | setTransitions KEYWORD2 163 | setTimeouts KEYWORD2 164 | getData KEYWORD2 165 | getTransitionTable KEYWORD2 166 | setCallback KEYWORD2 167 | nextState KEYWORD2 168 | thisState KEYWORD2 169 | thisMachine KEYWORD2 170 | signal KEYWORD2 171 | lastStatus KEYWORD2 172 | multipleSet KEYWORD2 173 | multipleClear KEYWORD2 174 | singleSet KEYWORD2 175 | singleClear KEYWORD2 176 | singleRead KEYWORD2 177 | singleToggle KEYWORD2 178 | singleWrite KEYWORD2 179 | multipleGet KEYWORD2 180 | clip KEYWORD2 181 | clipUpper KEYWORD2 182 | clipLower KEYWORD2 183 | isBetween KEYWORD2 184 | init KEYWORD2 185 | getInstance KEYWORD2 186 | setIdleTask KEYWORD2 187 | schedulerRelease KEYWORD2 188 | setSchedulerReleaseCallback KEYWORD2 189 | notify KEYWORD2 190 | hasPendingNotifications KEYWORD2 191 | eventFlagsModify KEYWORD2 192 | eventFlagsRead KEYWORD2 193 | eventFlagsCheck KEYWORD2 194 | findTaskByName KEYWORD2 195 | yieldToTask KEYWORD2 196 | getGlobalState KEYWORD2 197 | until KEYWORD2 198 | get KEYWORD2 199 | begin KEYWORD2 200 | end KEYWORD2 201 | from KEYWORD2 202 | swap KEYWORD2 203 | sort KEYWORD2 204 | length KEYWORD2 205 | getBack KEYWORD2 206 | getFront KEYWORD2 207 | remove KEYWORD2 208 | insert KEYWORD2 209 | getContainer KEYWORD2 210 | free KEYWORD2 211 | alloc KEYWORD2 212 | getFreeSize KEYWORD2 213 | reset KEYWORD2 214 | itemsAvailable KEYWORD2 215 | removeFront KEYWORD2 216 | receive KEYWORD2 217 | send KEYWORD2 218 | peek KEYWORD2 219 | isInitialized KEYWORD2 220 | getItemSize KEYWORD2 221 | received KEYWORD2 222 | firstCall KEYWORD2 223 | firstIteration KEYWORD2 224 | lastIteration KEYWORD2 225 | getTrigger KEYWORD2 226 | startDelay KEYWORD2 227 | self KEYWORD2 228 | getPriority KEYWORD2 229 | setPriority KEYWORD2 230 | getCycles KEYWORD2 231 | getState KEYWORD2 232 | setState KEYWORD2 233 | setIterations KEYWORD2 234 | setTime KEYWORD2 235 | setData KEYWORD2 236 | setName KEYWORD2 237 | getName KEYWORD2 238 | getID KEYWORD2 239 | getQueue KEYWORD2 240 | getBindedObject KEYWORD2 241 | eventData KEYWORD2 242 | disarm KEYWORD2 243 | reload KEYWORD2 244 | freeRun KEYWORD2 245 | remaining KEYWORD2 246 | elapsed KEYWORD2 247 | expired KEYWORD2 248 | deadLineCheck KEYWORD2 249 | getInterval KEYWORD2 250 | swapBytes KEYWORD2 251 | checkEndianness KEYWORD2 252 | outputString KEYWORD2 253 | printXData KEYWORD2 254 | outputRAW KEYWORD2 255 | inputRAW KEYWORD2 256 | hexStringToUnsigned KEYWORD2 257 | stringToFloat KEYWORD2 258 | floatToString KEYWORD2 259 | stringToInt KEYWORD2 260 | unsignedToString KEYWORD2 261 | integerToString KEYWORD2 262 | boolToString KEYWORD2 263 | var KEYWORD2 264 | mem KEYWORD2 265 | hex KEYWORD2 266 | dec KEYWORD2 267 | bin KEYWORD2 268 | oct KEYWORD2 269 | mem KEYWORD2 270 | endl KEYWORD2 271 | end KEYWORD2 272 | setOutputFcn KEYWORD2 273 | multipleSet KEYWORD2 274 | multipleClear KEYWORD2 275 | singleSet KEYWORD2 276 | singleClear KEYWORD2 277 | singleRead KEYWORD2 278 | singleToggle KEYWORD2 279 | singleWrite KEYWORD2 280 | multipleGet KEYWORD2 281 | arraySize KEYWORD2 282 | clip KEYWORD2 283 | clipUpper KEYWORD2 284 | clipLower KEYWORD2 285 | isBetween KEYWORD2 286 | byteNibbleLow KEYWORD2 287 | byteNibbleHigh KEYWORD2 288 | byteMergeNibbles KEYWORD2 289 | wordByteHigh KEYWORD2 290 | wordByteLow KEYWORD2 291 | wordMergeBytes KEYWORD2 292 | dWordWordHigh KEYWORD2 293 | dWordWordLow KEYWORD2 294 | dwordMergeWords KEYWORD2 295 | getType KEYWORD2 296 | getEvent KEYWORD2 297 | setChannel KEYWORD2 298 | getChannel KEYWORD2 299 | getUserData KEYWORD2 300 | isShared KEYWORD2 301 | setParameter KEYWORD2 302 | getCount KEYWORD2 303 | setReader KEYWORD2 304 | unShare KEYWORD2 305 | 306 | ####################################### 307 | # Constants(LITERAL1) 308 | 309 | ERROR LITERAL1 310 | NOT_ALLOWED LITERAL1 311 | NO_RESPONSE LITERAL1 312 | OK LITERAL1 313 | DEVID LITERAL1 314 | NOT_FOUND LITERAL1 315 | OUTPUT_RESPONSE LITERAL1 316 | UNDEF LITERAL1 317 | PARA LITERAL1 318 | TEST LITERAL1 319 | READ LITERAL1 320 | ACT LITERAL1 321 | NONE LITERAL1 322 | IMMEDIATE LITERAL1 323 | MINUTE LITERAL1 324 | HOUR LITERAL1 325 | DAY LITERAL1 326 | WEEK LITERAL1 327 | UNDEFINED LITERAL1 328 | SUSPENDED LITERAL1 329 | BEGINNING LITERAL1 330 | SIZE_8_BIT LITERAL1 331 | SIZE_16_BIT LITERAL1 332 | SIZE_32_BIT LITERAL1 333 | UNKNOWN LITERAL1 334 | ON LITERAL1 335 | OFF LITERAL1 336 | SIGNAL_START LITERAL1 337 | SIGNAL_EXIT LITERAL1 338 | SIGNAL_ENTRY LITERAL1 339 | SIGNAL_NONE LITERAL1 340 | SIGNAL_TIMEOUT0 LITERAL1 341 | SIGNAL_TIMEOUT1 LITERAL1 342 | SIGNAL_TIMEOUT2 LITERAL1 343 | SIGNAL_TIMEOUT3 LITERAL1 344 | SIGNAL_TIMEOUT4 LITERAL1 345 | SIGNAL_TIMEOUT5 LITERAL1 346 | SIGNAL_TIMEOUT6 LITERAL1 347 | SIGNAL_TIMEOUT7 LITERAL1 348 | SIGNAL_TIMEOUT8 LITERAL1 349 | SIGNAL_TIMEOUT9 LITERAL1 350 | MAX_SIGNAL LITERAL1 351 | MIN_SIGNAL LITERAL1 352 | TM_MAX LITERAL1 353 | TM_MIN LITERAL1 354 | BEFORE_ANY LITERAL1 355 | ABSENT LITERAL1 356 | FAILURE LITERAL1 357 | SUCCESS LITERAL1 358 | SIGNAL_HANDLED LITERAL1 359 | NO_HISTORY LITERAL1 360 | SHALLOW_HISTORY LITERAL1 361 | DEEP_HISTORY LITERAL1 362 | PS_SIGNAL_NOT_FOUND LITERAL1 363 | PS_SUBSCRIBER_NOT_FOUND LITERAL1 364 | PS_SUBSCRIBER_FOUND LITERAL1 365 | PS_SIGNAL_SLOTS_FULL LITERAL1 366 | PS_SUBSCRIBER_SLOTS_FULL LITERAL1 367 | TIMEOUT_SET_ENTRY LITERAL1 368 | TIMEOUT_RST_ENTRY LITERAL1 369 | TIMEOUT_SET_EXIT LITERAL1 370 | TIMEOUT_RST_EXIT LITERAL1 371 | TIMEOUT_KEEP_IF_SET LITERAL1 372 | TIMEOUT_PERIODIC LITERAL1 373 | TIMEOUT_INDEX LITERAL1 374 | SIGNAL_TIMEOUT LITERAL1 375 | SIGNAL_USER LITERAL1 376 | SIMPLE LITERAL1 377 | QUEUED LITERAL1 378 | EVENT_FLAG LITERAL1 379 | LOWEST_PRIORITY LITERAL1 380 | MEDIUM_PRIORITY LITERAL1 381 | HIGHEST_PRIORITY LITERAL1 382 | AT_BACK LITERAL1 383 | AT_FRONT LITERAL1 384 | FORWARD LITERAL1 385 | BACKWARD LITERAL1 386 | TO_BACK LITERAL1 387 | TO_FRONT LITERAL1 388 | MISSING LITERAL1 389 | TIMEOUT LITERAL1 390 | PERIODIC LITERAL1 391 | INDEFINITE LITERAL1 392 | SINGLE_SHOT LITERAL1 393 | ARMED LITERAL1 394 | DISARMED LITERAL1 395 | DISARM_VALUE LITERAL1 396 | REMAINING_IN_DISARMED_STATE LITERAL1 397 | DIGITAL_CHANNEL LITERAL1 398 | ANALOG_CHANNEL LITERAL1 399 | EXCEPTION LITERAL1 400 | ON_CHANGE LITERAL1 401 | FALLING_EDGE LITERAL1 402 | RISING_EDGE LITERAL1 403 | PULSATION_DOUBLE LITERAL1 404 | PULSATION_TRIPLE LITERAL1 405 | PULSATION_MULTI LITERAL1 406 | HIGH_THRESHOLD LITERAL1 407 | LOW_THRESHOLD LITERAL1 408 | IN_BAND LITERAL1 409 | STEADY_IN_HIGH LITERAL1 410 | STEADY_IN_LOW LITERAL1 411 | STEADY_IN_BAND LITERAL1 412 | 413 | 414 | ####################################### 415 | 416 | -------------------------------------------------------------------------------- /src/memory.cpp: -------------------------------------------------------------------------------- 1 | #include "include/memory.hpp" 2 | #include "include/helper.hpp" 3 | 4 | using namespace qOS; 5 | 6 | 7 | static const size_t BYTE_ALIGN_MASK = static_cast( Q_BYTE_ALIGNMENT ) - static_cast( 1U ); 8 | static const size_t ALLOC_BIT_SEL = ( sizeof(size_t)*static_cast( 8U ) ) - static_cast( 1U ); 9 | static const size_t BLOCK_ALLOCATED_BIT = static_cast( 1U ) << ALLOC_BIT_SEL; 10 | static const size_t HEAP_STRUCT_SIZE = ( sizeof(mem::blockConnect_t) + ( BYTE_ALIGN_MASK - static_cast( 1U ) ) ) & ~BYTE_ALIGN_MASK; 11 | 12 | /*============================================================================*/ 13 | bool mem::pool::setup( void *pArea, const size_t pSize ) noexcept 14 | { 15 | bool retValue = false; 16 | 17 | if ( ( nullptr != pArea ) && ( pSize > 0U ) ) { 18 | /*cstat -CERT-EXP36-C_b*/ 19 | poolMemory = static_cast( pArea ); 20 | /*cstat +CERT-EXP36-C_b*/ 21 | poolMemSize = pSize; 22 | freeBytesRemaining = pSize; 23 | end = nullptr; 24 | init(); 25 | retValue = true; 26 | } 27 | 28 | return retValue; 29 | } 30 | /*============================================================================*/ 31 | void mem::pool::insertBlockIntoFreeList( blockConnect_t *xBlock ) noexcept 32 | { 33 | mem::blockConnect_t *iterator; 34 | uint8_t *ptr; 35 | 36 | for ( iterator = &start ; iterator->next < xBlock ; iterator = iterator->next ) {} 37 | ptr = reinterpret_cast( iterator ); 38 | /*cstat -SEC-NULL-cmp-bef -PTR-null-cmp-bef -CERT-EXP34-C_g*/ 39 | if ( &ptr[ iterator->blockSize ] == reinterpret_cast( xBlock ) ) { 40 | iterator->blockSize += xBlock->blockSize; 41 | xBlock = iterator; 42 | } 43 | ptr = reinterpret_cast( xBlock ); 44 | if ( &ptr[ xBlock->blockSize ] == reinterpret_cast( iterator->next ) ) { 45 | if ( iterator->next != end ) { 46 | xBlock->blockSize += iterator->next->blockSize; 47 | xBlock->next = iterator->next->next; 48 | } 49 | else { 50 | xBlock->next = end; 51 | } 52 | } 53 | else { 54 | xBlock->next = iterator->next; 55 | } 56 | /*cstat +SEC-NULL-cmp-bef +PTR-null-cmp-bef +CERT-EXP34-C_g*/ 57 | if ( iterator != xBlock ) { 58 | iterator->next = xBlock; 59 | } 60 | } 61 | /*============================================================================*/ 62 | void mem::pool::free( void *ptr ) noexcept 63 | { 64 | /*cstat -CERT-EXP36-C_b*/ 65 | uint8_t *pToFree = static_cast( ptr ); 66 | /*cstat +CERT-EXP36-C_b*/ 67 | if ( nullptr != ptr ) { 68 | mem::blockConnect_t *xConnect; 69 | 70 | pToFree -= HEAP_STRUCT_SIZE; 71 | xConnect = aligned_cast( pToFree ); 72 | if ( 0U != ( xConnect->blockSize & BLOCK_ALLOCATED_BIT ) ) { 73 | if ( NULL == xConnect->next ) { 74 | bits::multipleClear( xConnect->blockSize, BLOCK_ALLOCATED_BIT ); 75 | freeBytesRemaining += xConnect->blockSize; 76 | insertBlockIntoFreeList( xConnect ); 77 | } 78 | } 79 | } 80 | } 81 | /*============================================================================*/ 82 | void mem::pool::init( void ) noexcept 83 | { 84 | mem::blockConnect_t *firstFreeBlock; 85 | uint8_t *aligned; 86 | mem::address_t address; 87 | mem::address_t xAddrTmp; 88 | size_t totalPoolSize = poolMemSize; 89 | 90 | /*cstat -CERT-INT36-C -CERT-EXP39-C_d -CERT-EXP36-C_a*/ 91 | address = reinterpret_cast( poolMemory ); 92 | 93 | if ( 0UL != ( address & BYTE_ALIGN_MASK ) ) { 94 | address += BYTE_ALIGN_MASK; 95 | address &= ~BYTE_ALIGN_MASK; 96 | totalPoolSize -= address - reinterpret_cast( poolMemory ); 97 | } 98 | 99 | aligned = reinterpret_cast( address ); 100 | start.next = aligned_cast( aligned ); 101 | start.blockSize = static_cast( 0U ); 102 | xAddrTmp = reinterpret_cast( aligned ); 103 | address = xAddrTmp + totalPoolSize; 104 | address -= HEAP_STRUCT_SIZE; 105 | address &= ~BYTE_ALIGN_MASK; 106 | end = reinterpret_cast( address ); 107 | end->next = nullptr; 108 | end->blockSize = static_cast( 0U ); 109 | firstFreeBlock = aligned_cast( aligned ); 110 | xAddrTmp = reinterpret_cast( firstFreeBlock ); 111 | /*cstat +CERT-INT36-C +CERT-EXP39-C_d +CERT-EXP36-C_a*/ 112 | firstFreeBlock->blockSize = address - xAddrTmp; 113 | firstFreeBlock->next = end; 114 | freeBytesRemaining = firstFreeBlock->blockSize; 115 | } 116 | /*============================================================================*/ 117 | void* mem::pool::alloc( size_t pSize ) noexcept 118 | { 119 | void *pAllocated = nullptr; 120 | 121 | if ( pSize > static_cast( 0U ) ) { 122 | const size_t additional = HEAP_STRUCT_SIZE + Q_BYTE_ALIGNMENT - ( pSize & BYTE_ALIGN_MASK ); 123 | if ( pSize > ( ( ~static_cast( 0U ) ) - additional ) ) { 124 | pSize = static_cast( 0U ); 125 | } 126 | else { 127 | /*cstat -ATH-overflow*/ 128 | pSize += additional; 129 | /*cstat +ATH-overflow*/ 130 | } 131 | } 132 | 133 | if ( static_cast( 0U ) == ( pSize & BLOCK_ALLOCATED_BIT ) ) { 134 | if ( ( pSize > static_cast( 0U ) ) && ( pSize < freeBytesRemaining ) ) { 135 | mem::blockConnect_t *xBlock; 136 | mem::blockConnect_t *previousBlock; 137 | 138 | previousBlock = &start; 139 | xBlock = start.next; 140 | while ( ( xBlock->blockSize < pSize ) && ( nullptr != xBlock->next ) ) { 141 | previousBlock = xBlock; 142 | xBlock = xBlock->next; 143 | } 144 | if ( xBlock != end ) { 145 | const size_t minBlockSize = ( HEAP_STRUCT_SIZE << static_cast( 1U ) ); 146 | 147 | pAllocated = static_cast( ( reinterpret_cast( previousBlock->next ) ) + HEAP_STRUCT_SIZE ); 148 | previousBlock->next = xBlock->next; 149 | if ( ( xBlock->blockSize - pSize ) > minBlockSize ) { 150 | mem::blockConnect_t *newBlockLink; 151 | /*cstat -MISRAC++2008-7-1-1*/ 152 | uint8_t *pBlockU8 = reinterpret_cast( xBlock ); 153 | uint8_t *ptrBlock = &pBlockU8[ pSize ]; 154 | /*cstat -CERT-EXP39-C_d -CERT-EXP36-C_a +MISRAC++2008-7-1-1*/ 155 | newBlockLink = aligned_cast( ptrBlock ); 156 | /*cstat +CERT-EXP39-C_d +CERT-EXP36-C_a*/ 157 | newBlockLink->blockSize = xBlock->blockSize - pSize; 158 | /*cstat -ATH-overflow*/ 159 | xBlock->blockSize = pSize; 160 | /*cstat +ATH-overflow*/ 161 | insertBlockIntoFreeList( newBlockLink ); 162 | } 163 | freeBytesRemaining -= xBlock->blockSize; 164 | bits::multipleSet( xBlock->blockSize, BLOCK_ALLOCATED_BIT ); 165 | xBlock->next = nullptr; 166 | } 167 | } 168 | } 169 | 170 | return pAllocated; 171 | } 172 | /*============================================================================*/ 173 | size_t mem::pool::getFreeSize( void ) const noexcept 174 | { 175 | size_t retValue = poolMemSize; 176 | 177 | if ( nullptr != end ) { 178 | retValue = freeBytesRemaining; 179 | } 180 | 181 | return retValue; 182 | } 183 | /*============================================================================*/ 184 | size_t mem::pool::getTotalSize( void ) const noexcept 185 | { 186 | return poolMemSize; 187 | } 188 | /*============================================================================*/ 189 | void* mem::pool::getPoolArea( void ) const noexcept 190 | { 191 | return poolMemory; 192 | } 193 | /*============================================================================*/ 194 | 195 | #if ( Q_DEFAULT_HEAP_SIZE >= 64 ) 196 | 197 | static uint8_t defaultPoolMemory[ Q_DEFAULT_HEAP_SIZE ] = { 0 }; 198 | static mem::pool defaultMemPool( defaultPoolMemory, Q_DEFAULT_HEAP_SIZE ); 199 | 200 | /*============================================================================*/ 201 | void * operator new(size_t size) 202 | { 203 | return defaultMemPool.alloc( size ); 204 | } 205 | /*============================================================================*/ 206 | void * operator new[]( size_t size ) 207 | { 208 | return operator new(size); 209 | } 210 | /*============================================================================*/ 211 | /*cstat -MISRAC++2008-7-1-2 -MISRAC++2008-0-1-11 -CPU-delete-void*/ 212 | void * operator new( size_t size, void *place ) noexcept 213 | { 214 | /* Nothing to do */ 215 | (void)size; 216 | return place; 217 | } 218 | /*============================================================================*/ 219 | void * operator new[]( size_t size, void *place ) noexcept 220 | { 221 | return operator new(size, place); 222 | } 223 | /*============================================================================*/ 224 | void operator delete( void * ptr ) noexcept 225 | { 226 | defaultMemPool.free( ptr ); 227 | } 228 | /*============================================================================*/ 229 | void operator delete[](void * ptr) noexcept 230 | { 231 | operator delete( ptr ); 232 | } 233 | /*============================================================================*/ 234 | void operator delete(void* ptr, void* place) noexcept 235 | { 236 | (void)ptr; 237 | (void)place; 238 | /*Nothing to do*/ 239 | } 240 | /*============================================================================*/ 241 | void operator delete[](void* ptr, void* place) noexcept 242 | { 243 | (void)ptr; 244 | (void)place; // unused 245 | /*Nothing to do*/ 246 | } 247 | /*cstat +MISRAC++2008-7-1-2 +MISRAC++2008-0-1-11 +CPU-delete-void*/ 248 | /*============================================================================*/ 249 | #endif /*Q_USE_MEM_ALLOCATION_SCHEME*/ 250 | -------------------------------------------------------------------------------- /src/include/helper.hpp: -------------------------------------------------------------------------------- 1 | #ifndef QOS_CPP_HELPER 2 | #define QOS_CPP_HELPER 3 | 4 | #include "include/types.hpp" 5 | 6 | namespace qOS { 7 | 8 | /** @addtogroup qflm 9 | * @{ 10 | */ 11 | 12 | /** 13 | * @brief Helper Bit-manipulation interfaces. 14 | */ 15 | namespace bits { 16 | /** @addtogroup qflm 17 | * @{ 18 | */ 19 | 20 | /*cstat -CERT-INT34-C_a -MISRAC++2008-5-0-10*/ 21 | /** 22 | * @brief Uses the bitwise OR operator to set bits into @a dst 23 | * @param[in] dst The variable where the operation will be applied 24 | * @param[in] xBits Indicates which bits are to be set 25 | */ 26 | template 27 | inline void multipleSet( T &dst, W xBits ) 28 | { 29 | dst = dst | static_cast( xBits ); 30 | } 31 | /** 32 | * @brief Uses the bitwise AND operator to clear bits into @a dst 33 | * @param[in] dst The variable where the operation will be applied 34 | * @param[in] xBits Indicates which bits are to be cleared 35 | */ 36 | template 37 | inline void multipleClear( T &dst, W xBits ) 38 | { 39 | dst = dst & ~static_cast( xBits ); 40 | } 41 | /** 42 | * @brief Uses the bitwise OR operator to set a single bit into @a dst 43 | * @param[in] dst The variable where the operation will be applied 44 | * @param[in] xBit The bit-index 45 | */ 46 | template 47 | inline void singleSet( T &dst, const size_t xBit ) 48 | { 49 | dst = dst | ( static_cast( 1U ) << static_cast( xBit ) ); 50 | } 51 | /** 52 | * @brief Uses the bitwise AND operator to clear a single bit into @a dst 53 | * @param[in] dst The variable where the operation will be applied 54 | * @param[in] xBit The bit-index 55 | */ 56 | template 57 | inline void singleClear( T &dst, const size_t xBit ) 58 | { 59 | dst = dst & ~( static_cast( 1U ) << static_cast( xBit ) ); 60 | } 61 | /** 62 | * @brief Uses the bitwise AND operator to read the value of a single bit 63 | * from @a dst 64 | * @param[in] dst The variable where the operation will be applied 65 | * @param[in] xBit The bit-index 66 | * @return The value of the requested bit. 67 | */ 68 | template 69 | inline bool singleRead( T dst, const size_t xBit ) 70 | { 71 | return ( static_cast( 0U ) != ( dst & ( static_cast( 1U ) << static_cast( xBit ) ) ) ); 72 | } 73 | /** 74 | * @brief Uses the bitwise XOR operator to toggle the value of a single bit 75 | * from @a dst 76 | * @param[in] dst The variable where the operation will be applied 77 | * @param[in] xBit The bit-index 78 | */ 79 | template 80 | inline void singleToggle( T &dst, const size_t xBit ) 81 | { 82 | dst = dst ^ ( static_cast( 1U ) << static_cast( xBit ) ); 83 | } 84 | /*cstat +CERT-INT34-C_a +MISRAC++2008-5-0-10*/ 85 | /** 86 | * @brief Write the boolean @a value in a single bit of the @a dst variable 87 | * @param[in] dst The variable where the operation will be applied 88 | * @param[in] xBit The bit-index 89 | * @param[in] value The boolean value to write 90 | */ 91 | template 92 | inline void singleWrite( T &dst, const size_t xBit, const bool value ) 93 | { 94 | ( value ) ? bits::singleSet( dst, xBit ) : bits::singleClear( dst, xBit ); 95 | } 96 | /** 97 | * @brief Read multiple bits by applying the mask given by @a xBits to 98 | * the @a dst variable 99 | * @param[in] reg The variable where the operation will be applied 100 | * @param[in] xBits The bit mask 101 | * @return The @a dst variable masked with @a xBits. 102 | */ 103 | template 104 | inline bool multipleGet( T reg, W xBits ) 105 | { 106 | return ( 0U != ( reg & xBits) ); 107 | } 108 | /** @}*/ 109 | } 110 | 111 | /*! @cond */ 112 | template 113 | inline DT aligned_cast( ST& src ) 114 | { 115 | /*cstat -CERT-EXP33-C_a*/ 116 | DT dst; 117 | (void)memcpy( &dst, &src, sizeof(ST) ); 118 | return dst; 119 | /*cstat +CERT-EXP33-C_a*/ 120 | } 121 | /*! @endcond */ 122 | 123 | /*! @cond */ 124 | template 125 | constexpr size_t arraySize( const T& ) noexcept 126 | { 127 | return 1; 128 | } 129 | /*! @endcond */ 130 | /** 131 | * @brief Calculates the size of an array. 132 | * This function takes a reference to an array and calculates its size. 133 | * For a one-dimensional array, the size is simply the number of elements. 134 | * For a multi-dimensional array, the size is the product of the sizes of 135 | * all dimensions. 136 | * @warning This function only works for raw-arrays. It is not intended for 137 | * boost or STL arrays and vectors 138 | * @tparam T The type of the array elements. 139 | * @tparam n The size of the first dimension (for a multi-dimensional array). 140 | * @param arr The array whose size to calculate. 141 | * @return The size of the array. 142 | */ 143 | template 144 | constexpr size_t arraySize( const T (&arr)[n] ) noexcept // skipcq: CXX-W2066 145 | { 146 | return n*arraySize(*arr); 147 | } 148 | /** 149 | * @brief Ensures that @a x is between the limits set by @a Min and @a Max. 150 | * @note If @a Min is greater than @a Max the result is undefined. 151 | * @param[in] x The value to clamp 152 | * @param[in] Min The minimum value allowed. 153 | * @param[in] Max The maximum value allowed. 154 | * @return The value of @a x clamped to the range between @a Min and @a Max. 155 | */ 156 | template 157 | inline T clip( T x, const T Min, const T Max ) 158 | { 159 | return ( x < Min ) ? Min : ( ( x > Max ) ? Max : x ); 160 | } 161 | /** 162 | * @brief Ensures that @a x is bellow the limits set by @a Max. 163 | * @param[in] x The value to clamp 164 | * @param[in] Max The maximum value allowed. 165 | * @return The value of @a x clamped to the value of @a Max. 166 | */ 167 | template 168 | inline T clipUpper( T x, const T Max ) 169 | { 170 | return ( x > Max ) ? Max : x ; 171 | } 172 | /** 173 | * @brief Ensures that @a x is above the value set by @a Min. 174 | * @param[in] x The value to clamp 175 | * @param[in] Min The minimum value allowed. 176 | * @return The value of @a x clamped to the value of @a Min. 177 | */ 178 | template 179 | inline T clipLower( T x, const T Min ) 180 | { 181 | return ( x < Min ) ? Min : x ; 182 | } 183 | /** 184 | * @brief Check if the value of @a x is within the limits defined by 185 | * @a Low and @a High. 186 | * @param[in] x The value to check 187 | * @param[in] Low The minimum value allowed. 188 | * @param[in] High The maximum value allowed. 189 | * @return @c true if the @a x is between the defined range. Otherwise returns 190 | * @c false. 191 | */ 192 | template 193 | inline T isBetween( T x, const T Low, const T High ) 194 | { 195 | return ( x >= Low ) && ( x <= High ); 196 | } 197 | /** 198 | * @brief Read the high-nibble from @a x 199 | * @param[in] x The input variable 200 | * @return The value of the high nibble taken from @a x 201 | */ 202 | inline uint8_t byteNibbleHigh( uint8_t x ) 203 | { 204 | return static_cast( x >> 4U ); 205 | } 206 | /** 207 | * @brief Read the low-nibble from @a x 208 | * @param[in] x The input variable 209 | * @return The value of the low nibble taken from @a x 210 | */ 211 | inline uint8_t byteNibbleLow( uint8_t x ) 212 | { 213 | return static_cast( x & 0x0FU ); 214 | } 215 | /** 216 | * @brief Merges two nibbles to form one byte. 217 | * @param[in] h The high nibble 218 | * @param[in] l The low nibble 219 | * @return The value of the resulting byte 220 | */ 221 | inline uint8_t byteMergeNibbles( uint8_t h, uint8_t l ) 222 | { 223 | return static_cast( ( h << 4U ) | ( 0x0FU & l ) ); 224 | } 225 | /** 226 | * @brief Read the high-byte from @a x 227 | * @param[in] x The input variable 228 | * @return The value of the high byte taken from @a x 229 | */ 230 | inline uint16_t wordByteHigh( uint16_t x ) 231 | { 232 | return static_cast( x >> 8U ); 233 | } 234 | /** 235 | * @brief Read the low-byte from @a x 236 | * @param[in] x The input variable 237 | * @return The value of the low byte taken from @a x 238 | */ 239 | inline uint16_t wordByteLow( uint16_t x ) 240 | { 241 | return static_cast( x & 0x00FFU ); 242 | } 243 | /** 244 | * @brief Merges two bytes to form one Word. 245 | * @param[in] h The high byte 246 | * @param[in] l The low byte 247 | * @return The value of the resulting word 248 | */ 249 | inline uint16_t wordMergeBytes( uint16_t h, uint16_t l ) 250 | { 251 | return static_cast( ( h << 8U ) | ( 0x00FFU & l ) ); 252 | } 253 | /** 254 | * @brief Read the high-word from @a x 255 | * @param[in] x The input variable 256 | * @return The value of the high word taken from @a x 257 | */ 258 | inline uint32_t dWordWordHigh( uint32_t x ) 259 | { 260 | return static_cast( x >> 16U ); 261 | } 262 | /** 263 | * @brief Read the low-word from @a x 264 | * @param[in] x The input variable 265 | * @return The value of the low word taken from @a x 266 | */ 267 | inline uint32_t dWordWordLow( uint32_t x ) 268 | { 269 | return static_cast( x & 0xFFFFU ); 270 | } 271 | /** 272 | * @brief Merges two words to form one DWord. 273 | * @param[in] h The high byte 274 | * @param[in] l The low byte 275 | * @return The value of the resulting word 276 | */ 277 | inline uint32_t dwordMergeWords( uint32_t h, uint32_t l ) 278 | { 279 | return static_cast( ( h << 16U ) | ( 0xFFFFU & l ) ); 280 | } 281 | 282 | /** @}*/ 283 | } 284 | 285 | #endif /*QOS_CPP_HELPER*/ 286 | -------------------------------------------------------------------------------- /src/include/util.hpp: -------------------------------------------------------------------------------- 1 | #ifndef QOS_CPP_UTIL 2 | #define QOS_CPP_UTIL 3 | 4 | #include "include/types.hpp" 5 | 6 | 7 | namespace qOS { 8 | 9 | /** 10 | * @brief Utilities. 11 | */ 12 | namespace util { 13 | 14 | /** @addtogroup qioutils I/O Utils 15 | * @brief API for input/output utilities and safe string interfaces. 16 | * @{ 17 | */ 18 | 19 | /** 20 | * @brief Pointer to function that write-out a single character 21 | * @note User should use bare-metal code to implement this function. 22 | * Example : 23 | * @code{.c} 24 | * void BSP_PutChar( void *sp, const char c ) { 25 | * (void)sp; 26 | * HAL_UARTWriteByte( c ); 27 | * } 28 | * @endcode 29 | * @param[in] sp The user storage pointer. 30 | * @param[in] c The character to write out. 31 | * @return none. 32 | */ 33 | using putChar_t = void (*)( void* , const char ); 34 | 35 | /** 36 | * @brief Pointer to function that perform a single character I/O operation 37 | * @note User should use bare-metal code to implement this function. 38 | * Example 1: Input operation 39 | * @code{.c} 40 | * char BSP_GetChar( void *sp, const char in ) { 41 | * (void)sp; 42 | * (void)in; 43 | * return HAL_UARTReceiveByte( ); 44 | * } 45 | * @endcode 46 | * Example 2: Ouput operation 47 | * @code{.c} 48 | * char BSP_GetChar( void *sp, char in ) { 49 | * (void)sp; 50 | * HAL_UARTPutByte( in ); 51 | * return 0u; 52 | * } 53 | * @endcode 54 | * @param[in] sp The user storage pointer. 55 | * @param[in] in The byte to write out. 56 | * @return If an input operation is performed, this function should return 57 | * the byte read from the input. 58 | */ 59 | using ioFcn_t = char (*)( void *, const char ); 60 | 61 | /** 62 | * @brief Returns a pointer to the first occurrence of character in the C 63 | * string @a s. 64 | * The terminating null-character is considered part of the C string. 65 | * Therefore, it can also be located in order to retrieve a pointer to the 66 | * end of a string. 67 | * @param[in] s Pointer to the null-terminated byte string to be examined 68 | * @param[in] c Character to be located. It is passed as its int promotion, 69 | * but it is internally converted back to char for the comparison. 70 | * @param[in] maxlen Maximum number of characters to examine 71 | * @return A pointer to the first occurrence of character in @a s. 72 | * If the character is not found, the function returns a null pointer. 73 | */ 74 | char* strchr( const char *s, int c, size_t maxlen ) noexcept; 75 | /** 76 | * @brief Returns the length of the given null-terminated byte string, that 77 | * is, the number of characters in a character array whose first element is 78 | * pointed to by @a str up to and not including the first null character. 79 | * The function returns zero if @a str is a null pointer and returns 80 | * @a maxlen if the null character was not found in the first @a maxlen bytes 81 | * of @a str. 82 | * @param[in] s Pointer to the null-terminated byte string to be examined 83 | * @param[in] maxlen Maximum number of characters to examine 84 | * @return The length of the null-terminated byte string @a str on success, 85 | * zero if @a str is a null pointer, @a maxlen if the null character was 86 | * not found. 87 | */ 88 | size_t strlen( const char* s, size_t maxlen ) noexcept; 89 | /** 90 | * @brief Copies up to @a (maxlen - 1) characters from the null-terminated 91 | * string @a src to 92 | * @a dst, null-terminating the result. 93 | * @param[out] dst The destination string 94 | * @param[in] src The source string 95 | * @param[in] maxlen Maximum number of characters to copy 96 | * @return The length of @a src 97 | */ 98 | size_t strcpy( char * dst, const char * src, size_t maxlen ) noexcept; 99 | /** 100 | * @brief appends no more than @a maxlen−len(dst)−1 characters pointed to by 101 | * @a src into the array pointed to by @a dst and always terminates the 102 | * result with a null character if @a maxlen is greater than zero. Both 103 | * the strings @a dst and @a src must be terminated with a null character on 104 | * entry the function and a byte for the terminating null should be included 105 | * in @a maxlen. 106 | * @note The behavior of this function is undefined if copying takes 107 | * place between objects that overlap. 108 | * @param[out] dst The destination string 109 | * @param[in] src The source string 110 | * @param[in] maxlen Maximum number of characters to copy 111 | * @return returns the number of characters it tried to copy, which is the 112 | * sum of the lengths of the strings @a dst and @a src or @a n, whichever 113 | * is smaller. 114 | */ 115 | size_t strcat( char *dst, const char *src, size_t maxlen ) noexcept; 116 | /** 117 | * @brief Invert the endianess for n bytes of the specified memory location. 118 | * @param[in,out] pData A pointer to block of data 119 | * @param[in] n The number of bytes to swap 120 | * @return @c true on success, otherwise returns @c false. 121 | */ 122 | bool swapBytes( void *pData, const size_t n ) noexcept; 123 | /** 124 | * @brief Check the system endianess 125 | * @return @c true if Little-Endian, otherwise returns @c false. 126 | */ 127 | bool checkEndianness( void ) noexcept; 128 | /** 129 | * @brief API interface to write a string through @a fcn 130 | * @param[in] fcn The basic output byte function 131 | * @param[in] pStorage The storage pointer passed to @a fcn 132 | * @param[in] s The string to be written 133 | * @param[in] aip Auto-Increment the storage-pointer 134 | * @return @c true on success, otherwise returns @c false. 135 | */ 136 | bool outputString( util::putChar_t fcn, const char *s, void* pStorage = nullptr, bool aip = false ) noexcept; 137 | /** 138 | * @brief API interface to write data in HEX notation through @a fcn 139 | * @param[in] fcn The basic output byte function 140 | * @param[in] pStorage The storage pointer passed to @a fcn 141 | * @param[in] pData A pointer to the block of data 142 | * @param[in] n The number of bytes to print out 143 | * @param[in] eol @c true to enable the EOL(End-Of-Line) termination. 144 | * @return @c true on success, otherwise returns @c false. 145 | */ 146 | bool printXData( util::putChar_t fcn, void *pData, size_t n, bool eol = true, void* pStorage = nullptr ) noexcept; 147 | /** 148 | * @brief API interface to write n RAW data through @a fcn 149 | * @param[in] fcn The basic output byte function 150 | * @param[in] pData A pointer to the block of data 151 | * @param[in] n The number of bytes that will be transferred to the output 152 | * @param[in] pStorage The storage pointer passed to @a fcn 153 | * @param[in] aip Auto-increment the storage-pointer 154 | * @return @c true on success, otherwise returns @c false. 155 | */ 156 | bool outputRAW( const ioFcn_t fcn, void *pData, const size_t n, void* pStorage = nullptr, bool aip = false ) noexcept; 157 | /** 158 | * @brief API interface to get n RAW data through @a fcn 159 | * @param[in] fcn The basic input byte function 160 | * @param[out] pData A pointer to the block where the read data will be saved 161 | * @param[in] n The number of bytes to get 162 | * @param[in] pStorage The storage pointer passed to @a fcn 163 | * @param[in] aip Auto-increment the storage-pointer 164 | * @return @c true on success, otherwise returns @c false. 165 | */ 166 | bool inputRAW( const ioFcn_t fcn, void *pData, const size_t n, void* pStorage = nullptr, bool aip = false ) noexcept; 167 | /** 168 | * @brief Converts the input string consisting of hexadecimal digits into an 169 | * unsigned integer value. The input parameter should consist exclusively of 170 | * hexadecimal digits, with optional whitespaces. The string will be 171 | * processed one character at a time, until the function reaches a character 172 | * which it doesn't recognize (including a null character). 173 | * @param[in] s The hex string to be converted. 174 | * @return The numeric value as @c uint32_t. 175 | */ 176 | uint32_t hexStringToUnsigned( const char *s ) noexcept; 177 | /** 178 | * @brief Parses the C string @a s, interpreting its content as a floating 179 | * point number and returns its value as a float( @c float32_t). The function 180 | * first discards as many whitespace characters (as in isspace) as necessary 181 | * until the first non-whitespace character is found. Then, starting from 182 | * this character, takes as many characters as possible that are valid 183 | * following a syntax resembling that of floating point literals, and 184 | * interprets them as a numerical value. The rest of the string after the 185 | * last valid character is ignored and has no effect on the behavior of this 186 | * function. 187 | * @param[in] s The string beginning with the representation of a 188 | * floating-point number. 189 | * @return On success, the function returns the converted floating point 190 | * number as a float( @c qFloat32_t ) value. 191 | * If no valid conversion could be performed, the function returns zero (0.0f). 192 | * If the converted value would be out of the range of representable values 193 | * by a float( @c qFloat32_t ), it causes undefined behavior 194 | */ 195 | float64_t stringToFloat( const char *s ) noexcept; 196 | /** 197 | * @brief Converts a float value to a formatted string. 198 | * @param[in] num Value to be converted to a string. 199 | * @param[out] str Array in memory where to store the resulting 200 | * null-terminated string. 201 | * @param[in] precision Desired number of significant fractional digits in 202 | * the string. (default = 10u ) 203 | * @return A pointer to the resulting null-terminated string, same as 204 | * parameter @a str. 205 | */ 206 | char* floatToString( float32_t num, char *str, uint8_t precision = 10U ) noexcept; 207 | /** 208 | * @brief Converts a double value to a formatted string. 209 | * @param[in] num Value to be converted to a string. 210 | * @param[out] str Array in memory where to store the resulting 211 | * null-terminated string. 212 | * @param[in] precision Desired number of significant fractional digits in 213 | * the string. (default = 10u ) 214 | * @return A pointer to the resulting null-terminated string, same as 215 | * parameter @a str. 216 | */ 217 | char* doubleToString( float64_t num, char* str, uint8_t precision ) noexcept; 218 | /** 219 | * @brief Parses the C-string @a s interpreting its content as an integral 220 | * number, which is returned as a value of type int. The function first 221 | * discards as many whitespace characters (as in @c isspace) as necessary until 222 | * the first non-whitespace character is found. Then, starting from this 223 | * character, takes an optional initial plus or minus sign followed by as 224 | * many base-10 digits as possible, and interprets them as a numerical value. 225 | * The string can contain additional characters after those that form the 226 | * integral number, which are ignored and have no effect on the behavior of 227 | * this function. If the first sequence of non-whitespace characters in @a s 228 | * is not a valid integral number, or if no such sequence exists because 229 | * either @a s is empty or it contains only whitespace characters, no 230 | * conversion is performed and zero is returned. 231 | * @param[in] s The string beginning with the representation of a integer 232 | * number. 233 | * @return On success, the function returns the converted integral number as 234 | * an @c int value. 235 | * If the converted value would be out of the range of representable values 236 | * by an @c int, it causes undefined behavior. 237 | */ 238 | int stringToInt( const char *s ) noexcept; 239 | /** 240 | * @brief Converts an unsigned value to a null-terminated string using the 241 | * specified base and stores the result in the array given by @a str 242 | * parameter. The argument @a str should be an array long enough to contain 243 | * any possible value: @c "sizeof(int)*8+1" for radix=2, i.e. 17 bytes in 244 | * 16-bits platforms and 33 in 32-bits platforms. 245 | * @param[in] num Value to be converted to a string. 246 | * @param[out] str Array in memory where to store the resulting 247 | * null-terminated string. 248 | * @param[in] base Numerical base used to represent the value as a string, 249 | * between 2 and 36, where 10 means decimal base, 16 hexadecimal, 8 octal, 250 | * and 2 binary. 251 | * @return A pointer to the resulting null-terminated string, same as 252 | * parameter @a str. 253 | */ 254 | char* unsignedToString( unsigned_t num, char* str, uint8_t base = 10U ) noexcept; 255 | /** 256 | * @brief Converts an integer value to a null-terminated string using the 257 | * specified base and stores the result in the array given by @a str 258 | * parameter. If base is 10 and value is negative, the resulting string is 259 | * preceded with a minus sign (-). With any other base, value is always 260 | * considered unsigned. 261 | * 262 | * The argument @a str should be an array long enough to contain any possible 263 | * value: (sizeof(int)*8+1) for radix=2, i.e. 17 bytes in 16-bits platforms 264 | * and 33 in 32-bits platforms. 265 | * @param[in] num Value to be converted to a string. 266 | * @param[out] str Array in memory where to store the resulting 267 | * null-terminated string. 268 | * @param[in] base Numerical base used to represent the value as a string, 269 | * between 2 and 36, where 10 means decimal base, 16 hexadecimal, 8 octal, 270 | * and 2 binary. 271 | * @return A pointer to the resulting null-terminated string, same as 272 | * parameter @a str. 273 | */ 274 | char* integerToString( signed_t num, char* str, uint8_t base = 10U ) noexcept; 275 | /** 276 | * @brief Converts a pointer value to a null-terminated string. 277 | * The pointer address is formatted in hexadecimal notation. 278 | * The buffer provided in @a str must be large enough to hold the resulting 279 | * string, including the null terminator. 280 | * @param[in] ptr Pointer value to convert. 281 | * @param[out] str Array in memory where to store the resulting 282 | * null-terminated string. 283 | * @return A pointer to the resulting null-terminated string, same as 284 | * parameter @a str. 285 | */ 286 | char* pointerToString( const void *ptr, char* str ) noexcept; 287 | char* boolToString( const bool num, char *str ) noexcept; 288 | 289 | /** @}*/ 290 | } 291 | 292 | } 293 | 294 | #endif /*QOS_CPP_UTIL*/ 295 | -------------------------------------------------------------------------------- /src/list.cpp: -------------------------------------------------------------------------------- 1 | #include "include/list.hpp" 2 | 3 | using namespace qOS; 4 | 5 | /*============================================================================*/ 6 | void node::init( void ) noexcept 7 | { 8 | next = nullptr; 9 | prev = nullptr; 10 | container = nullptr; 11 | } 12 | /*============================================================================*/ 13 | list::list() noexcept 14 | { 15 | clean(); 16 | } 17 | /*============================================================================*/ 18 | bool list::isMember( const void * const xNode ) const noexcept 19 | { 20 | bool retValue = false; 21 | 22 | if ( nullptr != xNode ) { 23 | /*cstat -CERT-EXP36-C_b*/ 24 | const node * const Node = static_cast( xNode ); 25 | 26 | if ( this == Node->container ) { 27 | retValue = true; 28 | } 29 | /*cstat +CERT-EXP36-C_b*/ 30 | } 31 | 32 | return retValue; 33 | } 34 | /*============================================================================*/ 35 | void list::insertAtFront( node * const xNode ) noexcept 36 | { 37 | xNode->next = this->head; 38 | head->prev = xNode; 39 | head = xNode; 40 | } 41 | /*============================================================================*/ 42 | void list::insertAtBack( node * const xNode ) noexcept 43 | { 44 | tail->next = xNode; 45 | xNode->prev = tail; 46 | tail = xNode; 47 | } 48 | /*============================================================================*/ 49 | node* list::removeFront( void ) noexcept 50 | { 51 | node * const removed = head; 52 | 53 | head = removed->next; 54 | if ( nullptr == head ) { 55 | tail = head; 56 | } 57 | else { 58 | head->prev = nullptr; 59 | } 60 | 61 | return removed; 62 | } 63 | /*============================================================================*/ 64 | node* list::removeBack( void ) noexcept 65 | { 66 | node * const removed = tail; 67 | 68 | tail = removed->prev; 69 | if ( nullptr == tail ) { 70 | head = tail; 71 | } 72 | else { 73 | tail->next = nullptr; 74 | } 75 | 76 | return removed; 77 | } 78 | /*============================================================================*/ 79 | node* list::getNodeAtIndex( const listPosition p ) const noexcept 80 | { 81 | node *iNode; 82 | base_t iPos = 0; 83 | /*cstat -MISRAC++2008-0-1-2_b*/ 84 | for ( iNode = head ; ( iPos < static_cast( p ) ) && ( nullptr != iNode->next ) ; iNode = iNode->next ) { 85 | ++iPos; 86 | } 87 | /*cstat +MISRAC++2008-0-1-2_b*/ 88 | return iNode; 89 | } 90 | /*============================================================================*/ 91 | bool list::insert( void * const xNode, const listPosition p ) noexcept 92 | { 93 | bool retValue = false; 94 | 95 | if ( ( nullptr != xNode ) && ( p >= listPosition::AT_BACK ) ) { 96 | if ( !isMember( xNode ) ) { 97 | /*cstat -CERT-EXP36-C_b*/ 98 | node * const newNode = static_cast( xNode ); 99 | /*cstat +CERT-EXP36-C_b*/ 100 | newNode->init(); 101 | 102 | retValue = true; 103 | if ( nullptr == head ){ 104 | head = newNode; 105 | tail = newNode; 106 | } 107 | else if ( listPosition::AT_FRONT == p ) { 108 | insertAtFront( newNode ); 109 | } 110 | /*cstat -MISRAC++2008-0-1-2_a*/ 111 | else if ( listPosition::AT_BACK == p ) { 112 | insertAtBack( newNode ); 113 | } 114 | /*cstat +MISRAC++2008-0-1-2_a*/ 115 | else { 116 | node *iNode; 117 | iNode = getNodeAtIndex( p ); 118 | newNode->next = iNode->next; /* NEW -> (i+1)NODE */ 119 | newNode->prev = iNode; /* iNODE <- NEW */ 120 | iNode->next->prev = newNode; /* NEW <- (i+1)NODE */ 121 | iNode->next = newNode; /* iNODE -> NEW */ 122 | } 123 | ++size; 124 | newNode->container = this; 125 | } 126 | } 127 | 128 | return retValue; 129 | } 130 | /*============================================================================*/ 131 | bool list::remove( void * const xNode ) noexcept 132 | { 133 | bool retValue = false; 134 | 135 | if ( nullptr != xNode ) { 136 | /*cstat -CERT-EXP36-C_b*/ 137 | node * const toRemove = static_cast( xNode ); 138 | /*cstat +CERT-EXP36-C_b*/ 139 | 140 | if ( this == toRemove->container ) { 141 | if ( toRemove == head ) { 142 | (void)removeFront(); 143 | } 144 | else if ( toRemove == tail ) { 145 | (void)removeBack(); 146 | } 147 | else { 148 | toRemove->prev->next = toRemove->next; 149 | if ( nullptr != toRemove->next ) { 150 | toRemove->next->prev = toRemove->prev; 151 | } 152 | } 153 | --size; 154 | toRemove->container = nullptr; 155 | retValue = true; 156 | } 157 | } 158 | 159 | return retValue; 160 | } 161 | /*============================================================================*/ 162 | void* list::remove( const listPosition p, void * const xNode ) noexcept 163 | { 164 | node *removed = nullptr; 165 | 166 | if ( ( nullptr != head ) && ( p >= listPosition::AT_BACK ) ) { 167 | if ( isMember( xNode ) ) { 168 | if ( remove( xNode ) ) { 169 | /*cstat -CERT-EXP36-C_b*/ 170 | removed = static_cast( xNode ); 171 | /*cstat +CERT-EXP36-C_b*/ 172 | } 173 | } 174 | else { 175 | if ( listPosition::AT_FRONT == p ) { 176 | removed = removeFront(); 177 | } 178 | /*cstat -MISRAC++2008-0-1-2_a*/ 179 | else if ( listPosition::AT_BACK == p ) { 180 | removed = removeBack(); 181 | } 182 | /*cstat +MISRAC++2008-0-1-2_a*/ 183 | else { 184 | node *iNode; 185 | const base_t lastIndex = ( static_cast( p ) - 1 ); 186 | 187 | iNode = getNodeAtIndex( static_cast( lastIndex ) ); 188 | removed = iNode->next; /* <-> (inode0) <-> inode1 <-> inode2 */ 189 | iNode->next = removed->next; 190 | if ( nullptr != removed->next ) { 191 | iNode->next->prev = iNode; 192 | } 193 | } 194 | removed->container = nullptr; 195 | --size; 196 | } 197 | } 198 | 199 | return removed; 200 | } 201 | /*============================================================================*/ 202 | void* list::getFront( void ) const noexcept 203 | { 204 | return static_cast( head ); 205 | } 206 | /*============================================================================*/ 207 | void* list::getBack( void ) const noexcept 208 | { 209 | return static_cast( tail ); 210 | } 211 | /*============================================================================*/ 212 | bool list::isEmpty( void ) const noexcept 213 | { 214 | return ( nullptr == head ); 215 | } 216 | /*============================================================================*/ 217 | size_t list::length( void ) const noexcept 218 | { 219 | return size; 220 | } 221 | /*============================================================================*/ 222 | /*cstat -MISRAC++2008-7-1-2*/ 223 | bool list::sort( listCompareFcn_t f ) noexcept 224 | { 225 | /*cstat +MISRAC++2008-7-1-2*/ 226 | bool retValue = false; 227 | 228 | if ( nullptr != f ) { 229 | const size_t count = size; 230 | 231 | if ( count >= 2U ) { 232 | node *current = nullptr; 233 | node *before; 234 | node *after; 235 | bool xRetCmp; 236 | 237 | for ( size_t i = 1U ; i < count ; ++i ) { 238 | const size_t n = count - i - 1U; 239 | current = head; 240 | for ( size_t j = 0U; j <= n; ++j ) { 241 | xRetCmp = f( current, current->next ); 242 | if ( xRetCmp ) { 243 | before = current->prev; 244 | after = current->next; 245 | 246 | if ( nullptr != before ) { 247 | before->next = after; 248 | } 249 | else { 250 | head = after; 251 | } 252 | current->next = after->next; 253 | current->prev = after; 254 | 255 | if ( nullptr != after->next ) { 256 | after->next->prev = current; 257 | } 258 | 259 | after->next = current; 260 | after->prev = before; 261 | retValue = true; 262 | } 263 | else { 264 | current = current->next; 265 | } 266 | } 267 | } 268 | while ( nullptr != current->next ) { 269 | current = current->next; 270 | } 271 | tail = current; 272 | } 273 | } 274 | 275 | return retValue; 276 | } 277 | /*============================================================================*/ 278 | bool list::swap( void* node1, void* node2 ) noexcept 279 | { 280 | bool retValue = false; 281 | 282 | if ( ( nullptr != node1 ) && ( nullptr != node2 ) && ( node1 != node2 ) ) { 283 | /*cstat -CERT-EXP36-C_b*/ 284 | node *n1 = static_cast( node1 ); 285 | node *n2 = static_cast( node2 ); 286 | /*cstat +CERT-EXP36-C_b*/ 287 | if ( ( this == n1->container ) && ( n1->container == n2->container ) ) { 288 | /*nodes are part of the same list*/ 289 | node *tmp1; 290 | node *tmp2; 291 | 292 | if ( n2->next == n1 ) { 293 | /*cstat -CERT-EXP36-C_b*/ 294 | n1 = static_cast( node2 ); 295 | n2 = static_cast( node1 ); 296 | /*cstat +CERT-EXP36-C_b*/ 297 | } 298 | tmp1 = n1->prev; 299 | tmp2 = n2->next; 300 | givenNodeSwapBoundaries( n1, n2 ); 301 | givenNodeSwapAdjacent( n1, n2 ); 302 | n2->prev = tmp1; 303 | n1->next = tmp2; 304 | givenNodesUpdateOuterLinks( n1, n2 ); 305 | retValue = true; 306 | } 307 | } 308 | 309 | return retValue; 310 | } 311 | /*============================================================================*/ 312 | void list::givenNodeSwapBoundaries( node *n1, node *n2 ) noexcept 313 | { 314 | if ( head == n1 ) { 315 | head = n2; 316 | } 317 | else if ( head == n2 ) { 318 | head = n1; 319 | } 320 | else { 321 | /*nothing to do here*/ 322 | } 323 | if ( tail == n1 ) { 324 | tail = n2; 325 | } 326 | else if ( tail == n2 ) { 327 | tail = n1; 328 | } 329 | else { 330 | /*nothing to do here*/ 331 | } 332 | } 333 | /*============================================================================*/ 334 | void list::givenNodeSwapAdjacent( node *n1, node *n2 ) noexcept 335 | { 336 | if ( ( ( n1->next == n2 ) && ( n2->prev == n1 ) ) || ( ( n1->prev == n2 ) && ( n2->next == n1 ) ) ) { 337 | n1->prev = n1->next; 338 | n2->next = n2->prev; 339 | } 340 | else { 341 | n1->prev = n2->prev; 342 | n2->next = n1->next; 343 | } 344 | } 345 | /*============================================================================*/ 346 | void list::givenNodesUpdateOuterLinks( node *n1, node *n2 ) noexcept 347 | { 348 | if ( nullptr != n1->prev ) { 349 | n1->prev->next = n1; 350 | } 351 | if ( nullptr != n1->next ) { 352 | n1->next->prev = n1; 353 | } 354 | if ( nullptr != n2->prev ) { 355 | n2->prev->next = n2; 356 | } 357 | if ( nullptr != n2->next ) { 358 | n2->next->prev = n2; 359 | } 360 | } 361 | /*============================================================================*/ 362 | bool list::move( list& src, const listPosition p ) noexcept 363 | { 364 | bool retValue = false; 365 | 366 | if ( ( nullptr != src.head) && ( p >= listPosition::AT_BACK ) ) { 367 | node *iNode; 368 | /* cppcheck-suppress postfixOperator */ 369 | for ( listIterator i = src.begin() ; i.untilEnd() ; i++ ) { 370 | iNode = i.get(); 371 | iNode->container = this; 372 | } 373 | if ( nullptr == head ) { /*destination is empty*/ 374 | head = src.head; 375 | tail = src.tail; 376 | } 377 | else if ( AT_FRONT == p ) { 378 | src.tail->next = head; 379 | head->prev = src.tail; 380 | head = src.head; 381 | } 382 | /*cstat -MISRAC++2008-0-1-2_a*/ 383 | else if ( AT_BACK == p ) { 384 | tail->next = src.head; 385 | src.head->prev = tail; 386 | tail = src.tail; 387 | } 388 | /*cstat +MISRAC++2008-0-1-2_a*/ 389 | else { 390 | iNode = getNodeAtIndex( p ); 391 | src.tail->next = iNode->next; 392 | src.head->prev = iNode; 393 | iNode->next = src.head; 394 | } 395 | size += src.size; 396 | src.clean(); 397 | retValue = true; 398 | } 399 | 400 | return retValue; 401 | } 402 | /*============================================================================*/ 403 | void list::clean( void ) noexcept 404 | { 405 | head = nullptr; 406 | tail = nullptr; 407 | size = 0U; 408 | } 409 | /*============================================================================*/ 410 | listIterator list::begin( void ) noexcept 411 | { 412 | listIterator it( *this, listDirection::FORWARD, nullptr ); 413 | return it; 414 | } 415 | /*============================================================================*/ 416 | listIterator list::end( void ) noexcept 417 | { 418 | listIterator it( *this, listDirection::BACKWARD, nullptr ); 419 | return it; 420 | } 421 | /*============================================================================*/ 422 | listIterator list::from( void *offset ) noexcept 423 | { 424 | listIterator it( *this, listDirection::FORWARD, offset ); 425 | return it; 426 | } 427 | /*============================================================================*/ 428 | listIterator::listIterator( list& xList, listDirection dir, void *nodeOffset ) noexcept 429 | { 430 | node *ret; 431 | /*cstat -CERT-EXP36-C_b*/ 432 | node * const offset = static_cast( nodeOffset ); 433 | /*cstat +CERT-EXP36-C_b*/ 434 | l = &xList; 435 | if ( listDirection::FORWARD == dir ) { 436 | ret = ( xList.isMember( nodeOffset ) ) ? offset : xList.head; 437 | iter = ( nullptr != ret ) ? ret->next : nullptr; 438 | } 439 | else { 440 | ret = ( xList.isMember( nodeOffset ) ) ? offset : xList.tail; 441 | iter = ( nullptr != ret ) ? ret->prev : nullptr; 442 | } 443 | current = static_cast( ret ); 444 | } 445 | /*============================================================================*/ 446 | bool listIterator::untilEnd( void ) const noexcept 447 | { 448 | return ( nullptr != current ); 449 | } 450 | /*============================================================================*/ 451 | bool listIterator::untilEnd( void* node ) const noexcept 452 | { 453 | return ( l->isMember( node ) ) && ( node != current ); 454 | } 455 | /*============================================================================*/ 456 | listIterator& listIterator::operator++( int ) noexcept 457 | { 458 | node * const ret = iter; 459 | iter = ( nullptr != iter ) ? iter->next : nullptr; 460 | current = static_cast( ret ); 461 | return *this; 462 | } 463 | /*============================================================================*/ 464 | listIterator& listIterator::operator--( int ) noexcept 465 | { 466 | node * const ret = iter; 467 | iter = ( nullptr != iter ) ? iter->prev : nullptr; 468 | current = static_cast( ret ); 469 | return *this; 470 | } 471 | /*============================================================================*/ 472 | -------------------------------------------------------------------------------- /src/include/list.hpp: -------------------------------------------------------------------------------- 1 | #ifndef QOS_CPP_LIST 2 | #define QOS_CPP_LIST 3 | 4 | #include "include/types.hpp" 5 | 6 | namespace qOS { 7 | 8 | /** 9 | * @addtogroup qlists 10 | * @brief The provided list implementation uses a generic doubly-linked 11 | * approach in which each node, apart from storing its data, has two link 12 | * pointers. The first link points to the previous node in the list and the 13 | * second link, points to the next node in the list. The first node of the 14 | * list has its previous link pointing to @c nullptr, similarly, the last node 15 | * of the list has its next node pointing to @c nullptr. 16 | * 17 | * The list data-structure, referenced through an object of type qList_t 18 | * also has a head and a tail pointer, to allow fast operations on boundary 19 | * nodes. 20 | * 21 | *
22 | * @htmlonly 23 | * 24 | * 25 | * 26 | * qlist 27 | * 28 | * 29 | *
30 | * 31 | * 32 | * 33 | * @endhtmlonly 34 | * Doubly-linked list implementation 35 | *
36 | * 37 | * Nodes should be an user-defined class inherited fromt he node class 38 | * 39 | * @code{.c} 40 | * class mynode : public node { 41 | * int a; 42 | * int b; 43 | * float y; 44 | * }; 45 | * @endcode 46 | * 47 | * @{ 48 | */ 49 | 50 | /** 51 | * @brief An enum with the possible options to specify a target position for a list. 52 | */ 53 | enum listPosition : int32_t { 54 | AT_FRONT = -1, 55 | AT_BACK = -2 56 | }; 57 | 58 | class list; 59 | /** 60 | * @brief A list-node object (Used internally) 61 | */ 62 | class node { 63 | private: 64 | node *next{ nullptr }; 65 | node *prev{ nullptr }; 66 | list *container{ nullptr }; 67 | void init( void ) noexcept; 68 | node( node const& ) = delete; 69 | void operator=( node const& ) = delete; 70 | public: 71 | /** 72 | * @brief Get a pointer to the list in which this node is contained. 73 | * @return A pointer to the list container. 74 | */ 75 | inline list* getContainer( void ) const noexcept 76 | { 77 | /*cstat -CONST-member-ret -MISRAC++2008-9-3-1*/ 78 | return container; 79 | /*cstat +CONST-member-ret +MISRAC++2008-9-3-1*/ 80 | } 81 | node() noexcept : next(nullptr), prev(nullptr), container(nullptr) {} 82 | /*! @cond */ 83 | virtual ~node() {} 84 | /*! @endcond */ 85 | 86 | friend class list; 87 | friend class listIterator; 88 | }; 89 | 90 | /** 91 | * @brief Pointer to a function used by the list::sort() method to compare 92 | * nodes of a list. 93 | * 94 | * Example : 95 | * @code{.c} 96 | * bool myNode_CompareFcn( const void *n1, const void *n2 ) { 97 | * mydata_t *node1 = (mydata_t *)n1; 98 | * mydata_t *node2 = (mydata_t *)n2; 99 | * return ( node1->x > node2->x ); 100 | * } 101 | * @endcode 102 | * @param[in] h The handler object containing the objects being compared. 103 | * @return @c true value indicates that element pointed by @a node1 goes 104 | * after the element pointed to by @a node2 105 | */ 106 | using listCompareFcn_t = bool (*)( const void *, const void * ); 107 | 108 | /** 109 | * @brief An enum with the possible options to transverse a list. 110 | */ 111 | enum class listDirection { 112 | FORWARD, 113 | BACKWARD 114 | }; 115 | 116 | class listIterator; 117 | 118 | /** 119 | * @brief A list object (Generic double-linked) 120 | */ 121 | class list : protected node { 122 | private: 123 | node *head{ nullptr }; 124 | node *tail{ nullptr }; 125 | size_t size{ 0U }; 126 | bool isMember( const void * const xNode ) const noexcept; 127 | void insertAtFront( node * const xNode ) noexcept; 128 | void insertAtBack( node * const xNode ) noexcept; 129 | node* removeFront( void ) noexcept; 130 | node* removeBack( void ) noexcept; 131 | node* getNodeAtIndex( const listPosition p ) const noexcept; 132 | void givenNodeSwapBoundaries( node *n1, node *n2 ) noexcept; 133 | static void givenNodeSwapAdjacent( node *n1, node *n2 ) noexcept; 134 | static void givenNodesUpdateOuterLinks( node *n1, node *n2 ) noexcept; 135 | list( list const& ) = delete; 136 | void operator=( list const& ) = delete; 137 | public: 138 | list() noexcept; 139 | /*! @cond */ 140 | virtual ~list() {} 141 | /*! @endcond */ 142 | /** 143 | * @brief Insert an item into the list. 144 | * @param[in] xNode A pointer to the node to be inserted 145 | * @param[in] p The position where the node will be inserted. Could be 146 | * listPosition::AT_FRONT, listPosition::AT_BACK or any other index 147 | * number where the node will be inserted after. 148 | * @return @c true if the item was successfully added to the list, otherwise 149 | * returns @c false 150 | */ 151 | bool insert( void * const xNode, const listPosition p = listPosition::AT_BACK ) noexcept; 152 | /** 153 | * @brief If the node is member of a list, the node will be removed from it. 154 | * @param[in] xNode A pointer to the node. 155 | * @return @c true on Success. @c false if removal can't be performed. 156 | */ 157 | bool remove( void * const xNode ) noexcept; 158 | /** 159 | * @brief Remove an item from the list. 160 | * @param[in] p The position of the node that will be removed. Could be 161 | * listPosition::AT_FRONT, listPosition::AT_BACK or any other index 162 | * number. 163 | * @param[in] xNode A pointer to the node to be deleted (to ignore 164 | * pass @c nullptr ). 165 | * @return A pointer to the removed node. @c nullptr if removal 166 | * can not be performed. 167 | */ 168 | void* remove( const listPosition p, void * const xNode = nullptr ) noexcept; 169 | /** 170 | * @brief Get a pointer to the front item of the list 171 | * @return A pointer to the front node. @c nullptr if the list is empty 172 | */ 173 | void* getFront( void ) const noexcept; 174 | /** 175 | * @brief Get a pointer to the back item of the list 176 | * @return A pointer to the back node. @c nullptr if the list is empty 177 | */ 178 | void* getBack( void ) const noexcept; 179 | /** 180 | * @brief Check if the list is empty. 181 | * @return @c true if the list is empty, @c false if it is not. 182 | */ 183 | bool isEmpty( void ) const noexcept; 184 | /** 185 | * @brief Get the number of items inside the list. 186 | * @return The number of items of the list. 187 | */ 188 | size_t length( void ) const noexcept; 189 | /** 190 | * @brief Sort the double linked list using the @a f function to 191 | * determine the order. The sorting algorithm used by this function compares 192 | * pairs of adjacent nodes by calling the specified @a f function 193 | * with pointers to them as arguments. The sort is performed only 194 | * modifying node's links without data swapping, improving performance if 195 | * nodes have a large storage. 196 | * @note The function modifies the content of the list by reordering its 197 | * elements as defined by @a f. 198 | * @param[in] f Pointer to a function that compares two nodes. 199 | * This function is called repeatedly by list::sort() to compare two nodes. 200 | * It shall follow the following prototype: 201 | * @code bool CompareFcn( listCompareHandle_t h ) @endcode 202 | * 203 | * The function defines the order of the elements by returning a Boolean data, 204 | * where a @c true value indicates that element pointed by @a node1 goes 205 | * after the element pointed to by @a node2. 206 | * @return @c true if at least one reordering is performed over the list. 207 | */ 208 | bool sort( listCompareFcn_t f ) noexcept; 209 | /** 210 | * @brief Swap two nodes that belongs to the list by changing its own 211 | * links. 212 | * @note The list containing nodes will be updated if any node is part 213 | * of the boundaries. 214 | * @param[in] node1 Pointer to the first node. 215 | * @param[in] node2 Pointer to the second node. 216 | * @return @c true if the swap operation is performed. Otherwise returns 217 | * @c false. 218 | */ 219 | bool swap( void* node1, void* node2 ) noexcept; 220 | /** 221 | * @brief Moves(or merge) the entire list @a src to the given list. 222 | * After the move operation, this function leaves empty the list 223 | * given by @a src. 224 | * @param[in] src Source list to be moved. 225 | * @param[in] p The position where @a src list will be inserted. 226 | * Could be listPosition::AT_FRONT, listPosition::AT_BACK or any 227 | * other index number. 228 | * @return @c true if the move operation is performed successfully, 229 | * otherwise returns @c false 230 | */ 231 | bool move( list& src, const listPosition p = listPosition::AT_BACK ) noexcept; 232 | /** 233 | * @brief Clean up the entire list leaving it empty 234 | */ 235 | void clean( void ) noexcept; 236 | /** 237 | * @brief Returns an iterator pointing to the first element in the 238 | * list container. 239 | * @return An iterator to the beginning of the sequence container. 240 | */ 241 | listIterator begin( void ) noexcept; 242 | /** 243 | * @brief Returns an iterator pointing to the last element in the 244 | * list container. 245 | * @return An iterator to the latest item of the sequence container. 246 | */ 247 | listIterator end( void ) noexcept; 248 | /** 249 | * @brief Returns an iterator pointing to the element given by 250 | * @a offset in the list container. 251 | * @return An iterator to the @a offset of the sequence container. 252 | */ 253 | listIterator from( void *offset ) noexcept; 254 | /** 255 | * @brief Check if the list has items (is non-empty). 256 | * @return @c true if instance has items 257 | */ 258 | explicit operator bool() const noexcept { 259 | return ( nullptr != head ); 260 | } 261 | friend class listIterator; 262 | }; 263 | 264 | /** 265 | * @brief A list iterator 266 | */ 267 | class listIterator { 268 | private: 269 | list *l{ nullptr }; 270 | node *iter{ nullptr }; 271 | void *current{ nullptr }; 272 | public: 273 | listIterator() = delete; 274 | /*! @cond */ 275 | virtual ~listIterator() {} 276 | /*! @endcond */ 277 | /** 278 | * @brief Instantiate a list iterator for the given list. 279 | * @param[in] xList The list 280 | * @param[in] dir The direction in which the iterator will traverse 281 | * the list 282 | * @param[in] nodeOffset A pointer to the node offset in the list 283 | */ 284 | explicit listIterator( list& xList, listDirection dir = listDirection::FORWARD, void *nodeOffset = nullptr ) noexcept; 285 | /** 286 | * @brief Check until current iterator reach one of its ends 287 | * @return @c true if the iterator has reach on of its ends. 288 | */ 289 | bool untilEnd( void ) const noexcept; 290 | /** 291 | * @brief Check until current iterator reach the given node 292 | * @param[in] node A pointer to the node you want to reach 293 | * @return @c true if the iterator has reach the given node. 294 | */ 295 | bool untilEnd( void* node ) const noexcept; 296 | /** 297 | * @brief Move the iterator forward 298 | */ 299 | listIterator& operator++( int ) noexcept; 300 | /** 301 | * @brief Move the iterator backward 302 | */ 303 | listIterator& operator--( int ) noexcept; 304 | /** 305 | * @brief Gets the node that the iterator is currently pointing to. 306 | * @return A pointer to the node currently being pointed. 307 | */ 308 | template 309 | inline T get( void ) noexcept 310 | { 311 | /*cstat -CERT-EXP36-C_b*/ 312 | return static_cast( current ); 313 | /*cstat +CERT-EXP36-C_b*/ 314 | } 315 | }; 316 | /** @}*/ 317 | } 318 | 319 | #endif /*QOS_CPP_LIST*/ 320 | -------------------------------------------------------------------------------- /src/include/logger.hpp: -------------------------------------------------------------------------------- 1 | #ifndef QOS_CPP_LOGGER 2 | #define QOS_CPP_LOGGER 3 | 4 | #include "include/types.hpp" 5 | #include "include/util.hpp" 6 | #include "include/clock.hpp" 7 | #include "include/task.hpp" 8 | #include "include/fsm.hpp" 9 | #include "include/timer.hpp" 10 | #include "include/input.hpp" 11 | #include "include/queue.hpp" 12 | #include "include/memory.hpp" 13 | #include "config/config.h" 14 | 15 | namespace qOS { 16 | 17 | /** @addtogroup qlogger Logger 18 | * @brief API interfaces to print out logging messages. 19 | * @{ 20 | */ 21 | 22 | #ifdef DOXYGEN 23 | /** 24 | * @brief The global class to output logging streams. Its usage requires 25 | * the static method: logger::out() 26 | */ 27 | class logger final { 28 | public: 29 | /** 30 | * @brief Specify a new logger output with severity level of 31 | * information (if defined). 32 | * @note Should be used only at the beginning of logger stream 33 | * @param[in] s Severity of the message 34 | * 35 | * Example 1: 36 | * @code{.c} 37 | * logger::out() << "some message" << logger::endl; 38 | * @endcode 39 | * Example 2: 40 | * @code{.c} 41 | * logger::out(logger::info) << "some information message" << logger::endl; 42 | * @endcode 43 | * Example 3: 44 | * @code{.c} 45 | * logger::out(logger::debug) << "some debug message" << logger::endl; 46 | * @endcode 47 | */ 48 | static logger& out( const logSeverity s ); 49 | /** 50 | * @brief Specify that the variable given by @a v should be printed 51 | * with its own name : = 52 | * @param[in] v variable to be logged 53 | * @code{.c} 54 | * int myVariable; 55 | * logger::out() << logger::var( myVariable ) << logger::endl; 56 | * @endcode 57 | */ 58 | static logger& var( const void &v ); 59 | }; 60 | #endif 61 | 62 | /** 63 | * @brief Logger interfaces. 64 | */ 65 | namespace logger { 66 | 67 | /** @addtogroup qlogger 68 | * @{ 69 | */ 70 | 71 | /*! @cond */ 72 | struct source_location { 73 | public: 74 | #if not defined(__apple_build_version__) and defined(__clang__) and (__clang_major__ >= 9) 75 | static constexpr source_location current(const char* fileName = __builtin_FILE(), 76 | const char* functionName = __builtin_FUNCTION(), 77 | const unsigned long lineNumber = __builtin_LINE(), 78 | const unsigned long columnOffset = __builtin_COLUMN() ) noexcept 79 | #elif defined(__GNUC__) and (__GNUC__ > 4 or (__GNUC__ == 4 and __GNUC_MINOR__ >= 8)) 80 | static constexpr source_location current(const char* fileName = __builtin_FILE(), 81 | const char* functionName = __builtin_FUNCTION(), 82 | const unsigned long lineNumber = __builtin_LINE(), 83 | const unsigned long columnOffset = 0 ) noexcept 84 | #else 85 | static constexpr source_location current(const char* fileName = "unsupported", 86 | const char* functionName = "unsupported", 87 | const unsigned long lineNumber = __LINE__, 88 | const unsigned long columnOffset = 0) noexcept 89 | #endif 90 | { 91 | return source_location( fileName, functionName, lineNumber, columnOffset ); // skipcq: CXX-W2033 92 | } 93 | 94 | source_location( const source_location & ) = default; 95 | source_location( source_location && ) = default; 96 | 97 | constexpr const char* file_name( void ) const noexcept 98 | { 99 | return fileName; 100 | } 101 | 102 | constexpr const char* function_name( void ) const noexcept 103 | { 104 | return functionName; 105 | } 106 | 107 | constexpr unsigned long line( void ) const noexcept 108 | { 109 | return lineNumber; 110 | } 111 | 112 | constexpr unsigned long column( void ) const noexcept 113 | { 114 | return columnOffset; 115 | } 116 | 117 | private: 118 | constexpr source_location( const char* FileName, const char* FunctionName, const unsigned long LineNumber, const unsigned long ColumnOffset ) noexcept 119 | : fileName(FileName), functionName(FunctionName), lineNumber(LineNumber), columnOffset(ColumnOffset) {} 120 | 121 | const char* fileName; 122 | const char* functionName; 123 | const unsigned long lineNumber; // skipcq: CXX-W2010 124 | const unsigned long columnOffset; // skipcq: CXX-W2010 125 | }; 126 | 127 | class lout_base final { 128 | public: 129 | uint8_t base; 130 | explicit lout_base(uint8_t b) : base(b) {} 131 | }; 132 | /*! @endcond */ 133 | 134 | enum logSeverity { 135 | none = 0, 136 | fatal = 1, 137 | error = 2, 138 | warning = 3, 139 | info = 4, 140 | debug = 5, 141 | verbose = 6, 142 | }; 143 | 144 | /** 145 | * @brief Class that sets the number of bytes to be logged when a pointer 146 | * is being used after. 147 | * Example: 148 | * @code{.c} 149 | * uint32_t myNumber = 0xAABBCCDD; 150 | * logger::out() << logger::mem( sizeof(myNumber ) ) << &myNumber << logger::endl; 151 | * @endcode 152 | */ 153 | class mem final { 154 | public: 155 | /*! @cond */ 156 | size_t n; 157 | /*! @endcond */ 158 | /** 159 | * @brief Instantiates a memory specifier to logger @a nb bytes. 160 | * @param[in] nb Number of bytes to be logged. 161 | */ 162 | explicit mem( size_t nb ) : n( nb ) {} 163 | }; 164 | 165 | /** 166 | * @brief Class that sets the decimal precision to be used to format 167 | * floating-point values on logger operations. 168 | * Example: 169 | * @code{.c} 170 | * float myNumber = 3.5787154; 171 | * logger::out() << logger::pre( 5 ) << myNumber << logger::endl; 172 | * @endcode 173 | */ 174 | class pre final { 175 | public: 176 | /*! @cond */ 177 | uint8_t precision; 178 | /*! @endcond */ 179 | /** 180 | * @brief Instantiates a precision specifier of @a p decimal points. 181 | * @param[in] p Number of decimal points for the precision 182 | */ 183 | explicit pre( uint8_t p ) : precision( p ) {} 184 | }; 185 | 186 | /** 187 | * @brief Modifies the default numeric base to decimal for integer 188 | * logger output 189 | * Example: 190 | * @code{.c} 191 | * uint16_t myNumber = 1000; 192 | * logger::out() << logger::dec << myNumber << logger::endl; 193 | * @endcode 194 | */ 195 | extern const lout_base dec; 196 | /** 197 | * @brief Modifies the default numeric base to hexadecimal for integer 198 | * logger output 199 | * Example: 200 | * @code{.c} 201 | * uint16_t myNumber = 1000; 202 | * logger::out() << logger::hex << myNumber << logger::endl; 203 | * @endcode 204 | */ 205 | extern const lout_base hex; 206 | /** 207 | * @brief Modifies the default numeric base to octal for integer 208 | * logger output 209 | * Example: 210 | * @code{.c} 211 | * uint16_t myNumber = 1000; 212 | * logger::out() << logger::oct << myNumber << logger::endl; 213 | * @endcode 214 | */ 215 | extern const lout_base oct; 216 | /** 217 | * @brief Modifies the default numeric base to binary for integer 218 | * logger output 219 | * Example: 220 | * @code{.c} 221 | * uint16_t myNumber = 1000; 222 | * logger::out() << logger::bin << myNumber << logger::endl; 223 | * @endcode 224 | */ 225 | extern const lout_base bin; 226 | /** 227 | * @brief Inserts a new-line character to the logger output. 228 | * Example: 229 | * @code{.c} 230 | * logger::out() << "hello world!" << logger::endl; 231 | * @endcode 232 | */ 233 | extern const char * const endl; 234 | /** 235 | * @brief Inserts a new-line character to the logger output and restore 236 | * the default color 237 | * Example: 238 | * @code{.c} 239 | * logger::out() << "hello world!" << logger::end; 240 | * @endcode 241 | */ 242 | extern const char * const end; 243 | /** 244 | * @brief Set colored output to "normal" after the usage of this statement 245 | * Example: 246 | * @code{.c} 247 | * logger::out() << logger::nrm <<"normal colored!" << logger::end; 248 | * @endcode 249 | */ 250 | extern const char * const nrm; 251 | /** 252 | * @brief Set colored output to "red" after the usage of this statement 253 | * Example: 254 | * @code{.c} 255 | * logger::out() << logger::red <<"red colored!" << logger::end; 256 | * @endcode 257 | */ 258 | extern const char * const red; 259 | /** 260 | * @brief Set colored output to "green" after the usage of this statement 261 | * Example: 262 | * @code{.c} 263 | * logger::out() << logger::grn <<"green colored!" << logger::end; 264 | * @endcode 265 | */ 266 | extern const char * const grn; 267 | /** 268 | * @brief Set colored output to "yellow" after the usage of this statement 269 | * Example: 270 | * @code{.c} 271 | * logger::out() << logger::yel <<"yellow colored!" << logger::end; 272 | * @endcode 273 | */ 274 | extern const char * const yel; 275 | /** 276 | * @brief Set colored output to "blue" after the usage of this statement 277 | * Example: 278 | * @code{.c} 279 | * logger::out() << logger::blu <<"blue colored!" << logger::end; 280 | * @endcode 281 | */ 282 | extern const char * const blu; 283 | /** 284 | * @brief Set colored output to "magenta" after the usage of this statement 285 | * Example: 286 | * @code{.c} 287 | * logger::out() << logger::mag <<"magenta colored!" << logger::end; 288 | * @endcode 289 | */ 290 | extern const char * const mag; 291 | /** 292 | * @brief Set colored output to "cyan" after the usage of this statement 293 | * Example: 294 | * @code{.c} 295 | * logger::out() << logger::cyn <<"cyan colored!" << logger::end; 296 | * @endcode 297 | */ 298 | extern const char * const cyn; 299 | /** 300 | * @brief Set colored output to "white" after the usage of this statement 301 | * Example: 302 | * @code{.c} 303 | * logger::out() << logger::wht <<"white colored!" << logger::end; 304 | * @endcode 305 | */ 306 | extern const char * const wht; 307 | 308 | struct ChainLoggerProxy; 309 | 310 | /*! @cond */ 311 | class _logger final : private nonCopyable { 312 | private: 313 | _logger() = default; 314 | _logger( _logger &other ) = delete; 315 | void operator=( const _logger & ) = delete; 316 | const char *s_str[ 7 ] = { "", "[fatal]: ", "[error]: ", "[warning]: ", "[info]: ", "[debug] ", "" }; // skipcq: CXX-W2066 317 | uint8_t base = { 10U }; 318 | size_t n{ 0U }; 319 | uint8_t precision { 6U }; 320 | #if ( Q_TRACE_BUFSIZE < 36 ) 321 | #define Q_TRACE_BUFSIZE ( 36 ) 322 | #endif 323 | char buffer[ Q_TRACE_BUFSIZE ] = { 0 }; // skipcq: CXX-W2066 324 | char preFix[ 5 ] = { 0 }; // skipcq: CXX-W2066 325 | util::putChar_t writeChar{ nullptr }; 326 | void writeNumStr( void ) noexcept; 327 | public: 328 | static _logger& getInstance( void ) noexcept; 329 | 330 | template 331 | auto toLog(const T& v) -> decltype((void)(T(1) % 1), (void)(-T(1)), void()) // only valid for integrals 332 | { 333 | /*cstat -CERT-INT31-C_a -MISRAC++2008-5-0-8 -MISRAC++2008-5-0-9 -MISRAC++2008-0-1-2_b -MISRAC++2008-0-1-2_a*/ 334 | if (T(-1) < T(0)) { 335 | (void)util::integerToString(static_cast(v), buffer, base); // skipcq: CXX-C1000 336 | } else { 337 | (void)util::unsignedToString(static_cast(v), buffer, base); // skipcq: CXX-C1000 338 | } 339 | /*cstat +CERT-INT31-C_a +MISRAC++2008-5-0-8 +MISRAC++2008-5-0-9 +MISRAC++2008-0-1-2_b +MISRAC++2008-0-1-2_a*/ 340 | writeNumStr(); 341 | } 342 | 343 | void toLog( const char& v ); 344 | void toLog( const char * s ); 345 | void toLog( const void * const p ); 346 | 347 | void toLog( const float32_t& v ); 348 | void toLog( const float64_t& v ); 349 | void toLog( const lout_base& f ); 350 | void toLog( const mem& m ); 351 | void toLog( const pre& m ); 352 | void toLog( const qOS::task& t ); 353 | void toLog( const qOS::timer& t ); 354 | void toLog( const qOS::stateMachine& sm ); 355 | void toLog( const qOS::sm::state& s ); 356 | void toLog( const qOS::trigger& t ); 357 | void toLog( const qOS::globalState& s ); 358 | void toLog( const qOS::taskEvent& e ); 359 | void toLog( const qOS::taskState& v ); 360 | void toLog( const qOS::queue& v ); 361 | void toLog( const qOS::mem::pool& v ); 362 | void toLog( const qOS::input::channel& in ); 363 | void toLog( const qOS::input::watcher& v ); 364 | void toLog( const qOS::sm::signalID& v ); 365 | void toLog( const qOS::sm::status& v ); 366 | void toLog( const qOS::sm::stateHandler& v ); 367 | void toLog( const qOS::string & s ); 368 | 369 | friend ChainLoggerProxy out( const logSeverity s, const source_location &loc ) noexcept; 370 | friend void setOutputFcn( util::putChar_t fcn ); 371 | friend class ChainLoggerProxy; 372 | }; 373 | extern _logger& _logger_out; // skipcq: CXX-W2011, CXX-W2009 374 | 375 | #define IMPL_CHAIN_LOGGER_OPERATOR( Type ) \ 376 | ChainLoggerProxy& operator<<( Type v ) \ 377 | { \ 378 | parent.toLog( v ); \ 379 | return *this; \ 380 | } \ 381 | 382 | struct ChainLoggerProxy { 383 | _logger& parent; // skipcq: CXX-W2010 384 | explicit ChainLoggerProxy( _logger& p) : parent(p) {} 385 | ChainLoggerProxy( const ChainLoggerProxy& ) = delete; 386 | ChainLoggerProxy( ChainLoggerProxy&& other ) noexcept : parent( other.parent ) {} 387 | ~ChainLoggerProxy(); 388 | 389 | template 390 | auto operator<<(const T& v) -> decltype((void)(v + 0), *this) 391 | { 392 | parent.toLog( v ); 393 | return *this; 394 | } 395 | IMPL_CHAIN_LOGGER_OPERATOR( const char& ) 396 | IMPL_CHAIN_LOGGER_OPERATOR( const char * ) 397 | IMPL_CHAIN_LOGGER_OPERATOR( const void * const ) 398 | IMPL_CHAIN_LOGGER_OPERATOR( const lout_base& ) 399 | IMPL_CHAIN_LOGGER_OPERATOR( const mem& ) 400 | IMPL_CHAIN_LOGGER_OPERATOR( const pre& ) 401 | IMPL_CHAIN_LOGGER_OPERATOR( const qOS::task& ) 402 | IMPL_CHAIN_LOGGER_OPERATOR( const qOS::timer& ) 403 | IMPL_CHAIN_LOGGER_OPERATOR( const qOS::stateMachine& ) 404 | IMPL_CHAIN_LOGGER_OPERATOR( const qOS::sm::state& ) 405 | IMPL_CHAIN_LOGGER_OPERATOR( const qOS::trigger& ) 406 | IMPL_CHAIN_LOGGER_OPERATOR( const qOS::globalState& ) 407 | IMPL_CHAIN_LOGGER_OPERATOR( const qOS::taskEvent& ) 408 | IMPL_CHAIN_LOGGER_OPERATOR( const qOS::taskState& ) 409 | IMPL_CHAIN_LOGGER_OPERATOR( const qOS::queue& ) 410 | IMPL_CHAIN_LOGGER_OPERATOR( const qOS::mem::pool& ) 411 | IMPL_CHAIN_LOGGER_OPERATOR( const qOS::input::channel& ) 412 | IMPL_CHAIN_LOGGER_OPERATOR( const qOS::input::watcher& ) 413 | IMPL_CHAIN_LOGGER_OPERATOR( const qOS::sm::signalID& ) 414 | IMPL_CHAIN_LOGGER_OPERATOR( const qOS::sm::status& ) 415 | IMPL_CHAIN_LOGGER_OPERATOR( const qOS::sm::stateHandler& ) 416 | IMPL_CHAIN_LOGGER_OPERATOR( const qOS::string& ) 417 | }; 418 | /*! @endcond */ 419 | 420 | /** 421 | * @brief Set the output method for the logger stream. 422 | * @param[in] fcn The basic output byte function. 423 | */ 424 | void setOutputFcn( util::putChar_t fcn ); 425 | 426 | /*! @cond */ 427 | ChainLoggerProxy out( const logSeverity s = logSeverity::none, const source_location &loc = source_location::current() ) noexcept; 428 | /* cppcheck-suppress functionStatic */ 429 | inline const char * var( const char * vname ){ return vname; } 430 | /*! @endcond */ 431 | 432 | /** @}*/ 433 | } 434 | /** @}*/ 435 | } 436 | 437 | /*! @cond */ 438 | #define var(v) var( #v ) << '=' << (v) 439 | /*! @endcond */ 440 | 441 | #endif /*QOS_CPP_LOGGER*/ 442 | -------------------------------------------------------------------------------- /src/input.cpp: -------------------------------------------------------------------------------- 1 | #include "include/input.hpp" 2 | 3 | using namespace qOS; 4 | 5 | /*============================================================================*/ 6 | void input::digitalChannel::updateReading( bool act ) noexcept 7 | { 8 | auto sample = reader( number ); 9 | (void)act; 10 | 11 | if ( negate ) { 12 | /*cstat -MISRAC++2008-5-0-3 -MISRAC++2008-5-3-1 -MISRAC++2008-5-0-6 */ 13 | sample = !sample; // skipcq: CXX-W2065 14 | /*cstat +MISRAC++2008-5-0-3 +MISRAC++2008-5-3-1 +MISRAC++2008-5-0-6 */ 15 | } 16 | value = sample; 17 | } 18 | /*============================================================================*/ 19 | void input::analogChannel::updateReading( bool act ) noexcept 20 | { 21 | value = ( isShared() ) ? ptrValue[ 0 ] : reader( number ); 22 | 23 | const analogValue_t currentStep = value/step; 24 | if ( currentStep != lastStep ) { 25 | analogValue_t diff; 26 | input::event dir; 27 | 28 | if ( currentStep > lastStep ) { 29 | diff = currentStep - lastStep; 30 | dir = input::event::STEP_UP; 31 | } 32 | else { 33 | diff = lastStep - currentStep; 34 | dir = input::event::STEP_DOWN; 35 | } 36 | for ( analogValue_t i = 0; i < diff; ++i ) { 37 | dispatchEvent( dir ); 38 | } 39 | lastStep = currentStep; 40 | } 41 | 42 | if ( act ) { 43 | const analogValue_t diff = ( value > lastSampled ) ? value - lastSampled 44 | : lastSampled - value; 45 | if ( diff >= delta ) { 46 | dispatchEvent( input::event::DELTA ); 47 | } 48 | lastSampled = value; 49 | } 50 | } 51 | /*============================================================================*/ 52 | void input::digitalChannel::fallingEdgeState( input::digitalChannel& c ) 53 | { 54 | const qOS::clock_t CURRENT_TIME = clock::getTick(); 55 | 56 | if ( 0 != c.value ) { 57 | c.channelState = &input::digitalChannel::risingEdgeState; 58 | c.dispatchEvent( input::event::RISING_EDGE ); 59 | c.dispatchEvent( input::event::ON_CHANGE ); 60 | if ( ( CURRENT_TIME - c.tChange ) > c.pulsationInterval ) { 61 | c.pulsationCount = 0U; 62 | } 63 | c.tChange = CURRENT_TIME; 64 | } 65 | if ( ( CURRENT_TIME - c.tChange ) > c.tSteadyLow ) { 66 | c.channelState = &input::digitalChannel::steadyInLowState; 67 | c.dispatchEvent( input::event::STEADY_IN_LOW ); 68 | c.tChange = CURRENT_TIME; 69 | } 70 | } 71 | /*============================================================================*/ 72 | void input::digitalChannel::steadyInLowState( input::digitalChannel& c ) 73 | { 74 | if ( 0 != c.value ) { 75 | c.channelState = &input::digitalChannel::risingEdgeState; 76 | c.dispatchEvent( input::event::RISING_EDGE ); 77 | c.dispatchEvent( input::event::ON_CHANGE ); 78 | c.tChange = clock::getTick(); 79 | } 80 | } 81 | /*============================================================================*/ 82 | void input::digitalChannel::risingEdgeState( input::digitalChannel& c ) 83 | { 84 | const qOS::clock_t CURRENT_TIME = clock::getTick(); 85 | 86 | if ( 0 == c.value ) { 87 | c.channelState = &input::digitalChannel::fallingEdgeState; 88 | c.dispatchEvent( input::event::FALLING_EDGE ); 89 | c.dispatchEvent( input::event::ON_CHANGE ); 90 | if ( ( CURRENT_TIME - c.tChange ) <= c.pulsationInterval ) { 91 | ++c.pulsationCount; 92 | } 93 | c.tChange = CURRENT_TIME; 94 | 95 | switch ( c.pulsationCount ) { 96 | case 0 : case 1: break; 97 | case 2: 98 | c.dispatchEvent( input::event::PULSATION_DOUBLE ); 99 | break; 100 | case 3: 101 | c.dispatchEvent( input::event::PULSATION_TRIPLE ); 102 | break; 103 | default: 104 | c.dispatchEvent( input::event::PULSATION_MULTI ); 105 | break; 106 | } 107 | } 108 | if ( ( CURRENT_TIME - c.tChange ) > c.tSteadyHigh ) { 109 | c.channelState = &input::digitalChannel::steadyInHighState; 110 | c.dispatchEvent( input::event::STEADY_IN_HIGH ); 111 | c.tChange = CURRENT_TIME; 112 | } 113 | } 114 | /*============================================================================*/ 115 | void input::digitalChannel::steadyInHighState( input::digitalChannel& c ) 116 | { 117 | if ( 0 == c.value ) { 118 | c.channelState = &input::digitalChannel::fallingEdgeState; 119 | c.dispatchEvent( input::event::FALLING_EDGE ); 120 | c.dispatchEvent( input::event::ON_CHANGE ); 121 | c.tChange = clock::getTick(); 122 | } 123 | } 124 | /*============================================================================*/ 125 | void input::analogChannel::lowThresholdState( input::analogChannel& c ) 126 | { 127 | const qOS::clock_t CURRENT_TIME = clock::getTick(); 128 | 129 | if ( c.value > c.high ) { 130 | c.channelState = &input::analogChannel::highThresholdState; 131 | c.dispatchEvent( input::event::HIGH_THRESHOLD ); 132 | c.dispatchEvent( input::event::ON_CHANGE ); 133 | c.tChange = CURRENT_TIME; 134 | } 135 | else if ( c.value > ( c.low + c.hysteresis ) ) { 136 | c.channelState = &input::analogChannel::inBandState; 137 | c.dispatchEvent( input::event::IN_BAND ); 138 | c.dispatchEvent( input::event::ON_CHANGE ); 139 | c.tChange = CURRENT_TIME; 140 | } 141 | else { 142 | /*Nothing to do here*/ 143 | } 144 | 145 | if ( ( CURRENT_TIME - c.tChange ) > c.tSteadyLow ) { 146 | c.channelState = &input::analogChannel::steadyInLowState; 147 | c.dispatchEvent( input::event::STEADY_IN_LOW ); 148 | c.tChange = CURRENT_TIME; 149 | } 150 | } 151 | /*============================================================================*/ 152 | void input::analogChannel::highThresholdState( input::analogChannel& c ) 153 | { 154 | const qOS::clock_t CURRENT_TIME = clock::getTick(); 155 | 156 | if ( c.value < c.low ) { 157 | c.channelState = &input::analogChannel::lowThresholdState; 158 | c.dispatchEvent( input::event::LOW_THRESHOLD ); 159 | c.dispatchEvent( input::event::ON_CHANGE ); 160 | c.tChange = CURRENT_TIME; 161 | } 162 | else if ( c.value < ( c.high - c.hysteresis ) ) { 163 | c.channelState = &input::analogChannel::inBandState; 164 | c.dispatchEvent( input::event::IN_BAND ); 165 | c.dispatchEvent( input::event::ON_CHANGE ); 166 | c.tChange = CURRENT_TIME; 167 | } 168 | else { 169 | /*Nothing to do here*/ 170 | } 171 | 172 | if ( ( CURRENT_TIME - c.tChange ) > c.tSteadyHigh ) { 173 | c.channelState = &input::analogChannel::steadyInHighState; 174 | c.dispatchEvent( input::event::STEADY_IN_HIGH ); 175 | c.tChange = CURRENT_TIME; 176 | } 177 | } 178 | /*============================================================================*/ 179 | void input::analogChannel::inBandState( input::analogChannel& c ) 180 | { 181 | const qOS::clock_t CURRENT_TIME = clock::getTick(); 182 | 183 | if ( c.value > c.high ) { 184 | c.channelState = &input::analogChannel::highThresholdState; 185 | c.dispatchEvent( input::event::HIGH_THRESHOLD ); 186 | c.dispatchEvent( input::event::ON_CHANGE ); 187 | c.tChange = CURRENT_TIME; 188 | } 189 | else if ( c.value < c.low ) { 190 | c.channelState = &input::analogChannel::lowThresholdState; 191 | c.dispatchEvent( input::event::LOW_THRESHOLD ); 192 | c.dispatchEvent( input::event::ON_CHANGE ); 193 | c.tChange = CURRENT_TIME; 194 | } 195 | else { 196 | /*Nothing to do here*/ 197 | } 198 | 199 | if ( ( CURRENT_TIME - c.tChange ) > c.tSteadyBand ) { 200 | c.channelState = &input::analogChannel::steadyInBandState; 201 | c.dispatchEvent( input::event::STEADY_IN_BAND ); 202 | c.tChange = CURRENT_TIME; 203 | } 204 | } 205 | /*============================================================================*/ 206 | void input::analogChannel::steadyInHighState( input::analogChannel& c ) 207 | { 208 | if ( c.value < c.low ) { 209 | c.channelState = &input::analogChannel::lowThresholdState; 210 | c.dispatchEvent( input::event::LOW_THRESHOLD ); 211 | c.dispatchEvent( input::event::ON_CHANGE ); 212 | c.tChange = clock::getTick(); 213 | } 214 | else if ( c.value < ( c.high - c.hysteresis ) ) { 215 | c.channelState = &input::analogChannel::inBandState; 216 | c.dispatchEvent( input::event::IN_BAND ); 217 | c.dispatchEvent( input::event::ON_CHANGE ); 218 | c.tChange = clock::getTick(); 219 | } 220 | else { 221 | /*Nothing to do here*/ 222 | } 223 | } 224 | /*============================================================================*/ 225 | void input::analogChannel::steadyInLowState( input::analogChannel& c ) 226 | { 227 | if ( c.value > c.high ) { 228 | c.channelState = &input::analogChannel::highThresholdState; 229 | c.dispatchEvent( input::event::HIGH_THRESHOLD ); 230 | c.dispatchEvent( input::event::ON_CHANGE ); 231 | c.tChange = clock::getTick(); 232 | } 233 | else if ( c.value > ( c.low + c.hysteresis ) ) { 234 | c.channelState = &input::analogChannel::inBandState; 235 | c.dispatchEvent( input::event::IN_BAND ); 236 | c.dispatchEvent( input::event::ON_CHANGE ); 237 | c.tChange = clock::getTick(); 238 | } 239 | else { 240 | /*Nothing to do here*/ 241 | } 242 | } 243 | /*============================================================================*/ 244 | void input::analogChannel::steadyInBandState( input::analogChannel& c ) 245 | { 246 | if ( c.value > c.high ) { 247 | c.channelState = &input::analogChannel::highThresholdState; 248 | c.dispatchEvent( input::event::HIGH_THRESHOLD ); 249 | c.dispatchEvent( input::event::ON_CHANGE ); 250 | c.tChange = clock::getTick(); 251 | } 252 | else if ( c.value < c.low ) { 253 | c.channelState = &input::analogChannel::lowThresholdState; 254 | c.dispatchEvent( input::event::LOW_THRESHOLD ); 255 | c.dispatchEvent( input::event::ON_CHANGE ); 256 | c.tChange = clock::getTick(); 257 | } 258 | else { 259 | /*Nothing to do here*/ 260 | } 261 | } 262 | /*============================================================================*/ 263 | bool input::watcher::watch( void ) noexcept 264 | { 265 | const bool act = waitDebounce.reloadIfExpired( debounceTime ); 266 | if ( ( digitalChannels.length() > 0U ) && act ) { 267 | for ( auto i = digitalChannels.begin(); i.untilEnd() ; i++ ) { 268 | input::channel& c = *i.get(); 269 | if ( nullptr != c.callback ) { 270 | if ( nullptr != digitalReader ) { 271 | c.updateReading( true ); 272 | c.evaluateState(); 273 | } 274 | else { 275 | c.dispatchEvent( input::event::EXCEPTION ); 276 | } 277 | } 278 | } 279 | } 280 | if ( analogChannels.length() > 0U ) { 281 | for ( auto i = analogChannels.begin(); i.untilEnd() ; i++ ) { 282 | input::channel& c = *i.get(); 283 | if ( nullptr != c.callback ) { 284 | /*cstat -MISRAC++2008-5-14-1*/ 285 | if ( ( nullptr != analogReader ) && c.isValidConfig() ) { // no side-effects here 286 | c.updateReading( act ); 287 | c.evaluateState(); 288 | } 289 | else { 290 | c.dispatchEvent( input::event::EXCEPTION ); 291 | } 292 | /*cstat +MISRAC++2008-5-14-1*/ 293 | } 294 | } 295 | } 296 | 297 | return true; 298 | } 299 | /*============================================================================*/ 300 | size_t input::watcher::getAnalogChannelsCount( void ) const noexcept 301 | { 302 | return analogChannels.length(); 303 | } 304 | /*============================================================================*/ 305 | size_t input::watcher::getDigitalChannelsCount( void ) const noexcept 306 | { 307 | return digitalChannels.length(); 308 | } 309 | /*============================================================================*/ 310 | void input::digitalChannel::setInitalState( void ) noexcept 311 | { 312 | auto val = ( nullptr != reader ) ? reader( number ) : -1; 313 | 314 | if ( negate ) { 315 | /*cstat -MISRAC++2008-5-0-3 -MISRAC++2008-5-3-1 -MISRAC++2008-5-0-6 */ 316 | val = !val; // skipcq: CXX-W2065 317 | /*cstat +MISRAC++2008-5-0-3 +MISRAC++2008-5-3-1 +MISRAC++2008-5-0-6 */ 318 | } 319 | channelState = ( 0 == val ) ? &input::digitalChannel::fallingEdgeState 320 | : &input::digitalChannel::risingEdgeState; 321 | } 322 | /*============================================================================*/ 323 | void input::analogChannel::setInitalState( void ) noexcept 324 | { 325 | const auto val = ( nullptr != reader ) ? reader( number ) : 0U; 326 | 327 | if ( val > high ) { 328 | channelState = &input::analogChannel::highThresholdState; 329 | } 330 | else if ( val < low ) { 331 | channelState = &input::analogChannel::lowThresholdState; 332 | } 333 | else { 334 | channelState = &input::analogChannel::inBandState; 335 | } 336 | lastStep = val/step; 337 | lastSampled = val; 338 | } 339 | /*============================================================================*/ 340 | bool input::watcher::add( input::channel& c ) noexcept 341 | { 342 | bool retValue; 343 | 344 | if ( input::type::DIGITAL_CHANNEL == c.getType() ) { 345 | (void)c.setReader( digitalReader ); 346 | c.setInitalState(); 347 | retValue = digitalChannels.insert( &c ); 348 | } 349 | else { 350 | (void)c.setReader( analogReader ); 351 | (void)c.setInitalState(); 352 | input::analogChannel& chan = static_cast( c ); 353 | /* check if channel is shared( same channel number)*/ 354 | for ( auto i = analogChannels.begin(); i.untilEnd() ; i++ ) { 355 | const input::analogChannel& channelInWatcher = *i.get(); 356 | 357 | if ( chan.number == channelInWatcher.number ) { 358 | /*cstat -CERT-EXP39-C_d*/ 359 | chan.ptrValue = const_cast(&channelInWatcher.value); 360 | /*cstat +CERT-EXP39-C_d*/ 361 | break; 362 | } 363 | } 364 | retValue = analogChannels.insert( &c ); 365 | } 366 | c.tChange = clock::getTick(); 367 | 368 | return retValue; 369 | } 370 | /*============================================================================*/ 371 | bool input::watcher::remove( input::channel& c ) noexcept 372 | { 373 | list* const channelContainer = c.getContainer(); 374 | const bool retValue = channelContainer->remove( &c ); 375 | (void)c.unShare(); 376 | 377 | /*cstat -MISRAC++2008-5-14-1*/ 378 | if ( ( input::type::ANALOG_CHANNEL == c.getType() ) && !c.isShared() ) { // no side-effects here 379 | /*cstat +MISRAC++2008-5-14-1*/ 380 | analogValue_t *newPtrVal = nullptr; 381 | /*find the next shared channel*/ 382 | for ( auto i = analogChannels.begin(); i.untilEnd() ; i++ ) { 383 | input::analogChannel& channelInList = *i.get(); 384 | 385 | if ( channelInList.number == c.number ) { 386 | if ( nullptr == newPtrVal ) { /*first shared channel*/ 387 | newPtrVal = &channelInList.value; 388 | channelInList.ptrValue = &channelInList.value; 389 | } 390 | else { 391 | channelInList.ptrValue = newPtrVal; 392 | } 393 | } 394 | } 395 | } 396 | 397 | return retValue; 398 | } 399 | /*============================================================================*/ 400 | bool input::digitalChannel::setTime( const input::event e, const qOS::duration_t t ) noexcept 401 | { 402 | bool retValue = true; 403 | 404 | if ( t > 0U ) { 405 | switch( e ) { 406 | case input::event::PULSATION_DOUBLE: // skipcq: CXX-C1001 407 | case input::event::PULSATION_TRIPLE: // skipcq: CXX-C1001 408 | case input::event::PULSATION_MULTI: // skipcq: CXX-C1001 409 | pulsationInterval = static_cast( t ); 410 | break; 411 | case input::event::STEADY_IN_HIGH: 412 | tSteadyHigh = static_cast( t ); 413 | break; 414 | case input::event::STEADY_IN_LOW: 415 | tSteadyLow = static_cast( t ); 416 | break; 417 | default: 418 | retValue = false; 419 | break; 420 | } 421 | } 422 | else { 423 | retValue = false; 424 | } 425 | 426 | return retValue; 427 | } 428 | /*============================================================================*/ 429 | bool input::analogChannel::setTime( const input::event e, const qOS::duration_t t ) noexcept 430 | { 431 | bool retValue = true; 432 | 433 | if ( t > 0U ) { 434 | switch( e ) { 435 | case input::event::STEADY_IN_BAND: 436 | tSteadyBand = static_cast( t ); 437 | break; 438 | case input::event::STEADY_IN_HIGH: 439 | tSteadyHigh = static_cast( t ); 440 | break; 441 | case input::event::STEADY_IN_LOW: 442 | tSteadyLow = static_cast( t ); 443 | break; 444 | default: 445 | retValue = false; 446 | break; 447 | } 448 | } 449 | else { 450 | retValue = false; 451 | } 452 | 453 | return retValue; 454 | } 455 | /*============================================================================*/ 456 | bool input::digitalChannel::setParameter( const input::event e, const analogValue_t p ) noexcept 457 | { 458 | (void)e; 459 | (void)p; 460 | return false; 461 | } 462 | /*============================================================================*/ 463 | bool input::analogChannel::setParameter( const input::event e, const analogValue_t p ) noexcept 464 | { 465 | bool retValue = true; 466 | 467 | switch( e ) { 468 | case input::event::HIGH_THRESHOLD: 469 | high = p; 470 | break; 471 | case input::event::LOW_THRESHOLD: 472 | low = p; 473 | break; 474 | case input::event::IN_BAND: 475 | hysteresis = p; 476 | break; 477 | case input::event::DELTA: 478 | delta = p; 479 | break; 480 | case input::event::STEP_UP: // [fallthrough] 481 | case input::event::STEP_DOWN: // skipcq: CXX-C1001 482 | step = p; 483 | break; 484 | default: 485 | retValue = false; 486 | break; 487 | } 488 | 489 | return retValue; 490 | } 491 | --------------------------------------------------------------------------------