shithub: heymac-node

ref: ad1df2d2a01bd064e643287ff305673dfede3ce3
dir: /dpp.qm/

View raw version
<?xml version="1.0" encoding="UTF-8"?>
<model version="5.2.5" links="1">
 <documentation>Dining Philosopher Problem example</documentation>
 <!--${qpc}-->
 <framework name="qpc"/>
 <!--${Events}-->
 <package name="Events" stereotype="0x01">
  <!--${Events::TableEvt}-->
  <class name="TableEvt" superclass="qpc::QEvt">
   <!--${Events::TableEvt::philoNum}-->
   <attribute name="philoNum" type="uint8_t" visibility="0x00" properties="0x00"/>
  </class>
 </package>
 <!--${AOs}-->
 <package name="AOs" stereotype="0x02">
  <!--${AOs::Philo}-->
  <class name="Philo" superclass="qpc::QActive">
   <!--${AOs::Philo::inst[N_PHILO]}-->
   <attribute name="inst[N_PHILO]" type="Philo" visibility="0x00" properties="0x01">
    <documentation>The array of static insts of the Philo class (Singleton pattern)</documentation>
   </attribute>
   <!--${AOs::Philo::timeEvt}-->
   <attribute name="timeEvt" type="QTimeEvt" visibility="0x02" properties="0x00"/>
   <!--${AOs::Philo::SM}-->
   <statechart properties="0x01">
    <!--${AOs::Philo::SM::initial}-->
    <initial target="../1">
     <action>static uint8_t registered = (uint8_t)0; /* starts off with 0, per C-standard */
(void)par; /* unused parameter */
// Here's a start:
if (registered == (uint8_t)0) {
    registered = (uint8_t)1;

    QS_OBJ_DICTIONARY(&amp;Philo_inst[0]);
    QS_OBJ_DICTIONARY(&amp;Philo_inst[0].timeEvt);
    QS_OBJ_DICTIONARY(&amp;Philo_inst[1]);
    QS_OBJ_DICTIONARY(&amp;Philo_inst[1].timeEvt);
    QS_OBJ_DICTIONARY(&amp;Philo_inst[2]);
    QS_OBJ_DICTIONARY(&amp;Philo_inst[2].timeEvt);
    QS_OBJ_DICTIONARY(&amp;Philo_inst[3]);
    QS_OBJ_DICTIONARY(&amp;Philo_inst[3].timeEvt);
    QS_OBJ_DICTIONARY(&amp;Philo_inst[4]);
    QS_OBJ_DICTIONARY(&amp;Philo_inst[4].timeEvt);

    QS_FUN_DICTIONARY(&amp;Philo_initial);
    QS_FUN_DICTIONARY(&amp;Philo_thinking);
    QS_FUN_DICTIONARY(&amp;Philo_hungry);
    QS_FUN_DICTIONARY(&amp;Philo_eating);
}
QS_SIG_DICTIONARY(HUNGRY_SIG, me);  /* signal for each Philos */
QS_SIG_DICTIONARY(TIMEOUT_SIG, me); /* signal for each Philos */

QActive_subscribe(&amp;me-&gt;super, EAT_SIG);
QActive_subscribe(&amp;me-&gt;super, TEST_SIG);</action>
     <initial_glyph conn="2,3,5,1,20,5,-3">
      <action box="0,-2,6,2"/>
     </initial_glyph>
    </initial>
    <!--${AOs::Philo::SM::thinking}-->
    <state name="thinking">
     <entry>QTimeEvt_armX(&amp;me-&gt;timeEvt, THINK_TIME, 0U);</entry>
     <exit>QTimeEvt_disarm(&amp;me-&gt;timeEvt);</exit>
     <!--${AOs::Philo::SM::thinking::TIMEOUT}-->
     <tran trig="TIMEOUT" target="../../2">
      <tran_glyph conn="2,13,3,1,20,12,-3">
       <action box="0,-2,6,2"/>
      </tran_glyph>
     </tran>
     <!--${AOs::Philo::SM::thinking::EAT, DONE}-->
     <tran trig="EAT, DONE">
      <action>/* EAT or DONE must be for other Philos than this one */
