[Tinyos Core WG] Tep 115
Philip Levis
pal at cs.stanford.edu
Mon Feb 12 09:21:05 PST 2007
On Feb 12, 2007, at 7:39 AM, Kevin Klues wrote:
> I really don't like the idea of start() returning SUCCESS when the
> device is already on because it seems strange to me to have to
> signal a startDone() event in these cases. We could just not
> signal the event, but I like to think that whenever you get a
> SUCCESS on start() it will be followed by a startDone(). By simply
> returning FAIL in these cases, this problem could be avoided.
>
> If we return FAIL on these calls, then returning EBUSY when
> starting would be ambiguous since you wouldn't know whether you
> should try and call start() again later or not. You wouldn't want
> to if it was returned while waiting on a startDone(), but you might
> if it was because you were waiting on a stopDone().
>
> With my proposal you would know the following information based on
> all return values...
> SUCCESS - your call to try and start the device succeeded and you
> will receive a startDone() event letting you know if it actually
> started up or not.
> FAIL - You really shouldn't have been calling start() in the first
> place because a) the device is already on or b) you are still
> waiting on a startDone() event at which point you will proceed as
> if your redundant call to start had succeeded.
Right -- the issue is that FAIL tells you that you shouldn't have
called start(), but it doesn't tell you when you can start an
operation. How would you possibly write code to handle FAIL? You
don't know whether an event is coming or not.
This comes down to what the priorities are; is it to allow possibly
faulty code to detect that it has done something wrong, or to
simplify the interface so it's easier to write code that will work
properly? I think you FAIL case falls into the former category.
Here's another approach: the return code to the call should clearly
tell you 2 things:
1) Whether or not you will receive a completion event for the
requested operation;
2) Whether or not you will receive a completion event for the *other*
operation.
There are two options for such a table. This is the first (with FAIL
on redundant operations):
+----------------------+-----------+------------+----------+----------+
| Call | Device On | Device Off | Starting | Stopping |
+======================+===========+============+==========+==========+
| SplitControl.start() | FAIL | SUCCESS | SUCCESS | EBUSY |
| | | FAIL | | |
+----------------------+-----------+------------+----------+----------+
| SplitControl.stop() | SUCCESS | FAIL | EBUSY | SUCCESS |
| | FAIL | | | |
+----------------------+-----------+------------+----------+----------+
| operation | depends | FAIL | FAIL | FAIL |
| | | EOFF | EOFF | EOFF |
| | | EOFF | SUCCESS | |
+----------------------+-----------+------------+----------+----------+
This is the first (with SUCCESS and events on redundant operations):
+----------------------+-----------+------------+----------+----------+
| Call | Device On | Device Off | Starting | Stopping |
+======================+===========+============+==========+==========+
| SplitControl.start() | SUCCESS | SUCCESS | SUCCESS | EBUSY |
| | | FAIL | | |
+----------------------+-----------+------------+----------+----------+
| SplitControl.stop() | SUCCESS | SUCCESS | EBUSY | SUCCESS |
| | FAIL | | | |
+----------------------+-----------+------------+----------+----------+
| operation | depends | FAIL | FAIL | FAIL |
| | | EOFF | EOFF | EOFF |
| | | EOFF | SUCCESS | |
+----------------------+-----------+------------+----------+----------+
In both of these cases, you can follow this logic in a caller:
1) If you receive a SUCCESS, you can expect a completion event;
2) If you receive an EBUSY, you can expect a completion event for the
other operation;
3) If you receive a FAIL, you should not expect an event.
This gives you a pretty clear and simple FSM on the caller side. With
your proposal, the FAIL on redundant operations requires you to keep
an extra bit of state (have I called this but not yet received the
event?) in order to decipher the FAIL.
I think the tradeoff in start() when on and stop() when off is
whether we want to push state into the caller or make the callee
more complex. If start() when on returns FAIL, then the caller needs
to keep track of whether the underlying component is started or not.
This goes back to Joe's comment on Jan 11, 2005 that a getState()
command would be useful. If start() when on returns SUCCESS, then the
callee needs to post a task or otherwise generate a startDone(), but
the caller doesn't have to keep a bit of state.
A third option might be to return a value besides SUCCESS and FAIL in
response to a start() when on... this would make the upper state
machine a lot simpler. E.g.:
SUCCESS: you will receive an event
EBUSY : you will receive an event for the other operation
FAIL: you will not receive an event
EALREADY: system is already in that state
So this:
+----------------------+-----------+------------+----------+----------+
| Call | Device On | Device Off | Starting | Stopping |
+======================+===========+============+==========+==========+
| SplitControl.start() | EALREADY | SUCCESS | SUCCESS | EBUSY |
| | | FAIL | | |
+----------------------+-----------+------------+----------+----------+
| SplitControl.stop() | SUCCESS | EALREADY | EBUSY | SUCCESS |
| | FAIL | | | |
+----------------------+-----------+------------+----------+----------+
| operation | depends | FAIL | FAIL | FAIL |
| | | EOFF | EOFF | EOFF |
| | | EOFF | SUCCESS | |
+----------------------+-----------+------------+----------+----------+
Phil
More information about the Tinyos-2.0wg
mailing list