.. _cpp-create-module:

Extending NAO API - Creating a new module
=========================================

This is a step by step tutorial.


You should have follow the :ref:`cpp-tutos-using-qibuild` tutorial fist.

Create the skeleton using qibuild create
----------------------------------------

qibuild create will simply create a new project.

Navigate to the work tree where you want to create your project then enter:

.. code-block:: console

  $ qibuild create mymodule

This will create a new project in work_tree/mymodule.
We now take a look at what has been generated:

.. code-block:: console

  myproject
  |__ CMakeLists.txt
  |__ main.cpp
  |__ qibuild.cmake
  |__ qibuild.manifest



* CMakeLists.txt:   this is a script file that will be read by CMake to generate makefiles, or Visual Studio solutions.
* main.cpp:         this is just a standard "Hello World".
* qibuild.cmake:    this file MUST be included by the CMakeLists.txt to find the qiBuild CMake framework.
* qibuild.manifest: this file MUST be present for qiBuild to know how to build the foo project.

Declare dependency in CMakeLists.txt
------------------------------------

This file is a standard CMakelists.

.. code-block:: cmake

  cmake_minimum_required(VERSION 2.8)

  # Give a name to the project.
  project(mymodule)

  # You need this to find the qiBuild CMake framework
  include("qibuild.cmake")

  # Create a executable named mymodule
  # with the source file: main.cpp
  qi_create_bin(mymodule "main.cpp")

To communicate with naoqi you need to use a proxy inside your code. Proxies are inside ALCommon library. You **need** to import ALCommon inside your CMakeLists.

Add inside the CMakeLists.txt:

.. code-block:: cmake

  qi_use_lib(<your_project_name> <library_you_want_use_1> <library_you_want_use_2>)

Your CMakeLists will looks like:

.. literalinclude:: /dev/cpp/examples/core/module/myfirstproject/CMakeLists.txt
   :language: cmake

main.cpp
++++++++

This generated file is a standard main.cpp, this one only print an "Hello, world" on standard output.

We now extend a little this file to communicate with NAOqi and call bind function from NAOqi's module.

First of all you need to do a small command line option parser with at least ``--pip`` and ``--pport`` option.

You need create a proxy to the module you want use. To do that you must to
include <alcommon/alproxy.h>, then create a proxy to the module and finally you
can call a method from this module.

.. literalinclude:: /dev/cpp/examples/core/module/myfirstproject/main.cpp
   :language: cpp

Now you know how to communicate with NAOqi and a method from a module, we want
to add some functionality to NAOqi. We will now create a module which it
extends, adds some new features.

How to create a remote module
-----------------------------

A remote module is a program which will connect to NAOqi over the network. It will allow you to extend/add basic NAOqi bind functions.

Right now you have few stuff to do before running a good module.

Create a new class derived from ALModule
++++++++++++++++++++++++++++++++++++++++

You need to create your own inherited class form ALModule. You'll need ALModule and ALBroker.

Here is an example of a basic mymodule.h

.. literalinclude:: /dev/cpp/examples/core/module/myfirstremotemodule/mymodule.h
   :language: cpp

Now you want to implement all your methods. Here an example of a basic mymodule.cpp

.. literalinclude:: /dev/cpp/examples/core/module/myfirstremotemodule/mymodule.cpp
   :language: cpp


Now you already create your inherited class, you can update your main.cpp to create broker and to allow every module to communicate with your bind methods.

Update CMakelists.txt
+++++++++++++++++++++

Here you just need to add the new source file you have created (mymodule.cpp, mymodule.h) using *set* CMake function:

.. code-block:: cmake

  set(<variable_name> <source_file>)

Your CMakeLists.txt should looks like

.. literalinclude:: /dev/cpp/examples/core/module/myfirstremotemodule/CMakeLists.txt
   :language: cmake


Update main.cpp
+++++++++++++++

First of all you need to create a broker, then you must add your new broker into the NAOqi's broker manager. Then you can create your custom module and link it with the new broker you have just created.

Example of main.cpp

.. literalinclude:: /dev/cpp/examples/core/module/myfirstremotemodule/main.cpp
   :language: cpp


Congratulation, you now have created your first module remote. To use it you just need to launch the program created with your robot ip address on parameters.

How to start remote module
--------------------------

Using binary program
++++++++++++++++++++

If you want to start your module on remote, you need to launcher the program you just compiled:

.. code-block:: sh

  ./mymodule --pip <robot_ip> --pport <robot_port>

Example:

.. code-block:: sh

  ./mymodule --pip 192.168.0.12 --pport 9559


Using autoload.ini
++++++++++++++++++

This way will launch your module at NAOqi startup. Be careful you MUST implement an option command line parser for ``--pip`` and ``--pport``.

First of all you need to send your program on your robot (using scp or rsync), and then add the path to your program into /home/nao/naoqi/preference/autoload.ini under [program] tag.

Example of autoload.ini:

