Example program for the lwIP TCP/IP stack (library lwip_1_4_0_rc2) and the QP state machine framework (library qp). This program demonstrates use of lwIP in hard real-time applications, in which the TCP/IP stack is used to monitor and configure the embedded device as well as to provide remote user interface (e.g., by means of a web browser). In particular, the lwIP stack, which is not reentrant, is strictly encapsulated inside a dedicated QP state machine object (active object in QP), so interrupt locking around calls to lwIP is unnecessary. Also, the Ethernet interrupt service routine (ISR) runs very fast without performing any lengthy copy operations. All this means that hard-real-time processing can be done at the task level, especially when you use the preemptive QK kernel built into QP for executing your application. No external RTOS component is needed to achieve fully deterministic real-time response of active object tasks prioritized above the lwiP task. The lwIP-QP integration uses exclusively the event-driven lwIP API. The heavyweight Berkeley-like socket API requiring a blocking RTOS and is not used, which results in much better performance of the lwIP stack and less memory consumption. NOTE: This example compiles cleanly, but does not run just yet because the low-level Ethernet driver in the lwIP library needs to be completed. See comments in the lwip_1_4_0_rc2 library for more information.

Dependencies:   mbed

philo.cpp

Committer:
QL
Date:
2011-03-27
Revision:
0:84f3d3d7e5d9

File content as of revision 0:84f3d3d7e5d9:

//////////////////////////////////////////////////////////////////////////////
// Product: DPP example
// Last Updated for Version: 4.0.03
// Date of the Last Update:  Mar 16, 2009
//
//                    Q u a n t u m     L e a P s
//                    ---------------------------
//                    innovating embedded systems
//
// Copyright (C) 2002-2009 Quantum Leaps, LLC. All rights reserved.
//
// 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").
//
// 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
//////////////////////////////////////////////////////////////////////////////
#include "qp_port.h"
#include "dpp.h"
#include "bsp.h"

Q_DEFINE_THIS_FILE

// Active object class -------------------------------------------------------
class Philo : public QActive {
private:
    QTimeEvt m_timeEvt;                       // to timeout thinking or eating

public:
    Philo();

private:
    static QState initial (Philo *me, QEvent const *e);
    static QState thinking(Philo *me, QEvent const *e);
    static QState hungry  (Philo *me, QEvent const *e);
    static QState eating  (Philo *me, QEvent const *e);
};

// Local objects -------------------------------------------------------------
static Philo l_philo[N_PHILO];                       // storage for all Philos

#define THINK_TIME  17
#define EAT_TIME    13
                              // helper macro to provide the ID of Philo "me_"
#define PHILO_ID(me_)    ((uint8_t)((me_) - l_philo))

enum InternalSignals {                                     // internal signals
    TIMEOUT_SIG = MAX_SIG
};
// Global objects ------------------------------------------------------------
QActive * const AO_Philo[N_PHILO] = {        // "opaque" pointers to Philo AOs
    &l_philo[0],
    &l_philo[1],
    &l_philo[2],
    &l_philo[3],
    &l_philo[4]
};

//............................................................................
Philo::Philo()
    : QActive((QStateHandler)&Philo::initial),
      m_timeEvt(TIMEOUT_SIG)
{}
//............................................................................
QState Philo::initial(Philo *me, QEvent const *) {
    static uint8_t registered;            // starts off with 0, per C-standard
    if (!registered) {
        QS_OBJ_DICTIONARY(&l_philo[0]);
        QS_OBJ_DICTIONARY(&l_philo[0].m_timeEvt);
        QS_OBJ_DICTIONARY(&l_philo[1]);
        QS_OBJ_DICTIONARY(&l_philo[1].m_timeEvt);
        QS_OBJ_DICTIONARY(&l_philo[2]);
        QS_OBJ_DICTIONARY(&l_philo[2].m_timeEvt);
        QS_OBJ_DICTIONARY(&l_philo[3]);
        QS_OBJ_DICTIONARY(&l_philo[3].m_timeEvt);
        QS_OBJ_DICTIONARY(&l_philo[4]);
        QS_OBJ_DICTIONARY(&l_philo[4].m_timeEvt);

        QS_FUN_DICTIONARY(&Philo::initial);
        QS_FUN_DICTIONARY(&Philo::thinking);
        QS_FUN_DICTIONARY(&Philo::hungry);
        QS_FUN_DICTIONARY(&Philo::eating);

        registered = (uint8_t)1;
    }
    QS_SIG_DICTIONARY(HUNGRY_SIG, me);               // signal for each Philos
    QS_SIG_DICTIONARY(TIMEOUT_SIG, me);              // signal for each Philos

    me->subscribe(EAT_SIG);

    return Q_TRAN(&Philo::thinking);
}
//............................................................................
QState Philo::thinking(Philo *me, QEvent const *e) {
    switch (e->sig) {
        case Q_ENTRY_SIG: {
            me->m_timeEvt.postIn(me, THINK_TIME);
            return Q_HANDLED();
        }
        case TIMEOUT_SIG: {
            return Q_TRAN(&Philo::hungry);
        }
        case EAT_SIG:                            // intentionally fall-through
        case DONE_SIG: {
                         // EAT or DONE must be for other Philos than this one
            Q_ASSERT(((TableEvt const *)e)->philoNum != PHILO_ID(me));
            return Q_HANDLED();
        }
    }
    return Q_SUPER(&QHsm::top);
}
//............................................................................
QState Philo::hungry(Philo *me, QEvent const *e) {
    switch (e->sig) {
        case Q_ENTRY_SIG: {
            TableEvt *pe = Q_NEW(TableEvt, HUNGRY_SIG);
            pe->philoNum = PHILO_ID(me);
            AO_Table->postFIFO(pe);
            return Q_HANDLED();
        }
        case EAT_SIG: {
            if (((TableEvt *)e)->philoNum == PHILO_ID(me)) {
                return Q_TRAN(&Philo::eating);
            }
            break;
        }
        case DONE_SIG: {
                                // DONE must be for other Philos than this one
            Q_ASSERT(((TableEvt const *)e)->philoNum != PHILO_ID(me));
            return Q_HANDLED();
        }
    }
    return Q_SUPER(&QHsm::top);
}
//............................................................................
QState Philo::eating(Philo *me, QEvent const *e) {
    switch (e->sig) {
        case Q_ENTRY_SIG: {
            me->m_timeEvt.postIn(me, EAT_TIME);
            return Q_HANDLED();
        }
        case Q_EXIT_SIG: {
            TableEvt *pe = Q_NEW(TableEvt, DONE_SIG);
            pe->philoNum = PHILO_ID(me);
            QF::publish(pe);
            return Q_HANDLED();
        }
        case TIMEOUT_SIG: {
            return Q_TRAN(&Philo::thinking);
        }
        case EAT_SIG:                            // intentionally fall-through
        case DONE_SIG: {
                         // EAT or DONE must be for other Philos than this one
            Q_ASSERT(((TableEvt const *)e)->philoNum != PHILO_ID(me));
            return Q_HANDLED();
        }
    }
    return Q_SUPER(&QHsm::top);
}