qpcpp/doxygen/ports_rtos.dox
2018-10-25 11:13:01 -04:00

516 lines
30 KiB
Plaintext

namespace QP {
/*! @page ports_rtos Ports to Third-Party RTOS
<p>The most important reason why you might consider using a traditional RTOS kernel for executing event-driven QP/C++ applications is compatibility with the existing software. For example, most communication stacks (TCP/IP, USB, CAN, etc.) are designed for a traditional **blocking** kernel. In addition, a lot of legacy code requires blocking mechanisms, such as semaphores or time-delays. A conventional RTOS allows you to run the existing software components as regular "blocking" tasks in parallel to the event-driven QP/C++ application.
</p>
Another reason you might be interested in running QP/C++ on top of a conventional RTOS is **safety certification**, which your RTOS kernel might have but the built-in QP kernels currently don't provide.
@note
You do **not** need to use a traditional RTOS just to achieve preemptive multitasking with QP. The @ref comp_qk "preemptive QK kernel", available as part of the QP package, supports preemptive priority-based multitasking and is fully compatible with Rate Monotonic Scheduling to achieve guaranteed, hard real-time performance. The preemptive, run-to-completion QK kernel perfectly matches the run-to-completion execution semantics of active objects, yet it is simpler, faster, and more efficient than any traditional blocking kernel.
@attention
QP/C++ 6.x includes a small, preemptive, priority-based, @ref qxk "dual-mode blocking QXK kernel" that executes active objects like the QK kernel (@ref qxk_basic "basic threads"), but can also execute traditional blocking threads (@ref qxk_extended "extended threads"). In this respect, QXK behaves exactly like a conventional RTOS. The QXK kernel is recommended as the preferred RTOS kernel for applications that need to mix active objects with traditional blocking code. Due to the tight and optimal integration between QXK and the rest of QP, QXK offers better performance and smaller memory footprint than any @ref ports_rtos "QP port to a 3rd-party RTOS". Additionally, QXK is already included in QP, so you avoid additional licensing costs of 3rd-party kernels.
The QP/C++ framework can work with virtually any traditional real-time operating
system (RTOS). The currently supported 3rd-party RTOS kernels are:
- @subpage freertos
- @subpage embos
- @subpage threadx
- @subpage ti-rtos
- @subpage ucos-ii
- <a href="http://erika.tuxfamily.org/drupal/news/qp-framework-erika-enterprise" target="_blank" class="extern">OSEK/VDX RTOS ERIKA Enterprise</a>
Combined with a conventional RTOS, QP/C++ takes full advantage of the multitasking capabilities of the RTOS by executing each active object in a separate RTOS task. The QP/C++ Platform Abstraction Layer (PAL) includes an abstract RTOS interface to enable integration between QP/C++ and the underlying RTOS. Specifically, the PAL allows adapting most message queue variants as event queues of active objects as well as most memory partitions as QP/C++ event pools.
@next{freertos}
*/
/*##########################################################################*/
/*! @page freertos FreeRTOS
@tableofcontents
@section freertos_about About the QP Port to FreeRTOS
The <span class="img folder">ports/freertos/</span> directory contains a generic platform-independent QP/C++ port to <a href="https://freertos.org" target="_blank" class="extern">FreeRTOS kernel</a> (version 10). The provided QP port to FreeRTOS has been designed *generically* to rely exclusively on the existing FreeRTOS API. This means that the port should run without changes on any CPU/compiler platform supported by FreeRTOS.
The QP-FreeRTOS port works as follows:
- The QP port uses the [static memory allocation of FreeRTOS](https://freertos.org/Static_Vs_Dynamic_Memory_Allocation.html). This requires the FreeRTOS configuration to define the [configSUPPORT_STATIC_ALLOCATION](https://freertos.org/a00110.html#configSUPPORT_STATIC_ALLOCATION)
- Each QP active object executes in a separate FreeRTOS task and requires a private stack space.
- The task-level critical section used in QF and QS is based on the FreeRTOS APIs `taskENTER_CRITICAL()`/`taskEXIT_CRITICAL()`.
- The ISR-level critical section used in QF and QS is based on the FreeRTOS APIs `taskENTER_CRITICAL_FROM_ISR()`/`taskEXIT_CRITICAL_FROM_ISR()`.
- The QP port to FreeRTOS provides new "FromISR" APIs, which must be used in the ISRs (but cannot be used at the task-level)
@attention
The design of FreeRTOS requires the use of special "FromISR" API inside ISRs, which imposes the requirement to also provide the "FromISR" variants of the QP APIs, such as `QACTIVE_POST_FROM_ISR()`, `QF_PUBLISH_FROM_ISR()`, etc. These "FromISR" QP APIs must be used inside ISRs instead of the task-level APIs (`QACTIVE_POST()`, `QF_PUBLISH()`, etc.) and conversely, they cannot be used inside tasks and active objects. Unfortunately, FreeRTOS provides no generic way to enforce the proper API use via assertions.
- The QP port uses the native event queue (::QEQueue) for active object event queues and internally calls the FreeRTOS API `xTaskNotifyGive()` to notify an active object when an event is posted to its event queue.
- The QP port internally calls the FreeRTOS API `ulTaskNotifyTake(pdTRUE, portMAX_DELAY)` to block an active object task when it waits for posting an event.
- The QP port uses the native QF memory pool (::QMPool) to implement event pools.
- The QP port does not mandate any specific method to manage the QP time events, but the provided examples use the FreeRTOS "hook" `vApplicationTickHook()` to periodically invoke the QP clock tick QF_TICK_X_FROM_ISR(). (NOTE: the `vApplicationTickHook()` executes in the ISR context and therefore mandates the use of the "FromISR" APIs).
------------------------------------------------------------------------------
@section freertos_examples Example Code
The QP port to FreeRTOS comes with examples located in the directory `qpc/examples/freertos/`. Currently, the examples are provided for the following boards and development toolchains:
- EK-TM4C123GXL (ARM Cortex-M4F), ARM-KEIL, GNU-ARM, IAR-ARM
- STM32F746G-Discovery (ARM Cortex-M7), ARM-KEIL, GNU-ARM, IAR-ARM
<div class="separate"></div>
@subsection freertos_isr Writing ISRs for QP/FreeRTOS
The provided examples show how to write regular "kernel-aware" ISRs as well as "kernel-unaware" ISRs for QP/FreeRTOS. (See also the FreeRTOS documentation for [configMAX_SYSCALL_INTERRUPT_PRIORITY](https://www.freertos.org/a00110.html#kernel_priority).
Here is an example of a regular "kernel-aware" ISR (note the use of the "FromISR" QP APIs"):
@code{cpp}
void GPIOPortA_IRQHandler(void) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
// for testing...
AO_Table->POST_FROM_ISR(
Q_NEW_FROM_ISR(QP::QEvt, DPP::MAX_PUB_SIG),
&xHigherPriorityTaskWoken,
&l_GPIOPortA_IRQHandler);
// the usual end of FreeRTOS ISR...
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
}
@endcode
Here is an example of a "kernel-unaware" ISR (See also the FreeRTOS documentation for [configMAX_SYSCALL_INTERRUPT_PRIORITY](https://www.freertos.org/a00110.html#kernel_priority):
@code{cpp}
// ISR for receiving bytes from the QSPY Back-End
// NOTE: This ISR is "kernel-unaware" meaning that it does not interact with
// the FreeRTOS or QP and is not disabled. Such ISRs don't need to call
// portEND_SWITCHING_ISR(() at the end, but they also cannot call any
// FreeRTOS or QP APIs.
//
void UART0_IRQHandler(void); // prototype
void UART0_IRQHandler(void) {
uint32_t status = UART0->RIS; // get the raw interrupt status
UART0->ICR = status; // clear the asserted interrupts
while ((UART0->FR & UART_FR_RXFE) == 0) { // while RX FIFO NOT empty
uint32_t b = UART0->DR;
QP::QS::rxPut(b);
}
}
@endcode
<div class="separate"></div>
@subsection freertos_hook Writing FreeRTOS Hooks Running in ISR Context
FreeRTOS provides "hooks" that are user functions that execute in the ISR context (e.g., `vApplicationTickHook()`). Such ISR-level functions are closely related to ISRs and should also use exclusively only the "FromISR" APIs. Here is an example of the `vApplicationTickHook()`:
@code{cpp}
// NOTE: only the "FromISR" API variants are allowed in vApplicationTickHook
void vApplicationTickHook(void) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
// process time events for rate 0
QP::QF::TICK_X_FROM_ISR(0U, &xHigherPriorityTaskWoken, &l_TickHook);
. . .
// notify FreeRTOS to perform context switch from ISR, if needed
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
}
@endcode
<div class="separate"></div>
@subsection freertos_ao Starting Active Objects in QP/FreeRTOS
As mentioned in the @ref freertos_about "FreeRTOS port summary", the QP port to FreeRTOS uses the [static memory allocation of FreeRTOS](https://freertos.org/Static_Vs_Dynamic_Memory_Allocation.html). This means that all memory for an active object, including the private queue buffer and the private **stack** for the the associated FreeRTOS task must be allocated by the user. Here is an example code that starts an active object:
@code{cpp}
int main() {
. . .
static QEvt const *tableQueueSto[N_PHILO];
static StackType_t tableStack[configMINIMAL_STACK_SIZE];
. . .
DPP::AO_Table->setAttr(QP::TASK_NAME_ATTR, "Table");
DPP::AO_Table->start(
static_cast<uint_fast8_t>(N_PHILO + 1), // QP priority of the AO
tableQueueSto, // event queue storage
Q_DIM(tableQueueSto), // queue length [events]
tableStack, // stack storage
sizeof(tableStack), // stack size [bytes]
static_cast<QP::QEvt *>(0)); // initialization event
. . .
return QP::QF::run(); // run the QF application
}
@endcode
@next{embos}
*/
/*##########################################################################*/
/*! @page embos embOS
<p>The QP/C/C++ ports and examples for embOS are described in the Quantum Leaps Application Note <a class="extern" target="_blank" href="https://www.state-machine.com/doc/AN_RTOS-embOS.pdf"><strong>QP and embOS</strong></a>.
</p>
@htmlonly
<div class="image">
<a target="_blank" href="https://www.state-machine.com/doc/AN_RTOS-embOS.pdf"><img border="0" src="img/AN.jpg" title="Download PDF"></a>
<div class="caption">
Application Note: QP and embOS
</div>
</div>
@endhtmlonly
@next{threadx}
*/
/*##########################################################################*/
/*! @page threadx ThreadX
<p>The QP/C/C++ ports and examples for ThreadX are described in the Quantum Leaps Application Note <a class="extern" target="_blank" href="https://www.state-machine.com/doc/AN_RTOS-ThreadX.pdf"><strong>QP and ThreadX</strong></a>.
</p>
@htmlonly
<div class="image">
<a target="_blank" href="https://www.state-machine.com/doc/AN_RTOS-ThreadX.pdf"><img border="0" src="img/AN.jpg" title="Download PDF"></a>
<div class="caption">
Application Note: QP and ThreadX
</div>
</div>
@endhtmlonly
@next{ti-rtos}
*/
/*##########################################################################*/
/*! @page ti-rtos TI-RTOS Kernel (SYS/BIOS)
@tableofcontents
@section ti-rtos_about About the QP Port to TI-RTOS
The <span class="img folder">ports/ti-rtos/</span> directory contains a generic platform-independent QP/C++ port to <a href="http://processors.wiki.ti.com/index.php/Category:SYSBIOS" target="_blank" class="extern">TI-RTOS kernel (SYS/BIOS)</a>. The provided QP port to TI-RTOS has been designed *generically* to rely exclusively on the existing TI-RTOS API. This means that the port should run without changes on any CPU/compiler platform supported by TI-RTOS.
@attention
The TI-RTOS requires its own tooling (XDCTOOLS) and is too big to fit into the <span class="img folder">3rd_party/</span> directory in the QP/C++ distribution. Therefore, you need to **download and install** TI-RTOS on your machine before you can build any examples. Please refer to the TI Application Note "TI-RTOS for TivaC Getting Started Guide" (Literature Number: <a href="http://www.ti.com/lit/ug/spruhu5d/spruhu5d.pdf" target="_blank" class="extern">SPRUHU5D</a>) for more information.
The QP-TI-RTOS port works as follows:
- Each QP active object executes in a separate <a href="http://focus.ti.com/download/trng/multimedia/dsp/OLT110026/swis.mp4" target="_blank" class="extern">TI-RTOS Software Interrupt (Swi)</a>.
- Each QP active object thread has a unique priority (the Swi priority).
- The critical section used in QF and QS is based on the TI-RTOS APIs `Hwi_disable()`/`Hwi_enable()`, which selectively disable interrupts and allow for nesting of critical sections.
- The QP port uses the native event queue (QP::QEQueue) for active object event queues.
- The QP port uses the native QF memory pool (QP::QMPool) to implement event pools.
- The QP port does not mandate any specific method to manage the QP time events, but the provided examples use the TI-RTOS clock package to periodically invoke the QP clock tick TICK_X() (see @ref exa_ti-rtos ).
@note
This QP port uses the TI-RTOS Swis ("Software Interrupts") to provide the thread context to run QP active objects. The TI-RTOS Swis are a perfect match to execute the run-to-completion (RTC) event processing in active objects and require far less resources (no private stacks) than regular blocking threads.
------------------------------------------------------------------------------
@section ti-rtos_qf_h The qf_port.h Header File
The <span class="img folder">ports/ti-rtos/qf_port.h</span> header file contains the customization of the QP framework for the TI-RTOS kernel. The file is shown below with the explanation sections following the source code:
@code{cpp}
#ifndef qf_port_h
#define qf_port_h
// TI-RTOS-specific event queue and thread types, see NOTE1
[1] #define QF_EQUEUE_TYPE QEQueue
[2] #define QF_OS_OBJECT_TYPE Swi_Struct
[3] #define QF_THREAD_TYPE Swi_Handle
// The maximum number of active objects in the application, see NOTE2
[4] #define QF_MAX_ACTIVE 32
// TI-RTOS-specific critical section operations, NOTE3
[5] #define QF_CRIT_STAT_TYPE UInt
[6] #define QF_CRIT_ENTRY(key_) ((key_) = Hwi_disable())
[7] #define QF_CRIT_EXIT(key_) (Hwi_restore((key_)))
[8] #include <ti/sysbios/hal/Hwi.h> // TI-RTOS Hwi package
[9] #include <ti/sysbios/knl/Swi.h> // TI-RTOS Swi package
#include "qep_port.h" // QEP port
#include "qequeue.h" // this QF port uses the native QF event queue
#include "qmpool.h" // this QF port uses the native QF memory pool
#include "qf.h" // QF platform-independent public interface
//****************************************************************************
// interface used only inside QF, but not in applications
//
#ifdef QP_IMPL
// TI-RTOS-specific scheduler locking, see NOTE4
[10] #define QF_SCHED_STAT_ UInt key_;
[11] #define QF_SCHED_LOCK_(dummy) (key_ = Swi_disable())
[12] #define QF_SCHED_UNLOCK_() (Swi_restore(key_))
// TI-RTOS-specific native event queue operations...
[13] #define QACTIVE_EQUEUE_WAIT_(me_) \
Q_ASSERT_ID(110, (me_)->m_eQueue.m_frontEvt != static_cast<QEvt *>(0))
[14] #define QACTIVE_EQUEUE_SIGNAL_(me_) Swi_post((me_)->m_thread)
[15] #define QACTIVE_EQUEUE_ONEMPTY_(dummy) ((void)0)
// TI-RTOS native QF event pool operations...
[16] #define QF_EPOOL_TYPE_ QMPool
[17] #define QF_EPOOL_INIT_(p_, poolSto_, poolSize_, evtSize_) \
(p_).init((poolSto_), (poolSize_), (evtSize_))
[18] #define QF_EPOOL_EVENT_SIZE_(p_) \
static_cast<uint_fast16_t>((p_).getBlockSize())
[19] #define QF_EPOOL_GET_(p_, e_, m_) \
((e_) = static_cast<QEvt *>((p_).get((m_))))
[20] #define QF_EPOOL_PUT_(p_, e_) ((p_).put(e_))
#endif // ifdef QP_IMPL
#endif // qf_port_h
@endcode
<ul class="tag">
<li><span class="tag">1</span> This port uses the native QP::QEQueue class for the event queues of active objects;
</li>
<li><span class="tag">2</span> This port stores the entire TI-RTOS Swi control block (`Swi_Struct`) in the QMActive::osObject attribute; <span class="highlight">The inclusion of the whole `Swi_Struct` inside QP::QMActive means that this port does not need any dynamic memory allocation by TI-RTOS, so that active objects can be allocated purely **statically.**</span>
</li>
<li><span class="tag">3</span> This port stores the TI-RTOS Swi handle (`Swi_Handle`) block in the QMActive::thread attribute;
</li>
<li><span class="tag">4</span> The maximum number of active objects in the application cannot exceed the number of Swi priority levels available in TI-RTOS. On 32-bit CPUs, such as ARM Cortex-M, the maximum number of Swi priority levels is 32;
</li>
<li><span class="tag">5</span> The macro #QF_CRIT_STAT_TYPE is defined, which means that the QF critical section implementation corresponds to the "save and restore interrupt status" policy;
</li>
<li><span class="tag">6</span> Critical section entry is implemented with the TI-RTOS facility `Hwi disable()`. This facilty returns the original interrupt status (status before disabling hardware interrupts); <span class="highlight">On ARM Cortex-M3/M4, `Hwi_disable()` disables interrupts selectively by means of the BASEPRI register. This means that interrupts above the 0x20 threashold are **never** disabled (run with "zero" latency). Such interrupts are "kernel unaware" and are **not allowed** to call any TI-RTOS APIs or QP APIs;</span>
</li>
<li><span class="tag">7</span> Critical section exit is implemented with the TI-RTOS facility `Hwi enable()`. This facilty restores the interrupt status from before entering the critical section; <span class="highlight">The critical section defined by means of TI-RTOS `Hwi disable()/Hwi_enable()` **can nest**;</span>
</li>
<li><span class="tag">8-9</span> The TI-RTOS APIs for Hwi and Swi are included;
</li>
<li><span class="tag">10-12</span> These macros define scheduler locking in the QF_PUBLISH() facility to make sure that event multicasting is done atomically to all subscribers. In general, the QF framework supports selective scheduler locking only to the level of the highest-priority subscriber. However, the TI-RTOS does not support such selective scheduler locking for Swis. Instead, the TI-RTOS locks all Swis during event multicasting. <span class="highlight">This means that publishing events to a multitude of subscribers might delay the execution of the high-priority active objects (Swis), even if they are not subscribed to those published events</span>;
</li>
<li><span class="tag">13</span> The macro QACTIVE_EQUEUE_WAIT_() customizes the behavior of the built-in queue inside the QMActive::get_() operation. In this port, the QActive_get_() operation is only inovked after TI-RTOS determines that the active object (Swi) needs activation. Therefore, the QACTIVE_EQUEUE_WAIT_() macro only asserts that the queue is not empty;
</li>
<li><span class="tag">14</span> The macro QACTIVE_EQUEUE_SIGNAL_() customizes the behavior of the built-in queue inside the QActive::post_() operation. In this port, every time an event is posted to the active object, the TI-RTOS API `Swi_post()` is used to activate the Swi of the active object. <span class="highlight">Note that a Swi can be posted more than once before it is actually scheduled to run (e.g., because higher-priority Swis are running). Therefore the Swi must be also posted inside the active object Swi function;</span>
</li>
<li><span class="tag">15</span> The macro QACTIVE_EQUEUE_ONEMPTY_() customizes the behavior of the built-in queue inside the QActive::get_() operation (when the queue is becoming empty). In this port, this macro is not used (expands to an empty C statement).
</li>
<li><span class="tag">16</span> This port uses the native QP::QMPool memory pool to implement the event pools for dynamic events;
</li>
<li><span class="tag">17-20</span> These macros customize the behavior of the native QP::QMPool memory pool to be used for event pools;
</li>
</ul>
------------------------------------------------------------------------------
@section ti-rtos_qf_cpp The qf_port.cpp Implementation File
The <span class="img folder">ports/ti-rtos/qf_port.cpp</span> file contains the implementation of the QP port to the TI-RTOS kernel. The file is shown below with the explanation sections following the source code:
@code{cpp}
~ ~ ~
#include <ti/sysbios/BIOS.h> // SYS/BIOS API (for BIOS_start())
// namespace QP ==============================================================
namespace QP {
~ ~ ~
//............................................................................
[1] void QF::init(void) {
}
//............................................................................
[2] int_t QF::run(void) {
[3] onStartup(); // configure & start interrupts, see NOTE0
[4] BIOS_start(); // start TI-RTOT (SYS/BIOS)
Q_ERROR_ID(100); // BIOS_start() should never return
return static_cast<int_t>(0); // dummy return to make the compiler happy
}
~ ~ ~
//............................................................................
[5] void QMActive::start(uint_fast8_t prio,
QEvt const *qSto[], uint_fast16_t qLen,
void *stkSto, uint_fast16_t stkSize,
QEvt const *ie)
{
/// @pre the priority must be in range and the stack storage must not
/// be provided, because this TI-RTOS port does not need per-AO stacks.
///
Q_REQUIRE_ID(400, (static_cast<uint_fast8_t>(0) < prio)
&& (prio <= static_cast<uint_fast8_t>(QF_MAX_ACTIVE))
[6] && (stkSto == static_cast<void *>(0)));
[7] m_eQueue.init(qSto, qLen); // initialize QEQueue of this AO
[8] m_prio = prio; // set QF priority of this AO before adding it to QF
[9] QF::add_(this); // make QF aware of this active object
[10] init(ie); // take the top-most initial tran.
[11] QS_FLUSH(); // flush the trace buffer to the host
// create TI-RTOS Swi to run this active object...
Swi_Params swiParams;
[12] Swi_Params_init(&swiParams);
[13] swiParams.arg0 = (xdc_UArg)this; // the "me" pointer
[14] swiParams.arg1 = 0; // not used
[15] swiParams.priority = prio; // TI-RTOS Swis can use the QP priority
swiParams.trigger = 0; // not used
[16] Swi_construct(&m_osObject, &swi_function, &swiParams, NULL);
[17] m_thread = Swi_handle(&m_osObject);
// TI-RTOS Swi must be created correctly
[18] Q_ENSURE_ID(490, m_thread != 0);
}
//............................................................................
[19] static void swi_function(UArg arg0, UArg arg1) { // TI-RTOS Swi
[20] QMActive *act = reinterpret_cast<QMActive *>(arg0);
[21] QEvt const *e = act->get_();
[22] act->dispatch(e);
[23] QF::gc(e);
// are events still available for this AO?
[24] if (!act->m_eQueue.isEmpty()) {
[25] Swi_post(act->m_thread);
}
}
} // namespace QP
@endcode
<ul class="tag">
<li><span class="tag">1</span> The QF::init() function is empty in this port;
</li>
<li><span class="tag">2</span> The QF::run() function transfers the control to the QF frameworks and starts multitasking. This function does not return in the TI-RTOS kernel;
</li>
<li><span class="tag">3</span> The QF::onStartup() callback function (typically implemented in the BSP), starts interrupts and the system clock tick for QF;
</li>
<li><span class="tag">4</span> The TI-RTOS API `BIOS_start()` should not return, so this assertion fires when `BIOS_start()` ever returns;
</li>
<li><span class="tag">5</span> The QMActive::start_() function starts active object execution. This function can be called before QF::run() or after QF::run(), from a running active object or TI-RTOS thread.
</li>
<li><span class="tag">6</span> In this port the active object does not need a private stack space. This assertion (precondition) makes sure that no stack memory is passed to the active object, so that the memory is wasted;
</li>
<li><span class="tag">7</span> The QP::QEQueue is initialized with the provided memory for the ring buffer;
</li>
<li><span class="tag">8</span> The active object priority is set;
</li>
<li><span class="tag">9</span> The active oject is added to the QF framework to be managed;
</li>
<li><span class="tag">10</span> The top-most initial transition in the state machine of this active object is taken;
</li>
<li><span class="tag">11</span> The QS software tracing buffer is flushed so that any QS trace records produced during the startup of the active object (this code is inactive in the Debug or Release build configurations);
</li>
<li><span class="tag">12</span> The TI-RTOS Swi parameters are initialized to the default values;
</li>
<li><span class="tag">13</span> The first Swi argument (`arg0`) of the Swi routine is set to the `me` pointer of this active object;
</li>
<li><span class="tag">14</span> The second Swi argument (`arg1`) of the Swi routine is set to zero (not used);
</li>
<li><span class="tag">15</span> The Swi priority is set to the priority of the active object. <span class="highlight">The QP priority numbering is compatible with the TI-RTOS priority numbering of Swis;</span>
</li>
<li><span class="tag">16</span> The TI-RTOS function `Swi_construct()` initializes the Swi in the provided memory (`me->osObject`). This function does not allocate any dynamic memory from TI-RTOS--it just uses the provided memory;
</li>
<li><span class="tag">17</span> The active object `thread` attribute is set to the Swi handle;
</li>
<li><span class="tag">18</span> The postcondition ensures that the handle is non-zero, meaning that the Swi has been created correctly;
</li>
<li><span class="tag">19</span> The `swi_function()` is the function that all active object Swis execute when activated. This is a one-shot function that runs to completion without looping;
</li>
<li><span class="tag">20</span> Even though all active object Swis run the same function they each refer to their own attributes by means of the `arg1` parameter, which was initialized to the `me` pointer;
</li>
<li><span class="tag">21</span> The active object queue is called to get an event, which must be available at this point or the Swi will not be activated (posted);
</li>
<li><span class="tag">22</span> The event is dispatched to the active object state machine;
</li>
<li><span class="tag">23</span> The event is passed to the QF garbage collector and is recycled if no longer in use;
</li>
<li><span class="tag">24</span> If any events are still available in the event queue...;
</li>
<li><span class="tag">25</span> The Swi of the active object is posted again (`Swi_post()`) so that TI-RTOS will keep the Swi ready-to-run;
</li>
</ul>
@next{ucos-ii}
*/
/*##########################################################################*/
/*! @page ucos-ii uC/OS-II
@section ucos-ii_about About the QP Port to uC/OS-II
This directory contains a generic platform-independent QP/C port to uC/OS-II V2.92.
Typically, you should not need to change the files in this directory to adapt the QP-uC/OS port on any CPU/Compiler to which uC/OS-II has been ported, because all the CPU and compiler specifics are handled by the uC/OS-II RTOS.
@note
Currently, the port has been tested only on ARM Cortex-M3 and M4F.
@section ucos-ii_source uC/OS-II Source and ARM Cortex-M3/M4 Ports
The uC/OS-II V2.92 source code and ports are located in 3rd_party/ucos-ii. Please make sure to read about uC/OS-II licensing in the README file found in this directory.
@note
The official Micrium ARM-Cortex-M ports have been modified by Quantum Leaps to remove the dependencies on the Micrium's uC-CPU and uC-LIB components, and instead to inter-operate with the Cortex Microcontroller Software Interface Standard (CMSIS).
------------------------------------------------------------------------------
@section ucos-ii_using Using this QP Port to uC/OS-II
The example projects for this port are located in @ref exa_ucos-ii "examples/ucos-ii/arm-cm/dpp_ek-tm4c123gxl".
Currently, ARM-KEIL and IAR-ARM toolsets are supported (in the <span class="img folder">arm</span> and <span class="img folder">iar</span> sub-directories within this example project).
The example projects use this port by directly including the QP source code (and this port) in the application projects. There is no QP library to build.
However, this port can also be used as a library, in which case you need to build the QP library yourself and include in your project.
<div class="separate"></div>
@subsection ucos-ii_build QP Source Files Needed in this QP Port
Whether you use this QP port as source files or as a library, it is important to note that not all QP soruce files should be included. Here is the list of QP source files needed:
@verbatim
qpc
+-source
| +-qep_hsm.c
| +-qep_msm.c
| +-qf_act.c
| +-qf_defer.c
| +-qf_dyn.c
| +-qf_ps.c
| +-qf_qeq.c
| +-qf_qmact.c
| +-qf_time.c
| |
| +-qs.c - included only in the Spy build configuration
| +-qs_fp.c - included only in the Spy build configuration
|
+-ports
| +-ucos-ii
| | +-qf_port.c
@endverbatim
@note
Specifically, the QP source files qf_actq.c and qf_mem.c must **NOT** be included in the build, because this functionality is taken from uC/OS-II.
<p>The QP/C/C++ ports and examples for uC/OS-II are described in the Quantum Leaps Application Note <a class="extern" target="_blank" href="https://www.state-machine.com/doc/AN_RTOS-uCOS2.pdf"><strong>QP and uC/OS-II</strong></a>.
</p>
@htmlonly
<div class="image">
<a target="_blank" href="https://www.state-machine.com/doc/AN_RTOS-uCOS2.pdf"><img border="0" src="img/AN.jpg" title="Download PDF"></a>
<div class="caption">
Application Note: QP and uC/OS-II
</div>
</div>
@endhtmlonly
@next{ports_os}
*/
} // namespace QP