mirror of
https://github.com/QuantumLeaps/qpc.git
synced 2025-01-28 07:03:10 +08:00
2048 lines
72 KiB
C
2048 lines
72 KiB
C
/*$file${include::qf.h} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
|
|
/*
|
|
* Model: qpc.qm
|
|
* File: ${include::qf.h}
|
|
*
|
|
* This code has been generated by QM 5.2.4 <www.state-machine.com/qm>.
|
|
* DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost.
|
|
*
|
|
* This code is covered by the following QP license:
|
|
* License # : LicenseRef-QL-dual
|
|
* Issued to : Any user of the QP/C real-time embedded framework
|
|
* Framework(s) : qpc
|
|
* Support ends : 2023-12-31
|
|
* License scope:
|
|
*
|
|
* Copyright (C) 2005 Quantum Leaps, LLC <state-machine.com>.
|
|
*
|
|
* SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-QL-commercial
|
|
*
|
|
* This software is dual-licensed under the terms of the open source GNU
|
|
* General Public License version 3 (or any later version), or alternatively,
|
|
* under the terms of one of the closed source Quantum Leaps commercial
|
|
* licenses.
|
|
*
|
|
* The terms of the open source GNU General Public License version 3
|
|
* can be found at: <www.gnu.org/licenses/gpl-3.0>
|
|
*
|
|
* The terms of the closed source Quantum Leaps commercial licenses
|
|
* can be found at: <www.state-machine.com/licensing>
|
|
*
|
|
* Redistributions in source code must retain this top-level comment block.
|
|
* Plagiarizing this software to sidestep the license obligations is illegal.
|
|
*
|
|
* Contact information:
|
|
* <www.state-machine.com/licensing>
|
|
* <info@state-machine.com>
|
|
*/
|
|
/*$endhead${include::qf.h} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
|
|
/*! @file
|
|
* @brief QF/C platform-independent public interface.
|
|
*/
|
|
#ifndef QP_INC_QF_H_
|
|
#define QP_INC_QF_H_
|
|
|
|
/*==========================================================================*/
|
|
/*$declare${QF-config} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
|
|
|
|
/*${QF-config::QF_MAX_ACTIVE} ..............................................*/
|
|
#ifndef QF_MAX_ACTIVE
|
|
/*! Maximum number of active objects (configurable value in qf_port.h)
|
|
* Valid values: [1U..64U]; default 32U
|
|
*/
|
|
#define QF_MAX_ACTIVE 32U
|
|
#endif /* ndef QF_MAX_ACTIVE */
|
|
|
|
/*${QF-config::QF_MAX_ACTIVE exceeds the maximu~} ..........................*/
|
|
#if (QF_MAX_ACTIVE > 64U)
|
|
#error QF_MAX_ACTIVE exceeds the maximum of 64U;
|
|
#endif /* (QF_MAX_ACTIVE > 64U) */
|
|
|
|
/*${QF-config::QF_MAX_TICK_RATE} ...........................................*/
|
|
#ifndef QF_MAX_TICK_RATE
|
|
/*! Maximum number of clock rates (configurable value in qf_port.h)
|
|
* Valid values: [0U..15U]; default 1U
|
|
*/
|
|
#define QF_MAX_TICK_RATE 1U
|
|
#endif /* ndef QF_MAX_TICK_RATE */
|
|
|
|
/*${QF-config::QF_MAX_TICK_RATE exceeds the max~} ..........................*/
|
|
#if (QF_MAX_TICK_RATE > 15U)
|
|
#error QF_MAX_TICK_RATE exceeds the maximum of 15U;
|
|
#endif /* (QF_MAX_TICK_RATE > 15U) */
|
|
|
|
/*${QF-config::QF_MAX_EPOOL} ...............................................*/
|
|
#ifndef QF_MAX_EPOOL
|
|
/*! Maximum number of event pools (configurable value in qf_port.h)
|
|
* Valid values: [0U..15U]; default 3U
|
|
*
|
|
* @note
|
|
* #QF_MAX_EPOOL set to zero means that dynamic events are NOT configured
|
|
* and should not be used in the application.
|
|
*/
|
|
#define QF_MAX_EPOOL 3U
|
|
#endif /* ndef QF_MAX_EPOOL */
|
|
|
|
/*${QF-config::QF_MAX_EPOOL exceeds the maximum~} ..........................*/
|
|
#if (QF_MAX_EPOOL > 15U)
|
|
#error QF_MAX_EPOOL exceeds the maximum of 15U;
|
|
#endif /* (QF_MAX_EPOOL > 15U) */
|
|
|
|
/*${QF-config::QF_TIMEEVT_CTR_SIZE} ........................................*/
|
|
#ifndef QF_TIMEEVT_CTR_SIZE
|
|
/*! Size of the QTimeEvt counter (configurable value in qf_port.h)
|
|
* Valid values: 1U, 2U, or 4U; default 4U
|
|
*/
|
|
#define QF_TIMEEVT_CTR_SIZE 4U
|
|
#endif /* ndef QF_TIMEEVT_CTR_SIZE */
|
|
|
|
/*${QF-config::QF_TIMEEVT_CTR_SIZE defined inco~} ..........................*/
|
|
#if (QF_TIMEEVT_CTR_SIZE != 1U) && (QF_TIMEEVT_CTR_SIZE != 2U) && (QF_TIMEEVT_CTR_SIZE != 4U)
|
|
#error QF_TIMEEVT_CTR_SIZE defined incorrectly, expected 1U, 2U, or 4U;
|
|
#endif /* (QF_TIMEEVT_CTR_SIZE != 1U) && (QF_TIMEEVT_CTR_SIZE != 2U) && (QF_TIMEEVT_CTR_SIZE != 4U) */
|
|
|
|
/*${QF-config::QF_EVENT_SIZ_SIZE} ..........................................*/
|
|
#ifndef QF_EVENT_SIZ_SIZE
|
|
/*! Size of the event-size (configurable value in qf_port.h)
|
|
* Valid values: 1U, 2U, or 4U; default 2U
|
|
*/
|
|
#define QF_EVENT_SIZ_SIZE 2U
|
|
#endif /* ndef QF_EVENT_SIZ_SIZE */
|
|
|
|
/*${QF-config::QF_EVENT_SIZ_SIZE defined incorr~} ..........................*/
|
|
#if (QF_EVENT_SIZ_SIZE != 1U) && (QF_EVENT_SIZ_SIZE != 2U) && (QF_EVENT_SIZ_SIZE != 4U)
|
|
#error QF_EVENT_SIZ_SIZE defined incorrectly, expected 1U, 2U, or 4U;
|
|
#endif /* (QF_EVENT_SIZ_SIZE != 1U) && (QF_EVENT_SIZ_SIZE != 2U) && (QF_EVENT_SIZ_SIZE != 4U) */
|
|
/*$enddecl${QF-config} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
|
|
|
|
/*==========================================================================*/
|
|
/*$declare${QF-types} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
|
|
|
|
/*${QF-types::QPSetBits} ...................................................*/
|
|
#if (8U < QF_MAX_ACTIVE) && (QF_MAX_ACTIVE <= 16U)
|
|
/*! bitmask for the internal representation of QPSet elements */
|
|
typedef uint16_t QPSetBits;
|
|
#endif /* (8U < QF_MAX_ACTIVE) && (QF_MAX_ACTIVE <= 16U) */
|
|
|
|
/*${QF-types::QPSetBits} ...................................................*/
|
|
#if (16 < QF_MAX_ACTIVE)
|
|
typedef uint32_t QPSetBits;
|
|
#endif /* (16 < QF_MAX_ACTIVE) */
|
|
|
|
/*${QF-types::QPSetBits} ...................................................*/
|
|
#if (QF_MAX_ACTIVE <= 8U)
|
|
typedef uint8_t QPSetBits;
|
|
#endif /* (QF_MAX_ACTIVE <= 8U) */
|
|
|
|
/*${QF-types::QTimeEvtCtr} .................................................*/
|
|
#if (QF_TIMEEVT_CTR_SIZE == 2U)
|
|
/*! Data type to store the block-size defined based on the macro
|
|
* #QF_TIMEEVT_CTR_SIZE.
|
|
*
|
|
* @details
|
|
* The dynamic range of this data type determines the maximum block
|
|
* size that can be managed by the pool.
|
|
*/
|
|
typedef uint16_t QTimeEvtCtr;
|
|
#endif /* (QF_TIMEEVT_CTR_SIZE == 2U) */
|
|
|
|
/*${QF-types::QTimeEvtCtr} .................................................*/
|
|
#if (QF_TIMEEVT_CTR_SIZE == 4U)
|
|
typedef uint32_t QTimeEvtCtr;
|
|
#endif /* (QF_TIMEEVT_CTR_SIZE == 4U) */
|
|
|
|
/*${QF-types::QTimeEvtCtr} .................................................*/
|
|
#if (QF_TIMEEVT_CTR_SIZE == 1U)
|
|
typedef uint8_t QTimeEvtCtr;
|
|
#endif /* (QF_TIMEEVT_CTR_SIZE == 1U) */
|
|
|
|
/*${QF-types::QF_LOG2} .....................................................*/
|
|
#ifndef QF_LOG2
|
|
/*! Log-base-2 calculation when hardware acceleration
|
|
* is NOT provided (#QF_LOG2 not defined).
|
|
*/
|
|
uint_fast8_t QF_LOG2(QPSetBits x);
|
|
#endif /* ndef QF_LOG2 */
|
|
|
|
/*${QF-types::QPrioSpec} ...................................................*/
|
|
/*! Priority specification for Active Objects in QP
|
|
*
|
|
* @details
|
|
* Active Object priorities in QP are integer numbers in the range
|
|
* [1..#QF_MAX_ACTIVE], whereas the special priority number 0 is reserved
|
|
* for the lowest-priority idle thread. The QP framework uses the *direct*
|
|
* priority numbering, in which higher numerical values denote higher urgency.
|
|
* For example, an AO with priority 32 has higher urgency than an AO with
|
|
* priority 23.
|
|
*
|
|
* ::QPrioSpec allows an application developer to assign **two**
|
|
* priorities to a given AO (see also Q_PRIO()):
|
|
*
|
|
* 1. The "QF-priority", which resides in the least-significant byte
|
|
* of the ::QPrioSpec data type. The "QF-priority" must be **unique**
|
|
* for each thread in the system and higher numerical values represent
|
|
* higher urgency (direct pirority numbering).
|
|
*
|
|
* 2. The "preemption-threshold" priority, which resides in the most-
|
|
* significant byte of the ::QPrioSpec data type. The second priority
|
|
* cannot be lower than the "QF-priority", but does NOT need to be
|
|
* unuque.
|
|
*
|
|
* In the QP native preemptive kernels, like QK and QXK, the "preemption-
|
|
* threshold" priority is used as to implement the "preemption-threshold
|
|
* scheduling" (PTS). It determines the conditions under which a given
|
|
* thread can be *preempted* by other threads. Specifically, a given
|
|
* thread can be preempted only by another thread with a *higher*
|
|
* priority than the "preemption-threshold" of the original thread.
|
|
*
|
|
* ![QF-priority and preemption-threshold relations](qp-prio.png)
|
|
*
|
|
* @note
|
|
* For backwards-compatibility, ::QPrioSpec data type might contain only
|
|
* the "QF-priority" component (and the "preemption-threshold" component
|
|
* left at zero). In that case, the "preemption-threshold" will be assumed
|
|
* to be the same as the "QF-priority". This corresponds exactly to the
|
|
* previous semantics of AO priority.
|
|
*
|
|
* @remark
|
|
* When QP runs on top of 3rd-party kernels/RTOSes or general-purpose
|
|
* operating systems, sthe second priority can have different meaning,
|
|
* depending on the specific RTOS/GPOS used.
|
|
*/
|
|
typedef uint16_t QPrioSpec;
|
|
|
|
/*${QF-types::QSchedStatus} ................................................*/
|
|
/*! The scheduler lock status used in some real-time kernels */
|
|
typedef uint_fast16_t QSchedStatus;
|
|
|
|
/*${QF-types::QPSet} .......................................................*/
|
|
/*! @brief Priority Set of up to #QF_MAX_ACTIVE elements
|
|
* @class QPSet
|
|
*
|
|
* @details
|
|
* The priority set represents the set of active objects that are ready to
|
|
* run and need to be considered by the scheduling algorithm. The set is
|
|
* capable of storing up to #QF_MAX_ACTIVE priority levels, which can be
|
|
* configured in the rage 1..64, inclusive.
|
|
*/
|
|
typedef struct {
|
|
/* public: */
|
|
|
|
#if (QF_MAX_ACTIVE <= 32)
|
|
/*! bitmask with a bit for each element */
|
|
QPSetBits volatile bits;
|
|
#endif /* (QF_MAX_ACTIVE <= 32) */
|
|
|
|
#if (32 < QF_MAX_ACTIVE)
|
|
/*! bitmasks with a bit for each element */
|
|
QPSetBits volatile bits[2];
|
|
#endif /* (32 < QF_MAX_ACTIVE) */
|
|
} QPSet;
|
|
|
|
/* public: */
|
|
|
|
/*! Make the priority set empty */
|
|
static inline void QPSet_setEmpty(QPSet * const me) {
|
|
#if (QF_MAX_ACTIVE <= 32)
|
|
me->bits = 0U;
|
|
#else
|
|
me->bits[0] = 0U;
|
|
me->bits[1] = 0U;
|
|
#endif
|
|
}
|
|
|
|
/*! Return 'true' if the priority set is empty */
|
|
static inline bool QPSet_isEmpty(QPSet const * const me) {
|
|
#if (QF_MAX_ACTIVE <= 32)
|
|
return (me->bits == 0U);
|
|
#else
|
|
return (me->bits[0] == 0U) ? (me->bits[1] == 0U) : false;
|
|
#endif
|
|
}
|
|
|
|
/*! Return 'true' if the priority set is NOT empty */
|
|
static inline bool QPSet_notEmpty(QPSet const * const me) {
|
|
#if (QF_MAX_ACTIVE <= 32)
|
|
return (me->bits != 0U);
|
|
#else
|
|
return (me->bits[0] != 0U) ? true : (me->bits[1] != 0U);
|
|
#endif
|
|
}
|
|
|
|
/*! Return 'true' if the priority set has the element n. */
|
|
static inline bool QPSet_hasElement(QPSet const * const me,
|
|
uint_fast8_t const n)
|
|
{
|
|
#if (QF_MAX_ACTIVE <= 32U)
|
|
return (me->bits & (1U << (n - 1U))) != 0U;
|
|
#else
|
|
return (n <= 32U)
|
|
? ((me->bits[0] & ((uint32_t)1U << (n - 1U))) != 0U)
|
|
: ((me->bits[1] & ((uint32_t)1U << (n - 33U))) != 0U);
|
|
#endif
|
|
}
|
|
|
|
/*! insert element `n` into the set (n = 1..::QF_MAX_ACTIVE) */
|
|
static inline void QPSet_insert(QPSet * const me,
|
|
uint_fast8_t const n)
|
|
{
|
|
#if (QF_MAX_ACTIVE <= 32U)
|
|
me->bits = (me->bits | (1U << (n - 1U)));
|
|
#else
|
|
if (n <= 32U) {
|
|
me->bits[0] = (me->bits[0] | ((uint32_t)1U << (n - 1U)));
|
|
}
|
|
else {
|
|
me->bits[1] = (me->bits[1] | ((uint32_t)1U << (n - 33U)));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/*! Remove element `n` from the set (n = 1U..::QF_MAX_ACTIVE) */
|
|
static inline void QPSet_remove(QPSet * const me,
|
|
uint_fast8_t const n)
|
|
{
|
|
#if (QF_MAX_ACTIVE <= 32U)
|
|
me->bits = (me->bits &
|
|
(QPSetBits)(~((QPSetBits)1U << (n - 1U))));
|
|
#else
|
|
if (n <= 32U) {
|
|
(me->bits[0] = (me->bits[0] & ~((uint32_t)1U << (n - 1U))));
|
|
}
|
|
else {
|
|
(me->bits[1] = (me->bits[1] & ~((uint32_t)1U << (n - 33U))));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/*! Find the maximum element in the set, returns zero if the set is empty */
|
|
static inline uint_fast8_t QPSet_findMax(QPSet const * const me) {
|
|
#if (QF_MAX_ACTIVE <= 32)
|
|
return QF_LOG2(me->bits);
|
|
#else
|
|
return (me->bits[1] != 0U)
|
|
? (QF_LOG2(me->bits[1]) + 32U)
|
|
: (QF_LOG2(me->bits[0]));
|
|
#endif
|
|
}
|
|
|
|
/*${QF-types::QSubscrList} .................................................*/
|
|
/*! Subscriber List (for publish-subscribe)
|
|
*
|
|
* @details
|
|
* This data type represents a set of Active Objects that subscribe to
|
|
* a given signal. The set is represented as priority-set, where each
|
|
* bit corresponds to the unique QF-priority of an AO (see ::QPrioSpec).
|
|
*/
|
|
typedef QPSet QSubscrList;
|
|
/*$enddecl${QF-types} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
|
|
/*$declare${QF::QActive} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
|
|
|
|
/*${QF::QActive} ...........................................................*/
|
|
/*! @brief Active object class (based on the QHsm implementation strategy)
|
|
* @class QActive
|
|
* @extends QHsm
|
|
*
|
|
* @details
|
|
* Active objects are encapsulated tasks (each containing an event queue and
|
|
* a state machine) that communicate with one another asynchronously by
|
|
* sending and receiving events. Within an active object, events are
|
|
* processed in a run-to-completion (RTC) fashion, while QF encapsulates
|
|
* all the details of thread-safe event exchange and queuing.<br>
|
|
*
|
|
* QActive represents an active object that uses the QHsm-style
|
|
* implementation strategy for state machines. This strategy is tailored
|
|
* to manual coding, but it is also supported by the QM modeling tool.
|
|
* The resulting code is slower than in the ::QMsm-style implementation
|
|
* strategy.
|
|
*
|
|
* @note
|
|
* QActive is not intended to be instantiated directly, but rather serves
|
|
* as the abstract base class for derivation of active objects in the
|
|
* applications.
|
|
*
|
|
* @sa QMActive
|
|
*
|
|
* @usage
|
|
* The following example illustrates how to derive an active object from
|
|
* QActive.
|
|
* @include qf_qactive.c
|
|
*/
|
|
typedef struct QActive {
|
|
/* protected: */
|
|
QHsm super;
|
|
|
|
/* private: */
|
|
|
|
#ifdef QF_EQUEUE_TYPE
|
|
/*! OS-dependent event-queue type
|
|
* @private @memberof QActive
|
|
*
|
|
* @details
|
|
* The type of the queue depends on the underlying operating system or
|
|
* a kernel. Many kernels support "message queues" that can be adapted
|
|
* to deliver QF events to the active object. Alternatively, QF provides
|
|
* a native event queue implementation that can be used as well.
|
|
*
|
|
* @note
|
|
* The native QF event queue is configured by defining the macro
|
|
* #QF_EQUEUE_TYPE as ::QEQueue.
|
|
*/
|
|
QF_EQUEUE_TYPE eQueue;
|
|
#endif /* def QF_EQUEUE_TYPE */
|
|
|
|
#ifdef QF_OS_OBJECT_TYPE
|
|
/*! OS-dependent per-thread object
|
|
* @private @memberof QActive
|
|
*
|
|
* @details
|
|
* This data might be used in various ways, depending on the QF port.
|
|
* In some ports me->osObject is used to block the calling thread when
|
|
* the native QF queue is empty. In other QF ports the OS-dependent
|
|
* object might be used differently.
|
|
*/
|
|
QF_OS_OBJECT_TYPE osObject;
|
|
#endif /* def QF_OS_OBJECT_TYPE */
|
|
|
|
#ifdef QF_THREAD_TYPE
|
|
/*! OS-dependent representation of the thread of the active object
|
|
* @private @memberof QActive
|
|
*
|
|
* @details
|
|
* This data might be used in various ways, depending on the QF port.
|
|
* In some ports me->thread is used store the thread handle. In other ports
|
|
* me->thread can be a pointer to the Thread-Local-Storage (TLS).
|
|
*/
|
|
QF_THREAD_TYPE thread;
|
|
#endif /* def QF_THREAD_TYPE */
|
|
|
|
/* public: */
|
|
|
|
/*! QF-priority [1..#QF_MAX_ACTIVE] of this AO.
|
|
* @private @memberof QActive
|
|
* @sa ::QPrioSpec
|
|
*/
|
|
uint8_t prio;
|
|
|
|
/*! preemption-threshold [1..#QF_MAX_ACTIVE] of this AO.
|
|
* @private @memberof QActive
|
|
* @sa ::QPrioSpec
|
|
*/
|
|
uint8_t pthre;
|
|
|
|
/* private: */
|
|
} QActive;
|
|
|
|
/* protected: */
|
|
|
|
/*! ::QActive constructor (abstract base class)
|
|
* @protected @memberof QActive
|
|
*/
|
|
void QActive_ctor(QActive * const me,
|
|
QStateHandler const initial);
|
|
|
|
/* private: */
|
|
|
|
/*! Starts execution of an active object and registers the object
|
|
* with the framework
|
|
* @private @memberof QActive
|
|
*
|
|
* @details
|
|
* Starts execution of the AO and registers the AO with the framework.
|
|
*
|
|
* @param[in] prioSpec priority specification for the AO (See ::QPrioSpec)
|
|
* @param[in] qSto pointer to the storage for the ring buffer of the
|
|
* event queue
|
|
* @param[in] qLen length of the event queue [# ::QEvt* pointers]
|
|
* @param[in] stkSto pointer to the stack storage (might be NULL)
|
|
* @param[in] stkSize stack size [bytes]
|
|
* @param[in] par pointer to an extra parameter (might be NULL)
|
|
*
|
|
* @usage
|
|
* The following example shows starting an AO when a per-task stack
|
|
* is needed:
|
|
* @include qf_start.c
|
|
*/
|
|
void QActive_start_(QActive * const me,
|
|
QPrioSpec const prioSpec,
|
|
QEvt const * * const qSto,
|
|
uint_fast16_t const qLen,
|
|
void * const stkSto,
|
|
uint_fast16_t const stkSize,
|
|
void const * const par);
|
|
|
|
/* protected: */
|
|
|
|
#ifdef QF_ACTIVE_STOP
|
|
/*! Stops execution of an active object and removes it from the
|
|
* framework's supervision
|
|
* @protected @memberof QActive
|
|
*
|
|
* @attention
|
|
* QActive_stop() must be called only from the AO that is about
|
|
* to stop its execution. By that time, any pointers or references
|
|
* to the AO are considered invalid (dangling) and it becomes
|
|
* illegal for the rest of the application to post events to the AO.
|
|
*/
|
|
void QActive_stop(QActive * const me);
|
|
#endif /* def QF_ACTIVE_STOP */
|
|
|
|
/* private: */
|
|
|
|
/*! Posts an event `e` directly to the event queue of the active object
|
|
* using the First-In-First-Out (FIFO) policy.
|
|
* @private @memberof QActive
|
|
*
|
|
* @details
|
|
* Direct event posting is the simplest asynchronous communication
|
|
* method available in QF.
|
|
*
|
|
* @param[in] e pointer to the event to be posted
|
|
* @param[in] margin number of required free slots in the queue
|
|
* after posting the event or ::QF_NO_MARGIN.
|
|
* @param[in] sender pointer to a sender object (used in QS only)
|
|
*
|
|
* @returns
|
|
* 'true' (success) if the posting succeeded (with the provided margin)
|
|
* and 'false' (failure) when the posting fails.
|
|
*
|
|
* @attention
|
|
* For `margin` == ::QF_NO_MARGIN, this function will assert internally
|
|
* if the event posting fails. In that case, it is unnecessary to check
|
|
* the retrun value from this function.
|
|
*
|
|
* @note
|
|
* This function might be implemented differently in various QP/C++
|
|
* ports. The provided implementation assumes that the ::QEQueue
|
|
* class is used for the ::QActive event queue.
|
|
*
|
|
* @usage
|
|
* @include qf_post.cpp
|
|
*
|
|
* @sa
|
|
* QActive_postLIFO()
|
|
*/
|
|
bool QActive_post_(QActive * const me,
|
|
QEvt const * const e,
|
|
uint_fast16_t const margin,
|
|
void const * const sender);
|
|
|
|
/*! Posts an event `e` directly to the event queue of the active object
|
|
* using the Last-In-First-Out (LIFO) policy.
|
|
* @private @memberof QActive
|
|
*
|
|
* @details
|
|
* The LIFO policy should be used only for self-posting and with caution,
|
|
* because it alters order of events in the queue.
|
|
*
|
|
* @param[in] e pointer to the event to be posted
|
|
*
|
|
* @attention
|
|
* This function asserts internally if the posting fails.
|
|
*
|
|
* @note
|
|
* This function might be implemented differently in various QP/C++
|
|
* ports. The provided implementation assumes that the ::QEQueue
|
|
* class is used for the QActive event queue.
|
|
*
|
|
* @sa
|
|
* QActive_post()
|
|
*/
|
|
void QActive_postLIFO_(QActive * const me,
|
|
QEvt const * const e);
|
|
|
|
/*! Get an event from the event queue of an active object
|
|
* @private @memberof QActive
|
|
*
|
|
* @details
|
|
* The behavior of this function depends on the kernel used in the
|
|
* QF port. For built-in kernels (Vanilla or QK) the function can be
|
|
* called only when the queue is not empty, so it doesn't block. For
|
|
* a blocking kernel/OS the function can block and wait for delivery
|
|
* of an event.
|
|
*
|
|
* @returns
|
|
* A pointer to the received event. The returned pointer is guaranteed
|
|
* to be valid (can't be NULL).
|
|
*
|
|
* @note
|
|
* This function might be implemented differently in various QP/C++
|
|
* ports. The provided implementation assumes that the ::QEQueue
|
|
* class is used for the QActive event queue.
|
|
*/
|
|
QEvt const * QActive_get_(QActive * const me);
|
|
|
|
/* public: */
|
|
|
|
/*! Subscribes for delivery of signal `sig` to the active object
|
|
* @public @memberof QActive
|
|
*
|
|
* @details
|
|
* This function is part of the Publish-Subscribe event delivery
|
|
* mechanism available in QF. Subscribing to an event means that the
|
|
* framework will start posting all published events with a given signal
|
|
* `sig` to the event queue of the active object.
|
|
*
|
|
* @param[in] sig event signal to subscribe
|
|
*
|
|
* The following example shows how the Table active object subscribes
|
|
* to three signals in the initial transition:
|
|
* @include qf_subscribe.cpp
|
|
*
|
|
* @sa
|
|
* QActive_publish_(), QActive_unsubscribe(), and
|
|
* QActive_unsubscribeAll()
|
|
*/
|
|
void QActive_subscribe(QActive const * const me,
|
|
enum_t const sig);
|
|
|
|
/*! Unsubscribes from the delivery of signal `sig` to the active object
|
|
* @public @memberof QActive
|
|
*
|
|
* @details
|
|
* This function is part of the Publish-Subscribe event delivery
|
|
* mechanism available in QF. Un-subscribing from an event means that
|
|
* the framework will stop posting published events with a given signal
|
|
* `sig` to the event queue of the active object.
|
|
*
|
|
* @param[in] sig event signal to unsubscribe
|
|
*
|
|
* @note
|
|
* Due to the latency of event queues, an active object should NOT
|
|
* assume that a given signal `sig` will never be dispatched to the
|
|
* state machine of the active object after un-subscribing from that
|
|
* signal. The event might be already in the queue, or just about to
|
|
* be posted and the un-subscribe operation will not flush such events.
|
|
*
|
|
* @note
|
|
* Un-subscribing from a signal that has never been subscribed in the
|
|
* first place is considered an error and QF will raise an assertion.
|
|
*
|
|
* @sa
|
|
* QActive_publish_(), QActive_subscribe(), and
|
|
* QActive_unsubscribeAll()
|
|
*/
|
|
void QActive_unsubscribe(QActive const * const me,
|
|
enum_t const sig);
|
|
|
|
/*! Unsubscribes from the delivery of all signals to the active object
|
|
* @public @memberof QActive
|
|
*
|
|
* @details
|
|
* This function is part of the Publish-Subscribe event delivery
|
|
* mechanism available in QF. Un-subscribing from all events means that
|
|
* the framework will stop posting any published events to the event
|
|
* queue of the active object.
|
|
*
|
|
* @note
|
|
* Due to the latency of event queues, an active object should NOT
|
|
* assume that no events will ever be dispatched to the state machine of
|
|
* the active object after un-subscribing from all events.
|
|
* The events might be already in the queue, or just about to be posted
|
|
* and the un-subscribe operation will not flush such events. Also, the
|
|
* alternative event-delivery mechanisms, such as direct event posting or
|
|
* time events, can be still delivered to the event queue of the active
|
|
* object.
|
|
*
|
|
* @sa
|
|
* QActive_publish_(), QActive_subscribe(), and QActive_unsubscribe()
|
|
*/
|
|
void QActive_unsubscribeAll(QActive const * const me);
|
|
|
|
/*! Publish event to all subscribers of a given signal `e->sig`
|
|
* @static @public @memberof QActive
|
|
*
|
|
* @details
|
|
* This function posts (using the FIFO policy) the event @a e to **all**
|
|
* active objects that have subscribed to the signal @a e->sig, which is
|
|
* called _multicasting_. The multicasting performed in this function is
|
|
* very efficient based on reference-counting inside the published event
|
|
* ("zero-copy" event multicasting). This function is designed to be
|
|
* callable from any part of the system, including ISRs, device drivers,
|
|
* and active objects.
|
|
*
|
|
* @note
|
|
* To avoid any unexpected re-ordering of events posted into AO queues,
|
|
* the event multicasting is performed with scheduler **locked**.
|
|
* However, the scheduler is locked only up to the priority level of
|
|
* the highest-priority subscriber, so any AOs of even higher priority,
|
|
* which did not subscribe to this event are *not* affected.
|
|
*/
|
|
void QActive_psInit(
|
|
QSubscrList * const subscrSto,
|
|
enum_t const maxSignal);
|
|
|
|
/* private: */
|
|
|
|
/*! Publish event to all subscribers of a given signal `e->sig`
|
|
* @static @private @memberof QActive
|
|
*
|
|
* @details
|
|
* This function posts (using the FIFO policy) the event @a e to **all**
|
|
* active objects that have subscribed to the signal @a e->sig, which is
|
|
* called _multicasting_. The multicasting performed in this function is
|
|
* very efficient based on reference-counting inside the published event
|
|
* ("zero-copy" event multicasting). This function is designed to be
|
|
* callable from any part of the system, including ISRs, device drivers,
|
|
* and active objects.
|
|
*
|
|
* @note
|
|
* To avoid any unexpected re-ordering of events posted into AO queues,
|
|
* the event multicasting is performed with scheduler **locked**.
|
|
* However, the scheduler is locked only up to the priority level of
|
|
* the highest-priority subscriber, so any AOs of even higher priority,
|
|
* which did not subscribe to this event are *not* affected.
|
|
*/
|
|
void QActive_publish_(
|
|
QEvt const * const e,
|
|
void const * const sender,
|
|
uint_fast8_t const qs_id);
|
|
|
|
/* protected: */
|
|
|
|
/*! Defer an event to a given separate event queue
|
|
* @protected @memberof QActive
|
|
*
|
|
* @details
|
|
* This function is part of the event deferral support. An active object
|
|
* uses this function to defer an event `e` to the QF-supported native
|
|
* event queue `eq`. QF correctly accounts for another outstanding
|
|
* reference to the event and will not recycle the event at the end of
|
|
* the RTC step. Later, the active object might recall one event at a
|
|
* time from the event queue.
|
|
*
|
|
* @param[in] eq pointer to a "raw" thread-safe queue to recall
|
|
* an event from.
|
|
* @param[in] e pointer to the event to be deferred
|
|
*
|
|
* @returns
|
|
* 'true' (success) when the event could be deferred and 'false'
|
|
* (failure) if event deferral failed due to overflowing the queue.
|
|
*
|
|
* An active object can use multiple event queues to defer events of
|
|
* different kinds.
|
|
*
|
|
* @sa
|
|
* QActive_recall(), ::QEQueue, QActive_flushDeferred()
|
|
*/
|
|
bool QActive_defer(QActive const * const me,
|
|
QEQueue * const eq,
|
|
QEvt const * const e);
|
|
|
|
/*! Recall a deferred event from a given event queue
|
|
* @protected @memberof QActive
|
|
*
|
|
* @details
|
|
* This function is part of the event deferral support. An active object
|
|
* uses this function to recall a deferred event from a given QF
|
|
* event queue. Recalling an event means that it is removed from the
|
|
* deferred event queue `eq` and posted (LIFO) to the event queue of
|
|
* the active object.
|
|
*
|
|
* @param[in] eq pointer to a "raw" thread-safe queue to recall
|
|
* an event from.
|
|
*
|
|
* @returns
|
|
* 'true' if an event has been recalled and 'false' if not.
|
|
*
|
|
* @note
|
|
* An active object can use multiple event queues to defer events of
|
|
* different kinds.
|
|
*
|
|
* @sa
|
|
* QActive_recall(), QActive_postLIFO_(), ::QEQueue
|
|
*/
|
|
bool QActive_recall(QActive * const me,
|
|
QEQueue * const eq);
|
|
|
|
/*! Flush the specified deferred queue 'eq'
|
|
* @protected @memberof QActive
|
|
*
|
|
* @details
|
|
* This function is part of the event deferral support. An active object
|
|
* can use this function to flush a given QF event queue. The function
|
|
* makes sure that the events are not leaked.
|
|
*
|
|
* @param[in] eq pointer to a "raw" thread-safe queue to flush.
|
|
*
|
|
* @returns
|
|
* the number of events actually flushed from the queue.
|
|
*
|
|
* @sa
|
|
* QActive_defer(), QActive_recall(), ::QEQueue
|
|
*/
|
|
uint_fast16_t QActive_flushDeferred(QActive const * const me,
|
|
QEQueue * const eq);
|
|
|
|
/* public: */
|
|
|
|
/*! Generic setting of additional attributes (useful in QP ports)
|
|
* @public @memberof QActive
|
|
*/
|
|
void QActive_setAttr(QActive * const me,
|
|
uint32_t attr1,
|
|
void const * attr2);
|
|
|
|
/* private: */
|
|
|
|
/*! Thread routine for executing an active object `act`
|
|
* @private @memberof QActive
|
|
*/
|
|
void QActive_thread_(QActive * act);
|
|
|
|
/* protected: */
|
|
|
|
/*! Register this active object to be managed by the framework
|
|
* @protected @memberof QActive
|
|
*
|
|
* @details
|
|
* This function adds a given active object to the active objects
|
|
* managed by the QF framework. It should not be called by the
|
|
* application directly, only through the function QActive::start().
|
|
*
|
|
* @note
|
|
* The priority of the active object a should be set before calling
|
|
* this function.
|
|
*
|
|
* @sa QActive_unregister_()
|
|
*/
|
|
void QActive_register_(QActive * const me);
|
|
|
|
/*! Un-register the active object from the framework
|
|
* @protected @memberof QActive
|
|
*
|
|
* @details
|
|
* This function un-registers a given active object from the active objects
|
|
* managed by the QF framework. It should not be called by the QP ports.
|
|
*
|
|
* @param[in] me pointer to the active object to remove from the
|
|
* framework.
|
|
*
|
|
* @note
|
|
* The active object that is removed from the framework can no longer
|
|
* participate in any event exchange.
|
|
*
|
|
* @sa QActive_register_()
|
|
*/
|
|
void QActive_unregister_(QActive * const me);
|
|
|
|
/* private: */
|
|
|
|
#ifdef QF_ISR_API
|
|
/*! the "FromISR" variant used in the QP port to "FreeRTOS"
|
|
* @private @memberof QActive
|
|
*/
|
|
bool QActive_postFromISR_(QActive * const me,
|
|
QEvt const * const e,
|
|
uint_fast16_t const margin,
|
|
void * par,
|
|
void const * const sender);
|
|
#endif /* def QF_ISR_API */
|
|
|
|
/* public: */
|
|
|
|
#ifdef QF_ISR_API
|
|
/*! the "FromISR" variant used in the QP port to "FreeRTOS"
|
|
* @private @memberof QActive
|
|
*/
|
|
void QActive_publishFromISR_(
|
|
QEvt const * e,
|
|
void * par,
|
|
void const * sender);
|
|
#endif /* def QF_ISR_API */
|
|
|
|
/*! Internal array of registered active objects
|
|
* @static @private @memberof QActive
|
|
*/
|
|
extern QActive * QActive_active_[QF_MAX_ACTIVE + 1U];
|
|
|
|
/*! pointer to the array of all subscriber AOs for a given event signal.
|
|
* @static @private @memberof QActive
|
|
*/
|
|
extern QSubscrList * QActive_subscrList_;
|
|
|
|
/*! The maximum published signal (the size of the subscrList_ array)
|
|
* @static @private @memberof QActive
|
|
*/
|
|
extern enum_t QActive_maxPubSignal_;
|
|
|
|
/*! Internal array of registered active objects
|
|
* @static @private @memberof QActive
|
|
*/
|
|
extern QActive * QActive_registry_[QF_MAX_ACTIVE + 1U];
|
|
/*$enddecl${QF::QActive} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
|
|
/*$declare${QF::QActiveVtable} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
|
|
|
|
/*${QF::QActiveVtable} .....................................................*/
|
|
/*! @brief Virtual table for the QActive class */
|
|
typedef struct QActiveVtable {
|
|
struct QHsmVtable super; /*!< @protected inherits ::QHsmVtable */
|
|
|
|
/*! @private virtual function to start the AO/thread
|
|
* @sa QACTIVE_START()
|
|
*/
|
|
void (*start)(QActive * const me, QPrioSpec prio,
|
|
QEvt const * * const qSto, uint_fast16_t const qLen,
|
|
void * const stkSto, uint_fast16_t const stkSize,
|
|
void const * const par);
|
|
|
|
/*! @private virtual function to asynchronously post (FIFO)
|
|
* an event to the AO
|
|
* @sa QACTIVE_POST() and QACTIVE_POST_X()
|
|
*/
|
|
bool (*post)(QActive * const me, QEvt const * const e,
|
|
uint_fast16_t const margin, void const * const sender);
|
|
|
|
/*! @private virtual function to asynchronously post (LIFO)
|
|
* an event to the AO
|
|
* @sa QACTIVE_POST_LIFO()
|
|
*/
|
|
void (*postLIFO)(QActive * const me, QEvt const * const e);
|
|
|
|
} QActiveVtable;
|
|
/*$enddecl${QF::QActiveVtable} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
|
|
/*$declare${QF::QMActive} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
|
|
|
|
/*${QF::QMActive} ..........................................................*/
|
|
/*! @brief Active object class (based on QMsm implementation strategy)
|
|
* @class QMActive
|
|
* @extends QActive
|
|
*
|
|
* @details
|
|
* ::QMActive represents an active object that uses the ::QMsm style state
|
|
* machine implementation strategy. This strategy requires the use of the
|
|
* QM modeling tool to generate state machine code automatically, but the
|
|
* code is faster than in the ::QHsm style implementation strategy and needs
|
|
* less run-time support (smaller event-processor).
|
|
*
|
|
* @note
|
|
* ::QMActive is not intended to be instantiated directly, but rather serves
|
|
* as the base class for derivation of active objects in the application.
|
|
*
|
|
* @tr{AQP214}
|
|
*
|
|
* @usage
|
|
* The following example illustrates how to derive an active object from
|
|
* ::QMActive. Please note that the ::QActive member @c super is defined as
|
|
* the **first** member of the derived struct (see @ref oop).
|
|
* @include qf_qmactive.c
|
|
*/
|
|
typedef struct {
|
|
/* protected: */
|
|
QActive super;
|
|
} QMActive;
|
|
|
|
/* protected: */
|
|
|
|
/*! Constructor of ::QMActive class.
|
|
* @protected @memberof QMActive
|
|
*
|
|
* @details
|
|
* Performs the first step of active object initialization by assigning
|
|
* the virtual pointer and calling the superclass constructor.
|
|
*
|
|
* @param[in,out] me current instance pointer (see @ref oop)
|
|
* @param[in] initial pointer to the event to be dispatched to the MSM
|
|
*
|
|
* @note Must be called only ONCE before QHSM_INIT().
|
|
*
|
|
* @sa QHsm_ctor()
|
|
*/
|
|
void QMActive_ctor(QMActive * const me,
|
|
QStateHandler const initial);
|
|
/*$enddecl${QF::QMActive} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
|
|
/*$declare${QF::QMActiveVtable} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
|
|
|
|
/*${QF::QMActiveVtable} ....................................................*/
|
|
/*! @brief Virtual Table for the ::QMActive class (inherited
|
|
* from ::QActiveVtable)
|
|
*
|
|
* @note
|
|
* ::QMActive inherits ::QActive exactly, without adding any new virtual
|
|
* functions and therefore, ::QMActiveVtable is typedef'ed as ::QActiveVtable.
|
|
*/
|
|
typedef QActiveVtable QMActiveVtable;
|
|
/*$enddecl${QF::QMActiveVtable} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
|
|
/*$declare${QF::QTimeEvt} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
|
|
|
|
/*${QF::QTimeEvt} ..........................................................*/
|
|
/*! @brief Time Event class
|
|
* @class QTimeEvt
|
|
* @extends QEvt
|
|
*
|
|
* @details
|
|
* Time events are special QF events equipped with the notion of time passage.
|
|
* The basic usage model of the time events is as follows. An active object
|
|
* allocates one or more ::QTimeEvt objects (provides the storage for them).
|
|
* When the active object needs to arrange for a timeout, it arms one of its
|
|
* time events to fire either just once (one-shot) or periodically. Each time
|
|
* event times out independently from the others, so a QF application can make
|
|
* multiple parallel timeout requests (from the same or different active
|
|
* objects). When QF detects that the appropriate moment has arrived, it
|
|
* inserts the time event directly into the recipient's event queue. The
|
|
* recipient then processes the time event just like any other event.
|
|
*
|
|
* Time events, as any other QF events derive from the ::QEvt base class.
|
|
* Typically, you will use a time event as-is, but you can also further
|
|
* derive more specialized time events from it by adding some more data
|
|
* members and/or specialized functions that operate on the specialized
|
|
* time events.
|
|
*
|
|
* Internally, the armed time events are organized into linked lists--one
|
|
* list for every supported ticking rate. These linked lists are scanned in
|
|
* every invocation of the QTIMEEVT_TICK_X() macro. Only armed (timing out)
|
|
* time events are in the list, so only armed time events consume CPU cycles.
|
|
*
|
|
* @sa ::QTimeEvt for the description of the data members
|
|
*
|
|
* @tr{AQP215}
|
|
*
|
|
* @note
|
|
* QF manages the time events in the QTIMEEVT_TICK_X() macro, which must
|
|
* be called periodically, from the clock tick ISR or from other periodic
|
|
* source. QTIMEEVT_TICK_X() caYou might also use the special ::QTicker
|
|
* active object.
|
|
*
|
|
* @note
|
|
* Even though ::QTimeEvt is a subclass of ::QEvt, ::QTimeEvt instances can NOT
|
|
* be allocated dynamically from event pools. In other words, it is illegal to
|
|
* allocate ::QTimeEvt instances with the Q_NEW() or Q_NEW_X() macros.
|
|
*/
|
|
typedef struct QTimeEvt {
|
|
/* protected: */
|
|
QEvt super;
|
|
|
|
/* private: */
|
|
|
|
/*! link to the next time event in the list
|
|
* @private @memberof QTimeEvt
|
|
*/
|
|
struct QTimeEvt * volatile next;
|
|
|
|
/*! The active object that receives the time events
|
|
* @private @memberof QTimeEvt
|
|
*/
|
|
void * volatile act;
|
|
|
|
/*! Internal down-counter of the time event.
|
|
* @private @memberof QTimeEvt
|
|
*
|
|
* @details
|
|
* The down-counter is decremented by 1 in every QTimeEvt_tick_() call.
|
|
* The time event fires (gets posted or published) when the down-counter
|
|
* reaches zero.
|
|
*/
|
|
QTimeEvtCtr volatile ctr;
|
|
|
|
/*! Interval for periodic time event (zero for one-shot time event)
|
|
* @private @memberof QTimeEvt
|
|
*
|
|
* @details
|
|
* The value of the interval is re-loaded to the internal down-counter
|
|
* when the time event expires, so that the time event keeps timing out
|
|
* periodically.
|
|
*/
|
|
QTimeEvtCtr interval;
|
|
|
|
/* public: */
|
|
} QTimeEvt;
|
|
|
|
/* public: */
|
|
|
|
/*! The extended "constructor" to initialize a Time Event.
|
|
* @public @memberof QTimeEvt
|
|
*
|
|
* @details
|
|
* When creating a time event, you must commit it to a specific active object
|
|
* `act`, tick rate `tickRate` and event signal `sig`. You cannot change
|
|
* these attributes later.
|
|
*
|
|
* @param[in,out] me current instance pointer (see @ref oop)
|
|
* @param[in] act pointer to the active object associated with this
|
|
* time event. The time event will post itself to this AO.
|
|
* @param[in] sig signal to associate with this time event.
|
|
* @param[in] tickRate system clock tick rate to associate with this
|
|
* time event in the range [0..15].
|
|
*
|
|
* @note You should call the constructor exactly once for every Time Event
|
|
* object **before** arming the Time Event. The ideal place for initializing
|
|
* the time event(s) associated with a given AO is the AO's constructor.
|
|
*/
|
|
void QTimeEvt_ctorX(QTimeEvt * const me,
|
|
QActive * const act,
|
|
enum_t const sig,
|
|
uint_fast8_t const tickRate);
|
|
|
|
/*! Arm a time event (one shot or periodic) for direct event posting.
|
|
* @public @memberof QTimeEvt
|
|
*
|
|
* @details
|
|
* Arms a time event to fire in a specified number of clock ticks and with
|
|
* a specified interval. If the interval is zero, the time event is armed for
|
|
* one shot ('one-shot' time event). When the timeout expires, the time event
|
|
* gets directly posted (using the FIFO policy) into the event queue of the
|
|
* host active object. After posting, a one-shot time event gets automatically
|
|
* disarmed while a periodic time event (interval != 0) is automatically
|
|
* re-armed.
|
|
*
|
|
* A time event can be disarmed at any time by calling QTimeEvt_disarm().
|
|
* Also, a time event can be re-armed to fire in a different number of clock
|
|
* ticks by calling the QTimeEvt_rearm().
|
|
*
|
|
* @param[in,out] me current instance pointer (see @ref oop)
|
|
* @param[in] nTicks number of clock ticks (at the associated rate)
|
|
* to rearm the time event with.
|
|
* @param[in] interval interval (in clock ticks) for periodic time event.
|
|
*
|
|
* @attention
|
|
* Arming an already armed time event is __not__ allowed and is considered
|
|
* a programming error. The QP/C framework will assert if it detects an
|
|
* attempt to arm an already armed time event.
|
|
*
|
|
* @usage
|
|
* The following example shows how to arm a periodic time event as well as
|
|
* one-shot time event from a state machine of an active object:
|
|
* @include qf_tevt.c
|
|
*/
|
|
void QTimeEvt_armX(QTimeEvt * const me,
|
|
QTimeEvtCtr const nTicks,
|
|
QTimeEvtCtr const interval);
|
|
|
|
/*! Disarm a time event.
|
|
* @public @memberof QTimeEvt
|
|
*
|
|
* @details
|
|
* Disarm the time event so it can be safely reused.
|
|
*
|
|
* @param[in,out] me current instance pointer (see @ref oop)
|
|
*
|
|
* @returns
|
|
* 'true' if the time event was truly disarmed, that is, it was running.
|
|
* The return of 'false' means that the time event was not truly disarmed,
|
|
* because it was not running. The 'false' return is only possible for one-
|
|
* shot time events that have been automatically disarmed upon expiration.
|
|
* In this case the 'false' return means that the time event has already
|
|
* been posted or published and should be expected in the active object's
|
|
* state machine.
|
|
*
|
|
* @note
|
|
* there is no harm in disarming an already disarmed time event
|
|
*/
|
|
bool QTimeEvt_disarm(QTimeEvt * const me);
|
|
|
|
/*! Rearm a time event.
|
|
* @public @memberof QTimeEvt
|
|
*
|
|
* @details
|
|
* Rearms a time event with a new number of clock ticks. This function can
|
|
* be used to adjust the current period of a periodic time event or to
|
|
* prevent a one-shot time event from expiring (e.g., a watchdog time event).
|
|
* Rearming a periodic timer leaves the interval unchanged and is a convenient
|
|
* method to adjust the phasing of a periodic time event.
|
|
*
|
|
* @param[in,out] me current instance pointer (see @ref oop)
|
|
* @param[in] nTicks number of clock ticks (at the associated rate)
|
|
* to rearm the time event with.
|
|
*
|
|
* @returns
|
|
* 'true' if the time event was running as it was re-armed. The 'false'
|
|
* return means that the time event was not truly rearmed because it was
|
|
* not running. The 'false' return is only possible for one-shot time events
|
|
* that have been automatically disarmed upon expiration. In this case the
|
|
* 'false' return means that the time event has already been posted or
|
|
* published and should be expected in the active object's state machine.
|
|
*/
|
|
bool QTimeEvt_rearm(QTimeEvt * const me,
|
|
QTimeEvtCtr const nTicks);
|
|
|
|
/*! Check the "was disarmed" status of a time event.
|
|
* @public @memberof QTimeEvt
|
|
*
|
|
* @details
|
|
* Useful for checking whether a one-shot time event was disarmed in the
|
|
* QTimeEvt_disarm() operation.
|
|
*
|
|
* @param[in,out] me current instance pointer (see @ref oop)
|
|
*
|
|
* @returns
|
|
* 'true' if the time event was truly disarmed in the last QTimeEvt_disarm()
|
|
* operation. The 'false' return means that the time event was not truly
|
|
* disarmed, because it was not running at that time. The 'false' return is
|
|
* only possible for one-shot time events that have been automatically disarmed
|
|
* upon expiration. In this case the 'false' return means that the time event
|
|
* has already been posted or published and should be expected in the active
|
|
* object's event queue.
|
|
*
|
|
* @note
|
|
* This function has a **side effect** of setting the "was disarmed" status,
|
|
* which means that the second and subsequent times this function is called
|
|
* the function will return 'true'.
|
|
*/
|
|
bool QTimeEvt_wasDisarmed(QTimeEvt * const me);
|
|
|
|
/*! Get the current value of the down-counter of a time event.
|
|
* @public @memberof QTimeEvt
|
|
*
|
|
* @details
|
|
* Useful for checking how many clock ticks (at the tick rate associated
|
|
* with the time event) remain until the time event expires.
|
|
*
|
|
* @param[in,out] me current instance pointer (see @ref oop)
|
|
*
|
|
* @returns
|
|
* For an armed time event, the function returns the current value of the
|
|
* down-counter of the given time event. If the time event is not armed,
|
|
* the function returns 0.
|
|
*
|
|
* @note
|
|
* The function is thread-safe.
|
|
*/
|
|
QTimeEvtCtr QTimeEvt_currCtr(QTimeEvt const * const me);
|
|
|
|
/*! Processes all armed time events at every clock tick.
|
|
* @static @private @memberof QTimeEvt
|
|
*
|
|
* @details
|
|
* This internal helper function processes all armed ::QTimeEvt objects
|
|
* associated wit the tick rate `tickRate`.
|
|
*
|
|
* This function must be called periodically from a time-tick ISR or from
|
|
* a task so that QF can manage the timeout events assigned to the given
|
|
* system clock tick rate.
|
|
*
|
|
* @param[in] tickRate clock tick rate serviced in this call [1..15].
|
|
* @param[in] sender pointer to a sender object (only for QS tracing)
|
|
*
|
|
* @note
|
|
* this function should be called only via the macro QTIMEEVT_TICK_X()
|
|
*
|
|
* @note
|
|
* the calls to QTimeEvt_tick_() with different `tickRate` parameter can
|
|
* preempt each other. For example, higher clock tick rates might be
|
|
* serviced from interrupts while others from tasks (active objects).
|
|
*
|
|
* @sa ::QTimeEvt.
|
|
*/
|
|
void QTimeEvt_tick_(
|
|
uint_fast8_t const tickRate,
|
|
void const * const sender);
|
|
|
|
#ifdef Q_UTEST
|
|
/*! Processes one clock tick for QUTest */
|
|
void QTimeEvt_tick1_(
|
|
uint_fast8_t const tickRate,
|
|
void const * const sender);
|
|
#endif /* def Q_UTEST */
|
|
|
|
/*! Returns 'true' if there are no armed time events at a given tick rate.
|
|
* @static @public @memberof QTimeEvt
|
|
*
|
|
* @details
|
|
* Find out if any time events are armed at the given clock tick rate.
|
|
*
|
|
* @param[in] tickRate system clock tick rate to find out about.
|
|
*
|
|
* @returns
|
|
* 'true' if no time events are armed at the given tick rate and
|
|
* 'false' otherwise.
|
|
*
|
|
* @note
|
|
* This function should be called in critical section.
|
|
*/
|
|
bool QTimeEvt_noActive(uint_fast8_t const tickRate);
|
|
|
|
/*! heads of linked lists of time events, one for every clock tick rate */
|
|
extern QTimeEvt QTimeEvt_timeEvtHead_[QF_MAX_TICK_RATE];
|
|
/*$enddecl${QF::QTimeEvt} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
|
|
/*$declare${QF::QTicker} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
|
|
|
|
/*${QF::QTicker} ...........................................................*/
|
|
/*! @brief "Ticker" Active Object class
|
|
* @class QTicker
|
|
* @extends QActive
|
|
*
|
|
* @details
|
|
* QTicker is an efficient active object specialized to process QF system
|
|
* clock tick at a specified tick rate [0..#QF_MAX_TICK_RATE].
|
|
* Placing system clock tick processing in an active object allows you
|
|
* to remove the non-deterministic QTIMEEVT_TICK_X() processing from the
|
|
* interrupt level and move it into the thread-level, where you can prioritize
|
|
* it as low as you wish.
|
|
*
|
|
* @usage
|
|
* The following example illustrates use of QTicker active objects:
|
|
* @include qf_ticker.c
|
|
*/
|
|
typedef struct {
|
|
/* protected: */
|
|
QActive super;
|
|
} QTicker;
|
|
|
|
/* public: */
|
|
|
|
/*! Constructor of the QTicker Active Object class
|
|
* @public @memberof QTicker
|
|
*/
|
|
void QTicker_ctor(QTicker * const me,
|
|
uint_fast8_t const tickRate);
|
|
|
|
/* private: */
|
|
|
|
/*! initialization (override)
|
|
* @private @memberof QTicker
|
|
*/
|
|
void QTicker_init_(
|
|
QHsm * const me,
|
|
void const * const par,
|
|
uint_fast8_t const qs_id);
|
|
|
|
/*! dispatching (override)
|
|
* @private @memberof QTicker
|
|
*/
|
|
void QTicker_dispatch_(
|
|
QHsm * const me,
|
|
QEvt const * const e,
|
|
uint_fast8_t const qs_id);
|
|
|
|
/* public: */
|
|
|
|
/*! post (override)
|
|
* @private @memberof QTicker
|
|
*/
|
|
bool QTicker_post_(
|
|
QActive * const me,
|
|
QEvt const * const e,
|
|
uint_fast16_t const margin,
|
|
void const * const sender);
|
|
|
|
/*! post-LIFO (override)
|
|
* @private @memberof QTicker
|
|
*/
|
|
void QTicker_postLIFO_(
|
|
QActive * const me,
|
|
QEvt const * const e);
|
|
/*$enddecl${QF::QTicker} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
|
|
|
|
/*$declare${QF::QF-base} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
|
|
|
|
/*${QF::QF-base::Attr} .....................................................*/
|
|
/*! @brief QF active object framework
|
|
* @class QF
|
|
*/
|
|
typedef struct QF_Attr {
|
|
uint8_t dummy; /*< dummy attribute */
|
|
} QF;
|
|
|
|
/*${QF::QF-base::intLock_} .................................................*/
|
|
/*! Interrupt lock up-down counter (used in some QF ports )
|
|
* @static @private @memberof QF
|
|
*/
|
|
extern uint_fast8_t volatile QF_intLock_;
|
|
|
|
/*${QF::QF-base::intNest_} .................................................*/
|
|
/*! Interrupt nesting up-down counter (used in some QF ports )
|
|
* @static @private @memberof QF
|
|
*/
|
|
extern uint_fast8_t volatile QF_intNest_;
|
|
|
|
/*${QF::QF-base::init} .....................................................*/
|
|
/*! QF initialization
|
|
* @static @public @memberof QF
|
|
*
|
|
* @details
|
|
* Initializes QF and must be called exactly once before any other QF
|
|
* function. Typcially, QF_init() is called from main() even before
|
|
* initializing the Board Support Package (BSP).
|
|
*
|
|
* @note
|
|
* QF_init() clears the internal QF variables, so that the framework
|
|
* can start correctly even if the startup code fails to clear the
|
|
* uninitialized data (as is required by the C Standard).
|
|
*/
|
|
void QF_init(void);
|
|
|
|
/*${QF::QF-base::stop} .....................................................*/
|
|
/*! Function invoked by the application layer to stop the QF
|
|
* application and return control to the OS/Kernel.
|
|
* @static @public @memberof QF
|
|
*
|
|
* @details
|
|
* This function stops the QF application. After calling this function,
|
|
* QF attempts to gracefully stop the application. This graceful shutdown
|
|
* might take some time to complete. The typical use of this function is
|
|
* for terminating the QF application to return back to the operating
|
|
* system or for handling fatal errors that require shutting down
|
|
* (and possibly re-setting) the system.
|
|
*
|
|
* @attention
|
|
* After calling QF_stop() the application must terminate and cannot
|
|
* continue. In particular, QF_stop() is **not** intended to be followed
|
|
* by a call to QF_init() to "resurrect" the application.
|
|
*
|
|
* @sa QF_onCleanup()
|
|
*/
|
|
void QF_stop(void);
|
|
|
|
/*${QF::QF-base::run} ......................................................*/
|
|
/*! Transfers control to QF to run the application.
|
|
* @static @public @memberof QF
|
|
*
|
|
* @details
|
|
* QF_run() is typically called from your startup code after you initialize
|
|
* the QF and start at least one active object with QACTIVE_START().
|
|
*
|
|
* @returns
|
|
* In QK, the QF_run() does not return.
|
|
*/
|
|
int_t QF_run(void);
|
|
|
|
/*${QF::QF-base::psInit} ...................................................*/
|
|
/*! initialization of publish-subscribe
|
|
*
|
|
* @deprecated
|
|
* @sa QActive_psInit()
|
|
*/
|
|
static inline void QF_psInit(
|
|
QSubscrList * const subscrSto,
|
|
enum_t const maxSignal)
|
|
{
|
|
QActive_psInit(subscrSto, maxSignal);
|
|
}
|
|
|
|
/*${QF::QF-base::getQueueMin} ..............................................*/
|
|
/*! This function returns the minimum of free entries of
|
|
* the given event queue.
|
|
* @static @public @memberof QF
|
|
*
|
|
* @details
|
|
* Queries the minimum of free ever present in the given event queue of
|
|
* an active object with priority `prio`, since the active object
|
|
* was started.
|
|
*
|
|
* @note
|
|
* This function is available only when the native QF event queue
|
|
* implementation is used. Requesting the queue minimum of an unused
|
|
* priority level raises an assertion in the QF. (A priority level becomes
|
|
* used in QF after the call to the QActive_register_() function.)
|
|
*
|
|
* @param[in] prio Priority of the active object, whose queue is queried
|
|
*
|
|
* @returns
|
|
* the minimum of free ever present in the given event queue of an active
|
|
* object with priority `prio`, since the active object was started.
|
|
*/
|
|
uint_fast16_t QF_getQueueMin(uint_fast8_t const prio);
|
|
|
|
/*${QF::QF-base::onStartup} ................................................*/
|
|
/*! Startup QF callback.
|
|
* @static @public @memberof QF
|
|
*
|
|
* @details
|
|
* The purpose of the QF_onStartup() callback is to configure and enable
|
|
* hardware interrupts. The callback is invoked from QF_run(), right before
|
|
* starting the underlying real-time kernel. By that time, the application
|
|
* is considered ready to receive and service interrupts.
|
|
*
|
|
* This function is application-specific and is not implemented in QF, but
|
|
* rather in the Board Support Package (BSP) for the given application.
|
|
*/
|
|
void QF_onStartup(void);
|
|
|
|
/*${QF::QF-base::onCleanup} ................................................*/
|
|
/*! Cleanup QF callback.
|
|
* @static @public @memberof QF
|
|
*
|
|
* @details
|
|
* QF_onCleanup() is called in some QF ports before QF returns to the
|
|
* underlying real-time kernel or operating system.
|
|
*
|
|
* This function is strongly platform-specific and is not implemented in
|
|
* the QF, but either in the QF port or in the Board Support Package (BSP)
|
|
* for the given application. Some QF ports might not require implementing
|
|
* QF_onCleanup() at all, because many embedded applications don't have
|
|
* anything to exit to.
|
|
*
|
|
* @sa QF_stop()
|
|
*/
|
|
void QF_onCleanup(void);
|
|
/*$enddecl${QF::QF-base} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
|
|
/*$declare${QF::QF-dyn} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
|
|
|
|
/*${QF::QF-dyn::poolInit} ..................................................*/
|
|
/*! Event pool initialization for dynamic allocation of events.
|
|
* @static @public @memberof QF
|
|
*
|
|
* @details
|
|
* This function initializes one event pool at a time and must be called
|
|
* exactly once for each event pool before the pool can be used.
|
|
*
|
|
* @param[in] poolSto pointer to the storage for the event pool
|
|
* @param[in] poolSize size of the storage for the pool in bytes
|
|
* @param[in] evtSize the block-size of the pool in bytes, which determines
|
|
* the maximum size of events that can be allocated from the pool.
|
|
*
|
|
* @attention
|
|
* You might initialize many event pools by making many consecutive calls
|
|
* to the QF_poolInit() function. However, for the simplicity of the internal
|
|
* implementation, you must initialize event pools in the **ascending order**
|
|
* of the event size.
|
|
*
|
|
* Many RTOSes provide fixed block-size heaps, a.k.a. memory pools that can
|
|
* be adapted for QF event pools. In case such support is missing, QF provides
|
|
* a native QF event pool implementation. The macro #QF_EPOOL_TYPE_ determines
|
|
* the type of event pool used by a particular QF port. See structure ::QMPool
|
|
* for more information.
|
|
*
|
|
* @note The actual number of events available in the pool might be actually
|
|
* less than (`poolSize` / `evtSize`) due to the internal alignment
|
|
* of the blocks that the pool might perform. You can always check the
|
|
* capacity of the pool by calling QF_getPoolMin().
|
|
*
|
|
* @note The dynamic allocation of events is optional, meaning that you
|
|
* might choose not to use dynamic events. In that case calling QF_poolInit()
|
|
* and using up memory for the memory blocks is unnecessary.
|
|
*
|
|
* @sa QF initialization example for QF_init()
|
|
*/
|
|
void QF_poolInit(
|
|
void * const poolSto,
|
|
uint_fast32_t const poolSize,
|
|
uint_fast16_t const evtSize);
|
|
|
|
/*${QF::QF-dyn::poolGetMaxBlockSize} .......................................*/
|
|
/*! Obtain the block size of any registered event pools.
|
|
* @static @public @memberof QF
|
|
*
|
|
* @details
|
|
* Obtain the block size of any registered event pools
|
|
*/
|
|
uint_fast16_t QF_poolGetMaxBlockSize(void);
|
|
|
|
/*${QF::QF-dyn::getPoolMin} ................................................*/
|
|
/*! Obtain the minimum of free entries of the given event pool.
|
|
* @static @public @memberof QF
|
|
*
|
|
* @details
|
|
* This function obtains the minimum number of free blocks in the given
|
|
* event pool since this pool has been initialized by a call to QF_poolInit().
|
|
*
|
|
* @param[in] poolId event pool ID in the range 1..QF_maxPool_, where
|
|
* QF_maxPool_ is the number of event pools initialized
|
|
* with the function QF_poolInit().
|
|
*
|
|
* @returns
|
|
* the minimum number of unused blocks in the given event pool.
|
|
*/
|
|
uint_fast16_t QF_getPoolMin(uint_fast8_t const poolId);
|
|
|
|
/*${QF::QF-dyn::newX_} .....................................................*/
|
|
/*! Internal QF implementation of creating new dynamic event.
|
|
* @static @private @memberof QF
|
|
*
|
|
* @details
|
|
* Allocates an event dynamically from one of the QF event pools.
|
|
*
|
|
* @param[in] evtSize the size (in bytes) of the event to allocate
|
|
* @param[in] margin the number of un-allocated events still available
|
|
* in a given event pool after the allocation completes.
|
|
* The special value ::QF_NO_MARGIN means that this function
|
|
* will assert if allocation fails.
|
|
* @param[in] sig the signal to be assigned to the allocated event
|
|
*
|
|
* @returns
|
|
* pointer to the newly allocated event. This pointer can be NULL only if
|
|
* margin != #QF_NO_MARGIN and the event cannot be allocated with the
|
|
* specified margin still available in the given pool.
|
|
*
|
|
* @note
|
|
* The internal QF function QF_newX_() raises an assertion when the
|
|
* `margin` parameter is #QF_NO_MARGIN and allocation of the event turns
|
|
* out to be impossible due to event pool depletion, or incorrect (too big)
|
|
* size of the requested event.
|
|
*
|
|
* @note
|
|
* The application code should not call this function directly.
|
|
* The only allowed use is thorough the macros Q_NEW() or Q_NEW_X().
|
|
*/
|
|
QEvt * QF_newX_(
|
|
uint_fast16_t const evtSize,
|
|
uint_fast16_t const margin,
|
|
enum_t const sig);
|
|
|
|
/*${QF::QF-dyn::gc} ........................................................*/
|
|
/*! Recycle a dynamic event
|
|
* @static @private @memberof QF
|
|
*
|
|
* @details
|
|
* This function implements a simple garbage collector for the dynamic events.
|
|
* Only dynamic events are candidates for recycling. (A dynamic event is one
|
|
* that is allocated from an event pool, which is determined as non-zero
|
|
* e->poolId_ attribute.) Next, the function decrements the reference counter
|
|
* of the event (e->refCtr_), and recycles the event only if the counter drops
|
|
* to zero (meaning that no more references are outstanding for this event).
|
|
* The dynamic event is recycled by returning it to the pool from which
|
|
* it was originally allocated.
|
|
*
|
|
* @param[in] e pointer to the event to recycle
|
|
*
|
|
* @note
|
|
* QF invokes the garbage collector at all appropriate contexts, when
|
|
* an event can become garbage (automatic garbage collection), so the
|
|
* application code should have no need to call QF_gc() directly. The QF_gc()
|
|
* function is exposed only for special cases when your application sends
|
|
* dynamic events to the "raw" thread-safe queues (see ::QEQueue). Such
|
|
* queues are processed outside of QF and the automatic garbage collection
|
|
* is **NOT** performed for these events. In this case you need to call
|
|
* QF_gc() explicitly.
|
|
*/
|
|
void QF_gc(QEvt const * const e);
|
|
|
|
/*${QF::QF-dyn::newRef_} ...................................................*/
|
|
/*! Internal QF implementation of creating new event reference.
|
|
* @static @private @memberof QF
|
|
*
|
|
* @details
|
|
* Creates and returns a new reference to the current event e
|
|
*
|
|
* @param[in] e pointer to the current event
|
|
* @param[in] evtRef the event reference
|
|
*
|
|
* @returns
|
|
* the newly created reference to the event `e`
|
|
*
|
|
* @note
|
|
* The application code should not call this function directly.
|
|
* The only allowed use is thorough the macro Q_NEW_REF().
|
|
*/
|
|
QEvt const * QF_newRef_(
|
|
QEvt const * const e,
|
|
void const * const evtRef);
|
|
|
|
/*${QF::QF-dyn::deleteRef_} ................................................*/
|
|
/*! Internal QF implementation of deleting event reference.
|
|
* @static @private @memberof QF
|
|
*
|
|
* @details
|
|
* Deletes an existing reference to the event e
|
|
*
|
|
* @param[in] evtRef the event reference
|
|
*
|
|
* @note
|
|
* The application code should not call this function directly.
|
|
* The only allowed use is thorough the macro Q_DELETE_REF().
|
|
*/
|
|
void QF_deleteRef_(void const * const evtRef);
|
|
/*$enddecl${QF::QF-dyn} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
|
|
/*$declare${QF::QF-extern-C} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
|
|
|
|
/*${QF::QF-extern-C::onContextSw} ..........................................*/
|
|
#ifdef QF_ON_CONTEXT_SW
|
|
/*! QF context switch callback used in built-in kernels (QV, QK, QXK)
|
|
* @static @public @memberof QF
|
|
*
|
|
* @details
|
|
* This callback function provides a mechanism to perform additional
|
|
* custom operations when one of the built-in kernels switches context
|
|
* from one thread to another.
|
|
*
|
|
* @param[in] prev pointer to the previous thread (active object)
|
|
* (prev==0 means that `prev` was the idle loop)
|
|
* @param[in] next pointer to the next thread (active object)
|
|
* (next==0) means that `next` is the idle loop)
|
|
* @attention
|
|
* QF_onContextSw() is invoked with interrupts **disabled** and must also
|
|
* return with interrupts **disabled**.
|
|
*
|
|
* @note
|
|
* This callback is enabled by defining the macro #QF_ON_CONTEXT_SW.
|
|
*
|
|
* @include qf_oncontextsw.c
|
|
*/
|
|
void QF_onContextSw(
|
|
QActive * prev,
|
|
QActive * next);
|
|
#endif /* def QF_ON_CONTEXT_SW */
|
|
/*$enddecl${QF::QF-extern-C} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
|
|
|
|
/*==========================================================================*/
|
|
/*$declare${QF-macros} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
|
|
|
|
/*${QF-macros::QF_NO_MARGIN} ...............................................*/
|
|
/*! Special value of margin that causes asserting failure in case
|
|
* event allocation or event posting fails
|
|
*/
|
|
#define QF_NO_MARGIN ((uint_fast16_t)0xFFFFU)
|
|
|
|
/*${QF-macros::Q_PRIO} .....................................................*/
|
|
/*! Create a ::QPrioSpec object to specify priorty of an AO or a thread */
|
|
#define Q_PRIO(prio_, pthre_) ((QPrioSpec)((prio_) | ((pthre_) << 8U)))
|
|
|
|
/*${QF-macros::Q_NEW} ......................................................*/
|
|
#ifndef Q_EVT_CTOR
|
|
/*! Allocate a dynamic event (case when ::QEvt is a POD)
|
|
*
|
|
* @details
|
|
* The macro calls the internal QF function QF::newX_() with
|
|
* margin == ::QF_NO_MARGIN, which causes an assertion when the event
|
|
* cannot be successfully allocated.
|
|
*
|
|
* @param[in] evtT_ event type (class name) of the event to allocate
|
|
* @param[in] sig_ signal to assign to the newly allocated event
|
|
*
|
|
* @returns a valid event pointer cast to the type `evtT_`.
|
|
*
|
|
* @note
|
|
* If #Q_EVT_CTOR is defined, the Q_NEW() macro becomes variadic and
|
|
* takes all the arguments needed by the constructor of the event
|
|
* class being allocated. The constructor is then called by means
|
|
* of the placement-new operator.
|
|
*
|
|
* @usage
|
|
* The following example illustrates dynamic allocation of an event:
|
|
* @include qf_post.c
|
|
*/
|
|
#define Q_NEW(evtT_, sig_) ((evtT_ *)QF_newX_((uint_fast16_t)sizeof(evtT_), \
|
|
QF_NO_MARGIN, (enum_t)(sig_)))
|
|
#endif /* ndef Q_EVT_CTOR */
|
|
|
|
/*${QF-macros::Q_NEW} ......................................................*/
|
|
#ifdef Q_EVT_CTOR
|
|
/*! Asserting allocate a dynamic event
|
|
* (case when ::QEvt is not a POD)
|
|
*/
|
|
#define Q_NEW(evtT_, sig_, ...) \
|
|
(evtT_##_ctor((evtT_ *)QF_newX_((uint_fast16_t)sizeof(evtT_), \
|
|
QF_NO_MARGIN, (sig_)), (enum_t)(sig_), ##__VA_ARGS__))
|
|
#endif /* def Q_EVT_CTOR */
|
|
|
|
/*${QF-macros::Q_NEW_X} ....................................................*/
|
|
#ifndef Q_EVT_CTOR
|
|
/*! Non-asserting allocate a dynamic event (case when ::QEvt is a POD).
|
|
*
|
|
* @details
|
|
* This macro allocates a new event and sets the pointer `e_`, while
|
|
* leaving at least `margin_` of events still available in the pool
|
|
*
|
|
* @param[out] e_ pointer to the newly allocated event
|
|
* @param[in] evtT_ event type (class name) of the event to allocate
|
|
* @param[in] margin_ number of events that must remain available
|
|
* in the given pool after this allocation. The
|
|
* special value ::QF_NO_MARGIN causes asserting
|
|
* failure in case event allocation fails.
|
|
* @param[in] sig_ signal to assign to the newly allocated event
|
|
*
|
|
* @returns an event pointer cast to the type `evtT_` or NULL if the
|
|
* event cannot be allocated with the specified `margin`.
|
|
*
|
|
* @note
|
|
* If #Q_EVT_CTOR is defined, the Q_NEW_X() macro becomes variadic and
|
|
* takes all the arguments needed by the constructor of the event
|
|
* class being allocated. The constructor is then called by means
|
|
* of the placement-new operator.
|
|
*
|
|
* @usage
|
|
* The following example illustrates dynamic allocation of an event:
|
|
* @include qf_postx.c
|
|
*/
|
|
#define Q_NEW_X(e_, evtT_, margin_, sig_) ((e_) = \
|
|
(evtT_ *)QF_newX_((uint_fast16_t)sizeof(evtT_), \
|
|
(margin_), (enum_t)(sig_)))
|
|
#endif /* ndef Q_EVT_CTOR */
|
|
|
|
/*${QF-macros::Q_NEW_X} ....................................................*/
|
|
#ifdef Q_EVT_CTOR
|
|
/*! Non-asserting allocate a dynamic event
|
|
* (case when ::QEvt is not a POD)
|
|
*/
|
|
#define Q_NEW_X(e_, evtT_, margin_, sig_, ...) do { \
|
|
(e_) = (evtT_ *)QF_newX_((uint_fast16_t)sizeof(evtT_), \
|
|
(margin_), (enum_t)(sig_));\
|
|
if ((e_) != (evtT_ *)0) { \
|
|
evtT_##_ctor((e_), (enum_t)(sig_), ##__VA_ARGS__); \
|
|
} \
|
|
} while (false)
|
|
#endif /* def Q_EVT_CTOR */
|
|
|
|
/*${QF-macros::Q_NEW_REF} ..................................................*/
|
|
/*! Create a new reference of the current event `e`
|
|
*
|
|
* @details
|
|
* The current event processed by an active object is available only for
|
|
* the duration of the run-to-completion (RTC) step. After that step, the
|
|
* current event is no longer available and the framework might recycle
|
|
* (garbage-collect) the event. The macro Q_NEW_REF() explicitly creates
|
|
* a new reference to the current event that can be stored and used beyond
|
|
* the current RTC step, until the reference is explicitly recycled by
|
|
* means of the macro Q_DELETE_REF().
|
|
*
|
|
* @param[in,out] evtRef_ event reference to create
|
|
* @param[in] evtT_ event type (class name) of the event reference
|
|
*
|
|
* @usage
|
|
* The example **defer** in the directory `examples/win32/defer` illustrates
|
|
* the use of Q_NEW_REF()
|
|
*
|
|
* @sa Q_DELETE_REF()
|
|
*/
|
|
#define Q_NEW_REF(evtRef_, evtT_) \
|
|
((evtRef_) = (evtT_ const *)QF_newRef_(e, (evtRef_)))
|
|
|
|
/*${QF-macros::Q_DELETE_REF} ...............................................*/
|
|
/*! Delete the event reference
|
|
*
|
|
* @details
|
|
* Every event reference created with the macro Q_NEW_REF() needs to be
|
|
* eventually deleted by means of the macro Q_DELETE_REF() to avoid leaking
|
|
* the event.
|
|
*
|
|
* @param[in,out] evtRef_ event reference to delete
|
|
*
|
|
* @usage
|
|
* The example **defer** in the directory `examples/win32/defer` illustrates
|
|
* the use of Q_DELETE_REF()
|
|
*
|
|
* @sa Q_NEW_REF()
|
|
*/
|
|
#define Q_DELETE_REF(evtRef_) do { \
|
|
QF_deleteRef_((evtRef_)); \
|
|
(evtRef_) = (void *)0; \
|
|
} while (false)
|
|
|
|
/*${QF-macros::QACTIVE_START} ..............................................*/
|
|
/*! Virtual call to start an active object.
|
|
*
|
|
* @details
|
|
* Starts execution of the AO and registers the AO with the framework.
|
|
*
|
|
* @param[in,out] me_ current instance pointer (see @ref oop)
|
|
* @param[in] prioSpec_ priority specification for the Active Object
|
|
* @param[in] qSto_ pointer to the storage for the ring buffer of the
|
|
* event queue (used only with the built-in ::QEQueue)
|
|
* @param[in] qLen_ length of the event queue (in events)
|
|
* @param[in] stkSto_ pointer to the stack storage (used only when
|
|
* per-AO stack is needed)
|
|
* @param[in] stkSize_ stack size (in bytes)
|
|
* @param[in] par_ pointer to the additional port-specific parameter(s)
|
|
* (might be NULL).
|
|
* @usage
|
|
* @include qf_start.c
|
|
*/
|
|
#define QACTIVE_START(me_, prioSpec_, qSto_, qLen_, stkSto_, stkSize_, par_) do { \
|
|
Q_ASSERT((Q_HSM_UPCAST(me_))->vptr); \
|
|
(*((QActiveVtable const *)((Q_HSM_UPCAST(me_))->vptr))->start)( \
|
|
(QActive *)(me_), (prioSpec_), \
|
|
(qSto_), (qLen_), (stkSto_), (stkSize_), (par_)); \
|
|
} while (false)
|
|
|
|
/*${QF-macros::QACTIVE_POST} ...............................................*/
|
|
#ifdef Q_SPY
|
|
/*! Invoke the direct event posting facility QActive_post_()
|
|
*
|
|
* @details
|
|
* This macro asserts if the queue overflows and cannot accept the event.
|
|
*
|
|
* @param[in,out] me_ current instance pointer (see @ref oop)
|
|
* @param[in] e_ pointer to the event to post
|
|
* @param[in] sender_ pointer to the sender object.
|
|
*
|
|
* @note
|
|
* The `sendedr_` parameter is actually only used when QS tracing
|
|
* is enabled (macro #Q_SPY is defined). When QS software tracing is
|
|
* disenabled, the QACTIVE_POST() macro does not pass the `sender_`
|
|
* parameter, so the overhead of passing this extra parameter is entirely
|
|
* avoided.
|
|
*
|
|
* @note the pointer to the sender object is not necessarily a pointer
|
|
* to an active object. In fact, if QACTIVE_POST() is called from an
|
|
* interrupt or other context, you can create a unique object just to
|
|
* unambiguously identify the sender of the event.
|
|
*
|
|
* @sa QActive_post_()
|
|
*/
|
|
#define QACTIVE_POST(me_, e_, sender_) \
|
|
((void)(*((QActiveVtable const *)((Q_HSM_UPCAST(me_))->vptr))->post)(\
|
|
(me_), (e_), QF_NO_MARGIN, (sender_)))
|
|
#endif /* def Q_SPY */
|
|
|
|
/*${QF-macros::QACTIVE_POST} ...............................................*/
|
|
#ifndef Q_SPY
|
|
#define QACTIVE_POST(me_, e_, dummy) \
|
|
((void)(*((QActiveVtable const *)((Q_HSM_UPCAST(me_))->vptr))->post)(\
|
|
(me_), (e_), QF_NO_MARGIN, (void *)0))
|
|
#endif /* ndef Q_SPY */
|
|
|
|
/*${QF-macros::QACTIVE_POST_X} .............................................*/
|
|
#ifdef Q_SPY
|
|
/*! Invoke the direct event posting facility QActive_post_()
|
|
* without delivery guarantee
|
|
*
|
|
* @details
|
|
* This macro does not assert if the queue overflows and cannot accept
|
|
* the event with the specified margin of free slots remaining.
|
|
*
|
|
* @param[in,out] me_ current instance pointer (see @ref oop)
|
|
* @param[in] e_ pointer to the event to post
|
|
* @param[in] margin_ the minimum free slots in the queue, which
|
|
* must still be available after posting the event.
|
|
* The special value ::QF_NO_MARGIN causes
|
|
* asserting failure in case event posting fails.
|
|
* @param[in] sender_ pointer to the sender object.
|
|
*
|
|
* @returns
|
|
* 'true' if the posting succeeded, and 'false' if the posting
|
|
* failed due to insufficient margin of free entries available in
|
|
* the queue.
|
|
*
|
|
* @note
|
|
* The `sender_` parameter is actually only used when QS tracing
|
|
* is enabled (macro #Q_SPY is defined). When QS software tracing is
|
|
* disabled, the POST_X() macro does not pass the `sender_` parameter,
|
|
* so the overhead of passing this extra parameter is entirely avoided.
|
|
*
|
|
* @note
|
|
* The pointer to the sender object is not necessarily a pointer
|
|
* to an active object. In fact, if POST_X() is called from an
|
|
* interrupt or other context, you can create a unique object just to
|
|
* unambiguously identify the sender of the event.
|
|
*
|
|
* @usage
|
|
* @include qf_postx.c
|
|
*/
|
|
#define QACTIVE_POST_X(me_, e_, margin_, sender_) \
|
|
((*((QActiveVtable const *)((Q_HSM_UPCAST(me_))->vptr))->post)((me_),\
|
|
(e_), (margin_), (sender_)))
|
|
#endif /* def Q_SPY */
|
|
|
|
/*${QF-macros::QACTIVE_POST_X} .............................................*/
|
|
#ifndef Q_SPY
|
|
#define QACTIVE_POST_X(me_, e_, margin_, dummy) \
|
|
((*((QActiveVtable const *)((Q_HSM_UPCAST(me_))->vptr))->post)((me_),\
|
|
(e_), (margin_), (void *)0))
|
|
#endif /* ndef Q_SPY */
|
|
|
|
/*${QF-macros::QACTIVE_POST_LIFO} ..........................................*/
|
|
/*! Virtual call to post an event to an active object using the
|
|
* Last-In-First-Out (LIFO) policy.
|
|
*
|
|
* @param[in,out] me_ current instance pointer (see @ref oop)
|
|
* @param[in] e_ pointer to the event to post
|
|
*/
|
|
#define QACTIVE_POST_LIFO(me_, e_) \
|
|
((*((QActiveVtable const *)((Q_HSM_UPCAST(me_))->vptr))->postLIFO)( \
|
|
(me_), (e_)))
|
|
|
|
/*${QF-macros::QACTIVE_PUBLISH} ............................................*/
|
|
#ifdef Q_SPY
|
|
/*! Publish an event to all subscriber Active Objects.
|
|
*
|
|
* @details
|
|
* If #Q_SPY is defined, this macro calls QActive_publish_() with
|
|
* the `sender_` parameter to identify the publisher of the event.
|
|
* Otherwise, `sender_` is not used.
|
|
*
|
|
* @param[in] e_ pointer to the posted event
|
|
* @param[in] sender_ pointer to the sender object (actually used
|
|
* only when #Q_SPY is defined)
|
|
*
|
|
* @note
|
|
* The pointer to the `sender_` object is not necessarily a pointer
|
|
* to an active object. In fact, if QACTIVE_PUBLISH() is called from an
|
|
* interrupt or other context, you can create a unique object just to
|
|
* unambiguously identify the sender of the event.
|
|
*
|
|
* @sa QActive_publish_()
|
|
*/
|
|
#define QACTIVE_PUBLISH(e_, sender_) \
|
|
(QActive_publish_((e_), (void const *)(sender_), (sender_)->prio))
|
|
#endif /* def Q_SPY */
|
|
|
|
/*${QF-macros::QACTIVE_PUBLISH} ............................................*/
|
|
#ifndef Q_SPY
|
|
#define QACTIVE_PUBLISH(e_, dummy) (QActive_publish_((e_), (void *)0, 0U))
|
|
#endif /* ndef Q_SPY */
|
|
|
|
/*${QF-macros::QTIMEEVT_TICK_X} ............................................*/
|
|
#ifdef Q_SPY
|
|
/*! Invoke the system clock tick processing QTimeEvt_tick_()
|
|
*
|
|
* @details
|
|
* This macro is the recommended way of invoking clock tick processing,
|
|
* because it provides the vital information for software tracing and
|
|
* avoids any overhead when the tracing is disabled.
|
|
*
|
|
* @param[in] tickRate_ clock tick rate to be serviced through this call
|
|
* @param[in] sender_ pointer to the sender object. This parameter
|
|
* is actually only used when QS software tracing is enabled
|
|
* (macro #Q_SPY is defined)
|
|
* @note
|
|
* When QS software tracing is disabled, the macro calls QTimeEvt_tick_()
|
|
* without the `sender` parameter, so the overhead of passing this
|
|
* extra parameter is entirely avoided.
|
|
*
|
|
* @note
|
|
* The pointer to the sender object is not necessarily a pointer
|
|
* to an active object. In fact, when QTIMEEVT_TICK_X() is called from
|
|
* an interrupt, you would create a unique object just to unambiguously
|
|
* identify the ISR as the sender of the time events.
|
|
*
|
|
* @sa QTimeEvt_tick_()
|
|
*/
|
|
#define QTIMEEVT_TICK_X(tickRate_, sender_) \
|
|
(QTimeEvt_tick_((tickRate_), (sender_)))
|
|
#endif /* def Q_SPY */
|
|
|
|
/*${QF-macros::QTIMEEVT_TICK_X} ............................................*/
|
|
#ifndef Q_SPY
|
|
#define QTIMEEVT_TICK_X(tickRate_, dummy) \
|
|
(QTimeEvt_tick_((tickRate_), (void *)0))
|
|
#endif /* ndef Q_SPY */
|
|
|
|
/*${QF-macros::QTIMEEVT_TICK} ..............................................*/
|
|
/*! Invoke the system clock tick processing
|
|
* for tick rate 0
|
|
*/
|
|
#define QTIMEEVT_TICK(sender_) QTIMEEVT_TICK_X(0U, (sender_))
|
|
|
|
/*${QF-macros::QF_CRIT_EXIT_NOP} ...........................................*/
|
|
#ifndef QF_CRIT_EXIT_NOP
|
|
/*! No-operation for exiting a critical section
|
|
*
|
|
* @details
|
|
* In some QF ports the critical section exit takes effect only on the
|
|
* next machine instruction. If this next instruction is another entry
|
|
* to a critical section, the critical section won't be really exited,
|
|
* but rather the two adjecent critical sections would be merged.
|
|
* The QF_CRIT_EXIT_NOP() macro contains minimal code required to
|
|
* prevent such merging of critical sections in such merging of
|
|
* critical sections in QF ports, in which it can occur.
|
|
*/
|
|
#define QF_CRIT_EXIT_NOP() ((void)0)
|
|
#endif /* ndef QF_CRIT_EXIT_NOP */
|
|
|
|
/*${QF-macros::QF_TICK_X} ..................................................*/
|
|
/*! Invoke the system clock tick processing
|
|
*
|
|
* @deprecated
|
|
* superseded by QTIMEEVT_TICK_X()
|
|
*/
|
|
#define QF_TICK_X(tickRate_, sender_) QTIMEEVT_TICK_X((tickRate_), (sender_))
|
|
|
|
/*${QF-macros::QF_TICK} ....................................................*/
|
|
/*! Invoke the system clock tick processing for tick rate 0
|
|
*
|
|
* @deprecated
|
|
* superseded by QTIMEEVT_TICK()
|
|
*/
|
|
#define QF_TICK(sender_) QTIMEEVT_TICK(sender_)
|
|
|
|
/*${QF-macros::QF_PUBLISH} .................................................*/
|
|
/*! Publish an event to all subscriber Active Objects.
|
|
*
|
|
* @deprecated
|
|
* superseded by QACTIVE_PUBLISH()
|
|
*/
|
|
#define QF_PUBLISH(e_, sender_) QACTIVE_PUBLISH((e_), (sender_))
|
|
/*$enddecl${QF-macros} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
|
|
|
|
#endif /* QP_INC_QF_H_ */
|