0% found this document useful (0 votes)
54 views7 pages

Gomez ESP2000

Uploaded by

sapa3
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
54 views7 pages

Gomez ESP2000

Uploaded by

sapa3
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 7

MARTIN GOMEZ

f e a t u r e

Embedded State
Machine
Implementation
Turning a state machine into a program can be pretty
straightforward if you follow the advice of a skilled
practitioner.

M
any embedded software applications are natural candi-
dates for mechanization as a state machine. A program
that must sequence a series of actions, or handle inputs
differently depending on what mode it’s in, is often best
implemented as a state machine.
This article describes a simple approach to implement-
ing a state machine for an embedded system. Over the last 15 years, I have
used this approach to design dozens of systems, including a softkey-based
user interface, several communications protocols, a silicon-wafer transport
mechanism, an unmanned air vehicle’s lost-uplink handler, and an orbital
mechanics simulator.

State machines
For purposes of this article, a state machine is defined as an algorithm that
can be in one of a small number of states. A state is a condition that causes
a prescribed relationship of inputs to outputs, and of inputs to next states.
A savvy reader will quickly note that the state machines described in this
article are Mealy machines. A Mealy machine is a state machine where the
outputs are a function of both present state and input, as opposed to a
Moore machine, in which the outputs are a function only of state.1 In both
cases, the next state is a function of both present state and input. Pressman

40 DECEMBER 2000 Embedded Systems Programming


One of the advantages of a state machine is that it forces the
programmer to think of all the cases and, therefore, to
extract all the required information from the user.

has several examples of state transition


diagrams used to document the
design of a software product.2 FIGURE 1 A simple state machine to parse a character string, looking for “//”
A simple example of a state input char = '/' /no output
machine is a protocol parser. Suppose
input char = '/'
you had to parse a string of text, look- / output end signal
Start
ing for the token “//”. Figure 1 shows Find 1st "/" Find 2nd "/"
a state machine to do that. In this Done!
example, the first occurrence of a
slash produces no output, but causes input char<> '/' /no output
the machine to advance to the second
state. If it encounters a non-slash while
in the second state, then it will go back cally actuated. An electrically driven Clearly, that’s important, but the
to the first state, because the two slash- hydraulic pump supplies pressure to user thinks he’s done. What about all
es must be adjacent. If it finds a sec- the hydraulic actuators. Our software the other cases? Is it okay to retract the
ond slash, however, then it produces can turn the pump on and off. A gear the instant the airplane leaves the
the “we’re done” output. direction valve is set by the computer ground? What if it simply bounced a
The state machine approach I rec- to either “up” or “down,” to allow the bit due to a bump in the runway? What
ommend proceeds as follows: hydraulic pressure to either raise or if the pilot moved the gear lever into
lower the landing gear. Each leg of the “up” position while he was parked,
• Learn what the user wants the gear has two limit switches: one and subequently takes off? Should the
• Sketch the state transition diagram that closes if the gear is up, and landing gear then come up?
• Code the skeleton of the state another that closes when it’s locked One of the advantages of thinking
machine, without filling in the in the down position. To determine if in state machine terms is that you can
details of the transition actions the airplane is on the ground, a limit quickly draw a state transition dia-
• Make sure the transitions work switch on the nose gear strut will gram on a whiteboard, in front of the
properly close if the weight of the airplane is user, and walk him through it. A com-
• Flesh out the transition details on the nose gear (commonly referred mon notation designates state transi-
• Test to as a “squat switch”). The pilot’s tions as follows: <event that caused
controls consist of a landing gear the transition>/<output as a result of
An example up/down lever and three lights (one the transition>.2 If we simply designed
A more illustrative example is a pro- per leg) that can either be off, glow what the user initially asked us for
gram that controls the retraction green (for down), or glow red (for in (“don’t retract the gear if the airplane
and extension of an airplane’s land- transit). is on the ground”), what he’d get
ing gear. While in most airplanes Let us now design the state would look a bit like Figure 2. It would
this is done with an electrohydraulic machine. The first step, and the hard- exhibit the “bad” behavior mentioned
control mechanism (simply because est, is to figure out what the user real- previously.
they don’t have a computer on ly wants the software to do. One of the Keep the following in mind when
board), cases exist—such as advantages of a state machine is that it designing the state transition diagram
unmanned air vehicles—where one forces the programmer to think of all (or indeed any embedded algorithm):
would implement the control mech- the cases and, therefore, to extract all
anism in software. the required information from the • Computers are very fast compared
Let’s describe the hardware in our user. Why do I describe this as the to mechanical hardware—you may
example so that we can later define hardest step? How many times have have to wait
RUPERT ADLEY

