2015-05-14 16:05:04 -04:00
|
|
|
/// @file
|
|
|
|
/// @brief QF/C++ platform-independent public interface.
|
|
|
|
/// @ingroup qf
|
|
|
|
/// @cond
|
2014-04-13 21:35:34 -04:00
|
|
|
///***************************************************************************
|
2015-12-31 14:56:37 -05:00
|
|
|
/// Last updated for version 5.6.0
|
|
|
|
/// Last updated on 2015-12-26
|
2014-04-13 21:35:34 -04:00
|
|
|
///
|
|
|
|
/// Q u a n t u m L e a P s
|
|
|
|
/// ---------------------------
|
|
|
|
/// innovating embedded systems
|
|
|
|
///
|
2015-12-31 14:56:37 -05:00
|
|
|
/// Copyright (C) Quantum Leaps. All rights reserved.
|
2014-04-13 21:35:34 -04:00
|
|
|
///
|
|
|
|
/// This program is open source software: you can redistribute it and/or
|
|
|
|
/// modify it under the terms of the GNU General Public License as published
|
|
|
|
/// by the Free Software Foundation, either version 3 of the License, or
|
|
|
|
/// (at your option) any later version.
|
|
|
|
///
|
|
|
|
/// Alternatively, this program may be distributed and modified under the
|
|
|
|
/// terms of Quantum Leaps commercial licenses, which expressly supersede
|
|
|
|
/// the GNU General Public License and are specifically designed for
|
|
|
|
/// licensees interested in retaining the proprietary status of their code.
|
|
|
|
///
|
|
|
|
/// This program is distributed in the hope that it will be useful,
|
|
|
|
/// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
/// GNU General Public License for more details.
|
2012-08-14 18:00:48 -04:00
|
|
|
///
|
2014-04-13 21:35:34 -04:00
|
|
|
/// You should have received a copy of the GNU General Public License
|
|
|
|
/// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
///
|
|
|
|
/// Contact information:
|
2015-09-29 11:34:38 -04:00
|
|
|
/// http://www.state-machine.com
|
|
|
|
/// mailto:info@state-machine.com
|
2014-04-13 21:35:34 -04:00
|
|
|
///***************************************************************************
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @endcond
|
2014-04-13 21:35:34 -04:00
|
|
|
|
|
|
|
#ifndef qf_h
|
|
|
|
#define qf_h
|
2012-08-14 18:00:48 -04:00
|
|
|
|
2013-10-10 20:01:51 -04:00
|
|
|
//****************************************************************************
|
2012-08-14 18:00:48 -04:00
|
|
|
#ifdef Q_EVT_CTOR
|
2014-04-13 21:35:34 -04:00
|
|
|
#include <new> // for placement new
|
|
|
|
#endif // Q_EVT_CTOR
|
2012-08-14 18:00:48 -04:00
|
|
|
|
2013-10-10 20:01:51 -04:00
|
|
|
//****************************************************************************
|
|
|
|
#if (QF_MAX_ACTIVE < 1) || (63 < QF_MAX_ACTIVE)
|
|
|
|
#error "QF_MAX_ACTIVE not defined or out of range. Valid range is 1..63"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//****************************************************************************
|
2012-08-14 18:00:48 -04:00
|
|
|
// apply defaults for all undefined configuration parameters
|
|
|
|
//
|
|
|
|
#ifndef QF_EVENT_SIZ_SIZE
|
2014-04-13 21:35:34 -04:00
|
|
|
//! Default value of the macro configurable value in qf_port.h
|
2012-08-14 18:00:48 -04:00
|
|
|
#define QF_EVENT_SIZ_SIZE 2
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef QF_MAX_EPOOL
|
2014-04-13 21:35:34 -04:00
|
|
|
//! Default value of the macro configurable value in qf_port.h
|
2012-08-14 18:00:48 -04:00
|
|
|
#define QF_MAX_EPOOL 3
|
|
|
|
#endif
|
|
|
|
|
2013-10-10 20:01:51 -04:00
|
|
|
#ifndef QF_MAX_TICK_RATE
|
2014-04-13 21:35:34 -04:00
|
|
|
//! Default value of the macro configurable value in qf_port.h
|
2013-10-10 20:01:51 -04:00
|
|
|
#define QF_MAX_TICK_RATE 1
|
|
|
|
#endif
|
|
|
|
|
2012-08-14 18:00:48 -04:00
|
|
|
#ifndef QF_TIMEEVT_CTR_SIZE
|
2014-04-13 21:35:34 -04:00
|
|
|
//! macro to override the default QTimeEvtCtr size.
|
|
|
|
//! Valid values 1, 2, or 4; default 2
|
2012-08-14 18:00:48 -04:00
|
|
|
#define QF_TIMEEVT_CTR_SIZE 2
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2013-10-10 20:01:51 -04:00
|
|
|
//****************************************************************************
|
|
|
|
namespace QP {
|
2012-08-14 18:00:48 -04:00
|
|
|
|
|
|
|
#if (QF_EVENT_SIZ_SIZE == 1)
|
2013-10-10 20:01:51 -04:00
|
|
|
typedef uint8_t QEvtSize;
|
|
|
|
#elif (QF_EVENT_SIZ_SIZE == 2)
|
2014-04-13 21:35:34 -04:00
|
|
|
//! The data type to store the block-size defined based on
|
|
|
|
//! the macro #QF_EVENT_SIZ_SIZE.
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @description
|
2012-08-14 18:00:48 -04:00
|
|
|
/// The dynamic range of this data type determines the maximum block
|
|
|
|
/// size that can be managed by the pool.
|
|
|
|
typedef uint16_t QEvtSize;
|
|
|
|
#elif (QF_EVENT_SIZ_SIZE == 4)
|
|
|
|
typedef uint32_t QEvtSize;
|
|
|
|
#else
|
|
|
|
#error "QF_EVENT_SIZ_SIZE defined incorrectly, expected 1, 2, or 4"
|
|
|
|
#endif
|
|
|
|
|
2013-10-10 20:01:51 -04:00
|
|
|
//****************************************************************************
|
2012-08-14 18:00:48 -04:00
|
|
|
#if (QF_TIMEEVT_CTR_SIZE == 1)
|
2013-10-10 20:01:51 -04:00
|
|
|
typedef uint8_t QTimeEvtCtr;
|
|
|
|
#elif (QF_TIMEEVT_CTR_SIZE == 2)
|
2014-04-13 21:35:34 -04:00
|
|
|
//! type of the Time Event counter, which determines the dynamic
|
|
|
|
//! range of the time delays measured in clock ticks.
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @description
|
2012-08-14 18:00:48 -04:00
|
|
|
/// This typedef is configurable via the preprocessor switch
|
|
|
|
/// #QF_TIMEEVT_CTR_SIZE. The other possible values of this type are
|
2015-05-14 16:05:04 -04:00
|
|
|
/// as follows: @n
|
|
|
|
/// uint8_t when (QF_TIMEEVT_CTR_SIZE == 1), and @n
|
2012-08-14 18:00:48 -04:00
|
|
|
/// uint32_t when (QF_TIMEEVT_CTR_SIZE == 4).
|
|
|
|
typedef uint16_t QTimeEvtCtr;
|
|
|
|
#elif (QF_TIMEEVT_CTR_SIZE == 4)
|
|
|
|
typedef uint32_t QTimeEvtCtr;
|
|
|
|
#else
|
|
|
|
#error "QF_TIMEEVT_CTR_SIZE defined incorrectly, expected 1, 2, or 4"
|
|
|
|
#endif
|
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
class QEQueue; // forward declaration
|
2012-08-14 18:00:48 -04:00
|
|
|
|
2013-10-10 20:01:51 -04:00
|
|
|
//****************************************************************************
|
2015-05-14 16:05:04 -04:00
|
|
|
//! QMActive active object (based on QP::QMsm implementation)
|
|
|
|
/// @description
|
2013-10-10 20:01:51 -04:00
|
|
|
/// Active objects in QF are encapsulated tasks (each embedding a state
|
|
|
|
/// machine and an event queue) 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.
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @n@n
|
|
|
|
/// QP::QMActive represents an active object that uses the QP::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 QP::QHsm-style implementation strategy
|
|
|
|
/// and needs less run-time support (smaller event-processor).
|
2012-08-14 18:00:48 -04:00
|
|
|
///
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @note
|
|
|
|
/// QP::QMActive is not intended to be instantiated directly, but rather
|
|
|
|
/// serves as the base class for derivation of active objects in the
|
|
|
|
/// applications.
|
2012-08-14 18:00:48 -04:00
|
|
|
///
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @sa QP::QActive
|
|
|
|
///
|
|
|
|
/// @usage
|
2012-08-14 18:00:48 -04:00
|
|
|
/// The following example illustrates how to derive an active object from
|
2015-05-14 16:05:04 -04:00
|
|
|
/// QP::QMActive.
|
|
|
|
/// @include qf_qmactive.cpp
|
|
|
|
///
|
|
|
|
class QMActive : public QMsm {
|
2012-08-14 18:00:48 -04:00
|
|
|
#ifdef QF_EQUEUE_TYPE
|
2014-04-13 21:35:34 -04:00
|
|
|
//! OS-dependent event-queue type.
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @description
|
2012-08-14 18:00:48 -04:00
|
|
|
/// 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.
|
|
|
|
///
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @note
|
2012-08-14 18:00:48 -04:00
|
|
|
/// The native QF event queue is configured by defining the macro
|
2014-04-13 21:35:34 -04:00
|
|
|
/// #QF_EQUEUE_TYPE as QP::QEQueue.
|
2012-08-14 18:00:48 -04:00
|
|
|
QF_EQUEUE_TYPE m_eQueue;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef QF_OS_OBJECT_TYPE
|
2014-04-13 21:35:34 -04:00
|
|
|
//! OS-dependent per-thread object.
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @description
|
2012-08-14 18:00:48 -04:00
|
|
|
/// This data might be used in various ways, depending on the QF port.
|
|
|
|
/// In some ports m_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 m_osObject;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef QF_THREAD_TYPE
|
2014-04-13 21:35:34 -04:00
|
|
|
//! OS-dependent representation of the thread of the active object.
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @description
|
2012-08-14 18:00:48 -04:00
|
|
|
/// This data might be used in various ways, depending on the QF port.
|
|
|
|
/// In some ports m_thread is used store the thread handle. In other ports
|
|
|
|
/// m_thread can be a pointer to the Thread-Local-Storage (TLS).
|
|
|
|
QF_THREAD_TYPE m_thread;
|
|
|
|
#endif
|
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! QF priority associated with the active object.
|
|
|
|
uint_fast8_t m_prio;
|
2012-08-14 18:00:48 -04:00
|
|
|
|
2015-09-29 11:34:38 -04:00
|
|
|
protected:
|
|
|
|
//! protected constructor (abstract class)
|
|
|
|
QMActive(QStateHandler const initial);
|
|
|
|
|
2012-08-14 18:00:48 -04:00
|
|
|
public:
|
2014-04-13 21:35:34 -04:00
|
|
|
//! Starts execution of an active object and registers the object
|
|
|
|
//! with the framework.
|
|
|
|
virtual void start(uint_fast8_t const prio,
|
|
|
|
QEvt const *qSto[], uint_fast16_t const qLen,
|
|
|
|
void * const stkSto, uint_fast16_t const stkSize,
|
2013-10-10 20:01:51 -04:00
|
|
|
QEvt const * const ie);
|
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! Overloaded start function (no initialization event)
|
|
|
|
virtual void start(uint_fast8_t const prio,
|
|
|
|
QEvt const *qSto[], uint_fast16_t const qLen,
|
|
|
|
void * const stkSto, uint_fast16_t const stkSize)
|
2013-10-10 20:01:51 -04:00
|
|
|
{
|
|
|
|
this->start(prio, qSto, qLen, stkSto, stkSize,
|
|
|
|
static_cast<QEvt const *>(0));
|
|
|
|
}
|
2012-08-14 18:00:48 -04:00
|
|
|
|
|
|
|
#ifndef Q_SPY
|
2015-05-14 16:05:04 -04:00
|
|
|
//! Posts an event @p e directly to the event queue of the active
|
|
|
|
//! object @p me using the First-In-First-Out (FIFO) policy.
|
2014-04-13 21:35:34 -04:00
|
|
|
virtual bool post_(QEvt const * const e, uint_fast16_t const margin);
|
2012-08-14 18:00:48 -04:00
|
|
|
#else
|
2014-04-13 21:35:34 -04:00
|
|
|
virtual bool post_(QEvt const * const e, uint_fast16_t const margin,
|
2014-04-21 21:48:04 -04:00
|
|
|
void const * const sender);
|
2012-08-14 18:00:48 -04:00
|
|
|
#endif
|
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! Posts an event directly to the event queue of the active object
|
|
|
|
//! using the Last-In-First-Out (LIFO) policy.
|
2013-10-10 20:01:51 -04:00
|
|
|
virtual void postLIFO(QEvt const * const e);
|
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! Un-subscribes from the delivery of all signals to the active object.
|
2012-08-14 18:00:48 -04:00
|
|
|
void unsubscribeAll(void) const;
|
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! Stops execution of an active object and removes it from the
|
|
|
|
//! framework's supervision.
|
2012-08-14 18:00:48 -04:00
|
|
|
void stop(void);
|
|
|
|
|
2015-05-14 16:05:04 -04:00
|
|
|
//! Subscribes for delivery of signal @p sig to the active object
|
2012-08-14 18:00:48 -04:00
|
|
|
void subscribe(enum_t const sig) const;
|
|
|
|
|
2015-05-14 16:05:04 -04:00
|
|
|
//! Un-subscribes from the delivery of signal @p sig to the active object.
|
2012-08-14 18:00:48 -04:00
|
|
|
void unsubscribe(enum_t const sig) const;
|
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! Defer an event to a given separate event queue.
|
2013-10-10 20:01:51 -04:00
|
|
|
bool defer(QEQueue * const eq, QEvt const * const e) const;
|
2012-08-14 18:00:48 -04:00
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! Recall a deferred event from a given event queue.
|
2012-08-14 18:00:48 -04:00
|
|
|
bool recall(QEQueue * const eq);
|
|
|
|
|
2015-05-14 16:05:04 -04:00
|
|
|
//! Get the priority of the active object.
|
|
|
|
uint_fast8_t getPrio(void) const {
|
|
|
|
return m_prio;
|
|
|
|
}
|
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! Set the priority of the active object.
|
|
|
|
void setPrio(uint_fast8_t const prio) {
|
2013-10-10 20:01:51 -04:00
|
|
|
m_prio = prio;
|
|
|
|
}
|
2012-08-14 18:00:48 -04:00
|
|
|
|
2014-09-22 11:48:11 -04:00
|
|
|
#ifdef QF_OS_OBJECT_TYPE
|
|
|
|
//! accessor to the OS-object for extern "C" functions, such as
|
|
|
|
//! the QK scheduler
|
|
|
|
QF_OS_OBJECT_TYPE &getOsObject(void) { return m_osObject; }
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef QF_THREAD_TYPE
|
|
|
|
//! accessor to the Thread for extern "C" functions, such as
|
|
|
|
//! the QK scheduler
|
|
|
|
QF_THREAD_TYPE &getThread(void) { return m_thread; }
|
|
|
|
#endif
|
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! Get an event from the event queue of an active object.
|
2012-08-14 18:00:48 -04:00
|
|
|
QEvt const *get_(void);
|
|
|
|
|
|
|
|
friend class QF;
|
|
|
|
friend class QTimeEvt;
|
2015-12-31 14:56:37 -05:00
|
|
|
friend class QMutex;
|
|
|
|
friend class QXK;
|
|
|
|
friend class QXThread;
|
|
|
|
friend class QXMutex;
|
|
|
|
friend class QXSemaphore;
|
2013-10-10 20:01:51 -04:00
|
|
|
};
|
2012-08-14 18:00:48 -04:00
|
|
|
|
2013-10-10 20:01:51 -04:00
|
|
|
//****************************************************************************
|
2015-05-14 16:05:04 -04:00
|
|
|
//! QMActive active object (based on QP::QHsm implementation)
|
|
|
|
/// @description
|
|
|
|
/// Active objects in QF are encapsulated tasks (each embedding a state
|
|
|
|
/// machine and an event queue) 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.
|
|
|
|
/// @n@n
|
|
|
|
/// QP::QActive represents an active object that uses the QP::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 QP::QMsm-style implementation
|
|
|
|
/// strategy.
|
|
|
|
///
|
|
|
|
/// @note
|
|
|
|
/// QP::QActive is not intended to be instantiated directly, but rather serves
|
|
|
|
/// as the base class for derivation of active objects in the applications.
|
|
|
|
///
|
|
|
|
/// @sa QP::QMActive
|
|
|
|
///
|
|
|
|
/// @usage
|
|
|
|
/// The following example illustrates how to derive an active object from
|
|
|
|
/// QP::QActive.
|
|
|
|
/// @include qf_qactive.cpp
|
|
|
|
///
|
|
|
|
class QActive : public QMActive {
|
2013-10-10 20:01:51 -04:00
|
|
|
public:
|
2015-05-14 16:05:04 -04:00
|
|
|
// all the following operations delegate to the QHsm class...
|
|
|
|
virtual void init(QEvt const * const e);
|
|
|
|
virtual void init(void);
|
|
|
|
virtual void dispatch(QEvt const * const e);
|
|
|
|
|
|
|
|
bool isIn(QStateHandler const s);
|
2013-10-10 20:01:51 -04:00
|
|
|
|
|
|
|
protected:
|
2015-09-29 11:34:38 -04:00
|
|
|
//! protected constructor (abstract class)
|
2015-05-14 16:05:04 -04:00
|
|
|
QActive(QStateHandler const initial);
|
2012-08-14 18:00:48 -04:00
|
|
|
};
|
|
|
|
|
2013-10-10 20:01:51 -04:00
|
|
|
|
|
|
|
//****************************************************************************
|
2014-04-13 21:35:34 -04:00
|
|
|
//! Time Event class
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @description
|
2012-08-14 18:00:48 -04:00
|
|
|
/// 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
|
2015-05-14 16:05:04 -04:00
|
|
|
/// like any other event.@n
|
|
|
|
/// @n
|
2014-04-13 21:35:34 -04:00
|
|
|
/// Time events, as any other QF events derive from the QP::QEvt base
|
2012-08-14 18:00:48 -04:00
|
|
|
/// 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
|
2015-05-14 16:05:04 -04:00
|
|
|
/// time events.@n
|
|
|
|
/// @n
|
2012-08-14 18:00:48 -04:00
|
|
|
/// Internally, the armed time events are organized into a bi-directional
|
|
|
|
/// linked list. This linked list is scanned in every invocation of the
|
2014-04-13 21:35:34 -04:00
|
|
|
/// QP::QF::tickX_() function. Only armed (timing out) time events are in the
|
|
|
|
/// list, so only armed time events consume CPU cycles.
|
2013-12-30 17:41:15 -05:00
|
|
|
///
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @note
|
2014-04-13 21:35:34 -04:00
|
|
|
/// QF manages the time events in the macro TICK_X(), which must be
|
|
|
|
/// called periodically, eitehr from a clock tick ISR, or from a task level.
|
2013-12-30 17:41:15 -05:00
|
|
|
///
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @note
|
2014-04-13 21:35:34 -04:00
|
|
|
/// In this version of QF QTimeEvt objects should __not__ be allocated
|
|
|
|
/// dynamically from event pools. Currently, QF will not correctly recycle
|
|
|
|
/// the dynamically allocated Time Events.
|
2012-08-14 18:00:48 -04:00
|
|
|
class QTimeEvt : public QEvt {
|
|
|
|
private:
|
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! link to the next time event in the list
|
2013-10-10 20:01:51 -04:00
|
|
|
QTimeEvt * volatile m_next;
|
2012-08-14 18:00:48 -04:00
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! the active object that receives the time events
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @description
|
2014-04-13 21:35:34 -04:00
|
|
|
/// The m_act pointer is reused inside the QP implementation to hold
|
|
|
|
/// the head of the list of newly armed time events.
|
2013-10-10 20:01:51 -04:00
|
|
|
void * volatile m_act;
|
2012-08-14 18:00:48 -04:00
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! the internal down-counter of the time event.
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @description
|
2014-04-13 21:35:34 -04:00
|
|
|
/// The down-counter is decremented by 1 in every TICK_X()
|
|
|
|
/// invocation. The time event fires (gets posted or published) when
|
|
|
|
/// the down-counter reaches zero.
|
2013-10-10 20:01:51 -04:00
|
|
|
QTimeEvtCtr volatile m_ctr;
|
2012-08-14 18:00:48 -04:00
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! the interval for the periodic time event (zero for the one-shot
|
|
|
|
//! time event).
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @description
|
2014-04-13 21:35:34 -04:00
|
|
|
/// The value of the interval is re-loaded to the internal
|
2012-08-14 18:00:48 -04:00
|
|
|
/// down-counter when the time event expires, so that the time event
|
|
|
|
/// keeps timing out periodically.
|
|
|
|
QTimeEvtCtr m_interval;
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! The Time Event constructor.
|
2015-05-14 16:05:04 -04:00
|
|
|
QTimeEvt(QMActive * const act, enum_t const sgnl,
|
2013-10-10 20:01:51 -04:00
|
|
|
uint8_t const tickRate = static_cast<uint8_t>(0));
|
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! Arm a time event (one shot or periodic) for event posting.
|
2013-10-10 20:01:51 -04:00
|
|
|
void armX(QTimeEvtCtr const nTicks,
|
|
|
|
QTimeEvtCtr const interval = static_cast<QTimeEvtCtr>(0));
|
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! Disarm a time event.
|
2012-08-14 18:00:48 -04:00
|
|
|
bool disarm(void);
|
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! Rearm a time event.
|
2012-08-14 18:00:48 -04:00
|
|
|
bool rearm(QTimeEvtCtr const nTicks);
|
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! Get the current value of the down-counter of a time event.
|
2012-08-14 18:00:48 -04:00
|
|
|
QTimeEvtCtr ctr(void) const;
|
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
#if (!defined QP_IMPL) && (QP_API_VERSION < 500)
|
2013-12-30 17:41:15 -05:00
|
|
|
|
2015-05-14 16:05:04 -04:00
|
|
|
//! @deprecated TimeEvt ctor provided for backwards compatibility.
|
2013-12-30 17:41:15 -05:00
|
|
|
QTimeEvt(enum_t const sgnl) :
|
|
|
|
#ifdef Q_EVT_CTOR
|
|
|
|
QEvt(static_cast<QSignal>(sgnl)),
|
|
|
|
#endif
|
|
|
|
m_next(static_cast<QTimeEvt *>(0)),
|
|
|
|
m_act(static_cast<void *>(0)),
|
|
|
|
m_ctr(static_cast<QTimeEvtCtr>(0)),
|
|
|
|
m_interval(static_cast<QTimeEvtCtr >(0))
|
|
|
|
{
|
|
|
|
#ifndef Q_EVT_CTOR
|
2014-04-13 21:35:34 -04:00
|
|
|
sig = static_cast<QSignal>(sgnl); // set QEvt::sig of this time event
|
2013-12-30 17:41:15 -05:00
|
|
|
#endif
|
2014-04-13 21:35:34 -04:00
|
|
|
// time event must be static, see NOTE01
|
|
|
|
poolId_ = static_cast<uint8_t>(0); // not from any event pool
|
|
|
|
refCtr_ = static_cast<uint8_t>(0); // default rate 0, see NOTE02
|
2013-12-30 17:41:15 -05:00
|
|
|
}
|
|
|
|
|
2015-05-14 16:05:04 -04:00
|
|
|
//! @deprecated interface provided for backwards compatibility.
|
|
|
|
void postIn(QMActive * const act, QTimeEvtCtr const nTicks) {
|
2013-12-30 17:41:15 -05:00
|
|
|
m_act = act;
|
|
|
|
armX(nTicks, static_cast<QTimeEvtCtr>(0));
|
|
|
|
}
|
|
|
|
|
2015-05-14 16:05:04 -04:00
|
|
|
//! @deprecated interface provided for backwards compatibility.
|
|
|
|
void postEvery(QMActive * const act, QTimeEvtCtr const nTicks) {
|
2013-12-30 17:41:15 -05:00
|
|
|
m_act = act;
|
|
|
|
armX(nTicks, nTicks);
|
|
|
|
}
|
2014-04-13 21:35:34 -04:00
|
|
|
#endif // (!defined QP_IMPL) && (QP_API_VERSION < 500)
|
2013-12-30 17:41:15 -05:00
|
|
|
|
2012-08-14 18:00:48 -04:00
|
|
|
private:
|
2014-04-13 21:35:34 -04:00
|
|
|
//! private default constructor only for friends
|
|
|
|
QTimeEvt(void);
|
|
|
|
|
|
|
|
//! private copy constructor to disallow copying of QTimeEvts
|
|
|
|
QTimeEvt(QTimeEvt const &);
|
|
|
|
|
|
|
|
//! private assignment operator to disallow assigning of QTimeEvts
|
|
|
|
QTimeEvt & operator=(QTimeEvt const &);
|
2012-08-14 18:00:48 -04:00
|
|
|
|
2015-05-14 16:05:04 -04:00
|
|
|
//! encapsulate the cast the m_act attribute to QMActive*
|
|
|
|
QMActive *toActive(void) { return static_cast<QMActive *>(m_act); }
|
2013-10-10 20:01:51 -04:00
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! encapsulate the cast the m_act attribute to QTimeEvt*
|
2013-12-30 17:41:15 -05:00
|
|
|
QTimeEvt *toTimeEvt(void) { return static_cast<QTimeEvt *>(m_act); }
|
2012-08-14 18:00:48 -04:00
|
|
|
|
|
|
|
friend class QF;
|
2015-12-31 14:56:37 -05:00
|
|
|
friend class QXThread;
|
2012-08-14 18:00:48 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2013-10-10 20:01:51 -04:00
|
|
|
//****************************************************************************
|
2014-04-13 21:35:34 -04:00
|
|
|
//! The size of the Subscriber list bit array
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @description
|
2012-08-14 18:00:48 -04:00
|
|
|
/// The size is determined of the maximum number of active objects in the
|
|
|
|
/// application configured by the #QF_MAX_ACTIVE macro.
|
|
|
|
uint8_t const QF_SUBSCR_LIST_SIZE =
|
|
|
|
static_cast<uint8_t>(((QF_MAX_ACTIVE - 1) / 8) + 1);
|
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! Subscriber List class
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @description
|
2012-08-14 18:00:48 -04:00
|
|
|
/// This data type represents a set of active objects that subscribe to
|
|
|
|
/// a given signal. The set is represented as an array of bits, where each
|
|
|
|
/// bit corresponds to the unique priority of an active object.
|
|
|
|
class QSubscrList {
|
|
|
|
private:
|
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! An array of bits representing subscriber active objects.
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @description
|
2014-04-13 21:35:34 -04:00
|
|
|
/// Each bit in the array corresponds to the unique priority of the
|
|
|
|
/// active object. The size of the array is determined of the maximum
|
|
|
|
/// number of active objects in the application configured by the
|
2015-05-14 16:05:04 -04:00
|
|
|
/// #QF_MAX_ACTIVE macro.@n
|
|
|
|
/// @n
|
2012-08-14 18:00:48 -04:00
|
|
|
/// For example, an active object of priority p is a subscriber if the
|
2013-10-10 20:01:51 -04:00
|
|
|
/// following is true: ((m_bits[QF_div8Lkup[p]] & QF::pwr2Lkup[p]) != 0)
|
2012-08-14 18:00:48 -04:00
|
|
|
///
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @sa QP::QF::psInit(), QP::QF::div8Lkup, QP::QF::pwr2Lkup,
|
2014-04-13 21:35:34 -04:00
|
|
|
/// and #QF_MAX_ACTIVE
|
2012-08-14 18:00:48 -04:00
|
|
|
uint8_t m_bits[QF_SUBSCR_LIST_SIZE];
|
|
|
|
|
|
|
|
friend class QF;
|
2015-05-14 16:05:04 -04:00
|
|
|
friend class QMActive;
|
2012-08-14 18:00:48 -04:00
|
|
|
};
|
|
|
|
|
2013-10-10 20:01:51 -04:00
|
|
|
//****************************************************************************
|
2014-04-13 21:35:34 -04:00
|
|
|
//! QF services.
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @description
|
2012-08-14 18:00:48 -04:00
|
|
|
/// This class groups together QF services. It has only static members and
|
|
|
|
/// should not be instantiated.
|
|
|
|
class QF {
|
|
|
|
public:
|
|
|
|
|
2015-05-14 16:05:04 -04:00
|
|
|
//! get the current QF version number string of the form X.Y.Z
|
2015-12-31 14:56:37 -05:00
|
|
|
static char_t const *getVersion(void) {
|
2015-05-14 16:05:04 -04:00
|
|
|
return versionStr;
|
|
|
|
}
|
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! QF initialization.
|
2012-08-14 18:00:48 -04:00
|
|
|
static void init(void);
|
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! Publish-subscribe initialization.
|
2012-08-14 18:00:48 -04:00
|
|
|
static void psInit(QSubscrList * const subscrSto,
|
2013-12-30 17:41:15 -05:00
|
|
|
enum_t const maxSignal);
|
2012-08-14 18:00:48 -04:00
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! Event pool initialization for dynamic allocation of events.
|
2015-05-14 16:05:04 -04:00
|
|
|
static void poolInit(void * const poolSto, uint_fast32_t const poolSize,
|
2014-04-13 21:35:34 -04:00
|
|
|
uint_fast16_t const evtSize);
|
2012-08-14 18:00:48 -04:00
|
|
|
|
2015-09-29 11:34:38 -04:00
|
|
|
//! Obtain the block size of any registered event pools
|
|
|
|
static uint_fast16_t poolGetMaxBlockSize(void);
|
|
|
|
|
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! Transfers control to QF to run the application.
|
2013-12-30 17:41:15 -05:00
|
|
|
static int_t run(void);
|
2012-08-14 18:00:48 -04:00
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! Startup QF callback.
|
2012-08-14 18:00:48 -04:00
|
|
|
static void onStartup(void);
|
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! Cleanup QF callback.
|
2012-08-14 18:00:48 -04:00
|
|
|
static void onCleanup(void);
|
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! Function invoked by the application layer to stop the QF
|
|
|
|
//! application and return control to the OS/Kernel.
|
2012-08-14 18:00:48 -04:00
|
|
|
static void stop(void);
|
|
|
|
|
2013-10-10 20:01:51 -04:00
|
|
|
#ifndef Q_SPY
|
2013-12-30 17:41:15 -05:00
|
|
|
static void publish_(QEvt const *e);
|
|
|
|
static void tickX_(uint8_t const tickRate);
|
2013-10-10 20:01:51 -04:00
|
|
|
#else
|
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! Publish event to the framework.
|
2013-12-30 17:41:15 -05:00
|
|
|
static void publish_(QEvt const *e, void const *sender);
|
2012-08-14 18:00:48 -04:00
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! Processes all armed time events at every clock tick.
|
2013-12-30 17:41:15 -05:00
|
|
|
static void tickX_(uint8_t const tickRate, void const * const sender);
|
2013-10-10 20:01:51 -04:00
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
#endif // Q_SPY
|
2012-08-14 18:00:48 -04:00
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! Returns true if all time events are inactive and false
|
|
|
|
//! any time event is active.
|
2013-10-10 20:01:51 -04:00
|
|
|
static bool noTimeEvtsActiveX(uint8_t const tickRate);
|
2012-08-14 18:00:48 -04:00
|
|
|
|
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! This function returns the minimum of free entries of the given
|
|
|
|
//! event pool.
|
|
|
|
static uint_fast16_t getPoolMin(uint_fast8_t const poolId);
|
2012-08-14 18:00:48 -04:00
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! This function returns the minimum of free entries of the given
|
|
|
|
//! event queue.
|
|
|
|
static uint_fast16_t getQueueMin(uint_fast8_t const prio);
|
2012-08-14 18:00:48 -04:00
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! Internal QP implementation of the dynamic event allocator.
|
|
|
|
static QEvt *newX_(uint_fast16_t const evtSize,
|
|
|
|
uint_fast16_t const margin, enum_t const sig);
|
2012-08-14 18:00:48 -04:00
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! Recycle a dynamic event.
|
2012-08-14 18:00:48 -04:00
|
|
|
static void gc(QEvt const *e);
|
|
|
|
|
2015-09-29 11:34:38 -04:00
|
|
|
//! Internal QF implementation of the event reference creator
|
|
|
|
static QEvt const *newRef_(QEvt const * const e,
|
|
|
|
QEvt const * const evtRef);
|
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! Remove the active object from the framework.
|
2015-05-14 16:05:04 -04:00
|
|
|
static void remove_(QMActive const * const a);
|
2012-08-14 18:00:48 -04:00
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! array of registered active objects
|
2015-05-14 16:05:04 -04:00
|
|
|
static QMActive *active_[QF_MAX_ACTIVE + 1];
|
2012-08-14 18:00:48 -04:00
|
|
|
|
2015-05-14 16:05:04 -04:00
|
|
|
//! Thread routine for executing an active object @p act.
|
|
|
|
static void thread_(QMActive *act);
|
2012-08-14 18:00:48 -04:00
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! Register an active object to be managed by the framework
|
2015-05-14 16:05:04 -04:00
|
|
|
static void add_(QMActive * const a);
|
2013-10-10 20:01:51 -04:00
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! Clear a specified region of memory to zero.
|
|
|
|
static void bzero(void * const start, uint_fast16_t len);
|
|
|
|
|
|
|
|
// to be used in QF ports only...
|
|
|
|
private:
|
|
|
|
|
|
|
|
//! heads of linked lists of time events, one for every clock tick rate
|
2013-10-10 20:01:51 -04:00
|
|
|
static QTimeEvt timeEvtHead_[QF_MAX_TICK_RATE];
|
|
|
|
|
2015-05-14 16:05:04 -04:00
|
|
|
friend class QMActive;
|
2013-10-10 20:01:51 -04:00
|
|
|
friend class QTimeEvt;
|
2015-12-31 14:56:37 -05:00
|
|
|
friend class QXThread;
|
2012-08-14 18:00:48 -04:00
|
|
|
};
|
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
} // namespace QP
|
2015-05-14 16:05:04 -04:00
|
|
|
|
2013-10-10 20:01:51 -04:00
|
|
|
//****************************************************************************
|
|
|
|
#ifndef QF_CRIT_EXIT_NOP
|
2014-04-13 21:35:34 -04:00
|
|
|
//! No-operation for exiting a critical section
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @description
|
2013-10-10 20:01:51 -04:00
|
|
|
/// 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
|
2012-08-14 18:00:48 -04:00
|
|
|
|
2013-10-10 20:01:51 -04:00
|
|
|
//****************************************************************************
|
2014-04-13 21:35:34 -04:00
|
|
|
// Provide the constructor for the QEvt class?
|
|
|
|
#ifdef Q_EVT_CTOR
|
2012-08-14 18:00:48 -04:00
|
|
|
|
2013-10-10 20:01:51 -04:00
|
|
|
#define Q_NEW(evtT_, sig_, ...) \
|
2014-04-13 21:35:34 -04:00
|
|
|
(new(QP::QF::newX_(static_cast<uint_fast16_t>(sizeof(evtT_)), \
|
|
|
|
static_cast<uint_fast16_t>(0), static_cast<enum_t>(0))) \
|
2013-10-10 20:01:51 -04:00
|
|
|
evtT_((sig_), ##__VA_ARGS__))
|
|
|
|
|
|
|
|
#define Q_NEW_X(e_, evtT_, margin_, sig_, ...) do { \
|
2014-04-13 21:35:34 -04:00
|
|
|
(e_) = static_cast<evtT_ *>(QP::QF::newX_(static_cast<uint_fast16_t>(\
|
2013-10-10 20:01:51 -04:00
|
|
|
sizeof(evtT_)), (margin_), static_cast<enum_t>(0))); \
|
|
|
|
if ((e_) != static_cast<evtT_ *>(0)) { \
|
|
|
|
new((e_)) evtT_((sig_), ##__VA_ARGS__); \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
#else // QEvt is a POD (Plain Old Datatype)
|
2013-10-10 20:01:51 -04:00
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! Allocate a dynamic event.
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @description
|
2014-04-13 21:35:34 -04:00
|
|
|
/// The macro calls the internal QF function QP::QF::newX_() with
|
|
|
|
/// margin == 0, which causes an assertion when the event cannot be
|
|
|
|
/// successfully allocated.
|
|
|
|
///
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @param[in] evtT_ event type (class name) of the event to allocate
|
|
|
|
/// @param[in] sig_ signal to assign to the newly allocated event
|
2014-04-13 21:35:34 -04:00
|
|
|
///
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @returns a valid event pointer cast to the type @p evtT_.
|
2012-08-14 18:00:48 -04:00
|
|
|
///
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @note
|
2014-04-13 21:35:34 -04:00
|
|
|
/// 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.
|
2012-08-14 18:00:48 -04:00
|
|
|
///
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @usage
|
2012-08-14 18:00:48 -04:00
|
|
|
/// The following example illustrates dynamic allocation of an event:
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @include qf_post.cpp
|
2012-08-14 18:00:48 -04:00
|
|
|
#define Q_NEW(evtT_, sig_) \
|
2013-10-10 20:01:51 -04:00
|
|
|
(static_cast<evtT_ *>(QP::QF::newX_( \
|
2014-04-13 21:35:34 -04:00
|
|
|
static_cast<uint_fast16_t>(sizeof(evtT_)), \
|
|
|
|
static_cast<uint_fast16_t>(0), (sig_))))
|
|
|
|
|
|
|
|
//! Allocate a dynamic event (non-asserting version).
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @description
|
|
|
|
/// This macro allocates a new event and sets the pointer @p e_, while
|
|
|
|
/// leaving at least @p margin_ of events still available in the pool
|
2014-04-13 21:35:34 -04:00
|
|
|
///
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @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
|
|
|
|
/// @param[in] sig_ signal to assign to the newly allocated event
|
2014-04-13 21:35:34 -04:00
|
|
|
///
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @returns an event pointer cast to the type @p evtT_ or NULL if the
|
|
|
|
/// event cannot be allocated with the specified @p margin.
|
2014-04-13 21:35:34 -04:00
|
|
|
///
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @note
|
2014-04-13 21:35:34 -04:00
|
|
|
/// 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.
|
|
|
|
///
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @usage
|
2013-10-10 20:01:51 -04:00
|
|
|
/// The following example illustrates dynamic allocation of an event:
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @include qf_postx.cpp
|
2013-10-10 20:01:51 -04:00
|
|
|
#define Q_NEW_X(e_, evtT_, margin_, sig_) ((e_) = static_cast<evtT_ *>(\
|
2014-04-13 21:35:34 -04:00
|
|
|
QP::QF::newX_(static_cast<uint_fast16_t>(sizeof(evtT_)),\
|
2013-10-10 20:01:51 -04:00
|
|
|
(margin_), (sig_))))
|
|
|
|
|
2012-08-14 18:00:48 -04:00
|
|
|
#endif
|
|
|
|
|
2015-09-29 11:34:38 -04:00
|
|
|
//! Create a new reference of the current event `e` */
|
|
|
|
/// @description
|
|
|
|
/// 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 refrence
|
|
|
|
///
|
|
|
|
/// @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_) = static_cast<evtT_ const *>(QP::QF::newRef_(e, (evtRef_))))
|
|
|
|
|
|
|
|
//! Delete the event reference */
|
|
|
|
/// @description
|
|
|
|
/// 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 { \
|
|
|
|
QP::QF::gc((evtRef_)); \
|
|
|
|
(evtRef_) = 0; \
|
|
|
|
} while (false)
|
|
|
|
|
|
|
|
|
2013-10-10 20:01:51 -04:00
|
|
|
//****************************************************************************
|
2012-08-14 18:00:48 -04:00
|
|
|
// QS software tracing integration, only if enabled
|
2014-04-13 21:35:34 -04:00
|
|
|
#ifdef Q_SPY
|
|
|
|
|
|
|
|
//! Invoke the system clock tick processing QP::QF::tickX_().
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @description
|
2014-04-13 21:35:34 -04:00
|
|
|
/// 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.
|
|
|
|
///
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @param[in] tickRate clock tick rate to be serviced through this call
|
|
|
|
/// @param[in] sender pointer to the sender object. This parameter
|
2014-04-13 21:35:34 -04:00
|
|
|
/// is actually only used when QS software tracing is enabled
|
|
|
|
/// (macro #Q_SPY is defined)
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @note
|
2014-04-13 21:35:34 -04:00
|
|
|
/// When QS software tracing is disabled, the macro calls QF_tickX_()
|
2015-05-14 16:05:04 -04:00
|
|
|
/// without the @p sender parameter, so the overhead of passing this
|
|
|
|
/// extra parameter is entirely avoided.
|
2014-04-13 21:35:34 -04:00
|
|
|
///
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @note
|
2014-04-13 21:35:34 -04:00
|
|
|
/// The pointer to the sender object is not necessarily a pointer
|
|
|
|
/// to an active object. In fact, when #QF_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.
|
|
|
|
///
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @sa QP::QF::tickX_()
|
2014-04-13 21:35:34 -04:00
|
|
|
#define TICK_X(tickRate_, sender_) tickX_((tickRate_), (sender_))
|
2012-08-14 18:00:48 -04:00
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! Invoke the event publishing facility QP::QF::publish_(). This macro
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @description
|
2014-04-13 21:35:34 -04:00
|
|
|
/// This macro is the recommended way of publishing events, because it
|
2012-08-14 18:00:48 -04:00
|
|
|
/// provides the vital information for software tracing and avoids any
|
|
|
|
/// overhead when the tracing is disabled.
|
|
|
|
///
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @param[in] e_ pointer to the posted event
|
|
|
|
/// @param[in] sender_ pointer to the sender object. This parameter is
|
2014-04-13 21:35:34 -04:00
|
|
|
/// actually only used when QS software tracing is enabled
|
|
|
|
/// (macro #Q_SPY is defined). When QS software tracing is
|
|
|
|
/// disabled, the macro calls QF_publish_() without the
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @p sender_ parameter, so the overhead of passing this
|
|
|
|
/// extra parameter is entirely avoided.
|
2014-04-13 21:35:34 -04:00
|
|
|
///
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @note
|
2014-04-13 21:35:34 -04:00
|
|
|
/// The pointer to the sender object is not necessarily a pointer
|
|
|
|
/// to an active object. In fact, if QF_PUBLISH() is called from an
|
2012-08-14 18:00:48 -04:00
|
|
|
/// interrupt or other context, you can create a unique object just to
|
|
|
|
/// unambiguously identify the publisher of the event.
|
|
|
|
///
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @sa QP::QF::publish_()
|
2013-12-30 17:41:15 -05:00
|
|
|
#define PUBLISH(e_, sender_) publish_((e_), (sender_))
|
2012-08-14 18:00:48 -04:00
|
|
|
|
2015-05-14 16:05:04 -04:00
|
|
|
//! Invoke the direct event posting facility QP::QMActive::post_().
|
|
|
|
/// @description
|
2014-04-13 21:35:34 -04:00
|
|
|
/// This macro asserts if the queue overflows and cannot accept the event.
|
2012-08-14 18:00:48 -04:00
|
|
|
///
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @param[in] e_ pointer to the event to post
|
|
|
|
/// @param[in] sender_ pointer to the sender object.
|
2014-04-13 21:35:34 -04:00
|
|
|
///
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @note
|
|
|
|
/// The @p sendedr_ parameter is actually only used when QS tracing
|
2014-04-13 21:35:34 -04:00
|
|
|
/// is enabled (macro #Q_SPY is defined). When QS software tracing is
|
2015-05-14 16:05:04 -04:00
|
|
|
/// disenabled, the QACTIVE_POST() macro does not pass the @p sender_
|
|
|
|
/// parameter, so the overhead of passing this extra parameter is entirely
|
2014-04-13 21:35:34 -04:00
|
|
|
/// avoided.
|
2012-08-14 18:00:48 -04:00
|
|
|
///
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @note the pointer to the sender object is not necessarily a pointer
|
2014-04-13 21:35:34 -04:00
|
|
|
/// to an active object. In fact, if QACTIVE_POST() is called from an
|
2012-08-14 18:00:48 -04:00
|
|
|
/// interrupt or other context, you can create a unique object just to
|
2014-04-13 21:35:34 -04:00
|
|
|
/// unambiguously identify the sender of the event.
|
2012-08-14 18:00:48 -04:00
|
|
|
///
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @sa QP::QMActive::post_()
|
2013-10-10 20:01:51 -04:00
|
|
|
#define POST(e_, sender_) \
|
2014-04-13 21:35:34 -04:00
|
|
|
post_((e_), static_cast<uint_fast16_t>(0), (sender_))
|
|
|
|
|
2015-05-14 16:05:04 -04:00
|
|
|
//! Invoke the direct event posting facility QP::QMActive::post_()
|
2014-04-13 21:35:34 -04:00
|
|
|
//! without delivery guarantee.
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @description
|
2014-04-13 21:35:34 -04:00
|
|
|
/// This macro does not assert if the queue overflows and cannot accept
|
|
|
|
/// the event with the specified margin of free slots remaining.
|
|
|
|
///
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @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
|
|
|
|
/// @param[in] sender_ pointer to the sender object.
|
2014-04-13 21:35:34 -04:00
|
|
|
///
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @returns
|
2014-04-13 21:35:34 -04:00
|
|
|
/// 'true' if the posting succeeded, and 'false' if the posting
|
|
|
|
/// failed due to insufficient margin of free entries available in
|
|
|
|
/// the queue.
|
|
|
|
///
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @note
|
|
|
|
/// The @p sender_ parameter is actually only used when QS tracing
|
2014-04-13 21:35:34 -04:00
|
|
|
/// is enabled (macro #Q_SPY is defined). When QS software tracing is
|
2015-05-14 16:05:04 -04:00
|
|
|
/// disabled, the QACTIVE_POST() macro does not pass the @p sender_
|
|
|
|
/// parameter, so the overhead of passing this extra parameter is
|
|
|
|
/// entirely avoided.
|
2014-04-13 21:35:34 -04:00
|
|
|
///
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @note
|
2014-04-13 21:35:34 -04:00
|
|
|
/// The pointer to the sender object is not necessarily a pointer
|
|
|
|
/// to an active object. In fact, if QACTIVE_POST() is called from an
|
2013-10-10 20:01:51 -04:00
|
|
|
/// interrupt or other context, you can create a unique object just to
|
|
|
|
/// unambiguously identify the sender of the event.
|
|
|
|
///
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @usage
|
|
|
|
/// @include qf_postx.cpp
|
2013-10-10 20:01:51 -04:00
|
|
|
#define POST_X(e_, margin_, sender_) \
|
2013-12-30 17:41:15 -05:00
|
|
|
post_((e_), (margin_), (sender_))
|
2012-08-14 18:00:48 -04:00
|
|
|
|
|
|
|
#else
|
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
#define PUBLISH(e_, dummy_) publish_((e_))
|
|
|
|
#define POST(e_, dummy_) post_((e_), static_cast<uint_fast16_t>(0))
|
2013-12-30 17:41:15 -05:00
|
|
|
#define POST_X(e_, margin_, dummy_) post_((e_), (margin_))
|
2014-04-13 21:35:34 -04:00
|
|
|
#define TICK_X(tickRate_, dummy_) tickX_((tickRate_))
|
2012-08-14 18:00:48 -04:00
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
#endif // Q_SPY
|
2012-08-14 18:00:48 -04:00
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
//! Invoke the system clock tick processing for rate 0
|
2015-05-14 16:05:04 -04:00
|
|
|
/// @sa TICK_X()
|
2013-12-30 17:41:15 -05:00
|
|
|
#define TICK(sender_) TICK_X(static_cast<uint8_t>(0), (sender_))
|
|
|
|
|
2014-04-13 21:35:34 -04:00
|
|
|
#endif // qf_h
|
2013-10-16 16:46:00 -04:00
|
|
|
|