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

Committer:
QL
Date:
Sun Mar 27 16:50:21 2011 +0000
Revision:
0:84f3d3d7e5d9
0.9

Who changed what in which revision?

UserRevisionLine numberNew contents of line
QL 0:84f3d3d7e5d9 1 //////////////////////////////////////////////////////////////////////////////
QL 0:84f3d3d7e5d9 2 // Product: BSP for lwIP example, mbed-LPC1768 board, QK kernel
QL 0:84f3d3d7e5d9 3 // Last Updated for Version: 4.1.06
QL 0:84f3d3d7e5d9 4 // Date of the Last Update: Feb 18, 2011
QL 0:84f3d3d7e5d9 5 //
QL 0:84f3d3d7e5d9 6 // Q u a n t u m L e a P s
QL 0:84f3d3d7e5d9 7 // ---------------------------
QL 0:84f3d3d7e5d9 8 // innovating embedded systems
QL 0:84f3d3d7e5d9 9 //
QL 0:84f3d3d7e5d9 10 // Copyright (C) 2002-2011 Quantum Leaps, LLC. All rights reserved.
QL 0:84f3d3d7e5d9 11 //
QL 0:84f3d3d7e5d9 12 // This software may be distributed and modified under the terms of the GNU
QL 0:84f3d3d7e5d9 13 // General Public License version 2 (GPL) as published by the Free Software
QL 0:84f3d3d7e5d9 14 // Foundation and appearing in the file GPL.TXT included in the packaging of
QL 0:84f3d3d7e5d9 15 // this file. Please note that GPL Section 2[b] requires that all works based
QL 0:84f3d3d7e5d9 16 // on this software must also be made publicly available under the terms of
QL 0:84f3d3d7e5d9 17 // the GPL ("Copyleft").
QL 0:84f3d3d7e5d9 18 //
QL 0:84f3d3d7e5d9 19 // Alternatively, this software may be distributed and modified under the
QL 0:84f3d3d7e5d9 20 // terms of Quantum Leaps commercial licenses, which expressly supersede
QL 0:84f3d3d7e5d9 21 // the GPL and are specifically designed for licensees interested in
QL 0:84f3d3d7e5d9 22 // retaining the proprietary status of their code.
QL 0:84f3d3d7e5d9 23 //
QL 0:84f3d3d7e5d9 24 // Contact information:
QL 0:84f3d3d7e5d9 25 // Quantum Leaps Web site: http://www.quantum-leaps.com
QL 0:84f3d3d7e5d9 26 // e-mail: info@quantum-leaps.com
QL 0:84f3d3d7e5d9 27 //////////////////////////////////////////////////////////////////////////////
QL 0:84f3d3d7e5d9 28 #include "qp_port.h" // QP port header file
QL 0:84f3d3d7e5d9 29 #include "dpp.h" // application events and active objects
QL 0:84f3d3d7e5d9 30 #include "bsp.h" // Board Support Package header file
QL 0:84f3d3d7e5d9 31
QL 0:84f3d3d7e5d9 32 #include "LPC17xx.h"
QL 0:84f3d3d7e5d9 33
QL 0:84f3d3d7e5d9 34 Q_DEFINE_THIS_FILE
QL 0:84f3d3d7e5d9 35
QL 0:84f3d3d7e5d9 36 static uint32_t l_nTicks;
QL 0:84f3d3d7e5d9 37
QL 0:84f3d3d7e5d9 38 enum ISR_Priorities { // ISR priorities starting from the highest urgency
QL 0:84f3d3d7e5d9 39 SYSTICK_PRIO,
QL 0:84f3d3d7e5d9 40 ENET_PRIO,
QL 0:84f3d3d7e5d9 41 // ...
QL 0:84f3d3d7e5d9 42 };
QL 0:84f3d3d7e5d9 43
QL 0:84f3d3d7e5d9 44 #ifdef Q_SPY
QL 0:84f3d3d7e5d9 45 #include "mbed.h" // mbed is used only for the built-in serial
QL 0:84f3d3d7e5d9 46
QL 0:84f3d3d7e5d9 47 QSTimeCtr l_tickTime;
QL 0:84f3d3d7e5d9 48 QSTimeCtr l_tickPeriod;
QL 0:84f3d3d7e5d9 49
QL 0:84f3d3d7e5d9 50 #define QSPY_BAUD_RATE 115200
QL 0:84f3d3d7e5d9 51
QL 0:84f3d3d7e5d9 52 Serial l_qspy(USBTX, USBRX);
QL 0:84f3d3d7e5d9 53 #endif
QL 0:84f3d3d7e5d9 54
QL 0:84f3d3d7e5d9 55 //............................................................................
QL 0:84f3d3d7e5d9 56 extern "C" void SysTick_Handler(void) {
QL 0:84f3d3d7e5d9 57 QK_ISR_ENTRY(); // inform the QK kernel of entering the ISR
QL 0:84f3d3d7e5d9 58
QL 0:84f3d3d7e5d9 59 #ifdef Q_SPY
QL 0:84f3d3d7e5d9 60 uint32_t volatile dummy = SysTick->CTRL; // clear the COUNTFLAG in SysTick
QL 0:84f3d3d7e5d9 61 l_tickTime += l_tickPeriod; // account for the clock rollover
QL 0:84f3d3d7e5d9 62 #endif
QL 0:84f3d3d7e5d9 63
QL 0:84f3d3d7e5d9 64 QF::tick(); // process all armed time events
QL 0:84f3d3d7e5d9 65
QL 0:84f3d3d7e5d9 66 QK_ISR_EXIT(); // inform the QK kernel of exiting the ISR
QL 0:84f3d3d7e5d9 67 }
QL 0:84f3d3d7e5d9 68
QL 0:84f3d3d7e5d9 69 //............................................................................
QL 0:84f3d3d7e5d9 70 void BSP_init(void) {
QL 0:84f3d3d7e5d9 71 SystemInit(); // initialize the clocking system
QL 0:84f3d3d7e5d9 72
QL 0:84f3d3d7e5d9 73 // set LED port to output
QL 0:84f3d3d7e5d9 74 LED_PORT->FIODIR |= (LED1_BIT | LED2_BIT | LED3_BIT | LED4_BIT);
QL 0:84f3d3d7e5d9 75
QL 0:84f3d3d7e5d9 76 // clear the LEDs
QL 0:84f3d3d7e5d9 77 LED_PORT->FIOCLR = (LED1_BIT | LED2_BIT | LED3_BIT | LED4_BIT);
QL 0:84f3d3d7e5d9 78
QL 0:84f3d3d7e5d9 79 if (QS_INIT((void *)0) == 0) { // initialize the QS software tracing
QL 0:84f3d3d7e5d9 80 Q_ERROR();
QL 0:84f3d3d7e5d9 81 }
QL 0:84f3d3d7e5d9 82 }
QL 0:84f3d3d7e5d9 83 //............................................................................
QL 0:84f3d3d7e5d9 84 void BSP_displyPhilStat(uint8_t n, char const *stat) {
QL 0:84f3d3d7e5d9 85 // represent LEDs in a const array for convenience
QL 0:84f3d3d7e5d9 86 static uint32_t const led[] = { LED1_BIT, LED2_BIT, LED3_BIT, LED4_BIT };
QL 0:84f3d3d7e5d9 87 if (n < 2) {
QL 0:84f3d3d7e5d9 88 if (stat[0] == 'e') {
QL 0:84f3d3d7e5d9 89 LED_PORT->FIOSET = led[n];
QL 0:84f3d3d7e5d9 90 }
QL 0:84f3d3d7e5d9 91 else {
QL 0:84f3d3d7e5d9 92 LED_PORT->FIOCLR = led[n];
QL 0:84f3d3d7e5d9 93 }
QL 0:84f3d3d7e5d9 94 }
QL 0:84f3d3d7e5d9 95
QL 0:84f3d3d7e5d9 96 QS_BEGIN(PHILO_STAT, AO_Philo[n]) // application-specific record begin
QL 0:84f3d3d7e5d9 97 QS_U8(1, n); // Philosopher number
QL 0:84f3d3d7e5d9 98 QS_STR(stat); // Philosopher status
QL 0:84f3d3d7e5d9 99 QS_END()
QL 0:84f3d3d7e5d9 100 }
QL 0:84f3d3d7e5d9 101 //............................................................................
QL 0:84f3d3d7e5d9 102 void QF::onStartup(void) {
QL 0:84f3d3d7e5d9 103 // set up the SysTick timer to fire at BSP_TICKS_PER_SEC rate
QL 0:84f3d3d7e5d9 104 SysTick_Config(SystemCoreClock / BSP_TICKS_PER_SEC);
QL 0:84f3d3d7e5d9 105
QL 0:84f3d3d7e5d9 106 // set priorities of all interrupts in the system...
QL 0:84f3d3d7e5d9 107 NVIC_SetPriority(SysTick_IRQn, SYSTICK_PRIO);
QL 0:84f3d3d7e5d9 108 NVIC_SetPriority(ENET_IRQn, ENET_PRIO);
QL 0:84f3d3d7e5d9 109
QL 0:84f3d3d7e5d9 110 NVIC_EnableIRQ(ENET_IRQn); // enable the Ethernet Interrupt
QL 0:84f3d3d7e5d9 111 }
QL 0:84f3d3d7e5d9 112 //............................................................................
QL 0:84f3d3d7e5d9 113 void QF::onCleanup(void) {
QL 0:84f3d3d7e5d9 114 }
QL 0:84f3d3d7e5d9 115 //............................................................................
QL 0:84f3d3d7e5d9 116 void QK::onIdle(void) {
QL 0:84f3d3d7e5d9 117
QL 0:84f3d3d7e5d9 118 QF_INT_LOCK(dummy);
QL 0:84f3d3d7e5d9 119 LED_PORT->FIOSET = LED4_BIT; // turn the LED4 on
QL 0:84f3d3d7e5d9 120 __NOP(); // delay a bit to see some light intensity
QL 0:84f3d3d7e5d9 121 __NOP();
QL 0:84f3d3d7e5d9 122 __NOP();
QL 0:84f3d3d7e5d9 123 __NOP();
QL 0:84f3d3d7e5d9 124 LED_PORT->FIOCLR = LED4_BIT; // turn the LED4 off
QL 0:84f3d3d7e5d9 125 QF_INT_UNLOCK(dummy);
QL 0:84f3d3d7e5d9 126
QL 0:84f3d3d7e5d9 127 #ifdef Q_SPY
QL 0:84f3d3d7e5d9 128 if (l_qspy.writeable()) {
QL 0:84f3d3d7e5d9 129 QF_INT_LOCK(dummy);
QL 0:84f3d3d7e5d9 130 uint16_t b = QS::getByte();
QL 0:84f3d3d7e5d9 131 QF_INT_UNLOCK(dummy);
QL 0:84f3d3d7e5d9 132 if (b != QS_EOD) {
QL 0:84f3d3d7e5d9 133 l_qspy.putc((uint8_t)b);
QL 0:84f3d3d7e5d9 134 }
QL 0:84f3d3d7e5d9 135 }
QL 0:84f3d3d7e5d9 136 #else
QL 0:84f3d3d7e5d9 137 // Put the CPU and peripherals to the low-power mode. You might need to
QL 0:84f3d3d7e5d9 138 // customize the clock management for your application, see the datasheet
QL 0:84f3d3d7e5d9 139 // for your particular Cortex-M3 MCU.
QL 0:84f3d3d7e5d9 140 //
QL 0:84f3d3d7e5d9 141 // Specifially for the mbed board, see the articles:
QL 0:84f3d3d7e5d9 142 // * "Power Management" http://mbed.org/cookbook/Power-Management; and
QL 0:84f3d3d7e5d9 143 // * "Interface Powerdown" at
QL 0:84f3d3d7e5d9 144 // http://mbed.org/users/simon/notebook/interface-powerdown/
QL 0:84f3d3d7e5d9 145 //
QL 0:84f3d3d7e5d9 146 __WFI();
QL 0:84f3d3d7e5d9 147 #endif
QL 0:84f3d3d7e5d9 148 }
QL 0:84f3d3d7e5d9 149
QL 0:84f3d3d7e5d9 150 //............................................................................
QL 0:84f3d3d7e5d9 151 void Q_onAssert(char const Q_ROM * const Q_ROM_VAR file, int line) {
QL 0:84f3d3d7e5d9 152 (void)file; // avoid compiler warning
QL 0:84f3d3d7e5d9 153 (void)line; // avoid compiler warning
QL 0:84f3d3d7e5d9 154 QF_INT_LOCK(dummy); // make sure that all interrupts are disabled
QL 0:84f3d3d7e5d9 155 // light up all LEDs
QL 0:84f3d3d7e5d9 156 LED_PORT->FIOSET = (LED1_BIT | LED2_BIT | LED3_BIT | LED4_BIT);
QL 0:84f3d3d7e5d9 157
QL 0:84f3d3d7e5d9 158 for (;;) { // NOTE: replace the loop with reset for final version
QL 0:84f3d3d7e5d9 159 }
QL 0:84f3d3d7e5d9 160 }
QL 0:84f3d3d7e5d9 161 //............................................................................
QL 0:84f3d3d7e5d9 162 // sys_now() is used in the lwIP stack
QL 0:84f3d3d7e5d9 163 extern "C" uint32_t sys_now(void) {
QL 0:84f3d3d7e5d9 164 return l_nTicks * (1000 / BSP_TICKS_PER_SEC);
QL 0:84f3d3d7e5d9 165 }
QL 0:84f3d3d7e5d9 166
QL 0:84f3d3d7e5d9 167 //----------------------------------------------------------------------------
QL 0:84f3d3d7e5d9 168 #ifdef Q_SPY
QL 0:84f3d3d7e5d9 169 //............................................................................
QL 0:84f3d3d7e5d9 170 uint8_t QS::onStartup(void const *arg) {
QL 0:84f3d3d7e5d9 171 static uint8_t qsBuf[6*256]; // buffer for Quantum Spy
QL 0:84f3d3d7e5d9 172 initBuf(qsBuf, sizeof(qsBuf));
QL 0:84f3d3d7e5d9 173
QL 0:84f3d3d7e5d9 174 l_qspy.baud(QSPY_BAUD_RATE);
QL 0:84f3d3d7e5d9 175
QL 0:84f3d3d7e5d9 176 l_tickPeriod = SystemCoreClock / BSP_TICKS_PER_SEC;
QL 0:84f3d3d7e5d9 177 l_tickTime = l_tickPeriod; // to start the timestamp at zero
QL 0:84f3d3d7e5d9 178
QL 0:84f3d3d7e5d9 179 // setup the QS filters...
QL 0:84f3d3d7e5d9 180 QS_FILTER_ON(QS_ALL_RECORDS);
QL 0:84f3d3d7e5d9 181
QL 0:84f3d3d7e5d9 182 QS_FILTER_OFF(QS_QEP_STATE_EMPTY);
QL 0:84f3d3d7e5d9 183 QS_FILTER_OFF(QS_QEP_STATE_ENTRY);
QL 0:84f3d3d7e5d9 184 QS_FILTER_OFF(QS_QEP_STATE_EXIT);
QL 0:84f3d3d7e5d9 185 QS_FILTER_OFF(QS_QEP_STATE_INIT);
QL 0:84f3d3d7e5d9 186 QS_FILTER_OFF(QS_QEP_INIT_TRAN);
QL 0:84f3d3d7e5d9 187 QS_FILTER_OFF(QS_QEP_INTERN_TRAN);
QL 0:84f3d3d7e5d9 188 QS_FILTER_OFF(QS_QEP_TRAN);
QL 0:84f3d3d7e5d9 189 QS_FILTER_OFF(QS_QEP_IGNORED);
QL 0:84f3d3d7e5d9 190 QS_FILTER_OFF(QS_QEP_DISPATCH);
QL 0:84f3d3d7e5d9 191
QL 0:84f3d3d7e5d9 192 QS_FILTER_OFF(QS_QF_ACTIVE_ADD);
QL 0:84f3d3d7e5d9 193 QS_FILTER_OFF(QS_QF_ACTIVE_REMOVE);
QL 0:84f3d3d7e5d9 194 QS_FILTER_OFF(QS_QF_ACTIVE_SUBSCRIBE);
QL 0:84f3d3d7e5d9 195 QS_FILTER_OFF(QS_QF_ACTIVE_UNSUBSCRIBE);
QL 0:84f3d3d7e5d9 196 QS_FILTER_OFF(QS_QF_ACTIVE_POST_FIFO);
QL 0:84f3d3d7e5d9 197 QS_FILTER_OFF(QS_QF_ACTIVE_POST_LIFO);
QL 0:84f3d3d7e5d9 198 QS_FILTER_OFF(QS_QF_ACTIVE_GET);
QL 0:84f3d3d7e5d9 199 QS_FILTER_OFF(QS_QF_ACTIVE_GET_LAST);
QL 0:84f3d3d7e5d9 200 QS_FILTER_OFF(QS_QF_EQUEUE_INIT);
QL 0:84f3d3d7e5d9 201 QS_FILTER_OFF(QS_QF_EQUEUE_POST_FIFO);
QL 0:84f3d3d7e5d9 202 QS_FILTER_OFF(QS_QF_EQUEUE_POST_LIFO);
QL 0:84f3d3d7e5d9 203 QS_FILTER_OFF(QS_QF_EQUEUE_GET);
QL 0:84f3d3d7e5d9 204 QS_FILTER_OFF(QS_QF_EQUEUE_GET_LAST);
QL 0:84f3d3d7e5d9 205 QS_FILTER_OFF(QS_QF_MPOOL_INIT);
QL 0:84f3d3d7e5d9 206 QS_FILTER_OFF(QS_QF_MPOOL_GET);
QL 0:84f3d3d7e5d9 207 QS_FILTER_OFF(QS_QF_MPOOL_PUT);
QL 0:84f3d3d7e5d9 208 QS_FILTER_OFF(QS_QF_PUBLISH);
QL 0:84f3d3d7e5d9 209 QS_FILTER_OFF(QS_QF_NEW);
QL 0:84f3d3d7e5d9 210 QS_FILTER_OFF(QS_QF_GC_ATTEMPT);
QL 0:84f3d3d7e5d9 211 QS_FILTER_OFF(QS_QF_GC);
QL 0:84f3d3d7e5d9 212 QS_FILTER_OFF(QS_QF_TICK);
QL 0:84f3d3d7e5d9 213 QS_FILTER_OFF(QS_QF_TIMEEVT_ARM);
QL 0:84f3d3d7e5d9 214 QS_FILTER_OFF(QS_QF_TIMEEVT_AUTO_DISARM);
QL 0:84f3d3d7e5d9 215 QS_FILTER_OFF(QS_QF_TIMEEVT_DISARM_ATTEMPT);
QL 0:84f3d3d7e5d9 216 QS_FILTER_OFF(QS_QF_TIMEEVT_DISARM);
QL 0:84f3d3d7e5d9 217 QS_FILTER_OFF(QS_QF_TIMEEVT_REARM);
QL 0:84f3d3d7e5d9 218 QS_FILTER_OFF(QS_QF_TIMEEVT_POST);
QL 0:84f3d3d7e5d9 219 QS_FILTER_OFF(QS_QF_INT_LOCK);
QL 0:84f3d3d7e5d9 220 QS_FILTER_OFF(QS_QF_INT_UNLOCK);
QL 0:84f3d3d7e5d9 221 QS_FILTER_OFF(QS_QF_ISR_ENTRY);
QL 0:84f3d3d7e5d9 222 QS_FILTER_OFF(QS_QF_ISR_EXIT);
QL 0:84f3d3d7e5d9 223
QL 0:84f3d3d7e5d9 224 QS_FILTER_OFF(QS_QK_MUTEX_LOCK);
QL 0:84f3d3d7e5d9 225 QS_FILTER_OFF(QS_QK_MUTEX_UNLOCK);
QL 0:84f3d3d7e5d9 226 QS_FILTER_OFF(QS_QK_SCHEDULE);
QL 0:84f3d3d7e5d9 227
QL 0:84f3d3d7e5d9 228 QS_FILTER_AO_OBJ(AO_LwIPMgr);
QL 0:84f3d3d7e5d9 229 QS_FILTER_AP_OBJ(AO_LwIPMgr);
QL 0:84f3d3d7e5d9 230
QL 0:84f3d3d7e5d9 231 return (uint8_t)1; // return success
QL 0:84f3d3d7e5d9 232 }
QL 0:84f3d3d7e5d9 233 //............................................................................
QL 0:84f3d3d7e5d9 234 void QS::onCleanup(void) {
QL 0:84f3d3d7e5d9 235 }
QL 0:84f3d3d7e5d9 236 //............................................................................
QL 0:84f3d3d7e5d9 237 QSTimeCtr QS::onGetTime(void) { // invoked with interrupts locked
QL 0:84f3d3d7e5d9 238 if ((SysTick->CTRL & 0x00000100) == 0) { // COUNTFLAG no set?
QL 0:84f3d3d7e5d9 239 return l_tickTime - (QSTimeCtr)SysTick->VAL;
QL 0:84f3d3d7e5d9 240 }
QL 0:84f3d3d7e5d9 241 else { // the rollover occured, but the SysTick_ISR did not run yet
QL 0:84f3d3d7e5d9 242 return l_tickTime + l_tickPeriod - (QSTimeCtr)SysTick->VAL;
QL 0:84f3d3d7e5d9 243 }
QL 0:84f3d3d7e5d9 244 }
QL 0:84f3d3d7e5d9 245 //............................................................................
QL 0:84f3d3d7e5d9 246 void QS::onFlush(void) {
QL 0:84f3d3d7e5d9 247 uint16_t b;
QL 0:84f3d3d7e5d9 248 QF_INT_LOCK(dummy);
QL 0:84f3d3d7e5d9 249 while ((b = QS::getByte()) != QS_EOD) {
QL 0:84f3d3d7e5d9 250 while (!l_qspy.writeable()) { // wait until serial port is writable
QL 0:84f3d3d7e5d9 251 }
QL 0:84f3d3d7e5d9 252 l_qspy.putc((uint8_t)b);
QL 0:84f3d3d7e5d9 253 }
QL 0:84f3d3d7e5d9 254 QF_INT_UNLOCK(dummy);
QL 0:84f3d3d7e5d9 255 }
QL 0:84f3d3d7e5d9 256 #endif // Q_SPY
QL 0:84f3d3d7e5d9 257 //----------------------------------------------------------------------------
QL 0:84f3d3d7e5d9 258
QL 0:84f3d3d7e5d9 259 //////////////////////////////////////////////////////////////////////////////
QL 0:84f3d3d7e5d9 260 // NOTE01:
QL 0:84f3d3d7e5d9 261 // The User LED is used to visualize the idle loop activity. The brightness
QL 0:84f3d3d7e5d9 262 // of the LED is proportional to the frequency of invcations of the idle loop.
QL 0:84f3d3d7e5d9 263 // Please note that the LED is toggled with interrupts locked, so no interrupt
QL 0:84f3d3d7e5d9 264 // execution time contributes to the brightness of the User LED.
QL 0:84f3d3d7e5d9 265 //