Appendix A: UML Notation – Design Patterns for Embedded Systems in C

Appendix A UML Notation

The UML is a rich and expressive language. The purpose of this appendix is to help you understand the most important notations of the language. For more detailed understanding of the richness of the UML language, the reader is referred to any of a number of books exploring the UML language in detail, such as my own Real-Time UML: Advances in the UML for Real-Time Systems (Addison-Wesley, 2004).

In the context of this book, UML was used to graphically depict both the structure and the behavior of the patterns. Three of the set of diagrams of the UML used in this book are discussed here: the Class Diagram, the Sequence Diagram, and the State Diagram. The UML provides a number of other diagrammatic types (not discussed here) and even for the diagrams discussed, there are other lesser-used features that are not discussed in this appendix.

1.1 Class Diagram

The Class Diagram is for showing system structure. It does this by showing Classes (specifications of software elements), Objects (instances of classes), and relations of various kinds. The UML is quite flexible about the amount of detail shown on a diagram.

1.1.1 Semantic Elements

This section describes the various elements on the Class Diagram.

1.1.1.1 Nodal Elements

1.1.1.1.1 Class

A class is a representation of an element that combines data elements (called attributes) with functions that act on them (called operations). Classes are normally implemented as structs containing the attributes.

1.1.1.1.2 Instance

An instance is a creation of a new variable of the type of the struct that defines the class.

1.1.1.1.3 Interface

An interface is a specification of a set of services (operations and/or event receptions) that a class must implement. An interface has no implementation and no attributes; it cannot be instantiated. An interface is depicted with the same kind of box as a class, so it is visually distinguished with the «Interface» stereotype.

Figure A-1 Basic Class Diagram

1.1.1.1.4 Attribute

A variable held within a class.

1.1.1.1.5 Operation

A function held within a class that typically manipulates the class attributes. In this book, the common implementation style of an operation is to use the notation <Class Name>_<Operation Name>, such as SensorClass_getData(). The first parameter passed to the class is a pointer to the instance of the class.

1.1.1.1.6 Event Reception

A special kind of operation that is invoked asynchronously and causes event transitions to take place on the state machine associated with the class.

1.1.1.1.7 Comment

A graphical way to representing textual comments. It may be anchored to one or more elements on the diagram or may be unanchored.

Figure A-2 More Class Diagram notations

1.1.1.2 Relations

1.1.1.2.1 Association

The specification of a navigable connection among classes. It may be unidirectional or bidirectional. Each end of the association is called an association role end and has a multiplicity. The multiplicity is the number of instances of the target class that participates in the interaction. “1” is the most common multiplicity and “*” means “zero or more”.

An association is most commonly implemented as a pointer or collection of pointers.

1.1.1.2.2 Link

A link is an instance of an association; that is, a link exists when the pointer is populated with the address of the instance; if the pointer is NULL, then the link doesn’t exist.

1.1.1.2.3 Generalization

Generalization is an is-a-specialized-kind-of relation with the arrow pointing to the more general class. The super- (more general) class’s features, including attributes, operations, and relations, are all inherited by the sub- (more specific) class.

Figure A-3 Structured class notation

1.1.1.2.4 Realization

Realization is the relation between an interface and a class that implements the services specified by an interface.

1.1.1.2.5 Aggregation

Aggregation is a weak form of a whole-part association between two classes where the diamond indicates the “whole” end. It is weak in the sense that this relation does not imply creation and destruction responsibilities on the part of the whole.

1.1.1.2.6 Composition

Composition is a strong form of a whole-part association between two classes; again, the (now filled) diamond is at the end of the whole. It is strong in the sense that the whole is responsible for both the creation and destruction of the part instance.

1.1.1.2.7 Dependency

This is a general relationship not otherwise denoted. It is common to add a stereotype (such as «Usage») to indicate what kind of dependency you want. The «Usage» dependency is common and indicates that the header of the target class or element should be included by the source class during compilation.

Figure A-4 Sequence Diagram

