Site Map | Contact Us
Quantum Leaps - innovating embedded systems Call us toll-free!
Quantum Developer Zone
Quantum Leaps Discussion Forum

Search the Forum for answers or post your questions to the
Quantum Leaps community


Return to Website

  First
  Prev
  Reply
  Forum
Next  
Last  
Search this Forum:  
Viewing Page 1 of 1 (Total Posts: 7)


Author Comment    
Harry

harrymc@decisions-and-designs.com.au


Feb 8, 08 - 12:04 AM
Immediate transition to substate within ENTRY handler

Hi Miro

Thanks for your book, it's helped me connect OO knowledge with small micro C coding in a way I didn't think was possible. My solution has been arrays of pointers to event handlers (listed as one clumsier method in your book).

I have a design using QPnano which could be described as "semi-polled"; I only arm events (from ISRs) when required.

From the non-compliant[1] UML below, haveData() is a BSP specific service which returns non-zero if an input buffer of data is available to process immediately. If no data is available, haveData() enables an ISR and returns zero to the caller. Later, the ISR posts an InputData event to the task when data becomes available.

Similarly, haveBuffer() returns non-zero if an output buffer is available to process the data (input buffer to output buffer). If no empty buffer is available, haveBuffer() enables an ISR and returns zero to the caller. Later, the ISR posts an OutBuffer event to the task when an empty output buffer becomes available.

Widget HSM diagram


As you can see from the two red arrows, my initial design posted Restart and ChunkReminder events to self on entry to initiate the first sub-state transitions (using guard conditions) and also to break up the processing into smaller time chunks (in WidgetProcessData).

To avoid queue activity (since the WidgetAwaitInputData and WidgetAwaitOutBuffer transitions are trivial and because most of the processing time is in WidgetProcessData) is it bad design to transition immediately to a substate (and do the first work in WidgetProcessData) from within the entry code ?

This would code simply as a drop through in these two states:


static QSTATE Widget_run(Widget *me)
{
switch (Q_SIG(me)) {
case Q_INIT_SIG: {
return (QSTATE)0;
}
case Q_EXIT_SIG: {
widgetDisable();
return (QSTATE)0;
}
case Q_ENTRY_SIG: {
widgetEnable();
} /* drop through into Restart handler */
case Q_RESTART_SIG: {
if (!haveData()) {
Q_TRAN(&Widget_awaitInputData);
return (QSTATE)0;
}
if (!haveBuffer()) {
Q_TRAN(&Widget_awaitOutBuffer);
return (QSTATE)0;
}
Q_TRAN(&Widget_processData);
return (QSTATE)0;
}

/* ... more handler .. */
}
return (QSTATE)&Widget_idle;
}

static QSTATE Widget_processData(Widget *me)
{
switch (Q_SIG(me)) {
case Q_INIT_SIG: {
return (QSTATE)0;
}
case Q_EXIT_SIG: {
return (QSTATE)0;
}
case Q_ENTRY_SIG: {
me->idx = 0;
} /* drop through into ChunkReminder handler */
case Q_CHUNKREMINDER_SIG: {
if (endOfBuffer(me->idx)) {
QF_post(Q_RESTART_SIG);
return (QSTATE)0;
}
ProcessData();
me->idx += CHUNK_SIZE;
QF_post(Q_CHUNKREMINDER_SIG);
return (QSTATE)0;
}
}
return (QSTATE)&Widget_run;
}


I need to go over the QPnano code to see if there is any gotcha in this but is it otherwise acceptable design ? As you can see, the initial state is WidgetIdle so there won't be any sub-state Q_ENTRY events during HSM instantiation.

Best wishes
Harry

[1] PSiCC, 4.3.3 UML-Compliant HSMs, Page 104
Miro Samek

www.quantum-leaps.com


Feb 8th, 2008 - 3:06 PM
Re: Immediate transition to substate within ENTRY handler

Harry,

For my taste, your state machine uses too much of self posting.

New information is provided only through external events, and self posting does not provide any _new_ information to the state machine. My point is that you have all the information necessary to make the decision of the target state _before_ self posting an event. In other words, self-posting an event hides some guards and choice points for a transition.

I like better straightforward state designs that make use of the new information as soon as it becomes available. If this leads to guards and choice points, so be it. This reflects faithfully the complexity of your problem and decisions that your state machine makes upon receiving external events.

Self-posting really introduces an indirection layer of the posted event. The state machine might perhaps look a little cleaner, but it's not necessarily easier to understand.

So, if you ask my opinion, I would leave the Reminder, because it has other function (short RTC step), but I'd try to eliminate self-posing of Restart.

The self-transition ChunkReminder in state "WidgetProcessData" seems incorrect. For one thing, the state already handles ChunkReminder as internal transition with complementary guards. Second, a self-transition would always trigger exit and re-entry, and your entry action would always set idx=0, which doesn't make sense to me.

As to the QP-nano code, I would not recommend falling-through from the entry action. This code does not reflect what the state diagram is saying.

I like your way of thinking though and the general approach to the problem.

Miro
Harry



Feb 11th, 2008 - 4:07 PM
Re: Immediate transition to substate within ENTRY handler

Thanks Miro

Your suggestions were the mental nudge I needed to rework the approach; posted back here in case it is useful for other designs.

After reading your reply I pondered if I'd thought enough about what I wanted Widget to do. To clarify the requirements, I wrote a storyboard:

-//-
A Widget receives a Config event and immediately starts responding to incoming buffers and free outgoing buffers to process data between the two.

If an external task or the Widget task issues a Restart then the Widget abandons any partial processing and restarts processing when a new input buffer and free output buffer are available (neglected to explain the external use of Restart earlier).

A Config0 event returns the Widget to an "unconfigured" or reset state and processing stops (another detail I omitted).
-//-

You explained that "New information is provided only through external events, and self posting does not provide any _new_ information to the state machine. ..."

From your comment, the only _new_ information to get the machine processing is the Config event which _should_ be sufficient to move Widget to immediately start processing.

I also realised that WidgetRun was really only serving to handle Restart events not handled by the three sub-states to provide common behaviour.

So if I merged the WidgetIdle and WidgetRun states together (renamed Widget) some handy commonality emerged. As the diagram below shows, the only difference in behaviour between Config (which could also be called Start) and the Restart event is that Config sets up the configuration of Widget operating
parameters and also the hardware (enableWidget()).

src="http://www.decisions-and-designs.com.au/images/electron/widget_simpler.gif"
alt="Improved Widget HSM diagram">



Config0 turns off the hardware with disableWidget(). I've also deleted clearConfigData() since it is private data and is therefore unused while the HSM is stopped waiting for another Config; so why bother to clear it.

Given that Restart means "start using a new incoming data buffer" I can see that resetting the buffer index (idx) fits into Restart behaviour.

The common behaviour means I could use a drop-through for the new implementation (see code below). While I can see on the diagram the behaviour in Widget state is common , I'm wondering if there is any way to rework the UML so it articulates the final code implementation ? I'd prefer
this than have tidier code being disallowed because the UML diagram prevents it :)


static QSTATE Widget(Widget *me)
{
switch (Q_SIG(me)) {
case Q_INIT_SIG: {
return (QSTATE)0;
}
case Q_EXIT_SIG: {
return (QSTATE)0;
}
case Q_ENTRY_SIG: {
return (QSTATE)0;
}
case Q_CONFIG0_SIG: {
widgetDisable();
return (QSTATE)0;
}
case Q_CONFIG_SIG: {
setConfigData();
widgetEnable();
/* drop through into Restart handler */
/* The rest of the Config behaviour is
* identical to Restart */
}
case Q_RESTART_SIG: {
me->idx = 0;
if (!haveData()) {
Q_TRAN(&Widget_awaitInputData);
return (QSTATE)0;
}
if (!haveBuffer()) {
Q_TRAN(&Widget_awaitOutBuffer);
return (QSTATE)0;
}
Q_TRAN(&Widget_processData);
return (QSTATE)0;
}
}
return (QSTATE)&Widget_idle;
}

static QSTATE Widget_processData(Widget *me)
{
switch (Q_SIG(me)) {
case Q_INIT_SIG: {
return (QSTATE)0;
}
case Q_EXIT_SIG: {
return (QSTATE)0;
}
/* ENTRY has identical behaviour to ChunkReminder event so .. */
case Q_ENTRY_SIG: /* .. drop through into ChunkReminder handler */
case Q_CHUNKREMINDER_SIG: {
if (!endOfBuffer(me->idx)) {
processData(me->idx);
me->idx += CHUNK_SIZE;
}
if (endOfBuffer(me->idx)) {
post(Q_RESTART_SIG);
return (QSTATE)0;
}
post(Q_CHUNKREMINDER_SIG);
return (QSTATE)0;
}
}
return (QSTATE)&Widget_run;
}


I've also deleted the (incorrect) self-transition ChunkReminder. I misunderstood that the internal transition was already documented inside the state.

Thanks for your feedback. A close proximity to this design is something I can use for quite a few processing tasks.

All the best
Harry McNally
Harry



Feb 11th, 2008 - 4:13 PM
Re: Immediate transition to substate within ENTRY handler

Hm. The forum has added a br / (due to line length I think) and mangled the img link on my last post. Can someone with edit permission fix that ?

Thanks
Harry
Harry McNally



Feb 11th, 2008 - 8:00 PM
Re: Immediate transition to substate within ENTRY handler

The diagram link fixed:

Improved Widget State Chart
Miro Samek

www.quantum-leaps.com


Feb 12th, 2008 - 4:30 PM
Re: Immediate transition to substate within ENTRY handler

Harry,

Your state machine looks much tidier now. I’m not in the position to tell if it is exactly doing what you’ve specified, but it looks better than before.

As far as your code goes, you code unnecessarily (and incorrectly!) the nested initial transition. Please check the other posting to this forum “Call to 0x0000 in QHsm_init”, which happened to “bubble up” quite recently. The point is that you actually code initial transition with Q_INIT_SIG _only_ if it is actually in the diagram. You don’t code it _at all_ if you don’t have it in the diagram. The same goes for entry and exit actions.

I still don’t like the fall-through in the entry action.

Miro
Harry McNally



Feb 13th, 2008 - 8:43 PM
Re: Immediate transition to substate within ENTRY handler

Hi Miro

Thanks for the link on correct use of INIT and ENTRY code. I whipped that sample code up and it had a few other errors; now fixed.

Harry


  First
  Prev
  Reply
  Forum
Next  
Last  


powered by Powered by Bravenet bravenet.com