# Handling of complementary errors in embedded software

I've to design a firmware for an embedded device which may be in different error conditions at the same time. Each error condition requires to set the hardware components of the system into different states. Means every error condition requires a dedicated transition callback function for entering the error sub-state or a dedicated "in state" logic which is executed simultaneously with potential other error sub-state logic. In addition the states of the HW system components may be conflicting in different error conditions. Means there is need for prioritization to resolve potential conflicts between "safe states" for different error conditions. Each error condition shall be acknowledge-able. Means each error sub-state requires explicit transition callback function for leaving the error sub-state.

How should I model this design using e.g. an UML state diagram?

BTW: I've designed UML state diagrams before. However I never had to deal with that kind of requiremenst before. In my opinion the requirements cannot be abstracted in an "off the shelf" state machine design like I used before. The question is not about UML state diagrams but the given requirements.

• Do you mean "save states" or "safe states"? If the former then what is a "save state"? (I'm just wondering. I don't think I'll be able to help.) – Transistor May 17 at 9:19
• Safe state. However it's not "safe" in the context of functional safety but to protect the device from beeing damaged only. – thinwybk May 17 at 9:23

Generally, the approach depends on if your program has a safe mode where certain outputs are always disabled, or if it must almost continue running though with reduced functionality. The former is by far the most common and the latter is typically just appearing in automotive & med-tech etc mission-critical control systems.

In the former case with a safe mode, you could weigh different kinds of errors to decide if they are severe enough to merit a transition to safe mode.

And then it also depends on the nature of your system, is it RTOS/multi-process or a single-process bare metal one. In either case you might want to implement a centralized error handler, how to do so might vary. C code example of a bare metal single thread system running a simple scheduler or state machine might look like this:

// main.c
for(;;)
{
pet_wdog();
result = run_state_machine[state]();
if(result != OK)
{
error_handler(result, &state);
}
}


Your error handler can then check the type of error returned from each state (or task, module etc), then make a decision based on the error. What state should it switch to next etc. Optionally you could run some callbacks from the error handler if that makes sense, in order to keep the module-specific code (disabling outputs etc) in the module where it belongs.

The advantage of handling all errors and state transitions from a single place is to avoid "stateghetti", a form of spaghetti programming where a state machine etc changes states from all over the place, with numerous local error handlers. Such designs make trouble-shooting and maintenance a real pain.

As for how you want to draw this design, that's not really important. Use UML, old school state charts or just some manner of generic bubbles & arrows. Long as the code reflects what you have drawn. What's most important is to give the design some thought before you start coding away. Re-designing an existing program is always a major task with high probability of introducing errors. Better then to get the design right from scratch... which is of course easier said than done.

• The thing is that for a single error condition the "save state" can conflict with the "save state" of another error condition. However for every error condition the system is malfunctioning and should go nito error state. First the OS will be a super loop and shall be migrted to an embedded RTOS. – thinwybk May 17 at 9:04
• @thinwybk Well it's kind of impossible to discuss generic design for a project where you have specific requirements, without knowing those specifics. – Lundin May 17 at 9:07
• Generally I agree. However the need for handling complementary error conditions should be very generic. – thinwybk May 17 at 9:09
• The requirements are not the problem cause they are given. I've highlighted them in the question. It's about the design. – thinwybk May 17 at 9:13
• I totally agree. Error handling needs to be done in a central place. When using a super loop potentially triggered error conditions need to be checked in every other state. With a RTOS one could e.g. use a single task to check all potentially triggered error conditions or one task to check a single potentially triggered error condition. – thinwybk May 17 at 9:21

A standard state machine can handle it. Each 'working' state would have a transition to the error states and the error state themselves would implement priority by switching to the 'most important' error.

Formally the switching condition (assuming E1 is more important than E2) would be:

on (E1) -> E1-state
on (E2 and not E1) -> E2-state


since to be unambiguous the transition conditions have to be mutually exclusive. In practice just code the E1 condition before the E2 one (unless you have a CASE tool, in which case the full expression is needed).

Do not try to graph such a state machine, it's an horrible mess! Pure state machines are not quite useable for these things (like, have you ever needed a counter in a pure FSM? good luck with the state count)

• The transition conditions are mutually exclusive. However instead of using sequential composite states for errors it seems to be reasonable to use concurrent composite states for errors instead. – thinwybk May 17 at 9:08