IDS (Internal Data Structure)

## Contents

- Your rights

- Introduction

- Component model

- Component description file

- GenoM IDL mappings

- Running GenoM

- Tutorials

  - Genom workflow

  - Simple service

  - IDS (Internal Data Structure)

  - Working with external software

- Templates

## IDS (Internal Data Structure)

IDS is a genom object that can be defined within a component in order to store and share private data among different services and codels of a component. Private data, in this context, means data that is not exported nor visible from the component interface, but used internally to store state, temporary computation data, etc. It is similar to the purpose of the `private` `C++` keyword.

### IDS versus static versus global

Private data can be defined in several ways, depending on the expected usage of the data. When deciding whether to define an IDS, different scenario can be considered:

#### Shared data between codels of the same service

In this case, declaring `static` data in the source file where the service codels are implemented is sufficient. Since no two codels of the same service will ever execute simultaneously, no locking or any synchronization strategies need to be implemented. This is the simplest scenario.

Note | a `static` definition enforces the private nature of the data. Technically, a global definition would also work, just providing less guarantees regarding the visibility of data.

#### Shared data between codels of the same tasks

Declaring `static` data in the source file where all the codels of the services of the task are defined is also sufficient in this case. No two codels of the same task can execute simultaneously (by definition of a task), so no synchronization strategies is required.

#### Shared data between codels of different tasks

Codels of different tasks (including codels of functions and attributes) can execute simultaneously. In order to share data between them, a mere global or `static` definition for the data is not sufficient and proper synchronization between the codels must be achieved. This is where the IDS definition becomes handy, as it handles the synchronization transparently and in an efficient manner, depending on which codel access which data.

### IDS example

In order to demonstate the IDS usage, let’s consider two simple services. The first one, `counter` will count from 0 some maximum value, at a fixed rate. The second one, `reset` will simply reset the current counter value so that `counter` starts again from 0. `counter` must be implemented as an activity, because it will iterate at a given frequency, while `reset` may be a simple function.

It should be obvious that in order to implement these two activities, they must share the current counter value. This is easily achieved by using an `IDS` declaration inside the component definition, that would look like this:

example.gen

      1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

      component example {
      ids { long current; };

      task t { period 1s; };

      activity counter(in long max = 42: "Maximum counter value") {
        doc "Count from 0 to max";
        task t;

        codel<start> counter_impl(in max, inout current) yield start, ether;
      };

      function reset() {
        codel reset_impl(out current);
      };
    };

In line 2 of this example, the IDS is declared, along with its content, much like a `structure` definition. In this example, a simple integer variable `current` is declared.

On line 6 and 13, the two services are declared, with their parameters. Activity `counter` takes an integer to define the maximum counter value, while `reset` has no parameter.

The interesting parts are on lines 10 and 14, with the codels definitions. The codel `counter_impl` for the `counter` activity needs two parameters: the `max` value given as input to the activity, and the private variable `current`, to be updated at each step. The different nature of the two parameters are automatically recognized by genom. The codel `reset_impl` for the `reset` function just need to zero the `current` value from the IDS.

The implementation of these two codels could be the following:

    genom_event
    counter_impl(int32_t max, int32_t *current, const genom_context self)
    {
      (*current)++;
      if (*current < max) return example_start; else return example_ether;
    }

    genom_event
    reset_impl(int32_t *current, const genom_context self)
    {
      *current = 0;
      return genom_ok;
    }

### Initializing IDS data

The values of the IDS are not initialized to any special value when the component starts. Often, though, it is desirable to assign them reasonable values. This can be achieved by defined a task start codel, that takes a list of IDS members to initialize.

For example:

example.gen

    component example {
      ids {
        long value;
        double parameter;
        string data;
      };

      task t {
        codel<start> init_ids(out value, out parameter, out data) yield ether;
      };
    };

`init_ids` will be called during the component startup and can thus initialize the designated members, for instance like this:

    genom_event
    init_ids(int32_t *value, double *parameter, char **data,
             const genom_context self)
    {
       *value = 0;
       *parameter = 3.14;
       *data = strdup("a string ...");

       return example_ether;
    }

When the IDS has many members, it might be more convenient to pass the whole IDS as a single parameter. This can be achieved by using the `parameter::name` syntax, with an empty `parameter` part and a name of your liking:

example.gen

    component example {
      ids {
        long value;
        double parameter;
        string data;
      };

      task t {
        codel<start> init_ids(out ::whole_ids) yield ether;
      };
    };

`init_ids` will then be passed a pointer on the whole IDS structure:

    genom_event
    init_ids(example_ids *whole_ids, const genom_context self)
    {
       whole_ids->value = 0;
       whole_ids->parameter = 3.14;
       whole_ids->data = strdup("a string ...");

       return example_ether;
    }

### Name disambiguation

As it was shown in the previous paragraphs, GenoM automatically recognize the codel parameter source when the parameter name is not ambiguous. However, it can happen that a member of the IDS has the same name as a service parameter (or a port name).

For instance, the following example is ambiguous and leads to some compilation errors:

example.gen

    component example {
      ids { long value; };

      function set_value(in long value) {
        codel set_value(in value, out value); /* this is ambiguous */
      };
    };

    $ genom3 -n example.gen
    example.gen:5: missing source qualifier for parameter 'value'
    example.gen:2:  ids member value declared here
    example.gen:4:  service parameter value declared here
    example.gen:5: missing source qualifier for parameter 'value'
    example.gen:2:  ids member value declared here
    example.gen:4:  service parameter value declared here
    genom3: 2 errors
    $

In order to distinguish between the `value` parameeter of the function `set_value` and the IDS member `value`, two changes must be done to the previous example.

- First, the codel `set_value` must indicate the origin of each value, using one of the `ids`, `local` and `port` keyword. `ids` and `port` designate a parameter from the IDS or a port name, respectively, while `local` refers to the service parameters.

- Then, since a codel cannot have two parameters with the same name, one of the parameters (or both) must be given another local name, by using the `parameter::name` syntax.

This would be written like so in the component description file:

example.gen

    component example {
      ids { long value; };

      function set_value(in long value) {
        codel set_value(local in value, ids out value::ids_value);
      };
    };