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

bsp.cpp

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

File content as of revision 0:84f3d3d7e5d9:

//////////////////////////////////////////////////////////////////////////////
// Product: BSP for lwIP example, mbed-LPC1768 board, QK kernel
// Last Updated for Version: 4.1.06
// Date of the Last Update:  Feb 18, 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.
//
// 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"                                    // QP port header file
#include "dpp.h"                      // application events and active objects
#include "bsp.h"                          // Board Support Package header file

#include "LPC17xx.h"

Q_DEFINE_THIS_FILE

static uint32_t l_nTicks;

enum ISR_Priorities {      // ISR priorities starting from the highest urgency
    SYSTICK_PRIO,
    ENET_PRIO,
    // ...
};

#ifdef Q_SPY
    #include "mbed.h"             // mbed is used only for the built-in serial

    QSTimeCtr l_tickTime;
    QSTimeCtr l_tickPeriod;

    #define QSPY_BAUD_RATE          115200

    Serial l_qspy(USBTX, USBRX);
#endif

//............................................................................
extern "C" void SysTick_Handler(void) {
    QK_ISR_ENTRY();                // inform the QK kernel of entering the ISR

#ifdef Q_SPY
    uint32_t volatile dummy = SysTick->CTRL; // clear the COUNTFLAG in SysTick
    l_tickTime += l_tickPeriod;              // account for the clock rollover
#endif

    QF::tick();                               // process all armed time events

    QK_ISR_EXIT();                  // inform the QK kernel of exiting the ISR
}

//............................................................................
void BSP_init(void) {
    SystemInit();                            // initialize the clocking system

                                                     // set LED port to output
    LED_PORT->FIODIR |= (LED1_BIT | LED2_BIT | LED3_BIT | LED4_BIT);
    
                                                             // clear the LEDs
    LED_PORT->FIOCLR  = (LED1_BIT | LED2_BIT | LED3_BIT | LED4_BIT);

    if (QS_INIT((void *)0) == 0) {       // initialize the QS software tracing
        Q_ERROR();
    }
}
//............................................................................
void BSP_displyPhilStat(uint8_t n, char const *stat) {
                            // represent LEDs in a const array for convenience
    static uint32_t const led[] = { LED1_BIT, LED2_BIT, LED3_BIT, LED4_BIT };
    if (n < 2) {
        if (stat[0] == 'e') {
            LED_PORT->FIOSET = led[n];
        }
        else {
            LED_PORT->FIOCLR = led[n];
        }
    }
    
    QS_BEGIN(PHILO_STAT, AO_Philo[n])     // application-specific record begin
        QS_U8(1, n);                                     // Philosopher number
        QS_STR(stat);                                    // Philosopher status
    QS_END()
}
//............................................................................
void QF::onStartup(void) {
                 // set up the SysTick timer to fire at BSP_TICKS_PER_SEC rate
    SysTick_Config(SystemCoreClock / BSP_TICKS_PER_SEC);

                          // set priorities of all interrupts in the system...
    NVIC_SetPriority(SysTick_IRQn, SYSTICK_PRIO);
    NVIC_SetPriority(ENET_IRQn,    ENET_PRIO);

    NVIC_EnableIRQ(ENET_IRQn);                // enable the Ethernet Interrupt
}
//............................................................................
void QF::onCleanup(void) {
}
//............................................................................
void QK::onIdle(void) {

    QF_INT_LOCK(dummy);
    LED_PORT->FIOSET = LED4_BIT;                           // turn the LED4 on
    __NOP();                        // delay a bit to see some light intensity
    __NOP();
    __NOP();
    __NOP();
    LED_PORT->FIOCLR = LED4_BIT;                          // turn the LED4 off
    QF_INT_UNLOCK(dummy);

#ifdef Q_SPY
    if (l_qspy.writeable()) {
        QF_INT_LOCK(dummy);
        uint16_t b = QS::getByte();
        QF_INT_UNLOCK(dummy);
        if (b != QS_EOD) {
            l_qspy.putc((uint8_t)b);
        }
    }
#else    
    // Put the CPU and peripherals to the low-power mode. You might need to
    // customize the clock management for your application, see the datasheet
    // for your particular Cortex-M3 MCU.
    //
    // Specifially for the mbed board, see the articles:
    // * "Power Management" http://mbed.org/cookbook/Power-Management; and
    // * "Interface Powerdown" at 
    //   http://mbed.org/users/simon/notebook/interface-powerdown/
    // 
    __WFI();
#endif
}

//............................................................................
void Q_onAssert(char const Q_ROM * const Q_ROM_VAR file, int line) {
    (void)file;                                      // avoid compiler warning
    (void)line;                                      // avoid compiler warning
    QF_INT_LOCK(dummy);          // make sure that all interrupts are disabled
                                                          // light up all LEDs
    LED_PORT->FIOSET = (LED1_BIT | LED2_BIT | LED3_BIT | LED4_BIT);

    for (;;) {          // NOTE: replace the loop with reset for final version
    }
}
//............................................................................
// sys_now() is used in the lwIP stack
extern "C" uint32_t sys_now(void) {
    return l_nTicks * (1000 / BSP_TICKS_PER_SEC);
}

