Manoeuvre Management Design Pattern

Intent

Decouple the management of manoeuvres from their implementation.

Based On

This pattern is essentially identical to the manoeuvre management pattern of the AOCS Framework (see also: A. Pasetti, Embedded Control Systems and Software Frameworks, Springer-Verlag, 2002). It can also be seen as an instance of the manager design pattern.

Motivation

The term manoeuvre is used here to designate a sequence of actions that must be performed by an application at specified times to achieve a specified goal. Although individual manoeuvres - to slew an antenna, to perform a unit switch-on sequence, etc - exist in almost any OBS application, their diversity is such that usually no concept of abstract manoeuvre is used. This also means that there is usually no attempt made to manage manoeuvres in a uniform manner. This lack of uniformity is incompatible with software reuse and with a framework approach.

This design pattern introduces a manoeuvre abstraction that allows the management of a generic manoeuvre to be done in a manner that is independent of the implementation of the manoeuvre, namely of the actions that must be performed to execute the manoeuvre.

Dictionary Entries

The following abstractions or domain-wide concepts are defined to support the implementation of this design pattern:

Structure

This design pattern postulates the encapsulation of manoeuvres in components and proposes an abstract interface Manoeuvre to characterize them. An abstract manoeuvre is characterized by:

The introduction of an abstract interface to characterize manoeuvres, makes it possible to introduce a manoeuvre manager component responsible for executing them. Since it sees the manoeuvres only through the abstract interface Manoeuvre, the manoeuvre manager can be developed as an application-independent component that can be reused across applications without changes to its source code.

The manoeuvre manager maintains a list of components of abstract type Manoeuvre. Whenever it is activated, it goes through the list and checks the status of each pending manoeuvre. If a pending manoeuvre has not yet started, then the manoeuvre manager asks it to perform a start check (method canStart). If this is successful, the manoeuvre manager starts the execution of the manoeuvre. If a manoeuvre is already executing, then the manoeuvre manager asks it to perform a continuation check (method canContinue). If this is successful, then the manoeuvre manager advances the execution of the manoeuvre (method doContinue). Finally, the manoeuvre manager asks executing manoeuvres to perform a termination check (method isFinished). If the outcome of the check indicates that the manoeuvre has terminated execution, then the manoeuvre manager removes it from its list of pending manoeuvres and unloads it.

The manoeuvre manager exposes a load method to allow clients to load manoeuvres that must be executed. Note that there is no corresponding unload method because removal from the list of pending manoeuvres is done autonomously and internally to the manoeuvre manager when a manoeuvre has terminated its execution. An abort method could however be provided to allow clients to force the interruption of the execution of pending manoeuvres.

Participants

Collaborations

The typical operational scenario for this design pattern is:

Consequences

Applicability

This design pattern is useful when:

Implementation Issues

What operations should be defined by the Manoeuvre interface? In addition to those defined above, there might be other housekeeping operations. One notable example could be an operation to abort an on-going manoeuvre.

There is an obvious similarity between manoeuvres as defined here and telecommands as defined in the telecommand management design pattern. Both categories of components encapsulate actions that must be performed on the (or by the) on-board software. Perhaps the main conceptual difference is that telecommands are intended to be performed in one shot whereas the execution of manoeuvres extends over time. This is not an essential difference though, because telecommands could be seen as special cases of manoeuvres with a punctual execution (their isFinished method always returns true). In the concept proposed here, manoeuvres and telecommands are kept separate primarily because they are normally seen as distinct by the on-board application designers but also for implementation reasons. Telecommands have special implementation needs because, unlike other components in an on-board application, they must be created dynamically upon reception of messages from the ground. This requirement is likely to have an impact on the management of the telecommands and advises against treating them as a special kind of manoeuvres.

In a typical implementation, the on-board software will internally store a number of manoeuvre components to perform often recurring manoeuvre such as antenna slews or unit switch-on sequences. When conditions warrant it or when the ground commands it, one of these pre-defined manoeuvre components can be loaded into the manoeuvre manager (by calling its load method). This will cause the manoeuvre to be executed.

OBS Framework Mapping

The implementation of this design pattern in the OBS Framework is supported by the following classes:

Sample Code

As an example of a concrete manoeuvre consider the case of an application that, upon entry into normal mode, must switch on a certain unit. Assume moreover that the switch-on procedure may extend over a maximum of 4 cycles spanning the interval between the time when the switch-on command is sent to the unit and the time when the unit, after completing its initialization procedure, is fully operational. This switch-on procedure can be implemented as a manoeuvre component. This means that it must be implemented as an instance of a class SwitchOnUnit that implements interface Manoeuvre. The basic definition of this class could be as follows:

    class SwitchOnUnit : Manoeuvre {

        bool canStart() {
          . . .    // return true if operational mode is NORMAL_MODE
        }
        
        void doContinue() {
        . . .    // The first time the method is called,
        . . .    // send a switch-on command to the unit.
        . . .    // Afterwards, do nothing
        }
        
        bool canContinue() {
        . . .    // return true if the number of cycles elapsed
        . . .    // since the manoeuvre started is less than four
        }
        
        bool isFinished() {
        . . .    // return true if the unit is operational
        }

    }
An instance of this manoeuvre should be loaded into the manoeuvre manager before the application enters normal mode. The code to load it might look like this:
    Manoeuvre* switchOnUnit = new SwitchOnUnit();
    . . .
    ManoeuvreManager* manoeuvreManager;
    . . .
    manoeuvreManager->load(switchOnUnit);
After it is loaded, the execution of the manoeuvre is entirely under the control of the manoeuvre manager and the component that created and loaded it need no longer be concerned with it.

As a second example of sample code, consider the manoeuvre manager. If the Manoeuvre interface is as hypothesized in the pattern class diagram, then its core could be implemented as follows:

    class ManoeuvreManager {

        // list of pending manoeuvres
        Manoeuvre* manoeuvreList[N];
        . . .
    
        void activate() {
    
            for (int j:=0; j++; j<N)
            {	if (manoeuvreList[j]->canStart())
                        if (manoeuvreList[j]->canContinue())
                            manoeuvreList[j]->doContinue();
                        else
                        . . .// abort manoeuvre
                        if (manoeuvreList[j]->isFinished())
                        . . .// remove manoeuvre from manoeuvreList[]
            }
        }
    
        void load(Manoeuvre* newManoeuvre) {
            . . .	// add newManoeuvre to manoeuvreList[]
        }
    }
In this implementation, the manoeuvre manager maintains a list of pending manoeuvres. The manoeuvre manager is intended to be periodically activated by some external agency (perhaps a scheduler). When it is activated it goes through the list of pending manoeuvres and checks which are ready to start. On active manoeuvres, it checks which ones are in a condition to continue execution and on the latter it calls method doContinue to advance the manoeuvre execution. Finally, the manoeuvre manager checks whether manoeuvres have terminated their execution and, if they have, removes them from the list of pending manoeuvres.

In a more realistic implementation, the manoeuvre manager would also perform other housekeeping operations such as recording execution or abortion of manoeuvres in a history area. The important point however is that all the operations performed by the manoeuvre manager are independent of the manoeuvre implementation and that therefore the manoeuvre manager is a potentially reusable component.

Remarks

None

Author

A. Pasetti (P&P Software)

Last Modified

2002-06-22

Contact Us | The OBS Framework Project