QP/C++  6.9.3
Real-Time Embedded Framework
qutest.cpp
Go to the documentation of this file.
1 
39 // only build when Q_UTEST is defined
40 #ifdef Q_UTEST
41 
42 #define QP_IMPL // this is QP implementation
43 #include "qf_port.hpp" // QF port
44 #include "qf_pkg.hpp" // QF package-scope internal interface
45 #include "qassert.h" // QP embedded systems-friendly assertions
46 #include "qs_port.hpp" // QS port
47 #include "qs_pkg.hpp" // QS package-scope internal interface
48 
49 namespace QP {
50 
51 Q_DEFINE_THIS_MODULE("qutest")
52 
53 // Global objects ============================================================
54 std::uint8_t volatile QF_intNest;
55 
56 // QF functions ==============================================================
57 void QF::init(void) {
61  QF_maxPool_ = 0U;
62  QF_subscrList_ = nullptr;
63  QF_maxPubSignal_ = 0;
64  QF_intNest = 0U;
65 
66  bzero(&active_[0], sizeof(active_));
67  bzero(&QS::rxPriv_.readySet, sizeof(QS::rxPriv_.readySet));
68 }
69 //............................................................................
70 void QF::stop(void) {
71  QS::onReset();
72 }
73 //............................................................................
74 int_t QF::run(void) {
75  // function dictionaries for the standard API
79 
80  // produce the QS_QF_RUN trace record
83  QS_END_PRE_()
84 
85  QS::onTestLoop(); // run the unit test
86  QS::onCleanup(); // application cleanup
87  return 0; // return no error
88 }
89 
90 //............................................................................
91 void QActive::start(std::uint_fast8_t const prio,
92  QEvt const * * const qSto, std::uint_fast16_t const qLen,
93  void * const stkSto, std::uint_fast16_t const stkSize,
94  void const * const par)
95 {
96  static_cast<void>(stkSto); // unused parameter
97  static_cast<void>(stkSize); // unused parameter
98 
99  // priority must be in range
100  Q_REQUIRE_ID(200, (0U < prio) && (prio <= QF_MAX_ACTIVE));
101 
102  m_eQueue.init(qSto, qLen); // initialize QEQueue of this AO
103  m_prio = static_cast<std::uint8_t>(prio); // set the QF prio of this AO
104 
105  QF::add_(this); // make QF aware of this AO
106 
107  this->init(par, m_prio); // take the top-most initial tran. (virtual)
108  //QS_FLUSH(); // flush the trace buffer to the host
109 }
110 //............................................................................
111 #ifdef QF_ACTIVE_STOP
112 void QActive::stop(void) {
113  unsubscribeAll(); // unsubscribe from all events
114  QF::remove_(this); // remove this object from QF
115 }
116 #endif
117 
118 //****************************************************************************
120  : QActive(nullptr)
121 {}
122 //............................................................................
124  QEvt const * * const qSto, std::uint_fast16_t const qLen,
125  void * const stkSto, std::uint_fast16_t const stkSize,
126  void const * const par)
127 {
128  // No special preconditions for checking parameters to allow starting
129  // dummy AOs the exact same way as the real counterparts.
130  static_cast<void>(qSto); // unusuded parameter
131  static_cast<void>(qLen); // unusuded parameter
132  static_cast<void>(stkSto); // unusuded parameter
133  static_cast<void>(stkSize); // unusuded parameter
134 
135  m_prio = static_cast<std::uint8_t>(prio); // set the QF prio of this AO
136 
137  QF::add_(this); // make QF aware of this AO
138 
139  this->init(par, m_prio); // take the top-most initial tran. (virtual)
140  //QS_FLUSH(); // flush the trace buffer to the host
141 }
142 //............................................................................
143 void QActiveDummy::init(void const * const e,
144  std::uint_fast8_t const qs_id) noexcept
145 {
146  static_cast<void>(e); // unused paramter
147  static_cast<void>(qs_id); // unused paramter (if Q_SPY not defined)
148 
151  QS_OBJ_PRE_(this); // this state machine object
152  QS_FUN_PRE_(m_state.fun); // the source state
153  QS_FUN_PRE_(m_temp.fun); // the target of the initial transition
154  QS_END_PRE_()
155 }
156 //............................................................................
157 void QActiveDummy::dispatch(QEvt const * const e,
158  std::uint_fast8_t const qs_id) noexcept
159 {
160  static_cast<void>(e); // unused paramter
161  static_cast<void>(qs_id); // unused paramter (if Q_SPY not defined)
162 
165  QS_TIME_PRE_(); // time stamp
166  QS_SIG_PRE_(e->sig); // the signal of the event
167  QS_OBJ_PRE_(this); // this state machine object
168  QS_FUN_PRE_(m_state.fun); // the current state
169  QS_END_PRE_()
170 }
171 //............................................................................
172 bool QActiveDummy::post_(QEvt const * const e,
173  std::uint_fast16_t const margin,
174  void const * const sender) noexcept
175 {
176  bool status = true;
178 
179  // test-probe#1 for faking queue overflow
181  status = false;
182  if (margin == QF_NO_MARGIN) {
183  // fake assertion Mod=qf_actq,Loc=110
184  Q_onAssert("qf_actq", 110);
185  }
186  )
187 
189  QF_CRIT_E_();
190 
191  // is it a dynamic event?
192  if (e->poolId_ != 0U) {
193  QF_EVT_REF_CTR_INC_(e); // increment the reference counter
194  }
195 
196  std::uint_fast8_t rec =
197  (status ? static_cast<std::uint8_t>(QS_QF_ACTIVE_POST)
198  : static_cast<std::uint8_t>(QS_QF_ACTIVE_POST_ATTEMPT));
199  QS_BEGIN_NOCRIT_PRE_(rec, m_prio)
200  QS_TIME_PRE_(); // timestamp
201  QS_OBJ_PRE_(sender); // the sender object
202  QS_SIG_PRE_(e->sig); // the signal of the event
203  QS_OBJ_PRE_(this); // this active object
204  QS_2U8_PRE_(e->poolId_, e->refCtr_); // pool Id & refCtr of the evt
205  QS_EQC_PRE_(0U); // number of free entries
206  QS_EQC_PRE_(margin); // margin requested
208 
209  // callback to examine the posted event under the same conditions
210  // as producing the #QS_QF_ACTIVE_POST trace record, which are:
211  // the local filter for this AO ('me->prio') is set
212  //
213  if ((QS::priv_.locFilter[m_prio >> 3U]
214  & (1U << (m_prio & 7U))) != 0U)
215  {
216  QS::onTestPost(sender, this, e, status);
217  }
218 
219  QF_CRIT_X_();
220 
221  // recycle the event immediately, because it was not really posted
222  QF::gc(e);
223 
224  return status;
225 }
226 //............................................................................
227 void QActiveDummy::postLIFO(QEvt const * const e) noexcept {
229 
230  // test-probe#1 for faking queue overflow
232  // fake assertion Mod=qf_actq,Loc=210
233  Q_onAssert("qf_actq", 210);
234  )
235 
237  QF_CRIT_E_();
238 
239  // is it a dynamic event?
240  if (e->poolId_ != 0U) {
241  QF_EVT_REF_CTR_INC_(e); // increment the reference counter
242  }
243 
245  QS_TIME_PRE_(); // timestamp
246  QS_SIG_PRE_(e->sig); // the signal of this event
247  QS_OBJ_PRE_(this); // this active object
248  QS_2U8_PRE_(e->poolId_, e->refCtr_); // pool Id & refCtr of the evt
249  QS_EQC_PRE_(0U); // number of free entries
250  QS_EQC_PRE_(0U); // min number of free entries
252 
253  // callback to examine the posted event under the same conditions
254  // as producing the #QS_QF_ACTIVE_POST trace record, which are:
255  // the local filter for this AO ('me->prio') is set
256  //
257  if ((QS::priv_.locFilter[m_prio >> 3U]
258  & (1U << (m_prio & 7U))) != 0U)
259  {
260  QS::onTestPost(nullptr, this, e, true);
261  }
262 
263  QF_CRIT_X_();
264 
265  // recycle the event immediately, because it was not really posted
266  QF::gc(e);
267 }
268 
269 //****************************************************************************
272 
273  // return immediately (do nothing) for Test Probe != 0
274  QS_TEST_PROBE(return;)
275 
276  while (rxPriv_.readySet.notEmpty()) {
278  QActive * const a = QF::active_[p];
279 
280  // perform the run-to-completion (RTC) step...
281  // 1. retrieve the event from the AO's event queue, which by this
282  // time must be non-empty and the "Vanialla" kernel asserts it.
283  // 2. dispatch the event to the AO's state machine.
284  // 3. determine if event is garbage and collect it if so
285  //
286  QEvt const * const e = a->get_();
287  a->dispatch(e, a->m_prio);
288  QF::gc(e);
289 
290  if (a->m_eQueue.isEmpty()) { // empty queue?
292  }
293  }
294 }
295 
296 //............................................................................
297 // The testing version of system tick processing performs as follows:
298 // 1. If the Current Time Event (TE) Object is defined and the TE is armed,
299 // the TE is disarmed (if one-shot) and then posted to the recipient AO.
300 // 2. The linked-list of all armed Time Events is updated.
301 //
302 void QS::tickX_(std::uint_fast8_t const tickRate,
303  void const * const sender) noexcept
304 {
305  QTimeEvt *t;
306  QActive *act;
308 
309  QF_CRIT_E_();
310  QTimeEvt *prev = &QF::timeEvtHead_[tickRate];
311 
313  ++prev->m_ctr;
314  QS_TEC_PRE_(prev->m_ctr); // tick ctr
315  QS_U8_PRE_(tickRate); // tick rate
317 
318  // is current Time Event object provided?
319  t = static_cast<QTimeEvt *>(QS::rxPriv_.currObj[QS::TE_OBJ]);
320  if (t != nullptr) {
321 
322  // the time event must be armed
323  Q_ASSERT_ID(810, t->m_ctr != 0U);
324 
325  act = static_cast<QActive *>(t->m_act); // temp. for volatile
326 
327  // the recipient AO must be provided
328  Q_ASSERT_ID(820, act != nullptr);
329 
330  // periodic time evt?
331  if (t->m_interval != 0U) {
332  t->m_ctr = t->m_interval; // rearm the time event
333  }
334  else { // one-shot time event: automatically disarm
335  t->m_ctr = 0U; // auto-disarm
336  // mark as unlinked
337  t->refCtr_ &= static_cast<std::uint8_t>(~TE_IS_LINKED);
338 
340  QS_OBJ_PRE_(t); // this time event object
341  QS_OBJ_PRE_(act); // the target AO
342  QS_U8_PRE_(tickRate); // tick rate
344  }
345 
347  QS_TIME_PRE_(); // timestamp
348  QS_OBJ_PRE_(t); // the time event object
349  QS_SIG_PRE_(t->sig); // signal of this time event
350  QS_OBJ_PRE_(act); // the target AO
351  QS_U8_PRE_(tickRate); // tick rate
353 
354  QF_CRIT_X_(); // exit crit. section before posting
355 
356  // asserts if queue overflows
357  static_cast<void>(act->POST(t, sender));
358 
359  QF_CRIT_E_();
360  }
361 
362  // update the linked list of time events
363  for (;;) {
364  t = prev->m_next; // advance down the time evt. list
365 
366  // end of the list?
367  if (t == nullptr) {
368 
369  // any new time events armed since the last run of QF::tickX_()?
370  if (QF::timeEvtHead_[tickRate].m_act != nullptr) {
371 
372  // sanity check
373  Q_ASSERT_CRIT_(830, prev != nullptr);
374  prev->m_next = QF::timeEvtHead_[tickRate].toTimeEvt();
375  QF::timeEvtHead_[tickRate].m_act = nullptr;
376  t = prev->m_next; // switch to the new list
377  }
378  else {
379  break; // all currently armed time evts. processed
380  }
381  }
382 
383  // time event scheduled for removal?
384  if (t->m_ctr == 0U) {
385  prev->m_next = t->m_next;
386  // mark time event 't' as NOT linked
387  t->refCtr_ &= static_cast<std::uint8_t>(~TE_IS_LINKED);
388  // do NOT advance the prev pointer
389  QF_CRIT_X_(); // exit crit. section to reduce latency
390 
391  // prevent merging critical sections, see NOTE1 below
393  }
394  else {
395  prev = t; // advance to this time event
396  QF_CRIT_X_(); // exit crit. section to reduce latency
397 
398  // prevent merging critical sections, see NOTE1 below
400  }
401  QF_CRIT_E_(); // re-enter crit. section to continue
402  }
403 
404  QF_CRIT_X_();
405 }
406 
407 } // namespace QP
408 
409 //****************************************************************************
410 extern "C" {
411 
412 Q_NORETURN Q_onAssert(char_t const * const module, int_t const location) {
414  QS_TIME_PRE_();
415  QS_U16_PRE_(location);
416  QS_STR_PRE_((module != nullptr) ? module : "?");
418  QP::QS::onFlush(); // flush the assertion record to the host
419  QP::QS::onTestLoop(); // loop to wait for commands (typically reset)
420  QP::QS::onReset(); // in case the QUTEST loop ever returns, reset manually
421  for (;;) { // onReset() should not return, but to ensure no-return...
422  }
423 }
424 
425 } // extern "C"
426 
427 #endif // Q_UTEST
428 
unsigned int uint_fast16_t
Definition: 16bit/stdint.h:38
unsigned char uint8_t
Definition: 16bit/stdint.h:29
unsigned int uint_fast8_t
Definition: 16bit/stdint.h:36
void start(std::uint_fast8_t const prio, QEvt const **const qSto, std::uint_fast16_t const qLen, void *const stkSto, std::uint_fast16_t const stkSize, void const *const par) override
Definition: qutest.cpp:123
QActiveDummy(void)
Definition: qutest.cpp:119
void init(void const *const e, std::uint_fast8_t const qs_id) noexcept override
executes the top-most initial transition in QP::QHsm
Definition: qutest.cpp:143
void postLIFO(QEvt const *const e) noexcept override
Definition: qutest.cpp:227
bool post_(QEvt const *const e, std::uint_fast16_t const margin, void const *const sender) noexcept override
Definition: qutest.cpp:172
void dispatch(QEvt const *const e, std::uint_fast8_t const qs_id) noexcept override
Dispatches an event to QHsm.
Definition: qutest.cpp:157
std::uint8_t m_prio
QF priority (1..QF_MAX_ACTIVE) of this active object.
Definition: qf.hpp:185
virtual void postLIFO(QEvt const *const e) noexcept
Definition: qf_actq.cpp:228
virtual bool post_(QEvt const *const e, std::uint_fast16_t const margin, void const *const sender) noexcept
Definition: qf_actq.cpp:90
void stop(void)
Definition: qutest.cpp:112
QEvt const * get_(void) noexcept
Get an event from the event queue of an active object.
Definition: qf_actq.cpp:313
Definition: qf.hpp:496
friend class QActive
Definition: qf.hpp:617
static void init(void)
QF initialization.
Definition: qk.cpp:78
friend class QS
Definition: qf.hpp:619
static void onCleanup(void)
Cleanup QF callback.
static int_t run(void)
Transfers control to QF to run the application.
Definition: qk.cpp:137
static QTimeEvt timeEvtHead_[QF_MAX_TICK_RATE]
heads of linked lists of time events, one for every clock tick rate
Definition: qf.hpp:615
static void gc(QEvt const *const e) noexcept
Recycle a dynamic event.
Definition: qf_dyn.cpp:219
static void add_(QActive *const a) noexcept
Register an active object to be managed by the framework.
Definition: qf_act.cpp:79
static void stop(void)
Definition: qk.cpp:111
static QActive * active_[QF_MAX_ACTIVE+1U]
array of registered active objects
Definition: qf.hpp:580
static void remove_(QActive *const a) noexcept
Remove the active object from the framework.
Definition: qf_act.cpp:103
virtual void dispatch(QEvt const *const e, std::uint_fast8_t const qs_id)
Dispatches an event to QHsm.
Definition: qep_hsm.cpp:242
void * currObj[MAX_OBJ]
current objects
Definition: qs.hpp:557
static struct QP::QS::QSrxPriv rxPriv_
static void onTestLoop(void)
callback to run the test loop
static QS priv_
Definition: qs.hpp:554
static void onFlush(void)
Callback to flush the QS trace data to the host.
@ TE_OBJ
time event object
Definition: qs.hpp:519
static void onReset(void)
callback function to reset the Target (to be implemented in the BSP)
static void processTestEvts_(void)
internal function to process posted events during test
Definition: qutest.cpp:270
QP::QPSet readySet
QUTEST ready-set of active objects.
Definition: qs.hpp:563
static void onTestPost(void const *sender, QActive *recipient, QEvt const *e, bool status)
static void tickX_(std::uint_fast8_t const tickRate, void const *const sender) noexcept
internal function to process armed time events during test
Definition: qutest.cpp:302
QTimeEvt * toTimeEvt(void) noexcept
encapsulate the cast the m_act attribute to QTimeEvt*
Definition: qf.hpp:469
QTimeEvtCtr volatile m_ctr
Definition: qf.hpp:421
QTimeEvtCtr m_interval
Definition: qf.hpp:429
QTimeEvt *volatile m_next
link to the next time event in the list
Definition: qf.hpp:408
void *volatile m_act
Definition: qf.hpp:414
Definition: struct.dox:1
std::uint_fast16_t const QF_NO_MARGIN
Definition: qf.hpp:627
@ QS_ASSERT_FAIL
assertion failed in the code
Definition: qs.hpp:161
@ QS_QF_TIMEEVT_AUTO_DISARM
a time event expired and was disarmed
Definition: qs.hpp:111
@ QS_QF_RUN
QF_run() was entered.
Definition: qs.hpp:162
@ QS_QEP_STATE_INIT
an initial transition was taken in a state
Definition: qs.hpp:69
@ QS_QF_ACTIVE_POST_LIFO
an event was posted (LIFO) directly to AO
Definition: qs.hpp:83
@ QS_QF_TIMEEVT_POST
a time event posted itself directly to an AO
Definition: qs.hpp:115
@ QS_QF_ACTIVE_POST_ATTEMPT
attempt to post an evt to AO failed
Definition: qs.hpp:127
@ QS_QF_TICK
QP::QF::tickX() was called.
Definition: qs.hpp:107
@ QS_QEP_DISPATCH
an event was dispatched (begin of RTC step)
Definition: qs.hpp:74
@ QS_QF_ACTIVE_POST
an event was posted (FIFO) directly to AO
Definition: qs.hpp:82
void QF_EVT_REF_CTR_INC_(QEvt const *const e) noexcept
increment the refCtr_ of an event e
Definition: qf_pkg.hpp:150
enum_t QF_maxPubSignal_
the maximum published signal
Definition: qf_ps.cpp:58
constexpr std::uint8_t TE_IS_LINKED
Definition: qf_pkg.hpp:132
std::uint_fast8_t QF_maxPool_
Definition: qf_dyn.cpp:55
QSubscrList * QF_subscrList_
the subscriber list array
Definition: qf_ps.cpp:57
std::uint8_t volatile QF_intNest
Definition: qutest.cpp:54
Customizable and memory-efficient assertions for embedded systems.
#define Q_DEFINE_THIS_MODULE(name_)
Definition: qassert.h:120
#define Q_NORETURN
Definition: qassert.h:223
char char_t
Definition: qassert.h:77
#define Q_ASSERT_ID(id_, test_)
Definition: qassert.h:155
int int_t
Definition: qassert.h:86
#define Q_REQUIRE_ID(id_, test_)
Definition: qassert.h:279
#define QF_CRIT_EXIT_NOP()
Definition: qf.hpp:674
Internal (package scope) QF/C++ interface.
#define QF_CRIT_STAT_
Definition: qf_pkg.hpp:56
#define Q_ASSERT_CRIT_(id_, test_)
Definition: qf_pkg.hpp:94
#define QF_CRIT_X_()
Definition: qf_pkg.hpp:77
#define QF_CRIT_E_()
Definition: qf_pkg.hpp:66
#define QS_CRIT_STAT_
Definition: qs.hpp:783
#define QS_TIME_PRE_()
Definition: qs.hpp:266
#define QS_FUN_DICTIONARY(fun_)
Definition: qs.hpp:1012
#define QS_TEST_PROBE_DEF(fun_)
QS macro to define the Test-Probe for a given fun_.
Definition: qs.hpp:1068
#define QS_TEST_PROBE(code_)
QS macro to apply a Test-Probe.
Definition: qs.hpp:1073
#define QS_TEST_PROBE_ID(id_, code_)
QS macro to apply a Test-Probe.
Definition: qs.hpp:1077
#define QS_BEGIN_PRE_(rec_, qs_id_)
Definition: qs_dummy.hpp:96
#define QS_U8_PRE_(data_)
Definition: qs_dummy.hpp:100
#define QS_BEGIN_NOCRIT_PRE_(rec_, qs_id_)
Definition: qs_dummy.hpp:98
#define QS_OBJ_PRE_(obj_)
Definition: qs_dummy.hpp:107
#define QS_FUN_PRE_(fun_)
Definition: qs_dummy.hpp:108
#define QS_TEC_PRE_(ctr_)
Definition: qs_dummy.hpp:112
#define QS_END_NOCRIT_PRE_()
Definition: qs_dummy.hpp:99
#define QS_U16_PRE_(data_)
Definition: qs_dummy.hpp:102
#define QS_2U8_PRE_(data1_, data2_)
Definition: qs_dummy.hpp:101
#define QS_SIG_PRE_(sig_)
Definition: qs_dummy.hpp:105
#define QS_EQC_PRE_(ctr_)
Definition: qs_dummy.hpp:109
#define QS_END_PRE_()
Definition: qs_dummy.hpp:97
Internal (package scope) QS/C++ interface.
#define QS_STR_PRE_(msg_)
Definition: qs_pkg.hpp:137
QS/C++ port to a 32-bit CPU, generic compiler.
Q_NORETURN Q_onAssert(char_t const *const module, int_t const location)
Definition: qutest.cpp:412
#define QF_MAX_ACTIVE
Definition: qxk/qf_port.hpp:57
QSignal sig
signal of the event instance
Definition: qep.hpp:210
std::uint8_t volatile refCtr_
reference counter
Definition: qep.hpp:212
void rmove(std::uint_fast8_t const n) noexcept
Definition: qpset.hpp:109
bool notEmpty(void) const noexcept
Evaluates to true if the priority set is not empty.
Definition: qpset.hpp:91
std::uint_fast8_t findMax(void) const noexcept
Definition: qpset.hpp:114