/**
\page dev-how-to Device Drivers How-To

\tableofcontents

For a more up-to-date method of dealing with devices see:

\li \ref add_a_device

In YARP, a device driver is a class that implements one or more
\ref dev_iface "interfaces".

If you're interested in learning how to use device drivers, see \ref
note_devices, \ref dev_examples, and \ref yarpdev.  If you're read all
that before and are interested in learning how to create devices, then
read on...


\section dev-howto-intro What is a device driver in YARP?

A device driver should derive from the abstract class
yarp::dev::DeviceDriver. This interface contains methods common to all
device drivers, such as open and close.

Additionally a device driver should implement a selection of other
interfaces that capture what it shares with other families of
devices. For example a camera might implement yarp:dev::IFrameGrabber (a "raw"
interface to the raw data) and/or yarp::dev::IFrameGrabberImage
(a higher-level source of images). For example,
the yarp::dev::DragonflyDeviceDriver class implements a few of
these interfaces. Interfaces are abstract classes, the idea is that
from outside the user can access a device by using a pointer to the
interface he/she needs, if that interface is supported by the
device. This is quite similar to the way COM works (in a simplified way).

In practice to implement a new device you create a new object which
derives from DeviceDriver and from the interface you want to support,
and you implement them. The interfaces are documented in the code,
using the doxygen standard. See \ref note_devices for an example.

\section dev-howto-lib Adding a device driver to YARP_dev

Some practical rules are also required to have cmake include your .cpp/.h
files in the YARP_dev (device library) project.

Let's assume you want to create the Foo device.
Start by creating a folder called:
\verbatim
YARP_dev/src/foo/
\endverbatim

Files in foo will be organized in:
- /foo/common: This folder can contain header/code files common to
all operating systems, if there are any such files.

- /foo/$os$ (where $os$ can be either "linux" or "winnt"): This stores operating-system specific files.

- /foo/default: This directory is intended for a "default" implementation which will be tried if the relevant operating-specific directory is not present.

Each of these directories should be organized as:

- /foo/$subdir$/dd_orig: This contains header and lib files provided with your
specific device by the manufacturer, if any.
- /foo/$subdir$/yarp: This contains header and cpp files implementing the YARP device driver (for example FooDeviceDriver.cpp).

CMake searches for YARP device drivers listed in:
\verbatim
YARP_dev/AvailableDevices.txt
\endverbatim

Here you specify the directory that contains the device driver tree (in the above example we called it foo). For example we could add "foo" in as follows:
\verbatim
SET(AVAILABLE_DEVICES picolo dragonfly esdMotionControl foo)
\endverbatim

This is the list of directories under YARP_dev that are searched for device drivers, when CMake runs.  CMake does this by searching for a file called libraries.txt.

The file libraries.txt tells cmake which additional libraries or
packages the device depends on. This files is platform
specific and is located in /foo/$os$/. If this file is not found cmake
simply warns the user and ignores the device.

The file libraries.txt has two options. If the device driver requires a library that is included in the YARP tree you write:
\verbatim
YARP_LOCAL;ntcan.lib
\endverbatim

This tells cmake that the device driver requires the library
"ntcan.lib" and that this file is available within the YARP tree (in
./dd_orig/). CMake will search ./dd_orig/lib for ntcan.lib. If
ntcan.lib is not found an error will be shown, and the user will have
the possibility to manually enter the correct location of the
file. This .lib file has probably header files associated with it. We
recommend you put them in ./dd_orig/include and include them directly
in you code as something like:

\code
  #include <../dd_orig/include/foo_lib.h>
\endcode

Be careful to "hide" header files specific of each device driver (in
this example foo_lib.h) so that symbols defined there are not visible
from outside. In practice you do this by avoiding to include them in
your header files.

If the device driver has external dependencies you write:
\verbatim
YARP_EXTERNAL;raw1394;dc1394_control
\endverbatim

In this example we are telling CMake that the device driver foo
depends on the packages raw1394 and dc1394_control. In this case cmake
will not do any check, but will print a warning message saying that
these modules are required. It is the user's responsibility (for now,
and perhaps forever) to install these packages in the correct locations.

Everything going well, you will see on CMake a list of variables whose
name follows the pattern ENABLE_device_name. These are the devices
that are listed in AvailableDevices.txt. By default each flag is OFF
meaning that the corresponding device will be ignored by CMake. You
can turn ON the flags for the devices you want to compile, and type
configure again. CMake will search for the file libraries.txt. If
among the selected drivers there are some that require additional
libraries there will be a list of variables whose name follows the
pattern PATH-device_name. If these libraries are correctly located in
the ./dd_orig/lib folder, all PATH-device_name entry should be
correctly set. Although you can manually locate the libraries
yourself, this probably means that there is an error in your YARP
distribution or in the way the device is configured.

If all libraries are located, you can go on with CMake and generate
your make/project files. If at least one device driver was selected
and correctly found, YARP_dev should now compile.

\section dev-howto-factory Adding a device driver factory

It is useful to be able to create devices in a reconfigurable way,
for example using the \ref yarpdev "yarpdev" application or the
yarp::dev::PolyDriver class.
This is done be adding a "factory" for your device driver to
YARP_dev.

Take a look at this file:
\verbatim
src/libYARP_dev/src/PopulateDrivers.cpp.in
\endverbatim

This is a template that CMake configures based on the devices the
user selects, adding factories for them to a global list.  Suppose
your device is called "foo".  Find the part of this file that
contains a list something like this:
\code
#cmakedefine ENABLE_dragonfly
#cmakedefine ENABLE_esdMotionControl
#cmakedefine ENABLE_microphone
#cmakedefine ENABLE_inertiacube2
#cmakedefine ENABLE_XSensMTx
#cmakedefine ENABLE_portaudio
#cmakedefine ENABLE_opencv_grabber
#cmakedefine ENABLE_ffmpeg
\endcode
and add:
\code
#cmakedefine ENABLE_foo
\endcode
This will be replaced with:
\code
#define ENABLE_foo
\endcode
by CMake if the user chooses to compile your device, otherwise it will
be commented out.  You can see the code CMake generates at:
\verbatim
src/libYARP_dev/src_generated/PopulateDrivers.cpp
\endverbatim
This is a generated file, do not modify it!  Make all your changes to
PopulateDrivers.cpp.in.

Now find the part of PopulateDrivers.cpp.in that has lines like:
\code
#ifdef ENABLE_opencv_grabber
#include <yarp/OpenCVGrabber.h>
#endif
\endcode
And add:
\code
#ifdef ENABLE_foo
#include <yarp/Foo.h>
#endif
\endcode
or whatever header file is needed for your device.  The path to the header
file should usually work just as yarp/Foo.h rather than anything more
complicated.

Finally, now that we have our define, and have included the right
header file, we can add the factory for your device.  Go to the
part of PopulateDrivers.cpp.in that has a list of lines like this:
\code
#ifdef ENABLE_portaudio
    add(new DriverCreatorOf<PortAudioDeviceDriver>("portaudio",
                                                   "grabber",
                                                   "PortAudioDeviceDriver"));
#endif
\endcode
Now add in an entry for your device:
\code
#ifdef ENABLE_foo
    add(new DriverCreatorOf<FooDeviceDriver>("foo",
                                             "",
                                             "FooDeviceDriver"));
#endif
\endcode

Replace FooDeviceDriver with the correct name of your class
(which must be derived from yarp::dev::DeviceDriver).
There are also three the
Replace the text "foo" with whatever you want humans to call your device
when they create it -- that's completely up to you.
If there is a network wrapper device that can transport the data
produced by your device, mention it as the second argument.
That's the "" above.  See the Server classes in \ref dev_impl_wrapper
for existing network wrappers.  A fairly generic wrapper is under
development; in the meantime yarp::dev::ServerInertial is an example
to start from if you find you have to write your own.
Note that network wrappers are completely optional.  They
are not needed for use of a device via yarp::dev::PolyDriver.

The last text argument just repeats the class name for documentation
purposes.

\section dev-howto-compile Getting things compiled

Now you should be able to compile your device the same way as any
other YARP device.

 - Start CMake and go to your YARP root directory.
 - Make sure that the "CREATE_DEVICE_LIBRARY_BUILTINS" option is
selected.  Otherwise YARP won't try to build any any hardware
devices into the library.  When this is selected, and you configure,
you get a list of options of the form: ENABLE_*.  There should
be a new one now, called ENABLE_foo (or whatever your device is called).
Select it, reconfigure, and compile.

Then run:
\verbatim
yarpdev --list
\endverbatim
Your device should show up in the list.  To learn more about
using devices from code, see \ref note_devices, and the
examples in example/dev.

\section dev-howto-wow Hey, why not automate all this?

True, we should do more automation than we do now.  For now,
we're just happy to have a mechanism that works solidly on
both UNIX and Windows.

*/
