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.
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. //