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

Revision:
0:84f3d3d7e5d9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bsp.cpp	Sun Mar 27 16:50:21 2011 +0000
@@ -0,0 +1,265 @@
+//////////////////////////////////////////////////////////////////////////////
+// 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.
+//