the software that controls it. The you been given a one-line problem • The mechanical engineer who’s
landing gear on this airplane consists description similar to this one: don’t describing what he wants probably
of a nose gear, a left main gear, and a retract the gear if the airplane is on doesn’t know as much about com-
right main gear. These are hydrauli- the ground. puters or algorithms as you do.

Embedded Systems Programming DECEMBER 2000 41


state machines

How will your program behave if a mechanical or electrical part


breaks? Provide for timeouts, sanity checks, and so on. machine. Listing 1 is my implementa-
tion of the state machine in Figure 3.
Let’s discuss a few features of the
example code. First, you’ll notice that
FIGURE 2 A state machine fragment that does only what the user requested the functionality of each individual
state is implemented by its own C func-
gear lever = up && not on ground / pump on, dir = up tion. You could just as easily imple-
ment it as a switch statement, with a
Start separate case for each state. However,
Gear Down RaisingGear this can lead to a very long function
(imagine 10 or 20 lines of code per
state for each of 20 or 30 states.) It can
gear lever = down / pump on, dir = down also lead you astray when you change
the code late in the testing phase—
perhaps you’ve never forgotten a
Good thing, too—otherwise you we rule out the “someone moved the break statement at the end of a case,
would be unnecessary! lever while the airplane was parked” but I sure have. Having one state’s
• How will your program behave if a problem. Also, we take into account code “fall into” the next state’s code is
mechanical or electrical part that the pilot might change his mind. usually a no-no.
breaks? Provide for timeouts, sanity Remember, the landing gear takes a To avoid the switch statement, you
checks, and so on few seconds to retract or extend, and can use an array of pointers to the
we have to handle the case where the individual state functions. The index
We can now suggest the following pilot reversed the lever during the into the array is the curr_state, which
state machine to the user, building process. Note, too, that if the airplane is declared as an enumerated type to
upon his requirements by adding a touches down again while we’re in the help our tools enforce correctness.
few states and transitions at a time. “Waiting for takeoff” state, the timer For simplicity, all the hardware I/O
The result is shown in Figure 3. Here, restarts—the airplane has to be air- (reading switches, turning pumps on
we want to preclude gear retraction borne for two seconds before we’ll and off, and so on) is represented as a
until the airplane is definitely air- retract the gear. simple variable access. It’s assumed
borne, by waiting a couple of seconds that these variables are “magic
after the squat switch opens. We also Implementation addresses” that are associated with the
want to respond to a rising edge of the This is a good point to introduce a hardware through invisible means.
pilot’s lever, rather than a level, so that clean way to code a finite state The next obvious thing is that the

FIGURE 3 The result of finding out what the user really wants

pilot's lever rising edge && squat_switch


= AIR/ start timer, lights = RED timer = 2 sec./pump on, dir = UP

Start Waiting
Gear Down for RaisingGear
Takeoff

pilot's lever down/dir = DOWN


squat switch = GND or pilot's
lever down / restart timer

pilot's lever up/dir = UP


All 3 down switches made/
pump off, lights = GREEN
Lowering Gear Up
Gear All 3 up switches are
made /pump off,
extinguish lights

pilot's lever down /lights = RED, pump on, dir = DOWN

42 DECEMBER 2000 Embedded Systems Programming


state machines

code doesn’t do much at this point. It