1.1.1.2.8 Type

A type is just that – a data type without the richness of a class to add behavior. It can be an enumerated type (enum), structured type (struct), array, typedef, or even a #define.

1.2 Sequence Diagram

A Sequence Diagram shows a particular sequence of messages exchanged between a set of instances. The instances are shown as vertical lines known as lifelines. Messages are shown as horizontal or downward slanted lines. Time flows (more or less) down the page. In addition, condition marks can be used to show state or the current value of attributes during the sequence.

1.2.1 Semantic Elements

Lifeline

A lifeline represents the usage of an instance. At the top of the lifeline, it is common to both name the instance and identify the type of class of the instance.

Environment Lifeline

This is a special lifeline that stands for “everything else.” It provides a notational shorthand for elements omitted from the diagram.

Message

A representation of an interaction between two instances. It may be synchronous (as in a function call) or asynchronous (as in an asynchronous event exchange). A message is shown as a directed line that may be either horizontal or downwards sloping.

Synchronous Message

A synchronous event (function call) is shown with a solid arrowhead. It is most commonly draw as a horizontal line.

Asynchronous Message

An asynchronous message (event reception) is shown with an open arrowhead. It is common (but not required) to draw it as a downward sloping line.

Condition Mark

This is a hexagon that contains a textual condition that is true at that point in the sequence, such as the value of a variable or the current state in a state machine.

Comment

It may be anchored to one or more elements on the diagram or may be unanchored.

1.3 State Diagram

A State Diagram is a directed graph consisting of states (rounded rectangles) and transitions (arrowed lines). It defines the order of action execution for its owner class.

1.3.1 Semantic Elements

1.3.1.1 State

A state is a condition of an instance of a class. A state may contain entry actions, exit actions, and internal transitions. It is drawn as a rounded rectangle.

1.3.1.2 Nested State

States may contain lower level, nested states. For example, while the DOOR_IS_OPEN state is true, it might be in DOOR_OPENING, DOOR_CLOSING, or DOOR_WAITING_OPEN nested state. Nested states are drawn by graphically including the nested state inside a composite state.

1.3.1.3 Composite State

A state that contains nested states. These may be OR-states (as in Figure A-5 and Figure A-6) or AND-states (as in Figure A-7).

Figure A-5 Basic State Diagram

Figure A-6 Advanced State Diagram

Figure A-7 AND-states on State Diagram

1.3.1.4 OR-State

A set of states at a given level of abstraction; the semantics of state machines are that at a given level of abstraction, the state machine must be in exactly one of its OR-States. In Figure A-5, state_0 and state_1 are OR-states; similarly, NestedState1 and NestedState2 are OR-states.

1.3.1.5 AND-State

AND-states are orthogonal regions within a composite state with the semantics that the instance must be in exactly one AND-state in each orthogonal region. AND-states are indicated with a dashed line in the composite state. While it is theoretically possible to implement AND-states in separate threads, this is almost never done. If an event is shared between AND-states, each AND-state must be allowed to independently act on it or reject it, but the order of execution of the transitions triggered by the same event is not known in principle. This leads to the possibility of race conditions.

If you look at Figure A-7, the transition from state_0 to state_1 is triggered by the event1 event. In this case, the instance enters both states UpperState1 and LowerState3; the instance is in both states at the same time. AND-states are most commonly used to model independent properties of an instance.

Note also in the figure the transition from state_1 to state_0 triggered by the event evGoBack. In this case, it doesn’t matter which combination of nested states is currently true; as long as the instance is in state_1, the transition is valid. However, in the event from nested state LowerState3 to state_2, triggered by event event10, which nested state in ANDStateRegion1 is true doesn’t matter, but the instance must be currently in LowerState3 state for that transition to be taken. If it is not, then the event is discarded.

1.3.1.6 Transition

A transition is a representation of a response to an event while the instance is in a specified state. It typically has an event signature consisting of an event trigger, guard, and list of actions, specified using the following syntax:

