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:
dispWindow that will manage the window creation and keyboard inputs. The main codel of this task waittill is declared as async for asynchronous since it is waiting indefinitely since there is a keyboard input. up and down codels will be able to access to mobile-loco SetSpeed and GetSpeed to manage the mobile speed.
dispPosition that will read position of the mobile from the mobile-loco module
#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; }; };
Link to external library
link to X11 library
.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:
read the data: E_current_position->read();
use it: E_current_position->data()->x;
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(¤t_speed); (... you can modify current speed in your code there...) SetSpeed->call(¤t_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.