Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
qf.h
00001 ////////////////////////////////////////////////////////////////////////////// 00002 // Product: QF/C++ platform-independent public interface 00003 // Last Updated for Version: 4.0.00 00004 // Date of the Last Update: Apr 06, 2008 00005 // 00006 // Q u a n t u m L e a P s 00007 // --------------------------- 00008 // innovating embedded systems 00009 // 00010 // Copyright (C) 2002-2008 Quantum Leaps, LLC. All rights reserved. 00011 // 00012 // This software may be distributed and modified under the terms of the GNU 00013 // General Public License version 2 (GPL) as published by the Free Software 00014 // Foundation and appearing in the file GPL.TXT included in the packaging of 00015 // this file. Please note that GPL Section 2[b] requires that all works based 00016 // on this software must also be made publicly available under the terms of 00017 // the GPL ("Copyleft"). 00018 // 00019 // Alternatively, this software may be distributed and modified under the 00020 // terms of Quantum Leaps commercial licenses, which expressly supersede 00021 // the GPL and are specifically designed for licensees interested in 00022 // retaining the proprietary status of their code. 00023 // 00024 // Contact information: 00025 // Quantum Leaps Web site: http://www.quantum-leaps.com 00026 // e-mail: info@quantum-leaps.com 00027 ////////////////////////////////////////////////////////////////////////////// 00028 #ifndef qf_h 00029 #define qf_h 00030 00031 /// \file 00032 /// \ingroup qf qk 00033 /// \brief QF/C++ platform-independent public interface. 00034 /// 00035 /// This header file must be included directly or indirectly 00036 /// in all modules (*.cpp files) that use QF/C++. 00037 00038 ////////////////////////////////////////////////////////////////////////////// 00039 #if (QF_MAX_ACTIVE < 1) || (63 < QF_MAX_ACTIVE) 00040 #error "QF_MAX_ACTIVE not defined or out of range. Valid range is 1..63" 00041 #endif 00042 00043 ////////////////////////////////////////////////////////////////////////////// 00044 #ifndef QF_EVENT_SIZ_SIZE 00045 00046 /// \brief Default value of the macro configurable value in qf_port.h 00047 #define QF_EVENT_SIZ_SIZE 2 00048 #endif 00049 #if (QF_EVENT_SIZ_SIZE == 1) 00050 00051 /// \brief The data type to store the block-size defined based on 00052 /// the macro #QF_EVENT_SIZ_SIZE. 00053 /// 00054 /// The dynamic range of this data type determines the maximum block 00055 /// size that can be managed by the pool. 00056 typedef uint8_t QEventSize; 00057 #elif (QF_EVENT_SIZ_SIZE == 2) 00058 typedef uint16_t QEventSize; 00059 #elif (QF_EVENT_SIZ_SIZE == 4) 00060 typedef uint32_t QEventSize; 00061 #else 00062 #error "QF_EVENT_SIZ_SIZE defined incorrectly, expected 1, 2, or 4" 00063 #endif 00064 00065 00066 ////////////////////////////////////////////////////////////////////////////// 00067 #ifndef QF_ACTIVE_SUPER_ 00068 00069 ////////////////////////////////////////////////////////////////////////// 00070 /// \brief The macro defining the base class for QActive. 00071 /// 00072 /// By default, the ::QActive class is derived from ::QHsm. However, 00073 /// if the macro QF_ACTIVE_SUPER_ is defined, QActive is derived from 00074 /// QF_ACTIVE_SUPER_. 00075 /// 00076 /// Clients might choose, for example, to define QF_ACTIVE_SUPER_ as QFsm 00077 /// to avoid the 1-2KB overhead of the hierarchical event processor. 00078 /// 00079 /// Clients might also choose to define QF_ACTIVE_SUPER_ as their own 00080 /// completely customized class that has nothing to do with QHsm or QFsm. 00081 /// The QF_ACTIVE_SUPER_ class must provide member functions init() and 00082 /// dispatch(), consistent with the signatures of QHsm and QFsm. But 00083 /// the implementatin of these functions is completely open. 00084 #define QF_ACTIVE_SUPER_ QHsm 00085 00086 /// \brief The argument of the base class' constructor. 00087 #define QF_ACTIVE_STATE_ QStateHandler 00088 00089 #endif 00090 00091 class QEQueue; // forward declaration 00092 00093 00094 /// \brief Base class for derivation of application-level active object 00095 /// classes. 00096 /// 00097 /// QActive is the base class for derivation of active objects. Active objects 00098 /// in QF are encapsulated tasks (each embedding a state machine and an event 00099 /// queue) that communicate with one another asynchronously by sending and 00100 /// receiving events. Within an active object, events are processed 00101 /// sequentially in a run-to-completion (RTC) fashion, while QF encapsulates 00102 /// all the details of thread-safe event exchange and queuing. 00103 /// 00104 /// \note QActive is not intended to be instantiated directly, but rather 00105 /// serves as the base class for derivation of active objects in the 00106 /// application code. 00107 /// 00108 /// The following example illustrates how to derive an active object from 00109 /// QActive. 00110 /// \include qf_qactive.cpp 00111 /// 00112 /// \sa #QF_ACTIVE_SUPER_ defines the base class for QActive 00113 class QActive : public QF_ACTIVE_SUPER_ { 00114 private: 00115 00116 /// \brief OS-dependent event-queue type. 00117 /// 00118 /// The type of the queue depends on the underlying operating system or 00119 /// a kernel. Many kernels support "message queues" that can be adapted 00120 /// to deliver QF events to the active object. Alternatively, QF provides 00121 /// a native event queue implementation that can be used as well. 00122 /// 00123 /// The native QF event queue is configured by defining the macro 00124 /// #QF_EQUEUE_TYPE as ::QEQueue. 00125 QF_EQUEUE_TYPE m_eQueue; 00126 00127 public: 00128 #ifdef QF_OS_OBJECT_TYPE 00129 /// \brief OS-dependent per-thread object. 00130 /// 00131 /// This data might be used in various ways, depending on the QF port. 00132 /// In some ports m_osObject is used to block the calling thread when 00133 /// the native QF queue is empty. In other QF ports the OS-dependent 00134 /// object might be used differently. 00135 QF_OS_OBJECT_TYPE m_osObject; 00136 #endif 00137 00138 #ifdef QF_THREAD_TYPE 00139 /// \brief OS-dependent representation of the thread of the active 00140 /// object. 00141 /// 00142 /// This data might be used in various ways, depending on the QF port. 00143 /// In some ports m_thread is used store the thread handle. In other ports 00144 /// m_thread can be the pointer to the Thread-Local-Storage (TLS). 00145 QF_THREAD_TYPE m_thread; 00146 #endif 00147 00148 /// \brief QF priority associated with the active object. 00149 /// \sa QActive::start() 00150 uint8_t m_prio; 00151 00152 /// \brief The Boolean loop variable determining if the thread routine 00153 /// of the active object is running. 00154 /// 00155 /// This flag is only used with the traditional loop-structured thread 00156 /// routines. Clearing this flag breaks out of the thread loop, which is 00157 /// often the cleanest way to terminate the thread. The following example 00158 /// illustrates the thread routine for Win32: 00159 /// \include qf_run.cpp 00160 uint8_t m_running; 00161 00162 public: 00163 00164 /// \brief Starts execution of an active object and registers the object 00165 /// with the framework. 00166 /// 00167 /// The function takes six arguments. 00168 /// \a prio is the priority of the active object. QF allows you to start 00169 /// up to 63 active objects, each one having a unique priority number 00170 /// between 1 and 63 inclusive, where higher numerical values correspond 00171 /// to higher priority (urgency) of the active object relative to the 00172 /// others. 00173 /// \a qSto[] and \a qLen arguments are the storage and size of the event 00174 /// queue used by this active object. 00175 /// \a stkSto and \a stkSize are the stack storage and size in bytes. 00176 /// Please note that a per-active object stack is used only when the 00177 /// underlying OS requies it. If the stack is not required, or the 00178 /// underlying OS allocates the stack internally, the \a stkSto should be 00179 /// NULL and/or \a stkSize should be 0. 00180 /// \a ie is an optional initialization event that can be used to pass 00181 /// additional startup data to the active object. (Pass NULL if your 00182 /// active object does not expect the initialization event). 00183 /// 00184 /// \note This function is strongly OS-dependent and must be defined in 00185 /// the QF port to a particular platform. 00186 /// 00187 /// The following example shows starting of the Philosopher object when a 00188 /// per-task stack is required: 00189 /// \include qf_start.cpp 00190 void start(uint8_t prio, 00191 QEvent const *qSto[], uint32_t qLen, 00192 void *stkSto, uint32_t stkSize, 00193 QEvent const *ie = (QEvent *)0); 00194 00195 /// \brief Posts an event \a e directly to the event queue of the acitve 00196 /// object \a me using the First-In-First-Out (FIFO) policy. 00197 /// 00198 /// Direct event posting is the simplest asynchronous communication method 00199 /// available in QF. The following example illustrates how the Philosopher 00200 /// active obejct posts directly the HUNGRY event to the Table active 00201 /// object. \include qf_post.cpp 00202 /// 00203 /// \note The producer of the event (Philosopher in this case) must only 00204 /// "know" the recipient (Table) by a generic (QActive *QDPP_table) 00205 /// pointer, but the specific definition of the Table class is not 00206 /// required. 00207 /// 00208 /// \note Direct event posting should not be confused with direct event 00209 /// dispatching. In contrast to asynchronous event posting through event 00210 /// queues, direct event dispatching is synchronous. Direct event 00211 /// dispatching occurs when you call QHsm::dispatch(), or QFsm::dispatch() 00212 /// function. 00213 void postFIFO(QEvent const *e); 00214 00215 /// \brief Posts an event directly to the event queue of the active object 00216 /// \a me using the Last-In-First-Out (LIFO) policy. 00217 /// 00218 /// \note The LIFO policy should be used only with great caution because 00219 /// it alters order of events in the queue. 00220 /// \sa QActive::postFIFO() 00221 void postLIFO(QEvent const *e); 00222 00223 /// \brief Traditional loop-structured thread routine for an active object 00224 /// 00225 /// This function is only used when QF is ported to a traditional 00226 /// RTOS/Kernel. QActive::run() is structured as a typical endless loop, 00227 /// which blocks on the event queue get() operation of an active object. 00228 /// When an event becomes available, it's dispatched to the active 00229 /// object's state machine and after this recycled with QF::gc(). 00230 /// The loop might optionally use the QActive::m_running flag to terminate 00231 /// and cause QActive::run() to return which is often the cleanest way to 00232 /// terminate the thread. 00233 void run(void); 00234 00235 /// \brief Get an event from the event queue of an active object. 00236 /// 00237 /// This function is used internally by a QF port to extract events from 00238 /// the event queue of an active object. This function depends on the 00239 /// event queue implementation and is sometimes implemented in the QF port 00240 /// (qf_port.cpp file). Depending on the underlying OS or kernel, the 00241 /// function might block the calling thread when no events are available. 00242 /// 00243 /// \note QActive::get_() is public because it often needs to be called 00244 /// from thread-run routines with difficult to foresee signature (so 00245 /// declaring friendship with such function(s) is not possible.) 00246 /// 00247 /// \sa QActive::postFIFO(), QActive::postLIFO() 00248 QEvent const *get_(void); 00249 00250 protected: 00251 00252 /// \brief protected constructor 00253 /// 00254 /// Performs the first step of active object initialization by assigning 00255 /// the initial pseudostate to the currently active state of the state 00256 /// machine. 00257 /// 00258 /// \note The constructor is protected to prevent direct instantiation 00259 /// of QActive objects. This class is intended only for derivation 00260 /// (abstract class). 00261 QActive(QF_ACTIVE_STATE_ initial) : QF_ACTIVE_SUPER_(initial) { 00262 } 00263 00264 /// \brief Stops execution of an active object and removes it from the 00265 /// framework's supervision. 00266 /// 00267 /// The preferred way of calling this function is from within the active 00268 /// object that needs to stop (that's why this function is protected). 00269 /// In other words, an active object should stop itself rather than being 00270 /// stopped by some other entity. This policy works best, because only 00271 /// the active object itself "knows" when it has reached the appropriate 00272 /// state for the shutdown. 00273 /// 00274 /// \note This function is strongly OS-dependent and should be defined in 00275 /// the QF port to a particular platform. This function is optional in 00276 /// embedded systems where active objects never need to be stopped. 00277 void stop(void); 00278 00279 /// \brief Subscribes for delivery of signal \a sig to the active object 00280 /// 00281 /// This function is part of the Publish-Subscribe event delivery 00282 /// mechanism available in QF. Subscribing to an event means that the 00283 /// framework will start posting all published events with a given signal 00284 /// \a sig to the event queue of the active object. 00285 /// 00286 /// The following example shows how the Table active object subscribes 00287 /// to three signals in the initial transition: 00288 /// \include qf_subscribe.cpp 00289 /// 00290 /// \sa QF::publish(), QActive::unsubscribe(), and 00291 /// QActive::unsubscribeAll() 00292 void subscribe(QSignal sig) const; 00293 00294 /// \brief Un-subscribes from the delivery of signal \a sig to the 00295 /// active object. 00296 /// 00297 /// This function is part of the Publish-Subscribe event delivery 00298 /// mechanism available in QF. Un-subscribing from an event means that 00299 /// the framework will stop posting published events with a given signal 00300 /// \a sig to the event queue of the active object. 00301 /// 00302 /// \note Due to the latency of event queues, an active object should NOT 00303 /// assume that a given signal \a sig will never be dispatched to the 00304 /// state machine of the active object after un-subscribing from that 00305 /// signal. The event might be already in the queue, or just about to be 00306 /// posted and the un-subscribe operation will not flush such events. 00307 /// 00308 /// \note Un-subscribing from a signal that has never been subscribed in 00309 /// the first place is considered an error and QF will rise an assertion. 00310 /// 00311 /// \sa QF::publish(), QActive::subscribe(), and QActive::unsubscribeAll() 00312 void unsubscribe(QSignal sig) const; 00313 00314 /// \brief Defer an event to a given separate event queue. 00315 /// 00316 /// This function is part of the event deferral support. An active object 00317 /// uses this function to defer an event \a e to the QF-supported native 00318 /// event queue \a eq. QF correctly accounts for another outstanding 00319 /// reference to the event and will not recycle the event at the end of 00320 /// the RTC step. Later, the active object might recall one event at a 00321 /// time from the event queue. 00322 /// 00323 /// An active object can use multiple event queues to defer events of 00324 /// different kinds. 00325 /// 00326 /// \sa QActive::recall(), QEQueue 00327 void defer(QEQueue *eq, QEvent const *e); 00328 00329 /// \brief Recall a deferred event from a given event queue. 00330 /// 00331 /// This function is part of the event deferral support. An active object 00332 /// uses this function to recall a deferred event from a given QF 00333 /// event queue. Recalling an event means that it is removed from the 00334 /// deferred event queue \a eq and posted (LIFO) to the event queue of 00335 /// the active object. 00336 /// 00337 /// QActive::recall() returns the pointer to the recalled event to the 00338 /// caller. The function returns NULL if no event has been recalled. 00339 /// 00340 /// An active object can use multiple event queues to defer events of 00341 /// different kinds. 00342 /// 00343 /// \sa QActive::defer(), QEQueue, QActive::postLIFO() 00344 QEvent const *recall(QEQueue *eq); 00345 00346 public: 00347 /// \brief Un-subscribes from the delivery of all signals to the active 00348 /// object. 00349 /// 00350 /// This function is part of the Publish-Subscribe event delivery 00351 /// mechanism available in QF. Un-subscribing from all events means that 00352 /// the framework will stop posting any published events to the event 00353 /// queue of the active object. 00354 /// 00355 /// \note Due to the latency of event queues, an active object should NOT 00356 /// assume that no events will ever be dispatched to the state machine of 00357 /// the active object after un-subscribing from all events. 00358 /// The events might be already in the queue, or just about to be posted 00359 /// and the un-subscribe operation will not flush such events. Also, the 00360 /// alternative event-delivery mechanisms, such as direct event posting or 00361 /// time events, can be still delivered to the event queue of the active 00362 /// object. 00363 /// 00364 /// \sa QF::publish(), QActive::subscribe(), and QActive::unsubscribe() 00365 void unsubscribeAll(void) const; 00366 00367 private: 00368 00369 friend class QF; 00370 friend class QTimeEvt; 00371 #ifndef QF_INT_KEY_TYPE 00372 friend void QK_schedule_(void); 00373 friend void QK_scheduleExt_(void); 00374 #else 00375 friend void QK_schedule_(QF_INT_KEY_TYPE intLockKey); 00376 friend void QK_scheduleExt_(QF_INT_KEY_TYPE intLockKey); 00377 #endif 00378 }; 00379 00380 00381 ////////////////////////////////////////////////////////////////////////////// 00382 #ifndef QF_TIMEEVT_CTR_SIZE 00383 /// \brief macro to override the default QTimeEvtCtr size. 00384 /// Valid values 1, 2, or 4; default 2 00385 #define QF_TIMEEVT_CTR_SIZE 2 00386 #endif 00387 #if (QF_TIMEEVT_CTR_SIZE == 1) 00388 00389 /// \brief type of the Time Event counter, which determines the dynamic 00390 /// range of the time delays measured in clock ticks. 00391 /// 00392 /// This typedef is configurable via the preprocessor switch 00393 /// #QF_TIMEEVT_CTR_SIZE. The other possible values of this type are 00394 /// as follows: \n 00395 /// uint8_t when (QF_TIMEEVT_CTR_SIZE == 1), and \n 00396 /// uint32_t when (QF_TIMEEVT_CTR_SIZE == 4). 00397 typedef uint8_t QTimeEvtCtr; 00398 #elif (QF_TIMEEVT_CTR_SIZE == 2) 00399 typedef uint16_t QTimeEvtCtr; 00400 #elif (QF_TIMEEVT_CTR_SIZE == 4) 00401 typedef uint32_t QTimeEvtCtr; 00402 #else 00403 #error "QF_TIMEEVT_CTR_SIZE defined incorrectly, expected 1, 2, or 4" 00404 #endif 00405 00406 ////////////////////////////////////////////////////////////////////////////// 00407 /// \brief Time Event class 00408 /// 00409 /// Time events are special QF events equipped with the notion of time 00410 /// passage. The basic usage model of the time events is as follows. An 00411 /// active object allocates one or more QTimeEvt objects (provides the 00412 /// storage for them). When the active object needs to arrange for a timeout, 00413 /// it arms one of its time events to fire either just once (one-shot) or 00414 /// periodically. Each time event times out independently from the others, 00415 /// so a QF application can make multiple parallel timeout requests (from the 00416 /// same or different active objects). When QF detects that the appropriate 00417 /// moment has arrived, it inserts the time event directly into the 00418 /// recipient's event queue. The recipient then processes the time event just 00419 /// like any other event. 00420 /// 00421 /// Time events, as any other QF events derive from the ::QEvent base 00422 /// class. Typically, you will use a time event as-is, but you can also 00423 /// further derive more specialized time events from it by adding some more 00424 /// data members and/or specialized functions that operate on the specialized 00425 /// time events. 00426 /// 00427 /// Internally, the armed time events are organized into a bi-directional 00428 /// linked list. This linked list is scanned in every invocation of the 00429 /// QF::tick() function. Only armed (timing out) time events are in the list, 00430 /// so only armed time events consume CPU cycles. 00431 /// 00432 /// \note QF manages the time events in the function QF::tick(), which 00433 /// must be called periodically, preferably from the clock tick ISR. 00434 /// \note In this version of QF QTimeEvt objects should be allocated 00435 /// statically rather than dynamically from event pools. Currently, QF will 00436 /// not correctly recycle the dynamically allocated Time Events. 00437 class QTimeEvt : public QEvent { 00438 private: 00439 00440 //// link to the previous time event in the list 00441 QTimeEvt *m_prev; 00442 00443 /// link to the next time event in the list 00444 QTimeEvt *m_next; 00445 00446 /// the active object that receives the time events. 00447 QActive *m_act; 00448 00449 /// the internal down-counter of the time event. The down-counter 00450 /// is decremented by 1 in every QF_tick() invocation. The time event 00451 /// fires (gets posted or published) when the down-counter reaches zero. 00452 QTimeEvtCtr m_ctr; 00453 00454 /// the interval for the periodic time event (zero for the one-shot 00455 /// time event). The value of the interval is re-loaded to the internal 00456 /// down-counter when the time event expires, so that the time event 00457 /// keeps timing out periodically. 00458 QTimeEvtCtr m_interval; 00459 00460 public: 00461 00462 /// \brief The Time Event constructor. 00463 /// 00464 /// The most important initialization performed in the constructor is 00465 /// assigning a signal to the Time Event. You can reuse the Time Event 00466 /// any number of times, but you cannot change the signal. 00467 /// This is because pointers to Time Events might still be held in event 00468 /// queues and changing signal could to hard-to-detect errors. 00469 /// 00470 /// The following example shows the use of QTimeEvt::QTimeEvt() 00471 /// constructor in the constructor initializer list of the Philosopher 00472 /// active object constructor that owns the time event 00473 /// \include qf_ctor.cpp 00474 QTimeEvt(QSignal s); 00475 00476 /// \brief Arm a one-shot time event for direct event posting. 00477 /// 00478 /// Arms a time event to fire in \a nTicks clock ticks (one-shot time 00479 /// event). The time event gets directly posted (using the FIFO policy) 00480 /// into the event queue of the active object \a act. 00481 /// 00482 /// After posting, the time event gets automatically disarmed and can be 00483 /// reused for a one-shot or periodic timeout requests. 00484 /// 00485 /// A one-shot time event can be disarmed at any time by calling the 00486 /// QTimeEvt::disarm() function. Also, a one-shot time event can be 00487 /// re-armed to fire in a different number of clock ticks by calling the 00488 /// QTimeEvt::rearm() function. 00489 /// 00490 /// The following example shows how to arm a one-shot time event from a 00491 /// state machine of an active object: 00492 /// \include qf_state.cpp 00493 void postIn(QActive *act, QTimeEvtCtr nTicks) { 00494 m_interval = (uint16_t)0; 00495 arm_(act, nTicks); 00496 } 00497 00498 /// \brief Arm a periodic time event for direct event posting. 00499 /// 00500 /// Arms a time event to fire every \a nTicks clock ticks (periodic time 00501 /// event). The time event gets directly posted (using the FIFO policy) 00502 /// into the event queue of the active object \a act. 00503 /// 00504 /// After posting, the time event gets automatically re-armed to fire 00505 /// again in the specified \a nTicks clock ticks. 00506 /// 00507 /// A periodic time event can be disarmed only by calling the 00508 /// QTimeEvt::disarm() function. After disarming, the time event can be 00509 /// reused for a one-shot or periodic timeout requests. 00510 /// 00511 /// \note An attempt to reuse (arm again) a running periodic time event 00512 /// raises an assertion. 00513 /// 00514 /// Also, a periodic time event can be re-armed to shorten or extend the 00515 /// current period by calling the QTimeEvt_rearm() function. After 00516 /// adjusting the current period, the periodic time event goes back 00517 /// timing out at the original rate. 00518 void postEvery(QActive *act, QTimeEvtCtr nTicks) { 00519 m_interval = nTicks; 00520 arm_(act, nTicks); 00521 } 00522 00523 /// \brief Disarm a time event. 00524 /// 00525 /// The time event gets disarmed and can be reused. The function 00526 /// returns 1 (TRUE) if the time event was truly disarmed, that is, it 00527 /// was running. The return of 0 (FALSE) means that the time event was 00528 /// not truly disarmed because it was not running. The FALSE return is 00529 /// only possible for one-shot time events that have been automatically 00530 /// disarmed upon expiration. In this case the FALSE return means that 00531 /// the time event has already been posted or published and should be 00532 /// expected in the active object's state machine. 00533 uint8_t disarm(void); 00534 00535 /// \brief Rearm a time event. 00536 /// 00537 /// The time event gets rearmed with a new number of clock ticks 00538 /// \a nTicks. This facility can be used to prevent a one-shot time event 00539 /// from expiring (e.g., a watchdog time event), or to adjusts the 00540 /// current period of a periodic time event. Rearming a periodic timer 00541 /// leaves the interval unchanged and is a convenient method to adjust the 00542 /// phasing of the periodic time event. 00543 /// 00544 /// The function returns 1 (TRUE) if the time event was running as it 00545 /// was re-armed. The return of 0 (FALSE) means that the time event was 00546 /// not truly rearmed because it was not running. The FALSE return is only 00547 /// possible for one-shot time events that have been automatically 00548 /// disarmed upon expiration. In this case the FALSE return means that 00549 /// the time event has already been posted or published and should be 00550 /// expected in the active object's state machine. 00551 uint8_t rearm(QTimeEvtCtr nTicks); 00552 00553 // for backwards compatibility 00554 00555 /// \brief Arm a one-shot time event for direct event posting (obsolete). 00556 /// 00557 /// This facility is now obsolete, please use \sa QTimeEvt::postIn(). 00558 void fireIn(QActive *act, QTimeEvtCtr nTicks) { 00559 postIn(act, nTicks); 00560 } 00561 00562 /// \brief Arm a periodic time event for direct event posting (obsolete). 00563 /// 00564 /// This facility is now obsolete, please use \sa QTimeEvt::postEvery(). 00565 void fireEvery(QActive *act, QTimeEvtCtr nTicks) { 00566 postEvery(act, nTicks); 00567 } 00568 00569 private: 00570 00571 /// \brief Arm a time event (internal function to be used through macros 00572 /// only). 00573 /// 00574 /// \sa QTimeEvt::postIn(), QTimeEvt::postEvery(), 00575 /// \sa QTimeEvt::publishIn(), QTimeEvt::publishEvery() 00576 void arm_(QActive *act, QTimeEvtCtr nTicks); 00577 00578 friend class QF; 00579 }; 00580 00581 00582 #if (QF_MAX_ACTIVE > 63) 00583 #error "QF_MAX_ACTIVE exceeds 63" 00584 #endif 00585 00586 ////////////////////////////////////////////////////////////////////////////// 00587 /// \brief Subscriber List class 00588 /// 00589 /// This data type represents a set of active objects that subscribe to 00590 /// a given signal. The set is represented as an array of bits, where each 00591 /// bit corresponds to the unique priority of an active object. 00592 class QSubscrList { 00593 private: 00594 00595 /// An array of bits representing subscriber active objects. Each bit 00596 /// in the array corresponds to the unique priority of the active object. 00597 /// The size of the array is determined of the maximum number of active 00598 /// objects in the application configured by the #QF_MAX_ACTIVE macro. 00599 /// For example, an active object of priority p is a subscriber if the 00600 /// following is true: ((m_bits[QF_div8Lkup[p]] & QF_pwr2Lkup[p]) != 0) 00601 /// 00602 /// \sa QF::psInit(), QF_div8Lkup, QF_pwr2Lkup, #QF_MAX_ACTIVE 00603 uint8_t m_bits[((QF_MAX_ACTIVE - 1) / 8) + 1]; 00604 00605 friend class QF; 00606 friend class QActive; 00607 }; 00608 00609 ////////////////////////////////////////////////////////////////////////////// 00610 /// \brief QF services. 00611 /// 00612 /// This class groups together QF services. It has only static members and 00613 /// should not be instantiated. 00614 class QF { 00615 public: 00616 00617 /// \brief QF initialization. 00618 /// 00619 /// This function initializes QF and must be called exactly once before 00620 /// any other QF function. 00621 static void init(void); 00622 00623 /// \brief Publish-subscribe initialization. 00624 /// 00625 /// This function initializes the publish-subscribe facilities of QF and 00626 /// must be called exactly once before any subscriptions/publications 00627 /// occur in the application. The arguments are as follows: \a subscrSto 00628 /// is a pointer to the array of subscriber-lists. \a maxSignal is the 00629 /// dimension of this array and at the same time the maximum signal that 00630 /// can be published or subscribed. 00631 /// 00632 /// The array of subscriber-lists is indexed by signals and provides 00633 /// mapping between the signals and subscirber-lists. The subscriber- 00634 /// lists are bitmasks of type ::QSubscrList, each bit in the bitmask 00635 /// corresponding to the unique priority of an active object. The size 00636 /// of the ::QSubscrList bitmask depends on the value of the 00637 /// #QF_MAX_ACTIVE macro. 00638 /// 00639 /// \note The publish-subscribe facilities are optional, meaning that 00640 /// you might choose not to use publish-subscribe. In that case calling 00641 /// QF::psInit() and using up memory for the subscriber-lists is 00642 /// unnecessary. 00643 /// 00644 /// \sa ::QSubscrList 00645 /// 00646 /// The following example shows the typical initialization sequence of 00647 /// QF: \include qf_main.cpp 00648 static void psInit(QSubscrList *subscrSto, QSignal maxSignal); 00649 00650 /// \brief Event pool initialization for dynamic allocation of events. 00651 /// 00652 /// This function initializes one event pool at a time and must be called 00653 /// exactly once for each event pool before the pool can be used. 00654 /// The arguments are as follows: \a poolSto is a pointer to the memory 00655 /// block for the events. \a poolSize is the size of the memory block in 00656 /// bytes. \a evtSize is the block-size of the pool in bytes, which 00657 /// determines the maximum size of events that can be allocated from the 00658 /// pool. 00659 /// 00660 /// You might initialize one, two, and up to three event pools by making 00661 /// one, two, or three calls to the QF_poolInit() function. However, 00662 /// for the simplicity of the internal implementation, you must initialize 00663 /// event pools in the ascending order of the event size. 00664 /// 00665 /// Many RTOSes provide fixed block-size heaps, a.k.a. memory pools that 00666 /// can be used for QF event pools. In case such support is missing, QF 00667 /// provides a native QF event pool implementation. The macro 00668 /// #QF_EPOOL_TYPE_ determines the type of event pool used by a 00669 /// particular QF port. See class ::QMPool for more information. 00670 /// 00671 /// \note The actual number of events available in the pool might be 00672 /// actually less than (\a poolSize / \a evtSize) due to the internal 00673 /// alignment of the blocks that the pool might perform. You can always 00674 /// check the capacity of the pool by calling QF::getPoolMargin(). 00675 /// 00676 /// \note The dynamic allocation of events is optional, meaning that you 00677 /// might choose not to use dynamic events. In that case calling 00678 /// QF::poolInit() and using up memory for the memory blocks is 00679 /// unnecessary. 00680 /// 00681 /// \sa QF initialization example for QF::init() 00682 static void poolInit(void *poolSto, uint32_t poolSize, 00683 QEventSize evtSize); 00684 00685 /// \brief Transfers control to QF to run the application. 00686 /// 00687 /// QF::run() is typically called from your startup code after you 00688 /// initialize the QF and start at least one active object with 00689 /// QActive::start(). Also, QF::start() call must precede the transfer 00690 /// of control to QF::run(), but some QF ports might call QF::start() 00691 /// from QF::run(). QF::run() typically never returns to the caller. 00692 /// 00693 /// \note This function is strongly platform-dependent and is not 00694 /// implemented in the QF, but either in the QF port or in the 00695 /// Board Support Package (BSP) for the given application. All QF ports 00696 /// must implement QF::run(). 00697 /// 00698 /// \note When the Quantum Kernel (QK) is used as the underlying real-time 00699 /// kernel for the QF, all platfrom dependencies are handled in the QK, so 00700 /// no porting of QF is necessary. In other words, you only need to 00701 /// recompile the QF platform-independent code with the compiler for your 00702 /// platform, but you don't need to provide any platform-specific 00703 /// implementation (so, no qf_port.cpp file is necessary). Moreover, QK 00704 /// implements the function QF::run() in a platform-independent way, 00705 /// in the modile qk.cpp. 00706 static void run(void); 00707 00708 /// \brief Startup QF callback. 00709 /// 00710 /// The timeline for calling QF::onStartup() depends on the particular 00711 /// QF port. In most cases, QF::onStartup() is called from QF::run(), 00712 /// right before starting any multitasking kernel or the background loop. 00713 static void onStartup(void); 00714 00715 /// \brief Cleanup QF callback. 00716 /// 00717 /// QF::onCleanup() is called in some QF ports before QF returns to the 00718 /// underlying operating system or RTOS. 00719 /// 00720 /// This function is strongly platform-specific and is not implemented in 00721 /// the QF but either in the QF port or in the Board Support Package (BSP) 00722 /// for the given application. Some QF ports might not require 00723 /// implementing QF::onCleanup() at all, because many embedded 00724 /// applications don't have anything to exit to. 00725 /// 00726 /// \sa QF::init() and QF::stop() 00727 static void onCleanup(void); 00728 00729 #ifndef QF_INT_KEY_TYPE 00730 static void onIdle(void); // interrupt lock key NOT defined 00731 00732 #else 00733 00734 /// \brief QF idle callback (customized in BSPs for QF) 00735 /// 00736 /// QF::onIdle() is called by the non-preemptive scheduler built into QF 00737 /// when the framework detects that no events are available for active 00738 /// objects (the idle condition). This callback gives the application an 00739 /// opportunity to enter a power-saving CPU mode, or perform some other 00740 /// idle processing (such as Q-Spy output). 00741 /// 00742 /// \note QF::onIdle() is invoked with interrupts LOCKED because the idle 00743 /// condition can be asynchronously changed at any time by an interrupt. 00744 /// QF::onIdle() MUST unlock the interrupts internally, but not before 00745 /// putting the CPU into the low-power mode. (Ideally, unlocking 00746 /// interrupts and low-power mode should happen atomically). At the very 00747 /// least, the function MUST unlock interrupts, otherwise interrups will 00748 /// be locked permanently. 00749 /// 00750 /// \note QF::onIdle() is only used by the non-preemptive scheduler built 00751 /// into QF in the "bare metal" port, and is NOT used in any other ports. 00752 /// When QF is combined with QK, the QK idle loop calls a different 00753 /// function QK::onIdle(), with different semantics than QF::onIdle(). 00754 /// When QF is combined with a 3rd-party RTOS or kernel, the idle 00755 /// processing mechanism of the RTOS or kernal is used instead of 00756 /// QF::onIdle(). 00757 static void onIdle(QF_INT_KEY_TYPE intLockKey); // int. lock key defined 00758 00759 #endif // QF_INT_KEY_TYPE 00760 00761 /// \brief Function invoked by the application layer to stop the QF 00762 /// application and return control to the OS/Kernel. 00763 /// 00764 /// This function stops the QF application. After calling this function, 00765 /// QF attempts to gracefully stop the application. This graceful 00766 /// shutdown might take some time to complete. The typical use of this 00767 /// funcition is for terminating the QF application to return back to the 00768 /// operating system or for handling fatal errors that require shutting 00769 /// down (and possibly re-setting) the system. 00770 /// 00771 /// This function is strongly platform-specific and is not implemented in 00772 /// the QF but either in the QF port or in the Board Support Package (BSP) 00773 /// for the given application. Some QF ports might not require 00774 /// implementing QF::stop() at all, because many embedded application 00775 /// don't have anything to exit to. 00776 /// 00777 /// \sa QF::stop() and QF::onCleanup() 00778 static void stop(void); 00779 00780 /// \brief Publish event to the framework. 00781 /// 00782 /// This function posts (using the FIFO policy) the event \a e it to ALL 00783 /// active object that have subscribed to the signal \a e->sig. 00784 /// This function is designed to be callable from any part of the system, 00785 /// including ISRs, device drivers, and active objects. 00786 /// 00787 /// In the general case, event publishing requires multi-casting the 00788 /// event to multiple subscribers. This happens in the caller's thread 00789 /// with the scheduler locked to prevent preemptions during the multi- 00790 /// casting process. (Please note that the interrupts are not locked.) 00791 static void publish(QEvent const *e); 00792 00793 /// \brief Processes all armed time events at every clock tick. 00794 /// 00795 /// This function must be called periodically from a time-tick ISR or from 00796 /// the highest-priority task so that QF can manage the timeout events. 00797 /// 00798 /// \note The QF::tick() function is not reentrant meaning that it must 00799 /// run to completion before it is called again. Also, QF::tick() assumes 00800 /// that it never will get preempted by a task, which is always the case 00801 /// when it is called from an ISR or the highest-priority task. 00802 /// 00803 /// \sa ::QTimeEvt. 00804 /// 00805 /// The following example illustrates the call to QF::tick(): 00806 /// \include qf_tick.cpp 00807 static void tick(void); 00808 00809 /// \brief Returns the QF version. 00810 /// 00811 /// This function returns constant version string in the format x.y.zz, 00812 /// where x (one digit) is the major version, y (one digit) is the minor 00813 /// version, and zz (two digits) is the maintenance release version. 00814 /// An example of the version string is "3.1.03". 00815 /// 00816 /// The following example illustrates the usage of this function: 00817 /// \include qf_version.cpp 00818 static char const Q_ROM * Q_ROM_VAR getVersion(void); 00819 00820 /// \brief Returns the QF-port version. 00821 /// 00822 /// This function returns constant version string in the format x.y.zz, 00823 /// where x (one digit) is the major version, y (one digit) is the minor 00824 /// version, and zz (two digits) is the maintenance release version. 00825 /// An example of the QF-port version string is "1.1.03". 00826 /// 00827 /// \sa QF::getVersion() 00828 static char const Q_ROM * Q_ROM_VAR getPortVersion(void); 00829 00830 /// \brief This function returns the margin of the given event pool. 00831 /// 00832 /// This function returns the margin of the given event pool \a poolId, 00833 /// where poolId is the ID of the pool initialized by the call to 00834 /// QF::poolInit(). The poolId of the first initialized pool is 1, the 00835 /// second 2, and so on. 00836 /// 00837 /// The returned pool margin is the minimal number of free blocks 00838 /// encountered in the given pool since system startup. 00839 /// 00840 /// \note Requesting the margin of an un-initialized pool raises an 00841 /// assertion in the QF. 00842 static uint32_t getPoolMargin(uint8_t poolId); 00843 00844 /// \brief This function returns the margin of the given event queue. 00845 /// 00846 /// This function returns the margin of the given event queue of an active 00847 /// object with priority \a prio. (QF priorities start with 1 and go up to 00848 /// #QF_MAX_ACTIVE.) The margin is the minimal number of free events 00849 /// encountered in the given queue since system startup. 00850 /// 00851 /// \note QF::getQueueMargin() is available only when the native QF event 00852 /// queue implementation is used. Requesting the queue margin of an unused 00853 /// priority level raises an assertion in the QF. (A priority level 00854 /// becomes used in QF after the call to the QF::add_() function.) 00855 static uint32_t getQueueMargin(uint8_t prio); 00856 00857 /// \brief Internal QF implementation of the dynamic event allocator. 00858 /// 00859 /// \note The application code should not call this function directly. 00860 /// Please use the macro #Q_NEW. 00861 static QEvent *new_(uint16_t evtSize, QSignal sig); 00862 00863 /// \brief Allocate a dynamic event. 00864 /// 00865 /// This macro returns an event pointer cast to the type \a evtT_. The 00866 /// event is initialized with the signal \a sig. Internally, the macro 00867 /// calls the internal QF function QF::new_(), which always returns a 00868 /// valid event pointer. 00869 /// 00870 /// \note The internal QF function QF::new_() raises an assertion when 00871 /// the allocation of the event turns out to be impossible due to event 00872 /// pool depletion, or incorrect (too big) size of the requested event. 00873 /// 00874 /// The following example illustrates dynamic allocation of an event: 00875 /// \include qf_post.cpp 00876 #define Q_NEW(evtT_, sig_) ((evtT_ *)QF::new_(sizeof(evtT_), (sig_))) 00877 00878 /// \brief Recycle a dynamic event. 00879 /// 00880 /// This function implements a simple garbage collector for the dynamic 00881 /// events. Only dynamic events are candidates for recycling. (A dynamic 00882 /// event is one that is allocated from an event pool, which is 00883 /// determined as non-zero e->attrQF__ attribute.) Next, the function 00884 /// decrements the reference counter of the event, and recycles the event 00885 /// only if the counter drops to zero (meaning that no more references 00886 /// are outstanding for this event). The dynamic event is recycled by 00887 /// returning it to the pool from which it was originally allocated. 00888 /// The pool-of-origin information is stored in the upper 2-MSBs of the 00889 /// e->attrQF__ attribute.) 00890 /// 00891 /// \note QF invokes the garbage collector at all appropriate contexts, 00892 /// when an event can become garbage (automatic garbage collection), 00893 /// so the application code should have NO need to call QF::gc() directly. 00894 /// The QF::gc() function is exposed only for special cases when your 00895 /// application sends dynamic events to the "raw" thread-safe queues 00896 /// (see ::QEQueue). Such queues are processed outside of QF and the 00897 /// automatic garbage collection CANNOT be performed for these events. 00898 /// In this case you need to call QF::gc() explicitly. 00899 static void gc(QEvent const *e); 00900 00901 /// \brief array of registered active objects 00902 /// 00903 /// \note Not to be used by Clients directly, only in ports of QF 00904 static QActive *active_[]; 00905 00906 private: // functions to be used in QF ports only 00907 00908 /// \brief Register an active object to be managed by the framework 00909 /// 00910 /// This function should not be called by the application directly, only 00911 /// through the function QActive::start(). The priority of the active 00912 /// object \a a should be set before calling this function. 00913 /// 00914 /// \note This function raises an assertion if the priority of the active 00915 /// object exceeds the maximum value #QF_MAX_ACTIVE. Also, this function 00916 /// raises an assertion if the priority of the active object is already in 00917 /// use. (QF requires each active object to have a UNIQUE priority.) 00918 static void add_(QActive *a); 00919 00920 public: 00921 /// \brief Remove the active object from the framework. 00922 /// 00923 /// This function should not be called by the application directly, only 00924 /// inside the QF port. The priority level occupied by the active object 00925 /// is freed-up and can be reused for another active object. 00926 /// 00927 /// The active object that is removed from the framework can no longer 00928 /// participate in the publish-subscribe event exchange. 00929 /// 00930 /// \note This function raises an assertion if the priority of the active 00931 /// object exceeds the maximum value #QF_MAX_ACTIVE or is not used. 00932 static void remove_(QActive const *a); 00933 00934 friend class QActive; 00935 }; 00936 00937 ////////////////////////////////////////////////////////////////////////////// 00938 // useful lookup tables 00939 00940 /// \brief Lookup table for (log2(n) + 1), where n is the index 00941 /// into the table. 00942 /// 00943 /// This lookup delivers the 1-based number of the most significant 1-bit 00944 /// of a byte. 00945 /// 00946 /// \note Index range n = 0..255. The first index (n == 0) should never 00947 /// be used. 00948 /// 00949 extern uint8_t const Q_ROM Q_ROM_VAR QF_log2Lkup[256]; 00950 00951 /// \brief Lookup table for (1 << ((n-1) % 8)), where n is the index 00952 /// into the table. 00953 /// 00954 /// \note Index range n = 0..64. The first index (n == 0) should never 00955 /// be used. 00956 extern uint8_t const Q_ROM Q_ROM_VAR QF_pwr2Lkup[65]; 00957 00958 /// \brief Lookup table for ~(1 << ((n-1) % 8)), where n is the index 00959 /// into the table. 00960 /// 00961 /// \note Index range n = 0..64. The first index (n == 0) should never 00962 /// be used. 00963 extern uint8_t const Q_ROM Q_ROM_VAR QF_invPwr2Lkup[65]; 00964 00965 /// \brief Lookup table for (n-1)/8 00966 /// 00967 /// \note Index range n = 0..64. The first index (n == 0) should never 00968 /// be used. 00969 extern uint8_t const Q_ROM Q_ROM_VAR QF_div8Lkup[65]; 00970 00971 00972 ////////////////////////////////////////////////////////////////////////////// 00973 // QS software tracing integration, only if enabled 00974 #ifdef Q_SPY // QS software tracing enabled? 00975 #ifndef qs_h 00976 #include "qs_port.h" // include QS port 00977 #endif // qs_h 00978 00979 #if (QF_EQUEUE_CTR_SIZE == 1) 00980 00981 /// \brief Internal QS macro to output an unformatted event queue 00982 /// counter data element 00983 /// \note the counter size depends on the macro #QF_EQUEUE_CTR_SIZE. 00984 #define QS_EQC_(ctr_) QS::u8_(ctr_) 00985 #elif (QF_EQUEUE_CTR_SIZE == 2) 00986 #define QS_EQC_(ctr_) QS::u16_(ctr_) 00987 #elif (QF_EQUEUE_CTR_SIZE == 4) 00988 #define QS_EQC_(ctr_) QS::u32_(ctr_) 00989 #else 00990 #error "QF_EQUEUE_CTR_SIZE not defined" 00991 #endif 00992 00993 00994 #if (QF_EVENT_SIZ_SIZE == 1) 00995 00996 /// \brief Internal QS macro to output an unformatted event size 00997 /// data element 00998 /// \note the event size depends on the macro #QF_EVENT_SIZ_SIZE. 00999 #define QS_EVS_(size_) QS::u8_(size_) 01000 #elif (QF_EVENT_SIZ_SIZE == 2) 01001 #define QS_EVS_(size_) QS::u16_(size_) 01002 #elif (QF_EVENT_SIZ_SIZE == 4) 01003 #define QS_EVS_(size_) QS::u32_(size_) 01004 #endif 01005 01006 01007 #if (QF_MPOOL_SIZ_SIZE == 1) 01008 01009 /// \brief Internal QS macro to output an unformatted memory pool 01010 /// block-size data element 01011 /// \note the block-size depends on the macro #QF_MPOOL_SIZ_SIZE. 01012 #define QS_MPS_(size_) QS::u8_(size_) 01013 #elif (QF_MPOOL_SIZ_SIZE == 2) 01014 #define QS_MPS_(size_) QS::u16_(size_) 01015 #elif (QF_MPOOL_SIZ_SIZE == 4) 01016 #define QS_MPS_(size_) QS::u32_(size_) 01017 #endif 01018 01019 #if (QF_MPOOL_CTR_SIZE == 1) 01020 01021 /// \brief Internal QS macro to output an unformatted memory pool 01022 /// block-counter data element 01023 /// \note the counter size depends on the macro #QF_MPOOL_CTR_SIZE. 01024 #define QS_MPC_(ctr_) QS::u8_(ctr_) 01025 #elif (QF_MPOOL_CTR_SIZE == 2) 01026 #define QS_MPC_(ctr_) QS::u16_(ctr_) 01027 #elif (QF_MPOOL_CTR_SIZE == 4) 01028 #define QS_MPC_(ctr_) QS::u32_(ctr_) 01029 #endif 01030 01031 01032 #if (QF_TIMEEVT_CTR_SIZE == 1) 01033 01034 /// \brief Internal QS macro to output an unformatted time event 01035 /// tick-counter data element 01036 /// \note the counter size depends on the macro #QF_TIMEEVT_CTR_SIZE. 01037 #define QS_TEC_(ctr_) QS::u8_(ctr_) 01038 #elif (QF_TIMEEVT_CTR_SIZE == 2) 01039 #define QS_TEC_(ctr_) QS::u16_(ctr_) 01040 #elif (QF_TIMEEVT_CTR_SIZE == 4) 01041 #define QS_TEC_(ctr_) QS::u32_(ctr_) 01042 #endif 01043 01044 #else 01045 #ifndef qs_dummy_h 01046 #include "qs_dummy.h" // disable the QS software tracing 01047 #endif 01048 #endif // Q_SPY 01049 01050 #endif // qf_h
Generated on Tue Jul 12 2022 20:22:36 by
1.7.2