Tutorial: making the mobileloco and mobiledisp Modules
Needs
Check this instruction page to install GenoM3 and associated templates and tools.
demo-mobile-loco and demo-mobile-disp modules that will be used in this tutorial are available through git:
git clone git://trac.laas.fr/git/robots/demo-mobile-loco git clone git://trac.laas.fr/git/robots/demo-mobile-disp
demo-mobile-loco is a demo module to emulate the locomotion of a 2D modules
demo-mobile-disp is a demo module to emulate the display in an X Window of the mobile locomotion, position comes from demo-mobile-loco module
part 1: How to write your first module ?
This section will illustrate a concrete use of genom3. The mobile-loco module will control a virtual mobile that can move in a 2D world. Some of the services the module offers are:
- select speed
- move the mobile to a given position
- read the current speed at any moment
- suspend the motion
To implement this, we first create a directory named mobile-loco.
mkdir mobile-loco cd mobile-loco
Write .gen File
In that directory, we will write the description file mobile-loco.gen. The file mobile-loco.gen is made up of several parts, each of them being identified with a keyword:
component module declaration
ids
task
attribute
function
activity
The entire file will look like this:
#include "mobile-loco-struct.idl" #include "mobile-loco-interface.gen" /* -------------------------- MODULE DECLARATION --------------------------- */ component mobileloco { version "1.0"; email "openrobots@laas.fr"; lang "c"; provides mobilelocointerface; /* ------------- DEFINITION OF THE MODULE’s INTERNAL DATABASE -------------- */ ids { mobilelocointerface::position start_position; mobilelocointerface::position current_position; mobilelocointerface::position end_position; }; /* ------------------ TASK DEFINITION -------------------- */ task motion { period mobileloco::task_period ms; priority 100; stack 4000; codel <start> InitMotionParameters(out ::ids, port out E_current_position) yield ether; }; /* ------------------ SERVICES DEFINITION: The ATTRIBUTES -------------------- */ attribute SetSpeed(in current_speed= :"Mobile speed") { doc "To increase speed"; validate controlSpeed (local in current_speed); throw INVALID_SPEED; }; attribute GetSpeed(out current_speed = :"Mobile speed") { doc "To get current speed value"; }; /* ------------------ SERVICES DEFINITION: The Functions -------------------- */ function Stop() { doc "Stops motion and interrupts all motion requests"; interrupts GotoPosition; }; /* ------------------ SERVICES DEFINITION: The activities -------------------- */ activity GotoPosition (in mobilelocointerface::position goto_position = :"Goto position") { doc "Move to the given position"; validate controlPosition (in goto_position); codel <start> gotoposStart(in goto_position, inout ::ids) yield exec, ether; codel <exec> gotoposExec(inout ::ids, port out E_current_position) yield exec, end, stop; codel <end,stop> gotoposStop(inout ::ids) yield ether; interrupts GotoPosition, Stop; task motion; throw INVALID_POSITION; }; };
Data Structure Definition
The #include "mobile-loco-struct.idl" statement works as a header file in C and includes idl data structure. This file contains all the necessary declarations for the definition of the internal database. These structures are then used in the .gen file. (The #include "mobile-loco-interface.gen" will be useful later when we would be able to link the module with another one). In this example, the file "mobile-loco-struct.idl" contains the definition of the position and the speed. This file is preferably located in the same directory as mobile-loco.gen, since it contributes to the definition of the module interface. rq: if you get demo-mobile-loco module through git, the idl definition is quite different and is moved to the mobile-loco-interface.gen file to interface with demo-mobile-disp
#ifndef IDL_MOBILE_LOCO_STRUCT #define IDL_MOBILE_LOCO_STRUCT module mobileloco { /* task period */ const unsigned long task_period = 400; /* mobile position definition*/ struct position { double x; double y; }; /* speed definition */ enum speed_enum { SLOW, MEDIUM, FAST }; struct speed { speed_enum s; }; }; #endif
Module generation
Once your description file (.gen) ready, you need to generate your module:
gupta[mobile-loco] genom3 skeleton mobile-loco.gen creating ./codels/mobileloco_motion_codels.c creating ./codels/mobileloco_codels.c creating ./libmobileloco_codels.pc.in creating ./libmobileloco_codels-uninstalled.pc.in creating ./bootstrap.sh creating ./autoconf/ag_templates.m4 creating ./configure.ac creating ./Makefile.am creating ./codels/Makefile.am
From now on, the module is ready to be compiled and run, but let's look at the result of the execution of the command:
gupta[mobile-loco] ls autoconf/ codels/ mobileloco-genom.pc.in Makefile.am mobile-loco-struct.idl bootstrap.sh configure.ac mobileloco-genom-uninstalled.pc.in mobile-loco.gen mobile-loco-interface.gen
GenoM3 created two new directories codels/ and autoconf/, and several new files.
Algorithms (or a part of them) are grouped in the directory codels/. The files in that directory give you template to start from, and also let GenoM3 produce a module even if you still do not have written a single line of code.
- The Makefile.am and configure.ac files are also under your control. These are the main files which are used for the compilation of the module.
Codels writing
Let's have a look in the codels directory.
gupta[codels] ls Makefile.am Makefile.in mobileloco_codels.c mobileloco_motion_codels.c
mobileloco_codels.c
In this file, we will found codels related to validation, e.g. controlSpeed (Validation codel of attribute SetSpeed) and controlPosition (Validation codel of activity GotoPosition).
rq: take care, code from git is quite different due to interface with mobile-disp but both works
At the beginning, the template will look like:
gupta[codels] more mobileloco_codels.c #include "acmobileloco.h" #include "mobileloco_c_types.h" /* --- Attribute SetSpeed ----------------------------------------------- */ /** Validation codel controlSpeed of attribute SetSpeed. * * Returns ok. * Throws INVALID_SPEED. */ mobileloco_event controlSpeed(const mobileloco_speed *current_speed) { /* skeleton sample: insert your code */ /* skeleton sample */ return mobileloco_ok; } /* --- Activity GotoPosition -------------------------------------------- */ /** Validation codel controlPosition of activity GotoPosition. * * Returns ok. * Throws INVALID_POSITION. */ mobileloco_event controlPosition(const mobileloco_position *goto_position) { /* skeleton sample: insert your code */ /* skeleton sample */ return mobileloco_ok; } /* --- Activity Monitor ------------------------------------------------- */ /** Validation codel controlPosition of activity Monitor. * * Returns ok. * Throws . */ /* already defined in service GotoPosition validation */
Let's have a look on how we can write such functions:
controlSpeed
mobileloco_event controlSpeed(const mobileloco_speed *current_speed) { if((current_speed->s != mobileloco_SLOW) && (current_speed->s != mobileloco_MEDIUM) && (current_speed->s != mobileloco_FAST)) return mobileloco_INVALID_SPEED; return mobileloco_ok; }
controlPosition
mobileloco_event controlPosition(const mobileloco_position *goto_position) { if((goto_position->x > 100.0) || (goto_position->x < -100.0) || (goto_position->y > 100.0) || (goto_position->y < -100.0)) return mobileloco_INVALID_POSITION; return mobileloco_ok; }
mobileloco_motion_codels.c
In this file, we will found functions attached to the motion task, such as :
InitMotionParameters: which is the <start> codel of the task
gotoposStart, gotoExec: which are <start> and <exec> codel of the GotoPosition activity
gupta[codels] more mobileloco_motion_codels.c #include "acmobileloco.h" #include "mobileloco_c_types.h" /* --- Task motion ------------------------------------------------------ */ /** Codel InitMotionParameters of task motion. * * Triggered by start. * Yields to ether. */ mobileloco_event InitMotionParameters(mobileloco_ids *ids, const mobileloco_E_current_position *E_current_position) { /* skeleton sample: insert your code */ /* skeleton sample */ return mobileloco_ether; } /* --- Activity GotoPosition -------------------------------------------- */ /** Codel gotoposStart of activity GotoPosition. * * Triggered by start. * Yields to exec, ether. * Throws INVALID_POSITION. */ mobileloco_event gotoposStart(const mobileloco_position *goto_position, mobileloco_ids *ids) { /* skeleton sample: insert your code */ /* skeleton sample */ return mobileloco_exec; } /** Codel gotoposExec of activity GotoPosition. * * Triggered by exec. * Yields to exec, end, stop. * Throws INVALID_POSITION. */ mobileloco_event gotoposExec(mobileloco_ids *ids, const mobileloco_E_current_position *E_current_position) { /* skeleton sample: insert your code */ /* skeleton sample */ return mobileloco_exec; } /** Codel gotoposStop of activity GotoPosition. * * Triggered by end, stop. * Yields to ether. * Throws INVALID_POSITION. */ mobileloco_event gotoposStop(mobileloco_ids *ids) { /* skeleton sample: insert your code */ /* skeleton sample */ return mobileloco_ether; } /* --- Activity Monitor ------------------------------------------------- */ /** Codel monitStart of activity Monitor. * * Triggered by start. * Yields to start, stop. */ mobileloco_event monitStart(const mobileloco_position *monitored_position, const mobileloco_ids *ids) { /* skeleton sample: insert your code */ /* skeleton sample */ return mobileloco_start; } /** Codel monitStop of activity Monitor. * * Triggered by stop. * Yields to ether. */ mobileloco_event monitStop(void) { /* skeleton sample: insert your code */ /* skeleton sample */ return mobileloco_ether; }
Let's have a look on how we can write such functions:
gotoposExec
mobileloco_event gotoposExec(mobileloco_ids *ids, const mobileloco_E_current_position *E_current_position) { double step; int end_x = 0; int end_y =0 ; switch(ids->current_speed.s){ case mobileloco_SLOW: step=0.1; break; case mobileloco_MEDIUM: step=0.5; break; case mobileloco_FAST: step=1.0; break; } if(x_direction==FORWARD) { if(ids->end_position.x > (ids->current_position.x + step)){ ids->current_position.x = ids->current_position.x + step; } else { ids->current_position.x = ids->end_position.x; end_x = 1; } } else { if(ids->end_position.x < (ids->current_position.x - step)){ ids->current_position.x = ids->current_position.x - step; } else { ids->current_position.x = ids->end_position.x; end_x = 1; } } if(y_direction==FORWARD) { if(ids->end_position.y > (ids->current_position.y + step)){ ids->current_position.y = ids->current_position.y + step; } else { ids->current_position.y = ids->end_position.y; end_y = 1; } } else { if(ids->end_position.y < (ids->current_position.y - step)){ ids->current_position.y = ids->current_position.y - step; } else { ids->current_position.y = ids->end_position.y; end_y = 1; } } E_current_position->data()->x= ids->current_position.x; E_current_position->data()->y= ids->current_position.y; E_current_position->write(); if ((end_x == 1) && (end_y==1)) { return mobileloco_end; } else { return mobileloco_exec; } }
gotoposStop
mobileloco_event gotoposStop(mobileloco_ids *ids) { ids->start_position.x=ids->current_position.x; ids->start_position.y=ids->current_position.y; return mobileloco_ether; }
Module compilation
There are two steps in compilation of the module:
configuration of the module by running the configure script
compilation itself, controlled by the Makefile generated in the previous step.
Bootstrap
- bootstrap the autotools build system
gupta[mobile-loco] ./bootstrap.sh autoreconf: Entering directory `.' autoreconf: configure.ac: not using Gettext autoreconf: running: aclocal -I autoconf autoreconf: configure.ac: tracing autoreconf: running: libtoolize --install --copy libtoolize: putting auxiliary files in AC_CONFIG_AUX_DIR, `autoconf'. libtoolize: copying file `autoconf/config.guess' libtoolize: copying file `autoconf/config.sub' libtoolize: copying file `autoconf/install-sh' libtoolize: copying file `autoconf/ltmain.sh' libtoolize: putting macros in AC_CONFIG_MACRO_DIR, `autoconf'. libtoolize: copying file `autoconf/libtool.m4' libtoolize: copying file `autoconf/ltoptions.m4' libtoolize: copying file `autoconf/ltsugar.m4' libtoolize: copying file `autoconf/ltversion.m4' libtoolize: copying file `autoconf/lt~obsolete.m4' autoreconf: running: /usr/bin/autoconf autoreconf: running: /usr/bin/autoheader autoreconf: running: automake --add-missing --copy --no-force configure.ac:9: installing `autoconf/missing' codels/Makefile.am: installing `autoconf/depcomp' autoreconf: Leaving directory `.'
Build directory
In order to keep objects files separated from the sources, for instance when you want to generate the module for several different architectures, or just in order to have a simple mean to clean up everything that was produced during the building phase, it is strongly recommended to create a separate build directory and run every command from there.
gupta[mobile-loco] mkdir build gupta[mobile-loco] cd build
Configuration
All the OpenRobots software and tools are generally installed in a specific directory (for instance ${HOME}/openrobots). This is the main information that needs to be specified to the configure script. Don't forget to run configure from the build directory. Then, the options will be different given the templates you want to generate, you have several possibilities:
- pocolibs ($TEMPLATES=pocolibs/server,pocolibs/client/c)
- pocolibs/server is the genom pocolibs module itself
- pocolibs/client/c is the pocolibs C client library
- ros ($TEMPLATES=ros/server,ros/client/c,ros/client/ros)
- ros/server is the genom ros module itself
- ros/client/c is the ros C client library
- openprs ($TEMPLATES=openprs/client), you can mix openprs template with the others (e.g.: $TEMPLATES=pocolibs/server,pocolibs/client/c,openprs/client)
e.g. here, if we set $TEMPLATES=pocolibs/server,pocolibs/client/c
gupta[build] ../configure --prefix=$INSTALL_DIR --with-templates=$TEMPLATES checking for a BSD-compatible install... /usr/bin/install -c checking whether build environment is sane... yes checking for a thread-safe mkdir -p... /bin/mkdir -p checking for gawk... gawk checking whether make sets $(MAKE)... yes checking build system type... x86_64-unknown-linux-gnu checking host system type... x86_64-unknown-linux-gnu ... ... ... checking for pocolibs... yes checking for genom3_pocolibs... yes checking for genom3... yes configure: creating ./config.status config.status: creating Makefile config.status: creating mobileloco-c-client.pc config.status: creating mobileloco-c-client-uninstalled.pc config.status: creating autoconf/acheader.h config.status: executing depfiles commands config.status: executing libtool commands configure: done configuring for pocolibs/client/c
Compilation
To compile the module, just run make from the build directory. The GNU make utility is required, but this is the standard make on linux systems.
gupta[build] make Making all in codels make[1]: Entering directory `/home/aclodic/Work/01_Demo/mobile-loco/build/codels' make all-am make[2]: Entering directory `/home/aclodic/Work/01_Demo/mobile-loco/build/codels' make[2]: Nothing to be done for `all-am'. ... ... ... lib/genom/client/c mobileloco_la-mobileloco_plugin.lo libtool: link: gcc -shared .libs/mobileloco_la-mobileloco_plugin.o -Wl,-rpath -Wl,/home/aclodic/Work/01_Demo/mobile-loco/build/pocolibs/client/c/.libs -Wl,-rpath -Wl,/home/aclodic/Work/01_Demo/INSTALL/lib ./.libs/libmobileloco-c-client.so -pthread -pthread -Wl,-soname -Wl,mobileloco-1.0.so -o .libs/mobileloco-1.0.so libtool: link: (cd ".libs" && rm -f "mobileloco.so" && ln -s "mobileloco-1.0.so" "mobileloco.so") libtool: link: ar cru .libs/mobileloco.a mobileloco_la-mobileloco_plugin.o libtool: link: ranlib .libs/mobileloco.a libtool: link: ( cd ".libs" && rm -f "mobileloco.la" && ln -s "../mobileloco.la" "mobileloco.la" ) make[1]: Leaving directory `/home/aclodic/Work/01_Demo/mobile-loco/build/pocolibs/client/c' make[1]: Entering directory `/home/aclodic/Work/01_Demo/mobile-loco/build' make[1]: Nothing to be done for `all-am'. make[1]: Leaving directory `/home/aclodic/Work/01_Demo/mobile-loco/build'
Installation
The built binaries and libraries (and some associated files) need to be copied to their final locations. This is achieved by executing make install. Depending of the {$INSTALL_PATH} you used, this may require root privilege.
gupta[build] make install Making install in codels make[1]: Entering directory `/home/aclodic/Work/01_Demo/mobile-loco/build/codels' make install-am make[2]: Entering directory `/home/aclodic/Work/01_Demo/mobile-loco/build/codels' make[3]: Entering directory `/home/aclodic/Work/01_Demo/mobile-loco/build/codels' test -z "/home/aclodic/Work/01_Demo/INSTALL/lib" || /bin/mkdir -p "/home/aclodic/Work/01_Demo/INSTALL/lib" /bin/bash ../libtool --mode=install /usr/bin/install -c libmobileloco_codels.la '/home/aclodic/Work/01_Demo/INSTALL/lib' libtool: install: /usr/bin/install -c .libs/libmobileloco_codels-1.0.so /home/aclodic/Work/01_Demo/INSTALL/lib/libmobileloco_codels-1.0.so libtool: install: (cd /home/aclodic/Work/01_Demo/INSTALL/lib && { ln -s -f libmobileloco_codels-1.0.so libmobileloco_codels.so || { rm -f libmobileloco_codels.so && ln -s libmobileloco_codels-1.0.so libmobileloco_codels.so; }; }) libtool: install: /usr/bin/install -c .libs/libmobileloco_codels.lai /home/aclodic/Work/01_Demo/INSTALL/lib/libmobileloco_codels.la libtool: install: /usr/bin/install -c .libs/libmobileloco_codels.a /home/aclodic/Work/01_Demo/INSTALL/lib/libmobileloco_codels.a libtool: install: chmod 644 /home/aclodic/Work/01_Demo/INSTALL/lib/libmobileloco_codels.a libtool: install: ranlib /home/aclodic/Work/01_Demo/INSTALL/lib/libmobileloco_codels.a libtool: finish: PATH="/home/aclodic/Work/01_Demo/INSTALL:/home/aclodic/Work/01_Demo/INSTALL/bin:/home/aclodic/Work/01_Demo/INSTALL/sbin:/home/aclodic/bin:/usr/local/bin:/home/aclodic/bin:/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:.:/sbin" ldconfig -n /home/aclodic/Work/01_Demo/INSTALL/lib ... ... ... test -z "/home/aclodic/Work/01_Demo/INSTALL/lib/pkgconfig" || /bin/mkdir -p "/home/aclodic/Work/01_Demo/INSTALL/lib/pkgconfig" /usr/bin/install -c -m 644 mobileloco-c-client.pc '/home/aclodic/Work/01_Demo/INSTALL/lib/pkgconfig' make[2]: Leaving directory `/home/aclodic/Work/01_Demo/mobile-loco/build/pocolibs/client/c' make[1]: Leaving directory `/home/aclodic/Work/01_Demo/mobile-loco/build/pocolibs/client/c' make[1]: Entering directory `/home/aclodic/Work/01_Demo/mobile-loco/build' make[2]: Entering directory `/home/aclodic/Work/01_Demo/mobile-loco/build' make[2]: Nothing to be done for `install-exec-am'. test -z "/home/aclodic/Work/01_Demo/INSTALL/lib/pkgconfig" || /bin/mkdir -p "/home/aclodic/Work/01_Demo/INSTALL/lib/pkgconfig" /usr/bin/install -c -m 644 libmobileloco_codels.pc '/home/aclodic/Work/01_Demo/INSTALL/lib/pkgconfig' make[2]: Leaving directory `/home/aclodic/Work/01_Demo/mobile-loco/build' make[1]: Leaving directory `/home/aclodic/Work/01_Demo/mobile-loco/build'
Module execution
Once compiled, the module is ready to be executed. The module is located in the bin subdirectory of the directory specified as prefix in the configuration step. This is an executable whose name will depend of the $TEMPLATE you choose. E.g., in our case, if we use pocolibs template, we will have mobileloco-pocolibs executable and if you use ros template, we will have mobileloco-ros.
pocolibs
tcl
h2 init & mobileloco-pocolibs & genomixd & eltclsh eltclsh > package require genomix 1.0 eltclsh > genomix::connect genomix1 eltclsh > genomix1 load mobileloco pocolibs execution environment version 2.12.99 Copyright (c) 1999-2011 CNRS-LAAS mobileloco eltclsh > mobileloco:: ::mobileloco::E_current_position ::mobileloco::GotoPosition ::mobileloco::SetSpeed ::mobileloco::abort_activity ::mobileloco::connect_remote ::mobileloco::GetSpeed ::mobileloco::Monitor ::mobileloco::Stop ::mobileloco::connect_port ::mobileloco::genom_state eltclsh > ::mobileloco::GetSpeed current_speed {s ::mobileloco::SLOW}
pkill mobileloco-pocolibs pkill genomix h2 end
ros
tcl
ros-core & mobileloco-ros & genomixd & eltclsh eltclsh > package require genomix 1.0 eltclsh > genomix::connect genomix1 eltclsh > genomix1 load mobileloco pocolibs execution environment version 2.12.99 Copyright (c) 1999-2011 CNRS-LAAS mobileloco eltclsh > mobileloco:: ::mobileloco::E_current_position ::mobileloco::GotoPosition ::mobileloco::SetSpeed ::mobileloco::abort_activity ::mobileloco::connect_remote ::mobileloco::GetSpeed ::mobileloco::Monitor ::mobileloco::Stop ::mobileloco::connect_port ::mobileloco::genom_state eltclsh > ::mobileloco::GetSpeed current_speed {s ::mobileloco::SLOW}
pkill mobileloco-pocolibs pkill genomix h2 end
ros
Launch
ros-core & mobileloco-ros &
Get info on your module:
export ROS_PACKAGE_PATH=$ROS_PACKAGE_PATH:$INSTALLDIR/build/ros/server/genom_mobileloco export PYTHONPATH=/opt/ros/fuerte/lib/python2.6/dist-packages:$INSTALLDIR/lib/python2.6/site-packages rosnode -info mobileloco
Send a command:
/opt/ros/electric/stacks/common/actionlib/tools/axclient.py /mobileloco/GotoPosition genom_mobileloco/GotoPosition ...
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:
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.
Contents