diff --git a/library.json b/library.json index 17e6bacb..e42b7497 100644 --- a/library.json +++ b/library.json @@ -16,7 +16,7 @@ "maintainer": true } ], - "version": "1.7.6", + "version": "1.7.7", "license": "MIT", "frameworks": "arduino", "platforms": "*" diff --git a/library.properties b/library.properties index 06e09768..41dd5e0a 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=QuarkTS -version=1.7.6 +version=1.7.7 license=MIT author=J. Camilo Gomez C. maintainer=J. Camilo Gomez C. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6df74fd3..d6ebd689 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required( VERSION 3.2 ) project( quarkts-cpp - VERSION 1.7.6 + VERSION 1.7.7 DESCRIPTION "An open-source OS for small embedded applications" LANGUAGES CXX ) diff --git a/src/QuarkTS.h b/src/QuarkTS.h index 08e44cba..7f8e261d 100644 --- a/src/QuarkTS.h +++ b/src/QuarkTS.h @@ -1,7 +1,7 @@ /*! * @file QuarkTS.h * @author J. Camilo Gomez C. - * @version 1.7.6 + * @version 1.7.7 * @note This file is part of the QuarkTS++ distribution. * @brief Global inclusion header **/ @@ -41,8 +41,8 @@ This file is part of the QuarkTS++ OS distribution. #ifndef QOS_CPP_H #define QOS_CPP_H -#define QUARKTS_CPP_VERSION "1.7.6" -#define QUARKTS_CPP_VERNUM ( 176u ) +#define QUARKTS_CPP_VERSION "1.7.7" +#define QUARKTS_CPP_VERNUM ( 177u ) #define QUARKTS_CPP_CAPTION "QuarkTS++ OS " QUARKTS_CPP_VERSION #include "config/config.h" @@ -66,7 +66,7 @@ This file is part of the QuarkTS++ OS distribution. namespace qOS { namespace build { - constexpr const uint32_t number = 4149; + constexpr const uint32_t number = 4181; constexpr const char* date = __DATE__; constexpr const char* time = __TIME__; constexpr const char* std = "c++11"; @@ -76,7 +76,7 @@ namespace qOS { constexpr const uint8_t number = QUARKTS_CPP_VERNUM; constexpr const uint8_t mayor = 1U; constexpr const uint8_t minor = 7U; - constexpr const uint8_t rev = 6U; + constexpr const uint8_t rev = 7U; } namespace product { constexpr const char* author = "J. Camilo Gomez C."; diff --git a/src/include/cli.hpp b/src/include/cli.hpp index 257ad295..c4546149 100644 --- a/src/include/cli.hpp +++ b/src/include/cli.hpp @@ -74,7 +74,7 @@ namespace qOS { volatile bool ready{ false }; void flush( void ); void operator=( input const& ) = delete; - input() {} + input() noexcept {} }; /*! @endcond */ diff --git a/src/include/clock.hpp b/src/include/clock.hpp index ec26c831..a4af7742 100644 --- a/src/include/clock.hpp +++ b/src/include/clock.hpp @@ -81,7 +81,7 @@ namespace qOS { /*! @cond */ static volatile qOS::clock_t sysTick_Epochs; // skipcq: CXX-W2009 static qOS::clock_t internalTick( void ) noexcept; - clock(); + clock() = default; /*! @endcond */ public: clock( clock &other ) = delete; diff --git a/src/include/input.hpp b/src/include/input.hpp index 0fb60652..05be189d 100644 --- a/src/include/input.hpp +++ b/src/include/input.hpp @@ -117,7 +117,7 @@ namespace qOS { public: /*! @cond */ virtual ~channel() {} - channel( uint8_t channelNumber ) : number( channelNumber ) {} + channel( uint8_t channelNumber ) noexcept : number( channelNumber ) {} /*! @endcond */ /** @@ -257,7 +257,7 @@ namespace qOS { * @param[in] inputChannel The specified channel(pin) number to read. * @param[in] invert To invert/negate the raw-reading. */ - explicit digitalChannel( const uint8_t inputChannel, bool invert = false ) : channel( inputChannel ), negate( invert) {} + explicit digitalChannel( const uint8_t inputChannel, bool invert = false ) noexcept : channel( inputChannel ), negate( invert) {} /** * @brief Get the channel type. * @return The channel type. @@ -373,7 +373,7 @@ namespace qOS { * @param[in] upperThreshold The upper threshold value. * @param[in] h Hysteresis for the in-band transition. */ - analogChannel( const uint8_t inputChannel, const analogValue_t lowerThreshold, const analogValue_t upperThreshold, const analogValue_t h = 20 ) + analogChannel( const uint8_t inputChannel, const analogValue_t lowerThreshold, const analogValue_t upperThreshold, const analogValue_t h = 20 ) noexcept : channel( inputChannel ), high( upperThreshold ), low( lowerThreshold ), @@ -453,7 +453,7 @@ namespace qOS { /** * @brief The digital input-channel watcher class. */ - class watcher : protected node, private nonCopyable { + class watcher : private nonCopyable { private: eventCallback_t exception{ nullptr }; list digitalChannels; diff --git a/src/include/kernel.hpp b/src/include/kernel.hpp index 4a99de76..9d9d6f3c 100644 --- a/src/include/kernel.hpp +++ b/src/include/kernel.hpp @@ -93,7 +93,8 @@ namespace qOS { list coreLists[ Q_PRIORITY_LEVELS + 2 ]; // skipcq: CXX-W2066 list& waitingList; // skipcq: CXX-W2012, CXX-W2010 list& suspendedList; // skipcq: CXX-W2012, CXX-W2010 - list inputWatchers; + //list inputWatchers; + void(*cpuIdle)(void){ nullptr }; static const priority_t MAX_PRIORITY_VALUE; static const uint32_t BIT_INIT; static const uint32_t BIT_FCALL_IDLE; @@ -104,8 +105,7 @@ namespace qOS { void dispatchTaskFillEventInfo( task *Task ) noexcept; void dispatch( list * const xList ) noexcept; void dispatchIdle( void ) noexcept; - void handleInputWatchers( void ) noexcept; - core() : waitingList( coreLists[ Q_PRIORITY_LEVELS ] ), suspendedList( coreLists[ Q_PRIORITY_LEVELS + 1 ] ) {} + core() noexcept : waitingList( coreLists[ Q_PRIORITY_LEVELS ] ), suspendedList( coreLists[ Q_PRIORITY_LEVELS + 1 ] ) {} core( core &other ) = delete; void operator=( const core & ) = delete; public: @@ -131,6 +131,8 @@ namespace qOS { * @param[in] callbackIdle Callback function to the Idle Task. To * disable the Idle-Task activities, ignore this parameter of pass * @c nullptr as argument. + * @param[in] coreIdleFcn The function that sets the CPU into + * low-power or idle state * @return @c true on success. Otherwise return @c false. * * Example : When tick is already provided @@ -165,7 +167,7 @@ namespace qOS { * } * @endcode */ - bool init( const getTickFcn_t tFcn = nullptr, taskFcn_t callbackIdle = nullptr ) noexcept; + bool init( const getTickFcn_t tFcn = nullptr, taskFcn_t callbackIdle = nullptr, void(*coreIdleFcn)(void) = nullptr ) noexcept; /** * @brief Add a task to the scheduling scheme. The task is scheduled to run * every @a t time units, @a n times and executing @a callback method on @@ -262,6 +264,15 @@ namespace qOS { bool add( task &Task, commandLineInterface &cli, const priority_t p, void *arg = nullptr ) noexcept; /** @}*/ #endif + + /** + * @brief Add an input-watcher so that its function is executed by + * the kernel + * @note The input-watcher is considered as an always-active task + * @param[in] w The input watcher. + * @return Returns @c true if success, otherwise returns @c false. + */ + bool add( task &Task, input::watcher &w, const priority_t p = HIGHEST_PRIORITY, const taskState s = taskState::ENABLED_STATE, void *arg = nullptr ) noexcept; /** * @brief Set/Change the callback for the Idle-task * @param[in] callback A pointer to a void callback method with a qOS::event_t @@ -277,6 +288,13 @@ namespace qOS { */ bool setNameIdleTask( const char *tName ) noexcept; /** + * @brief Set the function that puts the CPU into a low-power or + * idle state until an interrupt occurs. + * @param[in] pFcn The function to put the CPU into low-power or idle-state + * @return @c true on success. Otherwise return @c false. + */ + bool setCoreIdleFcn( void(*pFcn)(void) ) noexcept; + /** * @brief Disables the kernel scheduling. The main thread will continue * after the core::run() call. */ @@ -438,21 +456,6 @@ namespace qOS { */ globalState getGlobalState( task &Task ) const noexcept; /** - * @brief Add an input-watcher so that its function is executed by - * the kernel - * @note The input-watcher is considered as an always-active task - * @param[in] w The input watcher. - * @return Returns @c true if success, otherwise returns @c false. - */ - bool add( input::watcher &w ) noexcept; - /** - * @brief Remove an input-watcher so that the kernel stops executing - * its function - * @param[in] w The input-watcher. - * @return Returns @c true if success, otherwise returns @c false. - */ - bool remove( input::watcher &w ) noexcept; - /** * @brief Check if the OS instance has been initialized. * @return @c true if OS instance has been initialized */ diff --git a/src/include/list.hpp b/src/include/list.hpp index cbb8c717..5f1d6bfb 100644 --- a/src/include/list.hpp +++ b/src/include/list.hpp @@ -76,7 +76,7 @@ namespace qOS { { return container; } - node() : next(nullptr), prev(nullptr), container(nullptr) {} + node() noexcept : next(nullptr), prev(nullptr), container(nullptr) {} /*! @cond */ virtual ~node() {} /*! @endcond */ diff --git a/src/include/timer.hpp b/src/include/timer.hpp index e4d0e97e..7095ee50 100644 --- a/src/include/timer.hpp +++ b/src/include/timer.hpp @@ -28,7 +28,7 @@ namespace qOS { qOS::clock_t tStart{ 0U }; qOS::clock_t tv{ 0U }; public: - timer(); + timer() noexcept; /*! @cond */ virtual ~timer() {} /*! @endcond */ @@ -85,7 +85,23 @@ namespace qOS { * @return Returns @c true on success, otherwise, returns @c false. * @note A disarmed timer also returns @c false. */ - bool freeRun( const qOS::duration_t tTime ) noexcept; + bool reloadIfExpired( const qOS::duration_t tTime ) noexcept; + /** + * @brief Non-Blocking timer check with automatic arming. + * + * Behavior: + * If disarmed, it gets armed immediately with the previous + * specified time. + * + * If armed, the API only checks for expiration. When the time + * expires, the timer gets armed immediately using the previously + * assigned time. + * @note After the timer expiration, this method re-arms the timer + * @note The OS must be running before using a timer. + * @return Returns @c true on success, otherwise, returns @c false. + * @note A disarmed timer also returns @c false. + */ + bool reloadIfExpired( void ) noexcept; /** * @brief Retrieve the remaining time in epochs * @return The remaining time specified in epochs. diff --git a/src/input.cpp b/src/input.cpp index 7b19a5e4..fcc7ada6 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -262,7 +262,7 @@ void input::analogChannel::steadyInBandState( input::analogChannel& c ) /*============================================================================*/ bool input::watcher::watch( void ) noexcept { - const bool act = waitDebounce.freeRun( debounceTime ); + const bool act = waitDebounce.reloadIfExpired( debounceTime ); if ( ( digitalChannels.length() > 0U ) && act ) { for ( auto i = digitalChannels.begin(); i.untilEnd() ; i++ ) { input::channel& c = *i.get(); diff --git a/src/kernel.cpp b/src/kernel.cpp index af5156e2..a3c5f5af 100644 --- a/src/kernel.cpp +++ b/src/kernel.cpp @@ -21,12 +21,14 @@ const priority_t core::MEDIUM_PRIORITY = static_cast( Q_PRIORITY_LEV const priority_t core::HIGHEST_PRIORITY = static_cast( Q_PRIORITY_LEVELS ) - 1U; const notifier_t MAX_NOTIFICATION_VALUE = UINT32_MAX - 1UL; -#if ( Q_CLI == 1 ) +#if ( Q_FSM == 1 ) static void fsmTaskCallback( event_t e ); +#endif +#if ( Q_CLI == 1 ) static void cliTaskCallback( event_t e ); static void cliNotifyFcn( commandLineInterface *cli ); #endif - +static void inputWatcherTaskCallback( event_t e ); /*============================================================================*/ core& core::getInstance( void ) noexcept { @@ -35,13 +37,14 @@ core& core::getInstance( void ) noexcept } /*============================================================================*/ /*cstat -MISRAC++2008-7-1-2*/ -bool core::init( const getTickFcn_t tFcn, taskFcn_t callbackIdle ) noexcept +bool core::init( const getTickFcn_t tFcn, taskFcn_t callbackIdle, void(*coreIdleFcn)(void) ) noexcept { (void)clock::setTickProvider( tFcn ); (void)setNameIdleTask( "idle" ); (void)idle.setPriority( core::LOWEST_PRIORITY ); (void)idle.setState( taskState::DISABLED_STATE ); (void)idle.setCallback( callbackIdle ); + (void)setCoreIdleFcn( coreIdleFcn ); idle.entry = 0U; return true; } @@ -122,6 +125,26 @@ bool core::add( task &Task, commandLineInterface &cli, const priority_t p, void } #endif /*Q_CLI*/ /*============================================================================*/ +static void inputWatcherTaskCallback( event_t e ) +{ + /*cstat -CERT-EXP36-C_b*/ + input::watcher * const w = static_cast( e.thisTask().getBindedObject() ); + /*cstat +CERT-EXP36-C_b*/ + (void)w->watch(); +} +/*============================================================================*/ +bool core::add( task &Task, input::watcher &w, const priority_t p, const taskState s, void *arg ) noexcept +{ + bool retValue = core::add( Task, inputWatcherTaskCallback, p, 10_ms, task::PERIODIC, s, arg ); + + if ( retValue ) { + Task.aObj = &w; + retValue = true; + } + + return retValue; +} +/*============================================================================*/ /*cstat -MISRAC++2008-7-1-2*/ bool core::setIdleTask( taskFcn_t callback ) noexcept { @@ -143,6 +166,18 @@ bool core::setNameIdleTask( const char *tName ) noexcept return retValue; } /*============================================================================*/ +bool core::setCoreIdleFcn( void(*pFcn)(void) ) noexcept +{ + bool retValue = false; + + if ( pFcn != cpuIdle ) { + cpuIdle = pFcn; + retValue = true; + } + + return retValue; +} +/*============================================================================*/ bool core::schedulerRelease( void ) noexcept { bits::multipleSet( flag, BIT_RELEASE_SCHED ); @@ -373,7 +408,9 @@ bool core::run( void ) noexcept /*cstat +MISRAC++2008-0-1-6*/ do { - if ( checkIfReady() ) { + const bool anyActiveTask = checkIfReady(); + + if ( anyActiveTask) { priority_t xPriorityListIndex = MAX_PRIORITY_VALUE; do { @@ -383,14 +420,6 @@ bool core::run( void ) noexcept } } while( 0U != xPriorityListIndex-- ); } - else { - if ( nullptr != idle.callback ) { - dispatchIdle(); - } - } - if ( inputWatchers.length() > 0U ) { - handleInputWatchers(); - } if ( suspendedList.length() > 0U ) { (void)waitingList.move( suspendedList, listPosition::AT_BACK ); #if ( Q_PRESERVE_TASK_ENTRY_ORDER == 1 ) @@ -398,6 +427,13 @@ bool core::run( void ) noexcept (void)waitingList.sort( taskEntryOrderPreserver ); #endif } + + if ( !anyActiveTask ) { + dispatchIdle(); + if ( nullptr != cpuIdle ) { + cpuIdle(); + } + } } #if ( Q_ALLOW_SCHEDULER_RELEASE == 1 ) while ( !bits::multipleGet( flag, BIT_RELEASE_SCHED ) ); @@ -601,20 +637,3 @@ globalState core::getGlobalState( task &Task ) const noexcept return retValue; } /*============================================================================*/ -bool core::add( input::watcher &w ) noexcept -{ - return inputWatchers.insert( &w ); -} -/*============================================================================*/ -bool core::remove( input::watcher &w ) noexcept -{ - return inputWatchers.remove( &w ); -} -/*============================================================================*/ -void core::handleInputWatchers( void ) noexcept -{ - for ( auto i = inputWatchers.begin(); i.untilEnd() ; i++ ) { - input::watcher * const w = i.get(); - (void)w->watch(); - } -} \ No newline at end of file diff --git a/src/timer.cpp b/src/timer.cpp index ca64fc6b..8ef731cb 100644 --- a/src/timer.cpp +++ b/src/timer.cpp @@ -8,7 +8,7 @@ const qOS::clock_t timer::DISARM_VALUE = 0UL ; const qOS::clock_t timer::REMAINING_IN_DISARMED_STATE = 0xFFFFFFFFUL; /*============================================================================*/ -timer::timer() +timer::timer() noexcept { disarm(); } @@ -61,7 +61,7 @@ void timer::disarm( void ) noexcept tStart = timer::DISARM_VALUE; } /*============================================================================*/ -bool timer::freeRun( const qOS::duration_t tTime ) noexcept +bool timer::reloadIfExpired( const qOS::duration_t tTime ) noexcept { bool retValue = false; @@ -78,6 +78,20 @@ bool timer::freeRun( const qOS::duration_t tTime ) noexcept return retValue; } /*============================================================================*/ +bool timer::reloadIfExpired( void ) noexcept +{ + bool retValue = false; + + if ( timer::ARMED == status() ) { + if ( expired() ) { + reload(); + retValue = true; + } + } + + return retValue; +} +/*============================================================================*/ bool timer::operator()( const qOS::duration_t tTime ) { return set( tTime );