{{{#!wiki comment <> }}} = Tutorial: making the mobileloco and mobiledisp Modules = == Needs == Check this [[genom3/tutorial/install|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 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 gotoposStart(in goto_position, inout ::ids) yield exec, ether; codel gotoposExec(inout ::ids, port out E_current_position) yield exec, end, stop; codel 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 codel of the task * gotoposStart, gotoExec: which are and 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_dispWindow(out info) yield waittill, stop; async codel waittill_dispWindow(inout info, port in E_current_position) yield waittill, cleanwin, up, down, stop; codel cleanwin_dispWindow(inout info) yield waittill; codel up_dispWindow(in SetSpeed, in GetSpeed) yield waittill; codel down_dispWindow(in SetSpeed, in GetSpeed) yield waittill; codel stop_dispWindow() yield ether; throw memory_error, cannot_open_display; }; task dispPosition { period 100ms; codel start_dispPosition(inout info) yield display, stop; codel display_dispPosition(in info, port in E_current_position) yield display, stop; codel 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 #include #include #include 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_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_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_dispWindow(in SetSpeed, in GetSpeed) yield waittill; codel 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 [[transgen3/tutorial/demo-mobile-superv|tutorial]].