LISTING 1 Landing gear implementation just transitions from state to state. This
is an important intermediate step, and
typedef enum {GEAR_DOWN = 0, WTG_FOR_TKOFF, RAISING_GEAR, GEAR_UP, you shouldn’t skip it lightly. It would
LOWERING_GEAR} State_Type; be a good idea to add some #ifdef
DEBUG’d print statements that cause
/* This table contains a pointer to the function to call in each state.*/ each function to print “I’m in state
void (*state_table[])() = {GearDown, WtgForTakeoff, RaisingGear, GearUp, xxx” as well as the value of the inputs.
LoweringGear}; Half the battle is in the code that
induces the state transitions, that is,
State_Type curr_state; detecting that the input events have
occurred. Once the code is cycling
main() through states correctly, the next step
{
is to fill in the “meat” of the code,
InitializeLdgGearSM();
namely that which produces the out-
put. Remember that each transition
/* The heart of the state machine is this one loop. The function
has an input (the event that caused it),
corresponding to the current state is called once per iteration. */
and an output (the hardware I/O, in
while (1)
our example). It is often helpful to
{
state_table[curr_state]();
write this down as a state transition
DecrementTimer();
table. Keller and Shumate use a for-
mat similar to the one in Table 1, to
/* Do other functions, not related to this state machine.*/ which I’ve added an explicit listing of
} all the inputs and outputs.3 Here, we’ll
}; fill out the state transitions.
There is one line per state transi-
void InitializeLdgGearSM() tion in the state transition table. In
{ our relatively simple example, the
curr_state = GEAR_DOWN; “action” code is a very direct mapping
timer = 0.0; from the state transition table. This, as
you can imagine, is not always the
/* Stop all the hardware, turn off the lights, etc.*/ case.
} In coding a state machine, try to
preserve its greatest strength, name-
void GearDown() ly, the eloquently visible match
{ between the user’s requirements and
/* Raise the gear upon command, but not if the airplane is on the ground.*/
the code. It may be necessary to hide
if ((gear_lever == UP) && (prev_gear_lever == DOWN) && (squat_switch == UP))
hardware details in another layer of
{
functions, for instance, to keep the
timer = 2.0;
state machine’s code looking as
curr_state = WTG_FOR_TKOFF;
much as possible like the state tran-
};
sition table and the state transition
prev_gear_lever = gear_lever; /* Store for edge detection.*/
diagram. That symmetry helps pre-
}
vent mistakes, and is the reason why
state machines are such an impor-
void RaisingGear() tant part of the embedded software
{ engineer’s arsenal. Sure, you could
/* Once all 3 legs are up, go to the GEAR_UP state.*/ do the same thing by setting flags
if ((nosegear_is_up == MADE) && (leftgear_is_up == MADE) && (rtgear_is_up and having countless nested if state-
== MADE)) ments, but it would be much harder
{ to look at the code and compare it to
what the user wants. The code frag-
Listing 1 continued on p. 46 ment in Listing 2 fleshes out the
RaisingGear() function.

44 DECEMBER 2000 Embedded Systems Programming


state machines

LISTING 1, continued Landing gear implementation

curr_state = GEAR_UP;
};

/* If the pilot changes his mind, start lowering the gear.*/


if (gear_lever == DOWN)
{
curr_state = LOWERING_GEAR;
};
}

void GearUp()
{
/* If the pilot moves the lever to DOWN, lower the gear.*/
if (gear_lever == DOWN)
{
curr_state = LOWERING_GEAR;
};
}

void WtgForTakeoff()
{
/* Once we ve been airborne for 2 sec., start raising the gear.*/
if (timer <= 0.0)
{
curr_state = RAISING_GEAR;
};

/* If we touch down again, or if the pilot changes his mind, start over.*/
if ((squat_switch == DOWN) || (gear_lever == DOWN))
{
timer = 2.0;
curr_state = GEAR_DOWN;

/* Don't want to require that he toggle the lever again


this was just a bounce.*/
prev_gear_lever = DOWN;
};
}

void LoweringGear()
{
if (gear_lever == UP)
{
curr_state = RAISING_GEAR;
};

if ((nosegear_is_down == MADE) && (leftgear_is_down == MADE) &&


(rtgear_is_down == MADE))
{
curr_state = GEAR_DOWN;
};
}

46 DECEMBER 2000 Embedded Systems Programming


state machines

The beauty of coding even simple algorithms as state machines is


that the test plan almost writes itself. All you have to do is to go reduces the advantage that the state
through every state transition. machine conveys.
As an exercise, you may want to
expand the state machine we’ve
Notice that the code for code that says “Do this in one mode described to add a timeout to the
RaisingGear() attempts to mirror the but do that in another mode,” I’d extension or retraction cycle, because
two rows in the state transition table start to wonder if that state shouldn’t our mechanical engineer doesn’t want
for the Raising Gear state. be split into two. This choice would the hydraulic pump to run for more
One guideline to keep in mind is depend on how much stuff was con- than 60 seconds. If the cycle times out,
“Avoid hidden states.” A hidden state tained in the conditional. If your the pilot should be alerted by alternat-
is what you get (or more honestly, code is handling the same input in ing green and red lights, and he
what I got) when, out of laziness, you different ways (that is, triggering dif- should be able to cycle the lever to try
try to add a conditional substate ferent state transitions) depending again. Another feature to exercise
rather than explicitly add a state. For on a mode flag, then that’s a hidden your skills would be to ask our hypo-
instance, if your state function has state. To implement it that way thetical mechanical engineer “Does
the pump suffer from having the
direction reversed while it’s running?
LISTING 2 The RaisingGear() function We do it in the two cases where the
pilot changes his mind.” He’ll say
void RaisingGear() “yes,” of course. How would you modi-
{ fy the state machine to stop the pump
/* Once all 3 legs are up, go to the GEAR_UP state.*/ briefly when the direction is forced to
if ((nosegear_is_up == MADE) && (leftgear_is_up == MADE) && (rtgear_is_up reverse?
== MADE))
{ Testing
pump_motor = OFF; The beauty of coding even simple
gear_lights = EXTINGUISH; algorithms as state machines is that
curr_state = GEAR_UP; the test plan almost writes itself. All
}; you have to do is to go through every
state transition. I usually do it with a
/* If the pilot changes his mind, start lowering the gear.*/ highlighter in hand, crossing off the
if (gear_lever == DOWN) arrows on the state transition diagram
{ as they successfully pass their tests.
pump_direction = DOWN; This is a good reason to avoid “hidden
curr_state = GEAR_LOWERING; states”—they’re more likely to escape
}; testing than explicit states. Until you
} can use the “real” hardware to induce
state changes, either do it with a

