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 actions that are associated to the manoeuvres.
- a start check that verifies whether manoeuvre execution can start. Depending on the manoeuvre, readiness to start can be defined by a time tag or by the occurrence of certain operational conditions.
- a continuation check that verifies whether an on-going manoeuvre can continue its execution.
- a termination check that verifies whether the manoeuvre has terminated execution. Depending on the manoeuvre, termination can be defined by a time tag or by the achievement of pre-specified operational conditions.
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
ManoeuvreManager
:The component that is responsible for executing manoeuvres. Manoeuvre
:The abstract interface that characterizes all components that encapsulate manoeuvres. ConcreteManoeuvre
:Component implementing interface Manoeuvre
to represent a specific and concrete manoeuvre.
Collaborations
The typical operational scenario for this design pattern is:
- A client component wishes a manoeuvre to be executed. The manoeuvre is encapsulated in an object that
implements interface
Manoeuvre
. The client component loads the manoeuvre object in the manoeuvre manager by using itsload
method. - The manoeuvre manager periodically checks the status of the loaded manoeuvre and advances its execution accodingly
- When execution of the manoeuvre is terminated, the manoeuvre manager unloads the manoeuvre
Consequences
- The management of manoeuvres is decoupled from their implementation. New manoeuvres can be added and existing manoeuvres can be modified without impact on the code that performs the manoeuvre management and on the code that uses the manoeuvres.
- The manoeuvre management code (the manoeuvre manager component) can be developed as an application-independent component reusable without changes across applications.
-
For each manoeuvre, a dedicated class implementing interface
Manoeuvre
must be created. This may lead to a proliferation of small classes.
Applicability
This design pattern is useful when:
- there is a need to handle sequences of actions but the implementation of these actions can vary from application to application.
- there is a need to decouple the implementation of these sequences of actions from their managegement.
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:
- ManoeuvreManagercomponent -->
CC_ManoeuvreManager
- Manoeuvreabstract interface -->
Manoeuvre
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