part2: Let's two modules play together

In this part, we will build a new module: mobile-disp, that will be able to display the result of the mobile-loco module (basically the mobile position in a graphical window). That will help us to learn, among other things, to write an asynchronous codels and to use an information coming from another module.

mobile-disp Module

mobile-disp.gen

We define two tasks:

#include "../mobile-loco/mobile-loco-struct.idl"
#include "../mobile-loco/mobile-loco-interface.gen"
#include "mobile-disp-struct.idl"

component mobiledisp {
version   "1.0";
email     "openrobots@laas.fr";
lang      "c";
uses      mobilelocointerface;
native dispInfo;
ids {
  dispInfo info;
};
task dispWindow {
     codel <start>      start_dispWindow(out info) yield waittill, stop;
     async codel <waittill>   waittill_dispWindow(inout info, port in E_current_position) yield waittill, cleanwin, up, down, stop;
     codel <cleanwin>   cleanwin_dispWindow(inout info) yield waittill;
     codel <up>         up_dispWindow(in SetSpeed, in GetSpeed) yield waittill;
     codel <down>       down_dispWindow(in SetSpeed, in GetSpeed) yield waittill;
     codel <stop>       stop_dispWindow() yield ether;
     throw memory_error, cannot_open_display;
};

task dispPosition {
     period 100ms;
     codel <start>      start_dispPosition(inout info) yield display, stop;
     codel <display>    display_dispPosition(in info, port in E_current_position) yield display, stop;
     codel <stop>       stop_dispPosition() yield ether;
     };

};

.configure.ac edition

PKG_CHECK_MODULES([X11],[x11])

codels/makefile.am edition

libxaff_codels_la_CPPFLAGS=     $(genom3_CFLAGS) $(X11_CFLAGS)
libxaff_codels_la_LDFLAGS=      -release $(PACKAGE_VERSION) $(X11_LIBS)

mobiledisp.h

Since it is not possible to use, e.g. Window type directly in idl. We have to define a dedicated structure in .h file:

#include <math.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>

struct mobiledisp_dispInfo{
  Window win;
  Display *dpy;
  Display *dpy2;
  GC gc;
  GC gc2;
  double x_orig;
  double y_orig;
};

That enable us to define in the .gen file:

native dispInfo;
ids {
  dispInfo info;
};

that we can use as codel parameter, e.g.:

codel <start>   start_dispWindow(out info) yield waittill, stop;

Inter-Module Communication

Interface Definition

We first need to share common data structures, that's why we import header files in the .gen files.

#include "../mobile-loco/mobile-loco-struct.idl"
#include "../mobile-loco/mobile-loco-interface.gen"

As we already seen, mobile-loco-struct.idl contains basic mobile-loco structure definition. Let's have a look on the mobile-loco-interface.gen file.

gupta[mobile-loco] more mobile-loco-interface.gen

interface mobilelocointerface {
port out mobileloco::position E_current_position;

ids{
 mobileloco::speed current_speed;
};
attribute SetSpeed(in current_speed=    :"Mobile speed");
attribute GetSpeed(out current_speed =  :"Mobile speed");
};

In this file, we define the interface that the mobile-loco module offers to the other ones. If you want to share data, you should define an output port: port out mobileloco::position E_current_position; If you want to share a service (this is only possible for attributes), you should define:

ids{
 mobileloco::speed current_speed;
};
attribute SetSpeed(in current_speed=    :"Mobile speed");
attribute GetSpeed(out current_speed =  :"Mobile speed");
};

To be able to use this interface, we first need to include the file and then declare in .gen file that we want to use it uses          mobilelocointerface;.

Data sharing

If you want to access to an output port. In the dispPosition task, we will use information coming from mobile-loco module to display the mobile position in the window. That is the purpose of the display codel in the task which will take as input the port offered by the mobile-loco module: codel <display>    display_dispPosition(in info, port in E_current_position) yield display, stop;

Then to use the data in your code, there is two steps:

E.g. in the following codel:

gupta[codels] more mobiledisp_dispPosition_codels.c
(...)

/** Codel display_dispPosition of task dispPosition.
 *
 * Triggered by display.
 * Yields to display, stop.
 */
mobiledisp_event
display_dispPosition(const mobiledisp_dispInfo *info,
                     const mobiledisp_E_current_position *E_current_position)
{
  int x, y ;
  E_current_position->read();
  if(E_current_position->data()!=NULL){
    x=info->x_orig + E_current_position->data()->x;
    y=info->y_orig - E_current_position->data()->y;
    XDrawPoint(info->dpy2, info->win, info->gc2, x, y);
    XSync(info->dpy2, True);
  }
  /* skeleton sample: insert your code */
  /* skeleton sample */ return mobiledisp_display;
}
(...)

You need to connect the two modules before being able to use this functionality, e.g. in our case in tcl

eltclsh> mobiledisp::connect_port E_current_position mobileloco/E_current_position

Service sharing

If you want to access to a service of another module. N.B In general case, it is not recommended to do so and it is anyway reserved to attribute function.

In the dispWindow task

     codel <up>         up_dispWindow(in SetSpeed, in GetSpeed) yield waittill;
     codel <down>       down_dispWindow(in SetSpeed, in GetSpeed) yield waittill;

Then to use the service in your code:

gupta[codels] more mobiledisp_dispWindow_codels.c
(...)
/** Codel down_dispWindow of task dispWindow.
 *
 * Triggered by down.
 * Yields to waittill.
 * Throws memory_error, cannot_open_display.
 */
mobiledisp_event
down_dispWindow(const mobiledisp_SetSpeed *SetSpeed,
                const mobiledisp_GetSpeed *GetSpeed)
{
  mobileloco_speed current_speed;
  printf("down_dispwin\n");
  GetSpeed->call(&current_speed);

  (... you can modify current speed in your code there...)

  SetSpeed->call(&current_speed);
  return mobiledisp_waittill;
}
(...)

You need to connect the two modules before being able to use this functionality, e.g. in our case in tcl

eltclsh> mobiledisp::connect_remote SetSpeed mobileloco/SetSpeed
eltclsh> mobiledisp::connect_remote GetSpeed mobileloco/GetSpeed

Running an OpenPRS supervisor controlling these 2 modules

You can build an OpenPRS supervisor to control the two modules (mobileloco and mobiledisp) following this tutorial.