TABLE 1 State transition table

Current State Inputs Outputs

3 are 3 are Squat Timer Pilot’s Pump Dir Timer Lights Next State
up down switch lever on/off
Gear down X X Air X Rising edge NC NC Start RED Waiting for takeoff
Waiting for X X X 2 sec X ON UP stop NC Raising gear
takeoff
Waiting for X X GND X Down NC X Restart NC Gear down
takeoff
Raising gear Made X X X X OFF NC NC OFF Gear up
Raising gear X X X X Down NC DN NC NC Lowering gear
Gear up X X X X Down ON DN X RED Lowering gear
Lowering gear X X X X Up NC UP NC NC Raising gear
Lowering gear X Made X X X OFF NC NC GREEN Gear down

NC = No change in output X = Don’t care input

48 DECEMBER 2000 Embedded Systems Programming


state machines

Once the user’s requirements are fleshed out, I can crank out a state didn’t expect them to? Ideally, the out-
machine of this complexity in a couple of days. They almost always do put of your printfs would look a lot
what I want them to do. like the state transition table.
Finally, and this applies to all
embedded software and not just to
that based on state machines, be sus-
source-level debugger, or build an It is very handy to include print picious when you connect your soft-
“input poker” utility that lets you write statements that output the current ware to the actual hardware for the
the values of the inputs into your state, the value of the inputs, and the first time. It’s very easy to get the
application. value of the outputs each time through polarity wrong—“Oh, I thought a ‘1’
This requires a fair amount of the loop. This lets you easily observe meant raise the gear and a ‘0’ meant
patience and coffee, because even a what ought to be the Golden Rule of lower the gear.” On many occasions,
mid-size state machine can have 100 Software Testing: don’t just check that my hardware counterpart inserted a
different transitions. However, the it does what you want—also check that temporary “chicken switch” to protect
number of transitions is an excellent it doesn’t do what you don’t want. In his precious components until he was
measure of the system’s complexity. other words, are you getting only the sure my software wasn’t going to move
The complexity is driven by the user’s outputs that you expect? It’s easy to ver- things the wrong way.
requirements: the state machine ify that you get the outputs that you
makes it blindingly obvious how much expected, but what else is happening? Crank it
you have to test. With a less-organized Are there “glitch” state transitions, that Once the user’s requirements are
approach, the amount of testing is, states that are passed through inad- fleshed out, I can crank out a state
required might be equally large—you vertently, for only one cycle of the loop? machine of this complexity in a couple
just won’t know it. Are any outputs changing when you of days. They almost always do what I
want them to do. The hard part, of
course, is making sure that I understand
what the user wants, and ensuring that
the user knows what he wants—that
takes considerably longer! esp

Martin Gomez is a software engineer at the


Johns Hopkins University Applied Physics
Lab, where he is presently developing flight
software for a solar research spacecraft. He
has been working in the field of embedded
software development for 17 years. Martin
has a BS in aerospace engineering and an
MS in electrical engineering, both from
Cornell University. He may be reached at
[email protected].

References:
1. Hurst, S.L. The Logical Processing of
Digital Signals. New York: Crane,
Russak, 1978.
2. Pressman, Roger A. Software
Engineering: A Practitioner’s Approach,
3rd Edition. New York: McGraw-Hill,
1992.
3. Shumate, Kenneth C. and Marilyn M.
Keller. Software Specification and
Design: A Disciplined Approach for
Real-Time Systems. New York: John
Wiley & Sons, 1992.

50 DECEMBER 2000 Embedded Systems Programming

You might also like