event trigger ‘[‘ guard condition ‘]’ ‘/’ action list

All of the fields in the event are optional. A transition is shown on a state machine as an arrowed line coming from a predecessor state and terminating on a subsequent state.

If the event-trigger is omitted, the transition “fires” as soon as the predecessor state is entered, that is, as soon as the entry actions of the predecessor state complete. See Figure A-7 for an example.

1.3.1.7 Action

An action is a primitive behavior performed under some circumstance in a state machine. This is most often one of the following:

  • A function call, for example foo(x)

  • A direct primitive action, such as x += 10

  • The generation of an event sent to the current instance or another instance known to the current instance; a common way to indicate this is with a GEN(event) macro

  • A list of actions

Actions are separated from the rest of the event signature with a slash (‘/’) character.

1.3.1.8 Entry Action

An entry action is an action performed whenever a state is entered regardless of which transition is taken.

1.3.1.9 Exit Action

An exit action is an action performed whenever a state is left, regardless of which transition is taken.

1.3.1.10 Transition Action

A transition action is an action performed only when a specific transition is taken.

1.3.1.11 Internal Transition

An internal transition is when an action is performed when an event occurs but a state transition is not taken (that is, the exit and entry actions are not performed).

1.3.1.12 Event

An event is a specification of an event of interest that is received by the instance. It may be received synchronously or asynchronously. It may carry parameters, just like a function call. The syntax used here is that the event that carries data put those data into a struct called params. This struct may be dereferenced to access the data. For example, in Figure A-6, the evTerminate event carries a data element code. The actions in the state machine access the parameter by dereferencing the params struct.

Events may trigger a transition or an internal transition; if they do not, events are quietly discarded with no actions taken.

An event is consumed by the state machine; that is, once the state machine has completed its processing step for the current event, it is destroyed. Even if the newly assumed state has an event triggered by the same event, the event must occur again for this transition to be taken.

1.3.1.13 Event Trigger

The event trigger is the specification of an event. This may be asynchronous (which requires event queuing), synchronous, a timeout (usually indicated with a tm(duration) or after(duration) syntax), or when a state variable is changed.

1.3.1.14 Guard

A guard is an (optional) Boolean expression. If the guard evaluates to TRUE, then the transition is taken; if it evaluates to FALSE, then the event is discarded and the transition is not taken.

1.3.1.15 Default Transition

The default transition indicates that at a given level of abstraction, which, among a set of states, is entered first by default. It is shown as a transition with no event trigger or guard (although it may have actions) terminating on a state, but not beginning on one.

1.3.1.16 Pseudostate

A pseudostate is a perhaps poorly-named annotation of special semantics. The UML defines many pseudostates. In this limited description here, pseudostates include the default transition, conditional, fork, join, and terminal pseudostates.

1.3.1.17 Conditional Pseudostate

The conditional pseudostate indicates multiple potential outgoing transitions initiated by a single event with the proviso that only one such path will actually be taken. The different paths are selected on the basis of guards; that is, each transition segment will have a guard that will be evaluated to TRUE or FALSE. If multiple transition segment guards evaluate to TRUE, then any one of the true paths can be taken. If no guards evaluate to true then the event is discarded and no transition is taken. A special guard “else” is provided; if present, this transition path will be taken only if all the other transition segments are rejected.

1.3.1.18 Fork

When entering a composite state with nested AND-states, a fork can be used to specify nondefault states to enter, as in Figure A-7. The event event2 triggers the transition from state_4 to state_1, but specifically enters nested AND-states UpperState2 and LowerState1, bypassing the default states of UpperState1 and LowerState3.

1.3.1.19 Join

When leaving a composite state with nested AND-states, a join can be used to state the precondition that the transition should only be taken if the specific set of states (one per AND-state) is true when the event occurs. See Figure A-7.

1.3.1.20 Terminal Pseudostate

The terminal pseudostate is a special indicator that means that the instance no longer accepts events, usually because the instance is about to be destroyed.