Hello.
Note for this discussion. Salvo Lite has all of the functionality of Salvo LE and Pro, so you should be able to test anything we discuss here with Salvo Lite, assuming it does not require "extending" Salvo.
OK, I think I see the picture. So how about this approach:
Each state machine has a single task (and therefore priority) associated with it. Each state machine (SM) task looks like this:
code:
void SM1_task (void )
{
typeMySMStruct mySMStruct;
OStypeMsgP msgP;
/* init SM1 */ while (1) {
OS_WaitMsg(..., msgP, ...);
mySMstruct = (appropriate cast) msgP;
mySMStruct.fnP();
or
switch ( mySMStruct.state ) {
case SM1_STATE1:
SM1_STATE1_FN();
etc.
}
}
}
where typeMySMStruct is a struct that contains information for state machines, e.g. function pointers, states, etc. Basically the task waits for the message (or any other event, I just chose messages here) to be signaled, then runs that state, and then reverts to waiting for a transition. If one has already been specified (e.g. at the end of the current state), then it will run the next state as long as this SM task is the highest-priority eligible task.
So the idea here is that each state machine has a "stub" that's waiting to run the function associated with a particular state. Only it's completely general ... what you do is signal a message that contains information on the next state to run, e.g. a state number or a function pointer. In the case above we've used a struct that can contain any amount of data ...
You would probably associate each message with a particular SM task. Then, when you want that SM to run / when that SM transitions, you call OSSignalMsg() from anywhere in your code, and as an argument you pass a properly initialized struct that has the next transition in it.
The benefit of all this is that state transitions become events (a transition includes a call to OSSignalMsg()), and so you don't spend any time polling. You could also use, say, binSems instead, where a transition always means that newState = oldState+1, etc.
The bottom line is that you decide what sort of information accompanies the signalling of an event. You can make this as simple (state++) or as complex (state = stata_i) as you want.
You can signal events from foreground (ISR) or background (mainline, task, etc.) code.
I guess as system complexity grows, you will begin to see the benefit of the event-based approach. But keep in mind that the act of signaling and trips through the scheduler do take more cycles than simply polling a bit or byte. But if you need / want priorities, and your system is normally spending a lot of time polling for state transitions that do not happen, then you'll benefit from Salvo.
Also note that as a byproduct, you could easily have other tasks that are not SM tasks -- with appropriate priorities, etc. they can do other, somewhat "orthogonal" things in your system.
They key thing to realize is that the RTOS approach is very loosely-coupled, whereas the state machine and superloop approaches are very tightly-coupled. The SM tasks above are loosely coupled from a system point of view (because of waiting, priorities, and the presence of other tasks in the system), but their own behavior is very tightly coupled because they remain state machines.
------------------