.. code-block:: ini

  [program]
  /home/nao/mymodule
  # or
  /home/nao/myfolder/whatever/mymodule


How to create a local module
----------------------------

There is a second ways to create a module. This is a local module. This one is launch in NOAqi's process. Since this is in NOAqi process, this type of module by far the fastest one.

This type of module is not a program (binary) anymore. You will create a library. You need to modified your Cmakelists.txt to create a library and your main.cpp to specified the library entry points.

Modified Cmakelists.txt
+++++++++++++++++++++++

Here you need to replace your **qi_create_bin** by a **qi_create_lib** AND add a dependency to BOOST into your **qi_use_lib** (for boost::shared_ptr).

.. literalinclude:: /dev/cpp/examples/core/module/myfirstlocalmodule/CMakeLists.txt
   :language: cmake

Once you have update the CMakeLists the only thing you need to do is change the main.cpp

Change main.cpp
+++++++++++++++

When you create a NAOqi plugin (local module) you do not need main function, you need the entry and exit points.

They are define by two functions:

* int _createModule(boost::shared_ptr<AL::ALBroker> broker)
* int _closeModule()

If you want your library working one Windows you must export those entry point using **__declspec(dllexport)**.

Now your main.cpp should looks like

.. literalinclude:: /dev/cpp/examples/core/module/myfirstlocalmodule/main.cpp
   :language: cpp

You've just created your first local module for NAOqi.

How to start a local module
---------------------------

Using autoload.ini
++++++++++++++++++

Add the path to your library into the [user] tag in autoload.ini file is the first way to start your module.
This file is located into /home/nao/naoqi/preferences/autoload.ini on your robot.

Example:

.. code-block:: ini

  [user]
  /home/nao/mymodule.so
  # or
  /home/nao/myfolder/whatever/mymodule.so

When you add the path to you library, at NAOqi startup your module will be automatically load in NAOqi process. After that you can use your module as classic ones.


Note: for this to work on your robot, you must cross-compile your module.

You can read about this is the :ref:`cpp-tutos-using-qibuild` section

Using dynamic linking loader
++++++++++++++++++++++++++++

If you want to use your module in another one, the good way to do that is to use programming interface to dynamic linking loader (dlclose, dlerror, dlopen, dlsym).

The first thing is to find the library on your robot. If you use the standard
SDK layout described here (FIXME), you can use qi::path::findLib to obtain the
path to your library. Otherwise, you need to hard code the path to it.

Example:

.. code-block:: cpp

  // Find your library
  std::string filename = qi::path::findLib("mymodule.so");
  // Open your library
  void* handle = qi::os::dlopen(filename.c_str());
  if (!handle)
  {
    // Log the last message comming form dynamic linking function
    qiLogWarning("mymodule") << "Could not load library:"
                             << qi::os::dlerror() << std::endl;
    return -1;
  }

  myFunc fun;
  // Find the symbole you want to use
  fun = (myFunc)qi::os::dlsym(handle, "my_function");
  if (!fun)
  {
    qiLogWarning("mymodule") << "Could not find my_function method in plugin"
                             << std::endl;
    return -1;
  }

  // Use your function
  bool res = fun(args);
  if (!res)
  {
    qi::os::dlclose(handle);
    return -1;
  }




Switching from local to remote using a CMake option
---------------------------------------------------


This is totally optional of course, but that's how all
our examples are written.

For every example, you can choose whether you want a local
or a remote module by setting a CMake option looking like
`MYMODULE_IS_REMOTE`

Adding a CMake option
++++++++++++++++++++++


You should patch your CMake code to look like

.. code-block:: cmake


  option(MYMODULE_IS_REMOTE
    "module is compiled as a remote module (ON or OFF)"
    ON)


  if(MYMODULE_IS_REMOTE)
    add_definitions( " -DMYMODULE_IS_REMOTE ")
    qi_create_bin(....)
  else()
    qi_create_lib(...)
  endif()



Note the call to ``add_definitions``. This will make sure you
can use the same main.cpp, but in one case, create a lib an
export the ``_createModule`` symbol, and in an other case,
create a binary with a ``main`` symbol, by adding
a definition to the compiler.


Patching main.cpp
+++++++++++++++++

Finally, you should patch the ``main.cpp`` file to have something like

.. code-block:: cpp


  #ifdef MYMODULE_IS_REMOTE
  # define ALCALL
  #else
  // when not remote, we're in a dll, so export the entry point
  # ifdef _WIN32
  #  define ALCALL __declspec(dllexport)
  # else
  #  define ALCALL
  # endif
  #endif


  extern "C"
  {
    ALCALL int _createModule(...)
    // ...

  };

  #ifdef HELLOWORLD_IS_REMOTE
  int main(int argc, char* argv[])
  {
    // pointer to createModule
    TMainType sig;
    sig = &_createModule;
    // call main
    return ALTools::mainFunction("MyModule", argc, argv, sig);
  }
  #endif



The full resulting example can be found in here: :download:`helloworld.zip </../build/zip/helloworld.zip>`