Dining Philosophers Problem (DPP) example for the QP active object framework. Demonstrates: event-driven programming, hierarchical state machines in C++, modeling and graphical state machine design, code generation, preemptive multitasking, software tracing, power saving mode, direct event posting, publish-subscribe. More information available in the [[/users/QL/notebook|Quantum Leaps Notebook pages]]. See also [[http://www.state-machine.com|state-machine.com]].

Dependencies:   mbed qp

Revision:
4:6189d844a1a2
Parent:
3:81ceb3127876
--- a/table.cpp	Mon Sep 26 02:21:01 2011 +0000
+++ b/table.cpp	Tue Sep 04 22:41:20 2012 +0000
@@ -1,148 +1,283 @@
 //////////////////////////////////////////////////////////////////////////////
-// Product: DPP example
-// Last Updated for Version: 4.2.00
-// Date of the Last Update:  Jul 15, 2011
-//
-//                    Q u a n t u m     L e a P s
-//                    ---------------------------
-//                    innovating embedded systems
-//
-// Copyright (C) 2002-2011 Quantum Leaps, LLC. All rights reserved.
+// Model: dpp.qm
+// File:  ././table.cpp
 //
-// This software may be distributed and modified under the terms of the GNU
-// General Public License version 2 (GPL) as published by the Free Software
-// Foundation and appearing in the file GPL.TXT included in the packaging of
-// this file. Please note that GPL Section 2[b] requires that all works based
-// on this software must also be made publicly available under the terms of
-// the GPL ("Copyleft").
+// This file has been generated automatically by QP Modeler (QM).
+// DO NOT EDIT THIS FILE MANUALLY.
 //
-// Alternatively, this software may be distributed and modified under the
-// terms of Quantum Leaps commercial licenses, which expressly supersede
-// the GPL and are specifically designed for licensees interested in
-// retaining the proprietary status of their code.
-//
-// Contact information:
-// Quantum Leaps Web site:  http://www.quantum-leaps.com
-// e-mail:                  info@quantum-leaps.com
+// Please visit www.state-machine.com/qm for more information.
 //////////////////////////////////////////////////////////////////////////////
 #include "qp_port.h"
 #include "dpp.h"
 #include "bsp.h"
 
+namespace DPP {
+
 Q_DEFINE_THIS_FILE
 
 // Active object class -------------------------------------------------------
-class Table : public QActive {
+// @(/2/1) ...................................................................
+class Table : public QP::QActive {
 private:
     uint8_t m_fork[N_PHILO];
-    uint8_t m_isHungry[N_PHILO];
+    bool m_isHungry[N_PHILO];
 
 public:
     Table();
 
-private:
-    static QState initial(Table *me, QEvent const *e);
-    static QState serving(Table *me, QEvent const *e);
+protected:
+    static QP::QState initial(Table * const me, QP::QEvt const * const e);
+    static QP::QState active(Table * const me, QP::QEvt const * const e);
+    static QP::QState serving(Table * const me, QP::QEvt const * const e);
+    static QP::QState paused(Table * const me, QP::QEvt const * const e);
 };
 
-#define RIGHT(n_) ((uint8_t)(((n_) + (N_PHILO - 1)) % N_PHILO))
-#define LEFT(n_)  ((uint8_t)(((n_) + 1) % N_PHILO))
-enum ForkState { FREE, USED };
+// 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;                                    // local Table object
+static Table l_table; // the single instance of the Table active object
 
-// Public-scope objects ------------------------------------------------------
-QActive * const AO_Table = &l_table;                    // "opaque" AO pointer
+// Global-scope objects ------------------------------------------------------
+QP::QActive * const AO_Table = &l_table; // "opaque" AO pointer
 
 //............................................................................
-Table::Table() : QActive((QStateHandler)&Table::initial) {
-    uint8_t n;
-    for (n = 0; n < N_PHILO; ++n) {
+// @(/2/1) ...................................................................
+// @(/2/1/2) .................................................................
+Table::Table() 
+  : QActive(Q_STATE_CAST(&Table::initial))
+{
+    for (uint8_t n = 0U; n < N_PHILO; ++n) {
         m_fork[n] = FREE;
-        m_isHungry[n] = 0;
+        m_isHungry[n] = false;
     }
 }
-//............................................................................
-QState Table::initial(Table *me, QEvent const *) {
+
+// @(/2/1/3) .................................................................
+// @(/2/1/3/0)
+QP::QState Table::initial(Table * const me, QP::QEvt const * const e) {
+    (void)e; // suppress the compiler warning about unused parameter
 
     QS_OBJ_DICTIONARY(&l_table);
-    QS_FUN_DICTIONARY(&QHsm::top);
+    QS_FUN_DICTIONARY(&QP::QHsm::top);
     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,      0);                     // global signals
-    QS_SIG_DICTIONARY(EAT_SIG,       0);
-    QS_SIG_DICTIONARY(TERMINATE_SIG, 0);
+    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(TERMINATE_SIG, (void *)0);
 
-    QS_SIG_DICTIONARY(HUNGRY_SIG,    me);             // signal just for Table
+    QS_SIG_DICTIONARY(HUNGRY_SIG,    me); // signal just for Table
 
     me->subscribe(DONE_SIG);
+    me->subscribe(PAUSE_SIG);
     me->subscribe(TERMINATE_SIG);
 
+    for (uint8_t n = 0U; n < N_PHILO; ++n) {
+        me->m_fork[n] = FREE;
+        me->m_isHungry[n] = false;
+        BSP_displayPhilStat(n, THINKING);
+    }
     return Q_TRAN(&Table::serving);
 }
-//............................................................................
-QState Table::serving(Table *me, QEvent const *e) {
-    uint8_t n, m;
-    TableEvt *pe;
-
+// @(/2/1/3/1) ...............................................................
+QP::QState Table::active(Table * const me, QP::QEvt const * const e) {
+    QP::QState status;
     switch (e->sig) {
+        // @(/2/1/3/1/0)
+        case TERMINATE_SIG: {
+            BSP_terminate(0);
+            status = Q_HANDLED();
+            break;
+        }
+        // @(/2/1/3/1/1)
+        case EAT_SIG: {
+            Q_ERROR();
+            status = Q_HANDLED();
+            break;
+        }
+        default: {
+            status = Q_SUPER(&QHsm::top);
+            break;
+        }
+    }
+    return status;
+}
+// @(/2/1/3/1/2) .............................................................
+QP::QState Table::serving(Table * const me, QP::QEvt const * const e) {
+    QP::QState status;
+    switch (e->sig) {
+        // @(/2/1/3/1/2)
+        case Q_ENTRY_SIG: {
+            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;
+                    TableEvt *te = Q_NEW(TableEvt, EAT_SIG);
+                    te->philoNum = n;
+                    QP::QF::PUBLISH(te, me);
+                    me->m_isHungry[n] = false;
+                    BSP_displayPhilStat(n, EATING);
+                }
+            }
+            status = Q_HANDLED();
+            break;
+        }
+        // @(/2/1/3/1/2/0)
         case HUNGRY_SIG: {
-            n = ((TableEvt const *)e)->philoNum;
-                         // phil ID must be in range and he must be not hungry
+            uint8_t n = Q_EVT_CAST(TableEvt)->philoNum;
+            // phil ID must be in range and he must be not hungry
             Q_ASSERT((n < N_PHILO) && (!me->m_isHungry[n]));
 
-            BSP_displyPhilStat(n, "hungry  ");
-            m = LEFT(n);
+            BSP_displayPhilStat(n, HUNGRY);
+            uint8_t m = LEFT(n);
+            // @(/2/1/3/1/2/0/0)
             if ((me->m_fork[m] == FREE) && (me->m_fork[n] == FREE)) {
-                me->m_fork[m] = me->m_fork[n] = USED;
-                pe = Q_NEW(TableEvt, EAT_SIG);
+                me->m_fork[m] = USED;
+                me->m_fork[n] = USED;
+                TableEvt *pe = Q_NEW(TableEvt, EAT_SIG);
                 pe->philoNum = n;
-                QF::PUBLISH(pe, me);
-                BSP_displyPhilStat(n, "eating  ");
+                QP::QF::PUBLISH(pe, me);
+                BSP_displayPhilStat(n, EATING);
+                status = Q_HANDLED();
             }
+            // @(/2/1/3/1/2/0/1)
             else {
-                me->m_isHungry[n] = 1;
+                me->m_isHungry[n] = true;
+                status = Q_HANDLED();
             }
-            return Q_HANDLED();
+            break;
         }
+        // @(/2/1/3/1/2/1)
         case DONE_SIG: {
-            n = ((TableEvt const *)e)->philoNum;
-                         // phil ID must be in range and he must be not hungry
+            uint8_t n = Q_EVT_CAST(TableEvt)->philoNum;
+            // phil ID must be in range and he must be not hungry
             Q_ASSERT((n < N_PHILO) && (!me->m_isHungry[n]));
 
-            BSP_displyPhilStat(n, "thinking");
-            m = LEFT(n);
-                                         // both forks of Phil[n] must be used
+            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] = me->m_fork[n] = FREE;
-            m = RIGHT(n);                          // check the right neighbor
+            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] = me->m_fork[m] = USED;
-                me->m_isHungry[m] = 0;
-                pe = Q_NEW(TableEvt, EAT_SIG);
+                me->m_fork[n] = USED;
+                me->m_fork[m] = USED;
+                me->m_isHungry[m] = false;
+                TableEvt *pe = Q_NEW(TableEvt, EAT_SIG);
                 pe->philoNum = m;
-                QF::PUBLISH(pe, me);
-                BSP_displyPhilStat(m, "eating  ");
+                QP::QF::PUBLISH(pe, me);
+                BSP_displayPhilStat(m, EATING);
             }
-            m = LEFT(n);                            // check the left neighbor
-            n = LEFT(m);                     // left fork of the left neighbor
+            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] = me->m_fork[n] = USED;
-                me->m_isHungry[m] = 0;
-                pe = Q_NEW(TableEvt, EAT_SIG);
+                me->m_fork[m] = USED;
+                me->m_fork[n] = USED;
+                me->m_isHungry[m] = false;
+                TableEvt *pe = Q_NEW(TableEvt, EAT_SIG);
                 pe->philoNum = m;
-                QF::PUBLISH(pe, me);
-                BSP_displyPhilStat(m, "eating  ");
+                QP::QF::PUBLISH(pe, me);
+                BSP_displayPhilStat(m, EATING);
             }
-            return Q_HANDLED();
+            status = Q_HANDLED();
+            break;
+        }
+        // @(/2/1/3/1/2/2)
+        case EAT_SIG: {
+            Q_ERROR();
+            status = Q_HANDLED();
+            break;
         }
-        case TERMINATE_SIG: {
-            QF::stop();
-            return Q_HANDLED();
+        // @(/2/1/3/1/2/3)
+        case PAUSE_SIG: {
+            status = Q_TRAN(&Table::paused);
+            break;
+        }
+        default: {
+            status = Q_SUPER(&Table::active);
+            break;
         }
     }
-    return Q_SUPER(&QHsm::top);
+    return status;
 }
+// @(/2/1/3/1/3) .............................................................
+QP::QState Table::paused(Table * const me, QP::QEvt const * const e) {
+    QP::QState status;
+    switch (e->sig) {
+        // @(/2/1/3/1/3)
+        case Q_ENTRY_SIG: {
+            BSP_displayPaused(1U);
+            status = Q_HANDLED();
+            break;
+        }
+        // @(/2/1/3/1/3)
+        case Q_EXIT_SIG: {
+            BSP_displayPaused(0U);
+            status = Q_HANDLED();
+            break;
+        }
+        // @(/2/1/3/1/3/0)
+        case PAUSE_SIG: {
+            status = Q_TRAN(&Table::serving);
+            break;
+        }
+        // @(/2/1/3/1/3/1)
+        case HUNGRY_SIG: {
+            uint8_t n = Q_EVT_CAST(TableEvt)->philoNum;
+            // 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);
+            status = Q_HANDLED();
+            break;
+        }
+        // @(/2/1/3/1/3/2)
+        case DONE_SIG: {
+            uint8_t n = Q_EVT_CAST(TableEvt)->philoNum;
+            // phil 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;
+            status = Q_HANDLED();
+            break;
+        }
+        default: {
+            status = Q_SUPER(&Table::active);
+            break;
+        }
+    }
+    return status;
+}
+
+
+}                                                             // namespace DPP