Q_ASSERT(Q_EVT_CAST(TableEvt)-&gt;philoNum != PHILO_ID(me));</action>
      <tran_glyph conn="2,17,3,-1,13">
       <action box="0,-2,14,2"/>
      </tran_glyph>
     </tran>
     <!--${AOs::Philo::SM::thinking::TEST}-->
     <tran trig="TEST">
      <tran_glyph conn="2,20,3,-1,13">
       <action box="0,-2,11,4"/>
      </tran_glyph>
     </tran>
     <state_glyph node="2,5,17,16">
      <entry box="1,2,5,2"/>
      <exit box="1,4,6,2"/>
     </state_glyph>
    </state>
    <!--${AOs::Philo::SM::hungry}-->
    <state name="hungry">
     <entry>TableEvt *pe = Q_NEW(TableEvt, HUNGRY_SIG);
pe-&gt;philoNum = PHILO_ID(me);
QACTIVE_POST(AO_Table, &amp;pe-&gt;super, me);</entry>
     <!--${AOs::Philo::SM::hungry::EAT}-->
     <tran trig="EAT">
      <!--${AOs::Philo::SM::hungry::EAT::[Q_EVT_CAST(TableEvt)->philoNum=~}-->
      <choice target="../../../3">
       <guard>Q_EVT_CAST(TableEvt)-&gt;philoNum == PHILO_ID(me)</guard>
       <choice_glyph conn="15,30,5,1,7,13,-3">
        <action box="1,0,19,4"/>
       </choice_glyph>
      </choice>
      <tran_glyph conn="2,30,3,-1,13">
       <action box="0,-2,14,2"/>
      </tran_glyph>
     </tran>
     <!--${AOs::Philo::SM::hungry::DONE}-->
     <tran trig="DONE">
      <action>/* DONE must be for other Philos than this one */
Q_ASSERT(Q_EVT_CAST(TableEvt)-&gt;philoNum != PHILO_ID(me));</action>
      <tran_glyph conn="2,36,3,-1,14">
       <action box="0,-2,14,2"/>
      </tran_glyph>
     </tran>
     <state_glyph node="2,23,17,16">
      <entry box="1,2,5,2"/>
     </state_glyph>
    </state>
    <!--${AOs::Philo::SM::eating}-->
    <state name="eating">
     <entry>QTimeEvt_armX(&amp;me-&gt;timeEvt, EAT_TIME, 0U);</entry>
     <exit>TableEvt *pe = Q_NEW(TableEvt, DONE_SIG);
pe-&gt;philoNum = PHILO_ID(me);
QACTIVE_PUBLISH(&amp;pe-&gt;super, &amp;me-&gt;super);</exit>
     <!--${AOs::Philo::SM::eating::TIMEOUT}-->
     <tran trig="TIMEOUT" target="../../1">
      <tran_glyph conn="2,51,3,1,22,-41,-5">
       <action box="0,-2,6,2"/>
      </tran_glyph>
     </tran>
     <!--${AOs::Philo::SM::eating::EAT, DONE}-->
     <tran trig="EAT, DONE">
      <action>/* EAT or DONE must be for other Philos than this one */
Q_ASSERT(Q_EVT_CAST(TableEvt)-&gt;philoNum != PHILO_ID(me));</action>
      <tran_glyph conn="2,55,3,-1,13">
       <action box="0,-2,14,2"/>
      </tran_glyph>
     </tran>
     <state_glyph node="2,41,17,18">
      <entry box="1,2,5,2"/>
      <exit box="1,4,5,2"/>
     </state_glyph>
    </state>
    <state_diagram size="37,61"/>
   </statechart>
  </class>
  <!--${AOs::Table}-->
  <class name="Table" superclass="qpc::QActive">
   <!--${AOs::Table::inst}-->
   <attribute name="inst" type="Table" visibility="0x00" properties="0x01">
    <documentation>The only static inst of the Table class (Singleton pattern)</documentation>
   </attribute>
   <!--${AOs::Table::fork[N_PHILO]}-->
   <attribute name="fork[N_PHILO]" type="uint8_t" visibility="0x02" properties="0x00"/>
   <!--${AOs::Table::isHungry[N_PHILO]}-->
   <attribute name="isHungry[N_PHILO]" type="uint8_t" visibility="0x02" properties="0x00"/>
   <!--${AOs::Table::SM}-->
   <statechart properties="0x03">
    <!--${AOs::Table::SM::initial}-->
    <initial target="../1/2">
     <action>uint8_t n;
(void)par; /* unused parameter */

QS_OBJ_DICTIONARY(&amp;Table_inst);

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(HUNGRY_SIG,    me); /* signal just for Table */

QActive_subscribe(&amp;me-&gt;super, DONE_SIG);
QActive_subscribe(&amp;me-&gt;super, PAUSE_SIG);
QActive_subscribe(&amp;me-&gt;super, SERVE_SIG);
QActive_subscribe(&amp;me-&gt;super, TEST_SIG);

for (n = 0U; n &lt; N_PHILO; ++n) {
    me-&gt;fork[n] = FREE;
    me-&gt;isHungry[n] = 0U;
    BSP_displayPhilStat(n, &quot;thinking&quot;);
}</action>
     <initial_glyph conn="3,3,5,1,44,18,-9">
      <action box="0,-2,6,2"/>
     </initial_glyph>
    </initial>
    <!--${AOs::Table::SM::active}-->
    <state name="active">
     <!--${AOs::Table::SM::active::TEST}-->
     <tran trig="TEST">
      <tran_glyph conn="2,11,3,-1,14">
       <action box="0,-2,11,4"/>
      </tran_glyph>
     </tran>
     <!--${AOs::Table::SM::active::EAT}-->
     <tran trig="EAT">
      <action>Q_ERROR();</action>
      <tran_glyph conn="2,15,3,-1,14">
       <action box="0,-2,10,4"/>
      </tran_glyph>
     </tran>
     <!--${AOs::Table::SM::active::serving}-->
     <state name="serving">
      <entry brief="give pending permissions to eat">uint8_t n;
for (n = 0U; n &lt; N_PHILO; ++n) { /* give permissions to eat... */
    if ((me-&gt;isHungry[n] != 0U)
        &amp;&amp; (me-&gt;fork[LEFT(n)] == FREE)
        &amp;&amp; (me-&gt;fork[n] == FREE))
    {
        TableEvt *te;

        me-&gt;fork[LEFT(n)] = USED;
        me-&gt;fork[n] = USED;
        te = Q_NEW(TableEvt, EAT_SIG);
        te-&gt;philoNum = n;
        QACTIVE_PUBLISH(&amp;te-&gt;super, &amp;me-&gt;super);
        me-&gt;isHungry[n] = 0U;
        BSP_displayPhilStat(n, &quot;eating  &quot;);
    }
}</entry>
      <!--${AOs::Table::SM::active::serving::HUNGRY}-->
      <tran trig="HUNGRY">
       <action>uint8_t n, m;

n = Q_EVT_CAST(TableEvt)-&gt;philoNum;
/* phil ID must be in range and he must be not hungry */
Q_ASSERT((n &lt; N_PHILO) &amp;&amp; (me-&gt;isHungry[n] == 0U));

BSP_displayPhilStat(n, &quot;hungry  &quot;);
m = LEFT(n);</action>
       <!--${AOs::Table::SM::active::serving::HUNGRY::[bothfree]}-->
       <choice>
        <guard brief="both free">(me-&gt;fork[m] == FREE) &amp;&amp; (me-&gt;fork[n] == FREE)</guard>
        <action>TableEvt *pe;
me-&gt;fork[m] = USED;
me-&gt;fork[n] = USED;
pe = Q_NEW(TableEvt, EAT_SIG);
pe-&gt;philoNum = n;
QACTIVE_PUBLISH(&amp;pe-&gt;super, &amp;me-&gt;super);
BSP_displayPhilStat(n, &quot;eating  &quot;);</action>
        <choice_glyph conn="19,26,5,-1,10">
         <action box="1,0,10,2"/>
        </choice_glyph>
       </choice>
       <!--${AOs::Table::SM::active::serving::HUNGRY::[else]}-->
       <choice>
        <guard>else</guard>
        <action>me-&gt;isHungry[n] = 1U;</action>
        <choice_glyph conn="19,26,4,-1,5,10">
         <action box="1,5,6,2"/>
        </choice_glyph>
       </choice>
       <tran_glyph conn="4,26,3,-1,15">
        <action box="0,-2,8,2"/>
       </tran_glyph>
      </tran>
      <!--${AOs::Table::SM::active::serving::DONE}-->
      <tran trig="DONE">
       <action>uint8_t n, m;
TableEvt *pe;

n = Q_EVT_CAST(TableEvt)-&gt;philoNum;
/* phil ID must be in range and he must be not hungry */
Q_ASSERT((n &lt; N_PHILO) &amp;&amp; (me-&gt;isHungry[n] == 0U));

BSP_displayPhilStat(n, &quot;thinking&quot;);
m = LEFT(n);
/* both forks of Phil[n] must be used */
Q_ASSERT((me-&gt;fork[n] == USED) &amp;&amp; (me-&gt;fork[m] == USED));

me-&gt;fork[m] = FREE;
me-&gt;fork[n] = FREE;
m = RIGHT(n); /* check the right neighbor */

if ((me-&gt;isHungry[m] != 0U) &amp;&amp; (me-&gt;fork[m] == FREE)) {
    me-&gt;fork[n] = USED;
    me-&gt;fork[m] = USED;
    me-&gt;isHungry[m] = 0U;
    pe = Q_NEW(TableEvt, EAT_SIG);
    pe-&gt;philoNum = m;
    QACTIVE_PUBLISH(&amp;pe-&gt;super, &amp;me-&gt;super);
    BSP_displayPhilStat(m, &quot;eating  &quot;);
}
m = LEFT(n); /* check the left neighbor */
n = LEFT(m); /* left fork of the left neighbor */
if ((me-&gt;isHungry[m] != 0U) &amp;&amp; (me-&gt;fork[n] == FREE)) {
    me-&gt;fork[m] = USED;
    me-&gt;fork[n] = USED;
    me-&gt;isHungry[m] = 0U;
    pe = Q_NEW(TableEvt, EAT_SIG);
    pe-&gt;philoNum = m;
    QACTIVE_PUBLISH(&amp;pe-&gt;super, &amp;me-&gt;super);
    BSP_displayPhilStat(m, &quot;eating  &quot;);
}</action>
       <tran_glyph conn="4,34,3,-1,15">
        <action box="0,-2,6,2"/>
       </tran_glyph>
      </tran>
      <!--${AOs::Table::SM::active::serving::EAT}-->
      <tran trig="EAT">
       <action>Q_ERROR();</action>
       <tran_glyph conn="4,37,3,-1,15">
        <action box="0,-2,12,4"/>
       </tran_glyph>
      </tran>
      <!--${AOs::Table::SM::active::serving::PAUSE}-->
      <tran trig="PAUSE" target="../../3">
       <tran_glyph conn="4,41,3,1,37,6,-3">
        <action box="0,-2,7,2"/>
       </tran_glyph>
      </tran>
      <state_glyph node="4,19,34,24">
       <entry box="1,2,27,2"/>
      </state_glyph>
     </state>
     <!--${AOs::Table::SM::active::paused}-->
     <state name="paused">
      <entry>BSP_displayPaused(1U);</entry>
      <exit>BSP_displayPaused(0U);</exit>
      <!--${AOs::Table::SM::active::paused::SERVE}-->
      <tran trig="SERVE" target="../../2">
       <tran_glyph conn="4,57,3,1,39,-20,-5">
        <action box="0,-2,7,2"/>
       </tran_glyph>
      </tran>
      <!--${AOs::Table::SM::active::paused::HUNGRY}-->
      <tran trig="HUNGRY">
       <action>uint8_t n = Q_EVT_CAST(TableEvt)-&gt;philoNum;
/* philo ID must be in range and he must be not hungry */
Q_ASSERT((n &lt; N_PHILO) &amp;&amp; (me-&gt;isHungry[n] == 0U));
me-&gt;isHungry[n] = 1U;
BSP_displayPhilStat(n, &quot;hungry  &quot;);</action>
       <tran_glyph conn="4,60,3,-1,15">
        <action box="0,-2,6,2"/>
       </tran_glyph>
      </tran>
      <!--${AOs::Table::SM::active::paused::DONE}-->
      <tran trig="DONE">
       <action>uint8_t n, m;

n = Q_EVT_CAST(TableEvt)-&gt;philoNum;
/* phil ID must be in range and he must be not hungry */
Q_ASSERT((n &lt; N_PHILO) &amp;&amp; (me-&gt;isHungry[n] == 0U));

BSP_displayPhilStat(n, &quot;thinking&quot;);
m = LEFT(n);
/* both forks of Phil[n] must be used */
Q_ASSERT((me-&gt;fork[n] == USED) &amp;&amp; (me-&gt;fork[m] == USED));

me-&gt;fork[m] = FREE;
me-&gt;fork[n] = FREE;</action>
       <tran_glyph conn="4,63,3,-1,15">
        <action box="0,-2,6,2"/>
       </tran_glyph>
      </tran>
      <state_glyph node="4,45,34,20">
       <entry box="1,2,18,4"/>
       <exit box="1,6,18,4"/>
      </state_glyph>
     </state>
     <state_glyph node="2,5,43,62"/>
    </state>
    <state_diagram size="49,69"/>
   </statechart>
  </class>
  <!--${AOs::AO_Philo[N_PHILO]}-->
  <attribute name="AO_Philo[N_PHILO]" type="QActive * const" visibility="0x00" properties="0x00">
   <code>= { /* &quot;opaque&quot; pointers to Philo AO */
    &amp;Philo_inst[0].super,
    &amp;Philo_inst[1].super,
    &amp;Philo_inst[2].super,
    &amp;Philo_inst[3].super,
    &amp;Philo_inst[4].super
};</code>
  </attribute>
  <!--${AOs::AO_Table}-->
  <attribute name="AO_Table" type="QActive * const" visibility="0x00" properties="0x00">
   <code>= &amp;Table_inst.super; /* &quot;opaque&quot; pointer to Table AO */</code>
  </attribute>
  <!--${AOs::Philo_ctor}-->
  <operation name="Philo_ctor" type="void" visibility="0x00" properties="0x00">
   <code>uint8_t n;
Philo *me;
for (n = 0U; n &lt; N_PHILO; ++n) {
    me = &amp;Philo_inst[n];
    QActive_ctor(&amp;me-&gt;super, Q_STATE_CAST(&amp;Philo_initial));
    QTimeEvt_ctorX(&amp;me-&gt;timeEvt, &amp;me-&gt;super, TIMEOUT_SIG, 0U);
}</code>
  </operation>
  <!--${AOs::Table_ctor}-->
  <operation name="Table_ctor" type="void" visibility="0x00" properties="0x00">
   <code>Table *me = &amp;Table_inst;
uint8_t n;

QActive_ctor(&amp;me-&gt;super, Q_STATE_CAST(&amp;Table_initial));

for (n = 0U; n &lt; N_PHILO; ++n) {
    me-&gt;fork[n] = FREE;
    me-&gt;isHungry[n] = 0U;
}</code>
  </operation>
 </package>
 <!--${src}-->
 <directory name="src">
  <!--${src::dpp.h}-->
  <file name="dpp.h">
   <text>#ifndef DPP_H
#define DPP_H

enum DPPSignals {
    EAT_SIG = 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 serving forks */
    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 Philosophers for time events */
    MAX_SIG         /* the last signal */
};

$declare(Events::TableEvt)

/* number of philosophers */
#define N_PHILO ((uint8_t)5)

$declare(AOs::Philo_ctor)
$declare(AOs::AO_Philo[N_PHILO])

$declare(AOs::Table_ctor)
$declare(AOs::AO_Table)

#ifdef QXK_H
    void Test1_ctor(void);
    extern QXThread * const XT_Test1;
    void Test2_ctor(void);
    extern QXThread * const XT_Test2;
#endif /* QXK_H */

#endif /* DPP_H */
</text>
  </file>
  <!--${src::philo.c}-->
  <file name="philo.c">
   <text>#include &quot;qpc.h&quot;
#include &quot;dpp.h&quot;
#include &quot;bsp.h&quot;

Q_DEFINE_THIS_FILE

/* Active object class -----------------------------------------------------*/
$declare${AOs::Philo}

#define THINK_TIME  \
    (QTimeEvtCtr)((BSP_random() % BSP_TICKS_PER_SEC) + (BSP_TICKS_PER_SEC/2U))
#define EAT_TIME    \
    (QTimeEvtCtr)((BSP_random() % BSP_TICKS_PER_SEC) + BSP_TICKS_PER_SEC)

/* helper macro to provide the ID of Philo &quot;me_&quot; */
#define PHILO_ID(me_)    ((uint8_t)((me_) - &amp;Philo_inst[0]))

$define${AOs::AO_Philo[N_PHILO]}
$define${AOs::Philo_ctor}
$define${AOs::Philo}</text>
  </file>
  <!--${src::table.c}-->
  <file name="table.c">
   <text>#include &quot;qpc.h&quot;
#include &quot;dpp.h&quot;
#include &quot;bsp.h&quot;

Q_DEFINE_THIS_FILE

/* Active object class -----------------------------------------------------*/
$declare${AOs::Table}

#define RIGHT(n_) ((uint8_t)(((n_) + (N_PHILO - 1U)) % N_PHILO))
#define LEFT(n_)  ((uint8_t)(((n_) + 1U) % N_PHILO))
#define FREE      ((uint8_t)0)
#define USED      ((uint8_t)1)

$define${AOs::AO_Table}
$define${AOs::Table_ctor}
$define${AOs::Table}</text>
  </file>
 </directory>
</model>