QP/C++ 8.1.2
Real-Time Event Framework
Loading...
Searching...
No Matches
qp_port.hpp
Go to the documentation of this file.
1/*! @file
2@code_uid{qp_port.hpp, Sample @QPX port}
3@code_litem{Details}
4This is just an example of a QF port for a generic C11 compiler.
5Other specific QF ports will define the QF facilities differently.
6@endcode_uid
7*/
8
9#ifndef QP_PORT_HPP_
10#define QP_PORT_HPP_
11
12#include <cstdint> // Exact-width types. C++11 Standard
13
14/*!
15@code_uid{#Q_NORETURN, No-return specifier for the Q_onError() callback function.}
16@code_litem{Details}
17Per the Software Safety Requirement @ref SSRS_QA_FDM_20, the Q_onError() handler should never return. Starting with the C99 Standard, the no-return specification can be provided at the language level, which may allow the compiler to apply optimizations (e.g., for impossible code paths downstream of Q_onError()). Also, the no-return specification is immensely valuable for static analysis tools.
18@note
19If the `Q_NORETURN` macro is not defined in the QP port (`qf_port.h`), the default will be the C99 specifier `_Noreturn` applied in `qsafe.h`.
20@code_bw_trace{brief}
21- @tr{SSRS_QA_FDM_20}: <i>@QPX Application shall implement custom error handler such that it does <u>not return</u>.</i>
22@code_fw_trace
23- @tr{SSM_QA_CSOU_21}: <i>Mandate: @QPX Application must ensure that the Q_onError() Custom Error Handler does <u>not return</u>.</i>
24@endcode_uid
25*/
26#define Q_NORETURN [[ noreturn ]] void
27
28// QF configuration for the data members of the QActive class ----------------
29/*!
30@code_uid{QACTIVE_EQUEUE_TYPE, Port-specific ::QActive event queue type.}
31@code_fw_trace
32@endcode_uid
33*/
34#define QACTIVE_EQUEUE_TYPE QEQueue
35
36/*!
37@code_uid{QACTIVE_OS_OBJ_TYPE, Port-specific ::QActive "OS-object" type.}
38@code_fw_trace
39@endcode_uid
40*/
41#define QACTIVE_OS_OBJ_TYPE void*
42
43/*!
44@code_uid{QACTIVE_THREAD_TYPE, Port-specific ::QActive thread type.}
45@code_fw_trace
46@endcode_uid
47*/
48#define QACTIVE_THREAD_TYPE void const *
49
50// interrupt disabling mechanism ---------------------------------------------
51/*!
52@code_uid{QF_INT_DISABLE(), Port-specific interrupt disable}
53@code_fw_trace
54- @tr{DVR_QP_MP2_R19_0_2}: <i>Rule 19.0.2(Required): Function-like macros shall not be defined</i>
55@endcode_uid
56*/
57#define QF_INT_DISABLE() intDisable()
58
59/*!
60@code_uid{QF_INT_ENABLE(), Port-specific interrupt enable}
61@code_fw_trace
62- @tr{DVR_QP_MP2_R19_0_2}: <i>Rule 19.0.2(Required): Function-like macros shall not be defined</i>
63@endcode_uid
64*/
65#define QF_INT_ENABLE() intEnable()
66
67// QF critical section mechanism ---------------------------------------------
68/*!
69@code_uid{#QF_CRIT_STAT, Define the critical section status that was present before entering the critical section.}
70@code_litem{Details}
71For critical sections that are allowed to nest, the critical section status must be saved and restored at the end. This macro provides the storage for saving the status.
72@note
73This macro might be empty, in which case, the critical section status is not saved or restored. Such critical sections won't be able to nest. Also, note that the macro should be invoked without the closing semicolon.
74@code_fw_trace
75@endcode_uid
76*/
77#define QF_CRIT_STAT crit_stat_t crit_stat_;
78
79/*!
80@code_uid{QF_CRIT_ENTRY(), Port-specific critical section entry}
81@code_litem{Details}
82If the critical section status is provided, the macro saves the critical section status from before entering the critical section. Otherwise, the macro just unconditionally enters the critical section without saving the status.
83@code_fw_trace
84- @tr{DVR_QP_MP2_R19_0_2}: <i>Rule 19.0.2(Required): Function-like macros shall not be defined</i>
85@endcode_uid
86*/
87#define QF_CRIT_ENTRY() (crit_stat_ = critEntry())
88
89/*!
90@code_uid{QF_CRIT_EXIT(), Port-specific critical section exit}
91@code_litem{Details}
92If the critical section status is provided, the macro restores the critical section status saved by QF_CRIT_ENTRY(). Otherwise, the macro just unconditionally exits the critical section.
93@code_fw_trace
94- @tr{DVR_QP_MP2_R19_0_2}: <i>Rule 19.0.2(Required): Function-like macros shall not be defined</i>
95@endcode_uid
96*/
97#define QF_CRIT_EXIT() critExit(crit_stat_)
98
99/*!
100@code_uid{QF_CRIT_EXIT_NOP(), No-operation for exiting a critical section}
101@code_litem{Details}
102In 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 exited, but rather the two adjacent critical sections would be _merged_. The QF_CRIT_EXIT_NOP() macro contains minimal code required to prevent such merging of critical sections in QF ports.
103@code_fw_trace
104- @tr{DVR_QP_MP2_R19_0_2}: <i>Rule 19.0.2(Required): Function-like macros shall not be defined</i>
105@endcode_uid
106*/
107#define QF_CRIT_EXIT_NOP() __asm volatile ("isb" ::: "memory")
108
109/*!
110@code_uid{QF_CRIT_EST(), Port-specific establishing a critical section (without saving the status)}
111@code_litem{Details}
112This port-specific macro only establishes a critical section (to later call Q_onError() error handler), but since Q_onError() never returns, there is no need to exit such established critical section.
113@code_fw_trace
114- @tr{DVR_QP_MP2_R19_0_2}: <i>Rule 19.0.2(Required): Function-like macros shall not be defined</i>
115@endcode_uid
116*/
117#define QF_CRIT_EST() (static_cast<void>(critEntry()))
118
119/*!
120@code_uid{QF_LOG2(), Port-specific integer log-base-2 of a 32-bit bitmask}
121@code_litem{Details}
122Calculate integer log-base-2 of a given bitmask (1-based) used to quickly determine the higest-number 1-bit in the bitmask. This operation is used frequently during task scheduling and publish-subscribe.
123@param[in] bitmask_ 32-bit bitmask
124@returns 1-based integer log-base-2 of the provided bitmask. Examples:
125- QF_LOG2(0x00000000U) == 0U
126- QF_LOG2(0x00000001U) == 1U
127- QF_LOG2(0x00000002U) == 2U
128- QF_LOG2(0x00000004U) == 3U
129- QF_LOG2(0x00000008U) == 4U
130- QF_LOG2(0x00000010U) == 5U
131...
132- QF_LOG2(0x80000010U) == 32U
133
134@note
135This operation is performed frequently in time-critical parts of the code. Some CPUs provide such calculation in hardware (e.g., as a machine intruction). For example, ARMv7 and higher architectures support the related CLZ (count leading zeroes) instruction, with the following relationship:
136QF_LOG2(bitmask_) == 32U - CLZ(bitmask_).
137@code_fw_trace
138- @tr{DVR_QP_MP2_R19_0_2}: <i>Rule 19.0.2(Required): Function-like macros shall not be defined</i>
139@endcode_uid
140*/
141#define QF_LOG2(bitmask_) QF_qlog2(static_cast<std::uint32_t>(bitmask_))
142
143extern "C" {
144 //void intDisable(void);
145 //void intEnable(void);
146 //std::uint32_t critEntry(void);
147 //void critExit(std::uint32_t stat);
148 //std::uint32_t QK_get_IPSR(void);
149} // extern "C"
150
151
152#ifdef QF_MEM_ISOLATE
153
154 /*!
155 @code_uid{QF_ON_CONTEXT_SW, Enable memory isolation requires the context-switch}
156 @code_fw_trace
157 @endcode_uid
158 */
159 #define QF_ON_CONTEXT_SW 1U
160
161 /*!
162 @code_uid{QF_MEM_SYS(), Port-specific establishing _System Context_ for memory protection}
163 @code_fw_trace
164 - @tr{DVR_QP_MP2_R19_0_2}: <i>Rule 19.0.2(Required): Function-like macros shall not be defined</i>
165 @endcode_uid
166 */
167 #define QF_MEM_SYS() QF_onMemSys()
168
169 /*!
170 @code_uid{QF_MEM_APP(), Port-specific establishing _Application Context_ for memory protection}
171 @code_fw_trace
172 - @tr{DVR_QP_MP2_R19_0_2}: <i>Rule 19.0.2(Required): Function-like macros shall not be defined</i>
173 @endcode_uid
174 */
175 #define QF_MEM_APP() QF_onMemApp()
176
177#endif // QF_MEM_ISOLATE
178
179// QV-specific ---------------------------------------------------------------
180/*!
181@code_uid{QV_CPU_SLEEP(), Port-specific method to put the CPU to sleep __safely__ in the non-preemptive QV kernel (to be called from QV::QV_onIdle()).}
182@code_fw_trace
183@endcode_uid
184*/
185#define QV_CPU_SLEEP() \
186do { \
187 __disable_interrupt(); \
188 QF_INT_ENABLE(); \
189 __WFI(); \
190 __enable_interrupt(); \
191} while (false)
192
193
194// QK-specific ---------------------------------------------------------------
195/*!
196@code_uid{QK_ISR_CONTEXT_(), Port-specific method to check if the QK kernel executes in the ISR context (used internally in QK only).}
197@returns `true` if the caller executes in the ISR context and `false` otherwise
198@code_fw_trace
199- @tr{DVR_QP_MP2_R19_0_2}: <i>Rule 19.0.2(Required): Function-like macros shall not be defined</i>
200@endcode_uid
201*/
202#define QK_ISR_CONTEXT_() (QK_priv_.intNest != 0U)
203
204/*!
205@code_uid{QK_ISR_ENTRY(), Port-specific method to inform QK kernel about the ISR entry.}
206@code_fw_trace
207- @tr{DVR_QP_MP2_R19_0_2}: <i>Rule 19.0.2(Required): Function-like macros shall not be defined</i>
208@endcode_uid
209*/
210#define QK_ISR_ENTRY() \
211do { \
212 QF_INT_DISABLE(); \
213 ++QK::priv_.intNest; \
214 QF_QS_ISR_ENTRY(QK::priv_.intNest, QK_currPrio_);\
215 QF_INT_ENABLE(); \
216} while (false)
217
218/*!
219@code_uid{QK_ISR_EXIT(), Port-specific method to inform QK kernel about the ISR exit.}
220@code_fw_trace
221- @tr{DVR_QP_MP2_R19_0_2}: <i>Rule 19.0.2(Required): Function-like macros shall not be defined</i>
222@endcode_uid
223*/
224#define QK_ISR_EXIT() \
225do { \
226 QF_INT_DISABLE(); \
227 --QP::QK::priv_.intNest; \
228 if (QP::QK::priv_.intNest == 0U) {\
229 if (QP::QK::sched_() != 0U) { \
230 QP::QK::activate_(); \
231 } \
232 } \
233 QF_INT_ENABLE(); \
234} while (false)
235
236// QXK-specific --------------------------------------------------------------
237/*!
238@code_uid{QXK_ISR_CONTEXT_(), Port-specific method to check if the QXK kernel executes in the ISR context (used internally in QXK only).}
239@returns `true` if the caller executes in the ISR context and `false` otherwise
240@code_fw_trace
241- @tr{DVR_QP_MP2_R19_0_2}: <i>Rule 19.0.2(Required): Function-like macros shall not be defined</i>
242@endcode_uid
243*/
244#define QXK_ISR_CONTEXT_() (QXK_get_IPSR() != 0U)
245
246/*!
247@code_uid{QXK_CONTEXT_SWITCH_(), Port-specific method to trigger context switch (used internally in QXK only).}
248@code_fw_trace
249- @tr{DVR_QP_MP2_R19_0_2}: <i>Rule 19.0.2(Required): Function-like macros shall not be defined</i>
250@endcode_uid
251*/
252#define QXK_CONTEXT_SWITCH_() (trigPendSV())
253
254/*!
255@code_uid{QXK_ISR_ENTRY(), Port-specific method to inform QXK kernel about the ISR entry.}
256@code_fw_trace
257- @tr{DVR_QP_MP2_R19_0_2}: <i>Rule 19.0.2(Required): Function-like macros shall not be defined</i>
258@endcode_uid
259*/
260#define QXK_ISR_ENTRY() ((void)0)
261
262/*!
263@code_uid{QXK_ISR_EXIT(), Port-specific method to inform QXK kernel about the ISR exit.}
264@code_fw_trace
265- @tr{DVR_QP_MP2_R19_0_2}: <i>Rule 19.0.2(Required): Function-like macros shall not be defined</i>
266@endcode_uid
267*/
268#define QXK_ISR_EXIT() do { \
269 QF_INT_DISABLE(); \
270 if (QP::QXK::sched_() != 0U) { \
271 *Q_UINT2PTR_CAST(uint32_t, 0xE000ED04U) = (1U << 28U);\
272 } \
273 QF_INT_ENABLE(); \
274 QXK_ARM_ERRATUM_838869(); \
275} while (false)
276
277// Scheduling locking port interface (example) -------------------------------
278/*!
279@code_uid{QF_SCHED_STAT_, Port-specific type of the scheduler lock status (for internal use in QF only).}
280@code_fw_trace
281@endcode_uid
282*/
283#define QF_SCHED_STAT_ QSchedStatus lockStat_;
284
285/*!
286@code_uid{QF_SCHED_LOCK_(), Port-specific method to lock the scheduler (for internal use in QF only).}
287@param[in] ceil_ priority-ceiling up to which the scheduler should be locked
288@code_fw_trace
289- @tr{DVR_QP_MP2_R19_0_2}: <i>Rule 19.0.2(Required): Function-like macros shall not be defined</i>
290@endcode_uid
291*/
292#define QF_SCHED_LOCK_(ceil_) do { \
293 if (QK_ISR_CONTEXT_()) { \
294 lockStat_ = 0xFFU; \
295 } else { \
296 lockStat_ = QK::schedLock((ceil_)); \
297 } \
298} while (false)
299
300/*!
301@code_uid{QF_SCHED_UNLOCK_(), Port-specific method to unlock the scheduler (for internal use in QF only).}
302@code_fw_trace
303- @tr{DVR_QP_MP2_R19_0_2}: <i>Rule 19.0.2(Required): Function-like macros shall not be defined</i>
304@endcode_uid
305*/
306#define QF_SCHED_UNLOCK_() do { \
307 if (lockStat_ != 0xFFU) { \
308 QP::QK::schedUnlock(lockStat_); \
309 } \
310} while (false)
311
312// Event-Queue port interface (example) --------------------------------------
313// QActive event queue customization...
314/*!
315@code_uid{QACTIVE_EQUEUE_WAIT_(), Port-specific method to wait on an empty Active Object event queue (for internal use only).}
316@param[in,out] me_ current instance pointer
317@code_fw_trace
318- @tr{DVR_QP_MP2_R19_0_2}: <i>Rule 19.0.2(Required): Function-like macros shall not be defined</i>
319@endcode_uid
320*/
321#define QACTIVE_EQUEUE_WAIT_(me_) (static_cast<void>(0))
322
323/*!
324@code_uid{QACTIVE_EQUEUE_SIGNAL_(), Port-specific method to signal Active Object event queue (for internal use only).}
325@param[in,out] me_ current instance pointer
326@code_fw_trace
327- @tr{DVR_QP_MP2_R19_0_2}: <i>Rule 19.0.2(Required): Function-like macros shall not be defined</i>
328@endcode_uid
329*/
330#define QACTIVE_EQUEUE_SIGNAL_(me_) do { \
331 QP::QK::priv_.readySet.insert( \
332 static_cast<std::uint_fast8_t>((me_)->m_prio)); \
333 if (!QP::QK_ISR_CONTEXT_()) { \
334 if (QP::QK::sched_() != 0U) { \
335 QP::QK::activate_(); \
336 } \
337 } \
338} while (false)
339
340/*!
341@code_uid{QXTHREAD_EQUEUE_SIGNAL_(), Port-specific method to signal eXtended thread event queue (for internal use only).}
342@param[in,out] me_ current instance pointer
343@code_fw_trace
344- @tr{DVR_QP_MP2_R19_0_2}: <i>Rule 19.0.2(Required): Function-like macros shall not be defined</i>
345@endcode_uid
346*/
347#define QXTHREAD_EQUEUE_SIGNAL_(me_) do { \
348 if ((me_)->m_temp.obj == QXK::qmstate_cast_(&(me_)->m_eQueue)) { \
349 static_cast<void>(static_cast<QP::QXThread *>(me_)->teDisarm_()); \
350 QXK_priv_.readySet.insert( \
351 static_cast<std::uint_fast8_t>((me_)->m_prio)); \
352 QXK_priv_.readySet.update_(&QXK_priv_.readySet_dis); \
353 if (!QXK_ISR_CONTEXT_()) { \
354 static_cast<void>(QXK::sched_()); \
355 } \
356 } \
357} while (false)
358
359// Event-Pool port interface (example) ---------------------------------------
360/*!
361@code_uid{QF_EPOOL_TYPE_, Port-specific type of the event pool (for internal use in QF only).}
362@code_fw_trace
363@endcode_uid
364*/
365#define QF_EPOOL_TYPE_ QMPool
366
367/*!
368@code_uid{QF_EPOOL_INIT_(), Port-specific event pool initialization (for internal use in QF only).}
369@param[in,out] p_ event pool pointer
370@param[in] poolSto_ storage for the pool (pointer to the pool buffer)
371@param[in] poolSize_ size of the pool storage in [bytes]
372@param[in] evtSize_ event size of this pool in [bytes]
373@code_fw_trace
374- @tr{DVR_QP_MP2_R19_0_2}: <i>Rule 19.0.2(Required): Function-like macros shall not be defined</i>
375@endcode_uid
376*/
377#define QF_EPOOL_INIT_(p_, poolSto_, poolSize_, evtSize_) \
378 (p_).init((poolSto_), (poolSize_), (evtSize_))
379
380/*!
381@code_uid{QF_EPOOL_EVENT_SIZE_(), Port-specific event pool block-size() operation (for internal use in QF only).}
382@param[in,out] p_ event pool pointer
383@code_fw_trace
384- @tr{DVR_QP_MP2_R19_0_2}: <i>Rule 19.0.2(Required): Function-like macros shall not be defined</i>
385@endcode_uid
386*/
387#define QF_EPOOL_EVENT_SIZE_(p_) ((p_).getBlockSize())
388
389/*!
390@code_uid{QF_EPOOL_GET_(), Port-specific event pool get() operation (for internal use in QF only).}
391@param[in,out] p_ event pool pointer
392@param[out] e_ event pointer to be assigned the obtained event
393@param[in] m_ marign (# free events that must still remain in the pool)
394@param[in] qsId_ QS ID for the QS local filter
395@code_fw_trace
396- @tr{DVR_QP_MP2_R19_0_2}: <i>Rule 19.0.2(Required): Function-like macros shall not be defined</i>
397@endcode_uid
398*/
399#define QF_EPOOL_GET_(p_, e_, m_, qsId_) \
400 ((e_) = static_cast<QEvt *>((p_).get((m_), (qsId_))))
401
402/*!
403@code_uid{QF_EPOOL_PUT_(), Port-specific event pool put() operation (for internal use in QF only).}
404@param[in,out] p_ event pool pointer
405@param[out] e_ event pointer to return to the pool
406@param[in] qsId_ QS ID for the QS local filter
407@code_fw_trace
408- @tr{DVR_QP_MP2_R8_2_3}: <i>Rule 8.2.3(Required): A cast shall not remove any 'const' or 'volatile' qualification from the type pointer to by a pointer or by reference</i>
409- @tr{DVR_QP_MP2_R19_0_2}: <i>Rule 19.0.2(Required): Function-like macros shall not be defined</i>
410@endcode_uid
411*/
412#define QF_EPOOL_PUT_(p_, e_, qsId_) ((p_).put((e_), (qsId_)))
413
414/*!
415@code_uid{QF_EPOOL_USE_(), Port-specific event pool # used events operation (for internal use in QF only).}
416@param[in] ePool_ event pool pointer
417@returns # used events in the pool at this moment (allocated and not returned yet)
418@code_fw_trace
419- @tr{DVR_QP_MP2_R19_0_2}: <i>Rule 19.0.2(Required): Function-like macros shall not be defined</i>
420@endcode_uid
421*/
422#define QF_EPOOL_USE_(ePool_) ((ePool_)->getUse())
423
424/*!
425@code_uid{QF_EPOOL_FREE_(), Port-specific event pool # free events operation (for internal use in QF only).}
426@param[in] ePool_ event pool pointer
427@returns # free events in the pool at this moment (available to allocate)
428@code_fw_trace
429- @tr{DVR_QP_MP2_R19_0_2}: <i>Rule 19.0.2(Required): Function-like macros shall not be defined</i>
430@endcode_uid
431*/
432#define QF_EPOOL_FREE_(ePool_) ((ePool_)->getFree())
433
434/*!
435@code_uid{QF_EPOOL_MIN_(), Port-specific event pool minimum # events since initialization (for internal use in QF only).}
436@param[in] ePool_ event pool pointer
437@returns minimal # free events in the pool since initialization
438@code_fw_trace
439- @tr{DVR_QP_MP2_R19_0_2}: <i>Rule 19.0.2(Required): Function-like macros shall not be defined</i>
440@endcode_uid
441*/
442#define QF_EPOOL_MIN_(ePool_) ((ePool_)->getMin())
443
444// include files -------------------------------------------------------------
445#include "qequeue.hpp" // QK kernel uses the native QP event queue
446#include "qmpool.hpp" // QK kernel uses the native QP memory pool
447#include "qp.hpp" // QP framework
448#include "qk.hpp" // QK kernel
449
450#endif // QP_PORT_HPP_
QP native platform-independent QEQueue event queue interface.
QK (preemptive non-blocking kernel) platform-independent public interface.
QP/C++ native platform-independent memory pool QP::QMPool interface.
QP/C++ Framework platform-independent public interface.