Difference between revisions of "QL"
From emboxit
m (1 revision) |
|||
Line 598: | Line 598: | ||
<br><br><br><br> | <br><br><br><br> | ||
[[Category:All]] | [[Category:All]] | ||
+ | [[Category:UML]] | ||
+ | [[Category:QL]] |
Latest revision as of 20:11, 5 November 2017
Contents
- 1 Link to start
- 2 Quantum Leap QL UML statecharts
Link to start
- Practical UML Statecharts in C/C++, Second Edition: Event-Driven Programming for Embedded Systems best link to start
Quantum Leap QL UML statecharts
Ultimate Hook
- CHAPTER 5: State Patterns pdf-page 218
- The minimal example 152 lines single source file
- Build with openWatcom make.bat successfully for DOS [2011.08.16]
int main() { printf("Ultimate Hook pattern\nQEP version: %s\n" "Press 'a'..'c' to inject signals A..C\n" "Press 'd' or ESC to inject signal D and quit\n", QEP::getVersion()); l_test.init(); // trigger the initial transition before dispatching events for (;;) { printf("\n"); uint8_t c; c = (uint8_t)getch(); // read one character from the console printf("%c: ", c); QEvent e; switch (c) { case 'a': e.sig = A_SIG; break; case 'b': e.sig = B_SIG; break; case 'c': e.sig = C_SIG; break; case 'd': case 0x1B: e.sig = D_SIG; break; // terminate } l_test.dispatch(&e); // dispatch the event into the state machine } return 0; }
Transition to history
- CHAPTER 5: State Patterns
- PDF Page 258 simple toaster oven, is simple and easy to understand
- Project consists of only one file to make (Watcom)
- make.bat run successfully and build the .exe [2011.08.16]
- Seems to be the easiest example.
- But is used only for the State Patterns chapter...
- Not available for every CPU
- Go for Pelican example.
Pelican example from Book to eZ430-F2013
Practical UML Statecharts book companion home
- Download all-book-examples and place the folder-tree near to root. DO-NOT move the project folders away otherwise can not be build by IAR tool
- .
- .
- The (not easy to find) PATH of the project: Source code in 5 files
- .
- For the chapter-12, MSP430 Pelican example download IAR kickstart MSP430 Here
- IAR tool can not save a debug related file, but can build the project
- Again IAR debug mentions an error, but downloads and controls debug-flow as expected.
- The only available LED on eZ430-F2013 is active, ...seems like Pelican!
- TODO:
- IAR is fast, So do what the yellow letters say:
- Create the second state diagram:
I leave it as an exercise for you to draw the state diagram of the Pedestrian state machine from the source code found in the file <qp>\qpn\examples\msp430\iar\pelican-eZ430\ped.c.
Lets do it
ped.c
*****************************************************************************/ #include "qpn_port.h" #include "bsp.h" #include "pelican.h" /*--------------------------------------------------------------------------*/ typedef struct PedTag { /* Pedestrian active object */ QActive super; /* derived from QActive */ uint8_t retryCtr; } Ped; static QState Ped_initial(Ped *me); /* initial pseudostate-handler */ static QState Ped_wait (Ped *me); static QState Ped_off (Ped *me); enum PedTimeouts { /* various timeouts in ticks */ N_ATTEMPTS = 10, /* number of PED_WAITING attempts */ WAIT_TOUT = BSP_TICKS_PER_SEC * 3, /* wait between posting PED_WAITING */ OFF_TOUT = BSP_TICKS_PER_SEC * 8 /* wait time after posting OFF_SIG */ }; /* Global objects ----------------------------------------------------------*/ Ped AO_Ped; /* the single instance of the Ped active object */ /*..........................................................................*/ void Ped_ctor(void) { QActive_ctor((QActive *)&AO_Ped, (QStateHandler)&Ped_initial); } /* HSM definition ----------------------------------------------------------*/ QState Ped_initial(Ped *me) { return Q_TRAN(&Ped_wait);//------NX--------------------Initial state is 'Ped_wait' } /*..........................................................................*/ QState Ped_wait(Ped *me) { switch (Q_SIG(me)) { case Q_ENTRY_SIG: { BSP_showState(me->super.prio, "wait"); me->retryCtr = N_ATTEMPTS; QActive_arm((QActive *)me, WAIT_TOUT); return Q_HANDLED(); } case Q_TIMEOUT_SIG: { if ((--me->retryCtr) != 0) { QActive_arm((QActive *)me, WAIT_TOUT); QActive_post((QActive *)&AO_Pelican, PEDS_WAITING_SIG); } else { return Q_TRAN(&Ped_off); } return Q_HANDLED(); } } return Q_SUPER(&QHsm_top); //------NX------------------The Higher level STATE, in this case, return to TOP } /*..........................................................................*/ QState Ped_off(Ped *me) { switch (Q_SIG(me)) { case Q_ENTRY_SIG: { BSP_showState(me->super.prio, "off"); QActive_arm((QActive *)me, OFF_TOUT); QActive_post((QActive *)&AO_Pelican, OFF_SIG); return Q_HANDLED(); } case Q_TIMEOUT_SIG: { QActive_post((QActive *)&AO_Pelican, ON_SIG); return Q_TRAN(&Ped_wait); } } return Q_SUPER(&QHsm_top); //------NX------------------The Higher level STATE, in this case, return to TOP }
pelican.c
*****************************************************************************/ #include "qpn_port.h" #include "bsp.h" #include "pelican.h" /* Pelican class -----------------------------------------------------------*/ typedef struct PelicanTag { QActive super; /* derived from QActive */ uint8_t flashCtr; /* pedestrian flash counter */ } Pelican; static QState Pelican_initial (Pelican *me); static QState Pelican_offline (Pelican *me); static QState Pelican_operational (Pelican *me); static QState Pelican_carsEnabled (Pelican *me); static QState Pelican_carsGreen (Pelican *me); static QState Pelican_carsGreenNoPed (Pelican *me); static QState Pelican_carsGreenPedWait(Pelican *me); static QState Pelican_carsGreenInt (Pelican *me); static QState Pelican_carsYellow (Pelican *me); static QState Pelican_pedsEnabled (Pelican *me); static QState Pelican_pedsWalk (Pelican *me); static QState Pelican_pedsFlash (Pelican *me); enum PelicanTimeouts { /* various timeouts in ticks */ CARS_GREEN_MIN_TOUT = BSP_TICKS_PER_SEC * 8, /* min green for cars */ CARS_YELLOW_TOUT = BSP_TICKS_PER_SEC * 3, /* yellow for cars */ PEDS_WALK_TOUT = BSP_TICKS_PER_SEC * 3, /* walking time for peds */ PEDS_FLASH_TOUT = BSP_TICKS_PER_SEC / 5, /* flashing timeout for peds */ PEDS_FLASH_NUM = 5*2, /* number of flashes for peds */ OFF_FLASH_TOUT = BSP_TICKS_PER_SEC / 2 /* flashing timeout when off */ }; /* Global objects ----------------------------------------------------------*/ Pelican AO_Pelican; /* the single instance of the Pelican active object */ /*..........................................................................*/ void Pelican_ctor(void) { QActive_ctor((QActive *)&AO_Pelican, (QStateHandler)&Pelican_initial); } /* HSM definition ----------------------------------------------------------*/ QState Pelican_initial(Pelican *me) { return Q_TRAN(&Pelican_operational); } /*..........................................................................*/ QState Pelican_operational(Pelican *me) { switch (Q_SIG(me)) { case Q_ENTRY_SIG: { BSP_signalCars(CARS_RED); BSP_signalPeds(PEDS_DONT_WALK); return Q_HANDLED(); } case Q_INIT_SIG: { return Q_TRAN(&Pelican_carsEnabled); } case OFF_SIG: { return Q_TRAN(&Pelican_offline); } } return Q_SUPER(&QHsm_top); } /*..........................................................................*/ QState Pelican_carsEnabled(Pelican *me) { switch (Q_SIG(me)) { case Q_EXIT_SIG: { BSP_signalCars(CARS_RED); return Q_HANDLED(); } case Q_INIT_SIG: { return Q_TRAN(&Pelican_carsGreen); } } return Q_SUPER(&Pelican_operational); //NX------------------The Higher level STATE } /*..........................................................................*/ QState Pelican_carsGreen(Pelican *me) { switch (Q_SIG(me)) { case Q_ENTRY_SIG: { QActive_arm((QActive *)me, CARS_GREEN_MIN_TOUT); BSP_signalCars(CARS_GREEN); return Q_HANDLED(); } case Q_INIT_SIG: { return Q_TRAN(&Pelican_carsGreenNoPed); } } return Q_SUPER(&Pelican_carsEnabled); //NX------------------The Higher level STATE } /*..........................................................................*/ QState Pelican_carsGreenNoPed(Pelican *me) { switch (Q_SIG(me)) { case Q_ENTRY_SIG: { BSP_showState(me->super.prio, "carsGreenNoPed"); return Q_HANDLED(); } case PEDS_WAITING_SIG: { return Q_TRAN(&Pelican_carsGreenPedWait); } case Q_TIMEOUT_SIG: { return Q_TRAN(&Pelican_carsGreenInt); } } return Q_SUPER(&Pelican_carsGreen); //NX------------------The Higher level STATE } /*..........................................................................*/ QState Pelican_carsGreenPedWait(Pelican *me) { switch (Q_SIG(me)) { case Q_ENTRY_SIG: { BSP_showState(me->super.prio, "carsGreenPedWait"); return Q_HANDLED(); } case Q_TIMEOUT_SIG: { return Q_TRAN(&Pelican_carsYellow); } } return Q_SUPER(&Pelican_carsGreen); //NX------------------The Higher level STATE } /*..........................................................................*/ QState Pelican_carsGreenInt(Pelican *me) { switch (Q_SIG(me)) { case Q_ENTRY_SIG: { BSP_showState(me->super.prio, "carsGreenInt"); return Q_HANDLED(); } case PEDS_WAITING_SIG: { return Q_TRAN(&Pelican_carsYellow); } } return Q_SUPER(&Pelican_carsGreen); //NX------------------The Higher level STATE } /*..........................................................................*/ QState Pelican_carsYellow(Pelican *me) { switch (Q_SIG(me)) { case Q_ENTRY_SIG: { BSP_showState(me->super.prio, "carsYellow"); QActive_arm((QActive *)me, CARS_YELLOW_TOUT); BSP_signalCars(CARS_YELLOW); return Q_HANDLED(); } case Q_TIMEOUT_SIG: { return Q_TRAN(&Pelican_pedsEnabled); } } return Q_SUPER(&Pelican_carsEnabled); //NX------------------The Higher level STATE } /*..........................................................................*/ QState Pelican_pedsEnabled(Pelican *me) { switch (Q_SIG(me)) { case Q_EXIT_SIG: { BSP_signalPeds(PEDS_DONT_WALK); return Q_HANDLED(); } case Q_INIT_SIG: { return Q_TRAN(&Pelican_pedsWalk); } } return Q_SUPER(&Pelican_operational); //NX------------------The Higher level STATE } /*..........................................................................*/ QState Pelican_pedsWalk(Pelican *me) { switch (Q_SIG(me)) { case Q_ENTRY_SIG: { BSP_showState(me->super.prio, "pedsWalk"); QActive_arm((QActive *)me, PEDS_WALK_TOUT); BSP_signalPeds(PEDS_WALK); return Q_HANDLED(); } case Q_TIMEOUT_SIG: { return Q_TRAN(&Pelican_pedsFlash); } } return Q_SUPER(&Pelican_pedsEnabled); //NX------------------The Higher level STATE } /*..........................................................................*/ QState Pelican_pedsFlash(Pelican *me) { switch (Q_SIG(me)) { case Q_ENTRY_SIG: { BSP_showState(me->super.prio, "pedsWalk"); QActive_arm((QActive *)me, PEDS_FLASH_TOUT); me->flashCtr = PEDS_FLASH_NUM*2 + 1; return Q_HANDLED(); } case Q_TIMEOUT_SIG: { if (me->flashCtr != 0) { /* still flashing? */ if ((me->flashCtr & 1) == 0) { /* even counter? */ BSP_signalPeds(PEDS_DONT_WALK); } else { /* must be odd counter */ BSP_signalPeds(PEDS_BLANK); } --me->flashCtr; QActive_arm((QActive *)me, PEDS_FLASH_TOUT); } else { /* done flashing */ return Q_TRAN(&Pelican_carsEnabled); } return Q_HANDLED(); } } return Q_SUPER(&Pelican_pedsEnabled); } /*..........................................................................*/ QState Pelican_offline(Pelican *me) { switch (Q_SIG(me)) { case Q_ENTRY_SIG: { BSP_showState(me->super.prio, "offline"); QActive_arm((QActive *)me, OFF_FLASH_TOUT); me->flashCtr = 0; return Q_HANDLED(); } case Q_TIMEOUT_SIG: { QActive_arm((QActive *)me, OFF_FLASH_TOUT); if ((me->flashCtr & 1) == 0) { /* even counter? */ BSP_signalCars(CARS_RED); BSP_signalPeds(PEDS_DONT_WALK); } else { BSP_signalCars(CARS_OFF); BSP_signalPeds(PEDS_BLANK); } me->flashCtr ^= 1; /* toggle the flash counter */ return Q_HANDLED(); } case ON_SIG: { return Q_TRAN(&Pelican_operational); } } return Q_SUPER(&QHsm_top); }
QM graphical UML modeling tool
QM graphical UML modeling tool home
- View the 6 tutorials
QP™ Development Kits (QDKs) for Arduino™
tested 2011.07.22.22:05
- qp_pelican worked as expected
- qm_pelican generates 4 files (.cpp and .h) but not a sketch (.pde)
- By copying the qp_pelican.pde to qm_pelican it works BUT can not save the project, the 4 files are read-only
- TODO: check in the pdf the .pde structure. Is very simple, can be written by hand, not needed the QM for this. The other files are big and created by QM
- It seems that the bootloader inside Arduino is erased after every download??? It needs to download again with AVR_studio4 programmer from ISP
The structure of an Arduino sketch for QP
- Sketch = a group of files
- Main sketch file is the .pde
- Other files .cpp .h
- Sketch consists of 4 groups:
- setup
- events
- active objects
- BSP
- setup function in the .pde
- events are shared, so defined in the .h
- active-objects: one active object per .cpp
The structure of [.pde] setup() function
#include "qp_port.h" #include "dpp.h" #include "bsp.h" // Local-scope objects ------------------------------------------------------- static QEvent const *l_tableQueueSto[N_PHILO]; static QEvent const *l_philoQueueSto[N_PHILO][N_PHILO]; static QSubscrList l_subscrSto[MAX_PUB_SIG]; static TableEvt l_smlPoolSto[2*N_PHILO]; // storage for the small event pool //............................................................................ void setup() { BSP_init(); // initialize the BSP QF::init(); // initialize the framework and the underlying RT kernel // initialize event pools... QF::poolInit(l_smlPoolSto, sizeof(l_smlPoolSto), sizeof(l_smlPoolSto[0])); QF::psInit(l_subscrSto, Q_DIM(l_subscrSto)); // init publish-subscribe // start the active objects... uint8_t n; for (n = 0; n < N_PHILO; ++n) { AO_Philo[n]->start((uint8_t)(n + 1), l_philoQueueSto[n], Q_DIM(l_philoQueueSto[n])); } AO_Table->start((uint8_t)(N_PHILO + 1), l_tableQueueSto, Q_DIM(l_tableQueueSto)); }
- include
- storage allocation for
- event-qeues
- publish-subscribe
- framework-event-pools
- setup()
- initialize
- BSP
- Framework and RT-kernel
- Event-Pools
- Publish-Subscribe,
- Start the active objects
- initialize
The structure of [.h] application events and signals
#ifndef dpp_h #define dpp_h enum DPPSignals { EAT_SIG = Q_USER_SIG, // published by Table to let a philosopher eat DONE_SIG, // published by Philosopher when done eating TERMINATE_SIG, // published by BSP to terminate the application MAX_PUB_SIG, // the last published signal HUNGRY_SIG, // posted from hungry Philosopher to Table MAX_SIG // the last signal }; struct TableEvt : public QEvent { uint8_t philoNum; // philosopher number }; enum { N_PHILO = 5 }; // number of philosophers extern QActive * const AO_Philo[N_PHILO]; // "opaque" pointers to Philo AO extern QActive * const AO_Table; // "opaque" pointer to Table AO #endif // dpp_h
- All signals in a single enumeration
- Expand classes [To check this...]
- "opaque" pointers to active objects
HOTO start
HERE Arduino
- read this first: Application note in pdf explains everything
The PELICAN crossing example for QM™ (located in <qp_arduino.zip>/examples/qp/ qm_pelican/, see Listing 3) takes Arduino programming to the next level. Instead of coding the state machines by hand, you draw them with the free QM™ modeling tool, attach simple action code to states and transitions, and you generate the complete Arduino sketch automatically—literally by a press of a button
Modifying the Examples to Reduce Power Consumption As mentioned in Section 1.2, the QP/C++ framework allows you to take advantage of the Arduino processor's low-power sleep mode, which is the only way to achieve really low-power design. Both provided examples can be very easily modified to switch to the sleep mode when no events are available. In fact, the code is already provided for you, so all you need to do is just to enable this code. As shown in Figure 12, you select the file bsp.cpp (Board Support Package) and uncomment the definition of the SAVE_POWER macro.
After you recompile the code and download to Arduino, you will see that the User LED is no longer glowing. Actually, it is glowing, but only for a few microseconds out of every 10 milliseconds, so you cannot see it. This very low brightness of the User LED means that the Arduino Background loop uses very little power, yet the application performs exactly as before! The upcoming Section 4.1 explains what exactly happens when you define the macro SAVE_POWER in bsp.cpp.
ALL Tool and Development-Kits Downloads
NOTE: Each QDK™ contains only the software dependent on the particular processor, operating system, or the compiler, but does NOT contain the portable QP™ Baseline Code. In other words, you need to install the QP baseline code, before you install any port
Articles / Books
- Articles by Quantum Leaps state-machine.com
HAREL
- STATECHARTS: A VISUAL FORMALISM FOR COMPLEX SYSTEMS weizmann institute
- It is the basis of UML-Statecharts
- D. Harel and M. Politi, Modeling Reactive Systems with Statecharts: The STATEMATE Approach, (with M. Politi), McGraw-Hill, 1998.
- Book free downoload from weizmann institute
- STATEMATE now belongs to IBM
- RHAPSODY(IBM) is gaining the market, while STATEMATE not
UML
- UML wikipedia
UML diagrams represent two different views of a system model:[11] Static (or structural) view: emphasizes the static structure of the system using objects, attributes, operations and relationships. The structural view includes: class diagrams and composite structure diagrams. Dynamic (or behavioral) view: emphasizes the dynamic behavior of the system by showing collaborations among objects and changes to the internal states of objects. This view includes sequence diagrams, activity diagrams and state machine diagrams.
The UML notation and semantics are really geared toward computerized UML tools. A UML state machine, as represented in a tool, is not just the state diagram, but rather a mixture of graphical and textual representation that precisely captures both the state topology and the actions. The users of the tool can get several complementary views of the same state machine, both visual and textual, whereas the generated code is just one of the many available views.