QuantumLeaps / qpc

QP/C Real-Time Embedded Framework/RTOS for embedded systems based on active objects (actors) and hierarchical state machines
https://www.state-machine.com/products/qp
961 stars 251 forks source link

can a state Q_TRAN to SPUER? like Blinky_on back to Blinky_idle in fllowing code #21

Closed hehao9051 closed 2 years ago

hehao9051 commented 2 years ago

/........................................................................../ QState Blinky_idle(Blinky const me, QEvt const const e) { QState status; switch (e->sig) { case Q_ENTRY_SIG: { BSP_ledOff(); status = Q_HANDLED(); break; } case KEY_POWER_SIG: { status = Q_TRAN(&Blinky_off); break; } default: { status = Q_SUPER(&QHsm_top); break; } } return status; } /........................................................................../ QState Blinky_off(Blinky const me, QEvt const const e) { QState status; switch (e->sig) { case Q_ENTRY_SIG: { BSP_ledOff(); status = Q_HANDLED(); break; } case KEY_POWER_SIG: { status = Q_TRAN(&Blinky_idle); break; } case TIMEOUT_SIG: { status = Q_TRAN(&Blinky_on); break; } default: { status = Q_SUPER(&Blinky_idle); break; } } return status; } /........................................................................../ QState Blinky_on(Blinky const me, QEvt const const e) { QState status; switch (e->sig) { case Q_ENTRY_SIG: { BSP_ledOn(); status = Q_HANDLED(); break; } case KEY_POWER_SIG: { status = Q_TRAN(&Blinky_idle); break; } case TIMEOUT_SIG: { status = Q_TRAN(&Blinky_off); break; } default: { status = Q_SUPER(&Blinky_idle); break; } } return status; }

quantum-leaps commented 2 years ago

Of course. A transition can target any state, including the superstate of the source state and the source state itself (transition to self). This question and any other question of this type is "answered" by the QHsmTst state machine (see Figure 2.11 in the PSiCC2 book).

Fig2 11_corr

I would also highly recommend that you watch the video "State Machines Part-8: Semantics of Hierarchical State Machines"

hehao9051 commented 2 years ago

static QState Blinky_initial(Blinky const me, void const const par) { /.${AOs::Blinky::SM::initial} / (void)par; / unused parameter / QTimeEvt_armX(&me->timeEvt, BSP_TICKS_PER_SEC/2, BSP_TICKS_PER_SEC/2);

QS_FUN_DICTIONARY(&Blinky_off);
QS_FUN_DICTIONARY(&Blinky_on);

return Q_TRAN(&Blinky_off);

}

/.${AOs::Blinky::SM::off} ................................................./ static QState Blinkyidle(Blinky const me, QEvt const const e) { QState status; switch (e->sig) { /.${AOs::Blinky::SM::off} / case Q_ENTRY_SIG: { PRINTF_S("%s\n", "Blinkyidle entry"); status = Q_HANDLED(); break; } case Q_INIT_SIG: { PRINTF_S("%s\n", "Blinkyidle init"); status = Q_HANDLED(); break; } /.${AOs::Blinky::SM::off::TIMEOUT} / case TIMEOUTSIG: { status = Q_TRAN(&Blinkyon); break; } default: { status = Q_SUPER(&QHsmtop); break; } } return status; }

/.${AOs::Blinky::SM::on} ................................................../ static QState Blinkyon(Blinky const me, QEvt const const e) { QState status; switch (e->sig) { /.${AOs::Blinky::SM::on} / case Q_ENTRY_SIG: { BSPledOn(); status = Q_HANDLED(); break; } /.${AOs::Blinky::SM::on::TIMEOUT} / case TIMEOUTSIG: { status = Q_TRAN(&Blinkyoff); break; } default: { status = Q_SUPER(&Blinkyidle); break; } } return status; } /.$enddef${AOs::Blinky} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^/

/.${AOs::Blinky::SM::off} ................................................./ static QState Blinkyoff(Blinky const me, QEvt const const e) { QState status; switch (e->sig) { /.${AOs::Blinky::SM::off} / case Q_ENTRY_SIG: { BSPledOff(); status = Q_HANDLED(); break; } /.${AOs::Blinky::SM::off::TIMEOUT} / case TIMEOUTSIG: { status = Q_TRAN(&Blinkyidle); break; } default: { status = Q_SUPER(&Blinkyidle); break; } } return status; }

like this code, when Blinky_off Q_TRAN(&Blinky_idle),in Blinky_off state , there is no Q_ENTRY_SIG event ,only have Q_INIT_SIG, Is that right? I need help. @quantum-leaps

quantum-leaps commented 2 years ago

It's OK not to provide Q_ENTRY_SIG, Q_EXIT_SIG, or Q_INIT_SIG in a state handler. If you don't have anything to do upon entry, exit, or nested initial transition you simply don't provide that. I hope this clarifies the situation. --MME