mirror of
https://github.com/QuantumLeaps/qpcpp.git
synced 2025-02-04 06:13:00 +08:00
338 lines
11 KiB
XML
338 lines
11 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<package name="Cont" stereotype="0x02" namespace="DPP::">
|
|
<class name="TableEvt" superclass="qpcpp::QEvt">
|
|
<attribute name="philo" type="DPP::Philo *" visibility="0x00" properties="0x00"/>
|
|
</class>
|
|
<class name="CompTimeEvt" superclass="qpcpp::QTimeEvt">
|
|
<documentation>Specialized time event for components. The time evnet can be owned by a component and can dispatch itself to the component.</documentation>
|
|
<attribute name="m_comp" type="QP::QHsm *" visibility="0x00" properties="0x00"/>
|
|
<operation name="CompTimeEvt" type="" visibility="0x00" properties="0x00">
|
|
<documentation>The constructor to initialize a Component Time Event.
|
|
|
|
When creating a time event, you must commit it to a specific active object 'act', event signal 'sig', and tick rate 'tickRate'. You cannot change these attributes later.</documentation>
|
|
<parameter name="act" type="QP::QActive *"/>
|
|
<parameter name="comp" type="QP::QHsm *"/>
|
|
<parameter name="sig" type="enum_t const"/>
|
|
<parameter name="tickRate" type="uint_fast8_t const"/>
|
|
<code> : QTimeEvt(act, sig, tickRate)
|
|
|
|
m_comp = comp;</code>
|
|
</operation>
|
|
<operation name="dispatchToComp" type="void" visibility="0x00" properties="0x0a">
|
|
<code>m_comp->dispatch(this);</code>
|
|
</operation>
|
|
</class>
|
|
<class name="Table" superclass="qpcpp::QActive">
|
|
<attribute name="m_philo[N_PHILO]" type="Philo" visibility="0x02" properties="0x00">
|
|
<documentation>Embedded component state machine objects</documentation>
|
|
</attribute>
|
|
<attribute name="m_fork[N_PHILO]" type="uint8_t" visibility="0x02" properties="0x00"/>
|
|
<attribute name="m_isHungry[N_PHILO]" type="bool" visibility="0x02" properties="0x00"/>
|
|
<operation name="Table" type="" visibility="0x00" properties="0x00">
|
|
<code> : QActive(Q_STATE_CAST(&Table::initial))
|
|
|
|
for (uint8_t n = 0U; n < N_PHILO; ++n) {
|
|
m_fork[n] = FREE;
|
|
m_isHungry[n] = false;
|
|
}</code>
|
|
</operation>
|
|
<statechart>
|
|
<initial target="../1/3">
|
|
<action>(void)e; // suppress the compiler warning about unused parameter
|
|
|
|
QS_OBJ_DICTIONARY(&l_table);
|
|
QS_FUN_DICTIONARY(&Table::initial);
|
|
QS_FUN_DICTIONARY(&Table::active);
|
|
QS_FUN_DICTIONARY(&Table::serving);
|
|
QS_FUN_DICTIONARY(&Table::paused);
|
|
|
|
QS_SIG_DICTIONARY(DONE_SIG, (void *)0); // global signals
|
|
QS_SIG_DICTIONARY(EAT_SIG, (void *)0);
|
|
QS_SIG_DICTIONARY(PAUSE_SIG, (void *)0);
|
|
QS_SIG_DICTIONARY(SERVE_SIG, (void *)0);
|
|
QS_SIG_DICTIONARY(TEST_SIG, (void *)0);
|
|
|
|
QS_SIG_DICTIONARY(TIMEOUT_SIG, me); // signal just for Table
|
|
QS_SIG_DICTIONARY(HUNGRY_SIG, me); // signal just for Table
|
|
|
|
me->subscribe(PAUSE_SIG);
|
|
me->subscribe(SERVE_SIG);
|
|
me->subscribe(TEST_SIG);
|
|
|
|
for (uint8_t n = 0U; n < N_PHILO; ++n) {
|
|
me->m_philo[n].init(); // top-most initial tran.
|
|
me->m_fork[n] = FREE;
|
|
me->m_isHungry[n] = false;
|
|
BSP::displayPhilStat(n, THINKING);
|
|
}</action>
|
|
<initial_glyph conn="3,3,5,1,45,23,-10">
|
|
<action box="0,-2,6,2"/>
|
|
</initial_glyph>
|
|
</initial>
|
|
<state name="active">
|
|
<tran trig="TIMEOUT">
|
|
<action>Q_EVT_CAST(CompTimeEvt)->dispatchToComp();</action>
|
|
<tran_glyph conn="2,11,3,-1,14">
|
|
<action box="0,-2,11,4"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="EAT">
|
|
<action>Q_ERROR();</action>
|
|
<tran_glyph conn="2,15,3,-1,14">
|
|
<action box="0,-2,10,4"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="TEST">
|
|
<tran_glyph conn="2,20,3,-1,14">
|
|
<action box="0,-2,10,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<state name="serving">
|
|
<entry brief="give pending permitions to eat">for (uint8_t n = 0U; n < N_PHILO; ++n) { // give permissions to eat...
|
|
if (me->m_isHungry[n]
|
|
&& (me->m_fork[LEFT(n)] == FREE)
|
|
&& (me->m_fork[n] == FREE))
|
|
{
|
|
me->m_fork[LEFT(n)] = USED;
|
|
me->m_fork[n] = USED;
|
|
|
|
// synchronoulsy dispatch EAT event to the Philo component
|
|
TableEvt evt;
|
|
evt.sig = EAT_SIG;
|
|
evt.philo = &me->m_philo[n];
|
|
me->m_philo[n].dispatch(&evt);
|
|
|
|
me->m_isHungry[n] = false;
|
|
BSP::displayPhilStat(n, EATING);
|
|
}
|
|
}</entry>
|
|
<tran trig="HUNGRY">
|
|
<action>// find the index of the Philo from the event
|
|
uint8_t n = (Q_EVT_CAST(TableEvt)->philo - &me->m_philo[0]);
|
|
// philo ID must be in range and he must be not hungry
|
|
Q_ASSERT((n < N_PHILO) && (!me->m_isHungry[n]));
|
|
|
|
BSP::displayPhilStat(n, HUNGRY);
|
|
uint8_t m = LEFT(n);</action>
|
|
<choice>
|
|
<guard brief="both free">(me->m_fork[m] == FREE) && (me->m_fork[n] == FREE)</guard>
|
|
<action>me->m_fork[m] = USED;
|
|
me->m_fork[n] = USED;
|
|
|
|
// synchronoulsy dispatch EAT event to the Philo component
|
|
TableEvt evt;
|
|
evt.sig = EAT_SIG;
|
|
evt.philo = &me->m_philo[n];
|
|
me->m_philo[n].dispatch(&evt);
|
|
|
|
BSP::displayPhilStat(n, EATING);</action>
|
|
<choice_glyph conn="19,31,5,-1,10">
|
|
<action box="1,0,10,2"/>
|
|
</choice_glyph>
|
|
</choice>
|
|
<choice>
|
|
<guard>else</guard>
|
|
<action>me->m_isHungry[n] = true;</action>
|
|
<choice_glyph conn="19,31,4,-1,5,10">
|
|
<action box="1,5,6,2"/>
|
|
</choice_glyph>
|
|
</choice>
|
|
<tran_glyph conn="4,31,3,-1,15">
|
|
<action box="0,-2,8,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="DONE">
|
|
<action>// find the index of the Philo from the event
|
|
uint8_t n = (Q_EVT_CAST(TableEvt)->philo - &me->m_philo[0]);
|
|
// philo ID must be in range and he must be not hungry
|
|
Q_ASSERT((n < N_PHILO) && (!me->m_isHungry[n]));
|
|
|
|
BSP::displayPhilStat(n, THINKING);
|
|
uint8_t m = LEFT(n);
|
|
// both forks of Phil[n] must be used
|
|
Q_ASSERT((me->m_fork[n] == USED) && (me->m_fork[m] == USED));
|
|
|
|
me->m_fork[m] = FREE;
|
|
me->m_fork[n] = FREE;
|
|
m = RIGHT(n); // check the right neighbor
|
|
|
|
if (me->m_isHungry[m] && (me->m_fork[m] == FREE)) {
|
|
me->m_fork[n] = USED;
|
|
me->m_fork[m] = USED;
|
|
me->m_isHungry[m] = false;
|
|
|
|
// synchronoulsy dispatch EAT event to the Philo component
|
|
TableEvt evt;
|
|
evt.sig = EAT_SIG;
|
|
evt.philo = &me->m_philo[m];
|
|
me->m_philo[m].dispatch(&evt);
|
|
|
|
BSP::displayPhilStat(m, EATING);
|
|
}
|
|
m = LEFT(n); // check the left neighbor
|
|
n = LEFT(m); // left fork of the left neighbor
|
|
if (me->m_isHungry[m] && (me->m_fork[n] == FREE)) {
|
|
me->m_fork[m] = USED;
|
|
me->m_fork[n] = USED;
|
|
me->m_isHungry[m] = false;
|
|
|
|
// synchronoulsy dispatch EAT event to the Philo component
|
|
TableEvt evt;
|
|
evt.sig = EAT_SIG;
|
|
evt.philo = &me->m_philo[m];
|
|
me->m_philo[m].dispatch(&evt);
|
|
|
|
BSP::displayPhilStat(m, EATING);
|
|
}</action>
|
|
<tran_glyph conn="4,39,3,-1,15">
|
|
<action box="0,-2,6,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="EAT">
|
|
<action>Q_ERROR();</action>
|
|
<tran_glyph conn="4,42,3,-1,15">
|
|
<action box="0,-2,12,4"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="PAUSE" target="../../4">
|
|
<tran_glyph conn="4,46,3,1,37,6,-3">
|
|
<action box="0,-2,7,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<state_glyph node="4,24,34,24">
|
|
<entry box="1,2,27,2"/>
|
|
</state_glyph>
|
|
</state>
|
|
<state name="paused">
|
|
<entry>BSP::displayPaused(1U);</entry>
|
|
<exit>BSP::displayPaused(0U);</exit>
|
|
<tran trig="SERVE" target="../../3">
|
|
<tran_glyph conn="4,62,3,1,39,-29,-5">
|
|
<action box="0,-2,12,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="HUNGRY">
|
|
<action>// find the index of the Philo from the event
|
|
uint8_t n = (Q_EVT_CAST(TableEvt)->philo - &me->m_philo[0]);
|
|
// philo ID must be in range and he must be not hungry
|
|
Q_ASSERT((n < N_PHILO) && (!me->m_isHungry[n]));
|
|
|
|
me->m_isHungry[n] = true;
|
|
BSP::displayPhilStat(n, HUNGRY);</action>
|
|
<tran_glyph conn="4,65,3,-1,15">
|
|
<action box="0,-2,9,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<tran trig="DONE">
|
|
<action>// find the index of the Philo from the event
|
|
uint8_t n = (Q_EVT_CAST(TableEvt)->philo - &me->m_philo[0]);
|
|
// philo ID must be in range and he must be not hungry
|
|
Q_ASSERT((n < N_PHILO) && (!me->m_isHungry[n]));
|
|
|
|
BSP::displayPhilStat(n, THINKING);
|
|
|
|
uint8_t m = LEFT(n);
|
|
// both forks of Phil[n] must be used
|
|
Q_ASSERT((me->m_fork[n] == USED) && (me->m_fork[m] == USED));
|
|
|
|
me->m_fork[m] = FREE;
|
|
me->m_fork[n] = FREE;</action>
|
|
<tran_glyph conn="4,68,3,-1,15">
|
|
<action box="0,-2,6,2"/>
|
|
</tran_glyph>
|
|
</tran>
|
|
<state_glyph node="4,50,34,20">
|
|
<entry box="1,2,18,4"/>
|
|
<exit box="1,6,18,4"/>
|
|
</state_glyph>
|
|
</state>
|
|
<state_glyph node="2,5,44,67"/>
|
|
</state>
|
|
<state_diagram size="50,74"/>
|
|
</statechart>
|
|
</class>
|
|
<attribute name="AO_Table" type="QP::QActive * const" visibility="0x00" properties="0x00"/>
|
|
<directory name=".">
|
|
<file name="dpp.h">
|
|
<text>#ifndef dpp_h
|
|
#define dpp_h
|
|
|
|
namespace DPP {
|
|
|
|
enum DPPSignals {
|
|
EAT_SIG = QP::Q_USER_SIG, // published by Table to let a philosopher eat
|
|
DONE_SIG, // published by Philosopher when done eating
|
|
PAUSE_SIG, // published by BSP to pause the application
|
|
SERVE_SIG, // published by BSP to serve re-start serving forks
|
|
TEST_SIG, // published by BSP to test the application
|
|
MAX_PUB_SIG, // the last published signal
|
|
|
|
HUNGRY_SIG, // posted direclty to Table from hungry Philo
|
|
TIMEOUT_SIG, // used by the component time events
|
|
MAX_SIG // the last signal
|
|
};
|
|
|
|
class Philo; // forward declaration
|
|
|
|
} // namespace DPP
|
|
|
|
enum {
|
|
N_PHILO = 5 // number of Philos
|
|
};
|
|
|
|
$declare(Cont::CompTimeEvt)
|
|
|
|
$declare(Cont::AO_Table)
|
|
|
|
$declare(Comp::Philo)
|
|
|
|
$declare(Cont::TableEvt)
|
|
|
|
#endif // dpp_h</text>
|
|
</file>
|
|
<file name="table.cpp">
|
|
<text>#include "qpcpp.h"
|
|
#include "dpp.h"
|
|
#include "bsp.h"
|
|
|
|
Q_DEFINE_THIS_FILE
|
|
|
|
// Active object class -------------------------------------------------------
|
|
$declare(Cont::Table)
|
|
|
|
namespace DPP {
|
|
|
|
// helper function to provide the RIGHT neighbour of a Philo[n]
|
|
inline uint8_t RIGHT(uint8_t const n) {
|
|
return static_cast<uint8_t>((n + (N_PHILO - 1U)) % N_PHILO);
|
|
}
|
|
|
|
// helper function to provide the LEFT neighbour of a Philo[n]
|
|
inline uint8_t LEFT(uint8_t const n) {
|
|
return static_cast<uint8_t>((n + 1U) % N_PHILO);
|
|
}
|
|
|
|
static uint8_t const FREE = static_cast<uint8_t>(0);
|
|
static uint8_t const USED = static_cast<uint8_t>(1);
|
|
|
|
static char_t const * const THINKING = &"thinking"[0];
|
|
static char_t const * const HUNGRY = &"hungry "[0];
|
|
static char_t const * const EATING = &"eating "[0];
|
|
|
|
// Local objects -------------------------------------------------------------
|
|
static Table l_table; // the single instance of the Table active object
|
|
|
|
// Global-scope objects ------------------------------------------------------
|
|
QP::QActive * const AO_Table = &l_table; // "opaque" AO pointer
|
|
|
|
} // namespace DPP
|
|
|
|
|
|
//............................................................................
|
|
$define(Cont::CompTimeEvt)
|
|
|
|
$define(Cont::Table)</text>
|
|
</file>
|
|
</directory>
|
|
</package>
|