Search the Forum for answers or post your questions to the
Quantum Leaps community
|
| Home | | | Products | | | Services | | | Downloads | | | Licensing | | | Developer Zone | | | Resources |
![]() |
| Overview | | | Discussion | | | Cookbook | | | Design Patterns | | | Bugs | | | Contributions | | | Credits |
Quantum Leaps Discussion Forum
Search the Forum for answers or post your questions to the |
||
| Return to Website | ||
| Viewing Page 1 of 1 (Total Posts: 7) |
| Author | Comment |
Harry
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. ![]() 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:
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
Feb 8th, 2008 - 3:06 PM |
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 |
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()). 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 :)
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 |
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 |
The diagram link fixed: ![]() |
Miro Samek
Feb 12th, 2008 - 4:30 PM |
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 |
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 |
bravenet.com| Privacy Statement | About Us | Contact Us | © 2004-2005 quantum Leaps. All rights reserved. |