//----------------------------------------------------------------------------
#ifdef Q_SPY
//............................................................................
uint8_t QS::onStartup(void const *arg) {
    static uint8_t qsBuf[6*256];                     // buffer for Quantum Spy
    initBuf(qsBuf, sizeof(qsBuf));
    
    l_qspy.baud(QSPY_BAUD_RATE);
    
    l_tickPeriod = SystemCoreClock / BSP_TICKS_PER_SEC;
    l_tickTime   = l_tickPeriod;             // to start the timestamp at zero

                                                    // setup the QS filters...
    QS_FILTER_ON(QS_ALL_RECORDS);

    QS_FILTER_OFF(QS_QEP_STATE_EMPTY);
    QS_FILTER_OFF(QS_QEP_STATE_ENTRY);
    QS_FILTER_OFF(QS_QEP_STATE_EXIT);
    QS_FILTER_OFF(QS_QEP_STATE_INIT);
    QS_FILTER_OFF(QS_QEP_INIT_TRAN);
    QS_FILTER_OFF(QS_QEP_INTERN_TRAN);
    QS_FILTER_OFF(QS_QEP_TRAN);
    QS_FILTER_OFF(QS_QEP_IGNORED);
    QS_FILTER_OFF(QS_QEP_DISPATCH);

    QS_FILTER_OFF(QS_QF_ACTIVE_ADD);
    QS_FILTER_OFF(QS_QF_ACTIVE_REMOVE);
    QS_FILTER_OFF(QS_QF_ACTIVE_SUBSCRIBE);
    QS_FILTER_OFF(QS_QF_ACTIVE_UNSUBSCRIBE);
    QS_FILTER_OFF(QS_QF_ACTIVE_POST_FIFO);
    QS_FILTER_OFF(QS_QF_ACTIVE_POST_LIFO);
    QS_FILTER_OFF(QS_QF_ACTIVE_GET);
    QS_FILTER_OFF(QS_QF_ACTIVE_GET_LAST);
    QS_FILTER_OFF(QS_QF_EQUEUE_INIT);
    QS_FILTER_OFF(QS_QF_EQUEUE_POST_FIFO);
    QS_FILTER_OFF(QS_QF_EQUEUE_POST_LIFO);
    QS_FILTER_OFF(QS_QF_EQUEUE_GET);
    QS_FILTER_OFF(QS_QF_EQUEUE_GET_LAST);
    QS_FILTER_OFF(QS_QF_MPOOL_INIT);
    QS_FILTER_OFF(QS_QF_MPOOL_GET);
    QS_FILTER_OFF(QS_QF_MPOOL_PUT);
    QS_FILTER_OFF(QS_QF_PUBLISH);
    QS_FILTER_OFF(QS_QF_NEW);
    QS_FILTER_OFF(QS_QF_GC_ATTEMPT);
    QS_FILTER_OFF(QS_QF_GC);
    QS_FILTER_OFF(QS_QF_TICK);
    QS_FILTER_OFF(QS_QF_TIMEEVT_ARM);
    QS_FILTER_OFF(QS_QF_TIMEEVT_AUTO_DISARM);
    QS_FILTER_OFF(QS_QF_TIMEEVT_DISARM_ATTEMPT);
    QS_FILTER_OFF(QS_QF_TIMEEVT_DISARM);
    QS_FILTER_OFF(QS_QF_TIMEEVT_REARM);
    QS_FILTER_OFF(QS_QF_TIMEEVT_POST);
    QS_FILTER_OFF(QS_QF_INT_LOCK);
    QS_FILTER_OFF(QS_QF_INT_UNLOCK);
    QS_FILTER_OFF(QS_QF_ISR_ENTRY);
    QS_FILTER_OFF(QS_QF_ISR_EXIT);

    QS_FILTER_OFF(QS_QK_MUTEX_LOCK);
    QS_FILTER_OFF(QS_QK_MUTEX_UNLOCK);
    QS_FILTER_OFF(QS_QK_SCHEDULE);
    
    QS_FILTER_AO_OBJ(AO_LwIPMgr);
    QS_FILTER_AP_OBJ(AO_LwIPMgr);

    return (uint8_t)1;                                       // return success
}
//............................................................................
void QS::onCleanup(void) {
}
//............................................................................
QSTimeCtr QS::onGetTime(void) {              // invoked with interrupts locked
    if ((SysTick->CTRL & 0x00000100) == 0) {              // COUNTFLAG no set?
        return l_tickTime - (QSTimeCtr)SysTick->VAL;
    }
    else {        // the rollover occured, but the SysTick_ISR did not run yet
        return l_tickTime + l_tickPeriod - (QSTimeCtr)SysTick->VAL;
    }
}
//............................................................................
void QS::onFlush(void) {
    uint16_t b;
    QF_INT_LOCK(dummy);
    while ((b = QS::getByte()) != QS_EOD) {
        while (!l_qspy.writeable()) {    // wait until serial port is writable
        }
        l_qspy.putc((uint8_t)b);
    }
    QF_INT_UNLOCK(dummy);
}
#endif                                                                // Q_SPY
//----------------------------------------------------------------------------

//////////////////////////////////////////////////////////////////////////////
// NOTE01:
// The User LED is used to visualize the idle loop activity. The brightness
// of the LED is proportional to the frequency of invcations of the idle loop.
// Please note that the LED is toggled with interrupts locked, so no interrupt
// execution time contributes to the brightness of the User LED.
//