A Genom component is a server that provides a number of services and communicates through data ports with other components in the system. Services are asynchronous (meaning that they can be started without waiting for termination).
The execution of a service is controlled by a finite state automaton and an optional clock. Several services can be active in parallel in the same component, using distinct execution tasks or not.
A running service can be observed and controlled from outside the component. In particular it can be interrupted if needed, and the programmer can provide code to handle the interruption in a clean and safe way (for example offering a clean stop of an ongoing motor motion).
The algorithms executed by a service must be decomposed in chunks whose execution cannot be interrupted, and thus should not run for too long (otherwise compromising the ability to interrupt it). Those chunks form the basic code elements manipulated by Genom and are called "codels".
Genom provides an exception mechanism to handle errors that can be detected during codel execution. Genom exceptions can transmit any kind of data available to the codels to describe the error to the component that called the service, making it possible to perform a diagnostic of the error, and eventually to recover from it.
Each component is a specialization of the generic architecture shown in Figure 1. Individual elements are described hereafter.
The Internal Data Structure
is a collection of typed data, private to
the component and not visible in its public interface. It allows to share
parameters, computed values or state variables between codels (see below) of
the component implementation, much as global variables would do. Component
entities that need to read or write members of the IDS must specify them
individually in their argument list, so that a proper synchronization between
different threads of the component can be achieved automatically on behalf of
the user, typically by using system mutex and locking primitives.
They describe structured data that are part of the component public
interface and allow components to export (out port
) or asynchronously import
data (in port
) to or from other components. Ports are named resources,
accessed in an atomic way, so that contained data are always
consistent. Components accessing these data declare them in the argument list
of their services, so that automatic handling with respect to the underlying
middleware can be achieved on behalf of the user.
Services are procedures taking arguments and returning values, also part of the component public interface. They represent the core functionality of a component and implement the user algorithms. Depending on their characteristics, services fall into three subcategories that are part of their definition: attribute, function and activity.
are accessors for the IDS
members that need to be exposed
publicly without further algorithmic processing but possibly filtered by a
validation procedure. This is typically used for setting or getting the
value of a parameter or a group of parameters used by others algorithms
implemented by other services. attributes services are considered to have
zero processing time (or take a negligible amount of time in practice).
are used to implement simple procedures that are meant to produce a result immediately and not remain in a running state once their execution is done. For this reason, they are typically invoked synchronously and are not expected to linger.
implement complex procedures that are meant to run for a long time. They usually do not provide a result directly but rather as a side effect of their execution, by performing some actions through connected hardware, continuously executing an algorithm on incoming data retrieved by input ports or producing data exported to output ports. They are typically invoked asynchronously and modify the component state. Because of their long-lasting nature, activities are interruptible, at the client request, or as a specified side effect of another service starting.
Components provide a remote procedure call interface that enables external clients to request the execution of services at any time. This is implemented via a request-reply protocol specific to the middleware and transparent to the user. In addition to any data computed and returned as a result of the service execution, the reports always contain the status of the execution: in case of failure or anomalous execution, an exception is raised. Exceptions are user-defined types, like any other data type, that describe precisely the nature of the execution error and allows error recovery in the client invoking the failing service.
It is an internal unit of execution (typically a thread) that manages in an infinite loop the control flow of a component by processing incoming requests made by external clients, triggering the execution of the subroutines associated with the requests and sending corresponding reports once the execution is complete. The control task is directly in charge of executing the user code associated with attributes and functions services, while it delegates the execution of activities to execution tasks (see below). All components have exactly one control task.
They are also a cyclic internal unit of execution. They execute the user code associated with activities that they are in charge of and are driven by the control task. At the user choice, they can be periodic or run freely, depending on the algorithms that they are to run. They can also optionally execute a particular activity, named permanent activity, during their whole lifecycle instead of just as the result of a user request. A component can have from zero to many execution tasks.
A codel (``code element'') is a function implementing some user processing. It is specified with:
the name of a C function (implementing C or C++ code),
the arguments to pass when calling it (from or to the IDS
, in or out ports
data and service input parameters or output values) and
a list of allowed return values. The returned values are used by the activity automata, defined in the next paragraph.
Activities are modeled with an automaton that breaks
down the processing into different states. Each state is associated with a
codel. The execution of that codel leads to (yields) the next state in the
automaton, to execute immediately, or in the next period if this next state
name is prefixed with pause
.
In order to build a GenoM component, the programmer has to write two kind of inputs:
the formal description of the component, describing the tasks, services, input and output ports, activities automaton and data types.
the code of the codels that implements the algorithms of the services.
Genom processes these inputs with a middleware specific template to generate several outputs:
the source code of the component itself, interfaced with the codels and the communication layer for the selected middleware bound to all external libraries that the component may depend upon.
a set of client libraries that use the chosen middleware to interact with the component. The API of those libraries are themselves middleware independent, making it possible to control component with middleware independent code.
Note that Genom templates can potentially generate any kind of source code, such as a graphical test program or even documentation, so Genom itself is highly extensible.