/**
\page note_devices Getting Started with YARP Devices

\tableofcontents

For robotics, we need access to all sorts of strange devices.
This section contains a tutorial on the YARP view of what devices are.
If you just want to get coding immediately, see
the \link dev_all main page for YARP Devices\endlink, including
information on interfaces, implementation, configuration and
\link dev_runtime commandline\endlink usage.

\section note_devices_yarp YARP Devices

There are three separate concerns related to devices in YARP:

\li Implementing specific drivers for particular devices
\li Defining interfaces for device families
\li Implementing network wrappers for interfaces

The first step, creating drivers for particular devices, is obvious;
every robotics project needs to interface with hardware somehow.

The second step, defining interfaces for families of devices,
is important in the longer term.  If you change your camera
or your motor control board, how much of your code needs to
change too?  If you view your devices through well thought out
interfaces, the impact of device change can be minimized.

The third step, network wrappers, is important to give
flexibility.  You can scale up your computing cluster, or
isolate hardware devices that don't play well together,
or have specific OS dependencies etc.

A driver in YARP is just a C++ class.  Interfaces are simply abstract
base classes.  And network wrappers are just special cases of devices
that happen to use network resources to satisfy their interfaces.
Let's look at some examples to make this clear.


\section note_devices_example Framegrabber interfaces

We call devices that produce a stream of images "framegrabbers" for
historical reasons.  There are a number of interfaces associated with
framegrabbers.  Here's one, IFrameGrabberImage:

\code
class yarp::dev::IFrameGrabberImage {
public:
    virtual bool getImage(yarp::sig::ImageOf<yarp::sig::PixelRgb>& image) = 0;
    virtual int height() const = 0;
    virtual int width() const = 0;
};
\endcode

Notice that IFrameGrabberImage doesn't do anything itself -- it
just declares methods to get an image and image dimensions.
There are several classes in YARP that implement this interface
(in other words, they inherit from it and define the methods).
One example is DragonflyDeviceDriver.  This interfaces
with a Point Grey digital camera, using different libraries on
different operating systems.  It implements several
interfaces; here are just two of them:

\dot
digraph device_example1 {
	node [shape=record, fontname=Helvetica, fontsize=10];
	edge [fontname=Helvetica, fontsize=10, arrowhead="open", style="solid"];
	IFrameGrabberImage;
	IFrameGrabberControls;

//	PicoloDeviceDriver;
	DragonflyDeviceDriver;
//	FakeFrameGrabber;
//	RemoteFrameGrabber;
//	ServerFrameGrabber;

//	PicoloDeviceDriver    -> IFrameGrabberImage;
//	PicoloDeviceDriver    -> IFrameGrabberControls;
	DragonflyDeviceDriver -> IFrameGrabberImage;
	DragonflyDeviceDriver -> IFrameGrabberControls;
//	FakeFrameGrabber      -> IFrameGrabberImage;
//	FakeFrameGrabber      -> IFrameGrabberControls;
//	RemoteFrameGrabber    -> IFrameGrabberImage;
//	RemoteFrameGrabber    -> IFrameGrabberControls;
//	ServerFrameGrabber    -> IFrameGrabberImage;
//	ServerFrameGrabber    -> IFrameGrabberControls;

}
\enddot

Since you may not have any hardware devices available to you
right now, let's make a "fake" framegrabber that implements
the IFrameGrabberImage interface:

\code
class FakeFrameGrabber : public IFrameGrabberImage {
private:
    int w, int h;
public:
    FakeFrameGrabber(int w, int h) : w(w), h(h) {
    }

    virtual bool getImage(yarp::sig::ImageOf<yarp::sig::PixelRgb>& image) {
	Time::delay(0.5);  // simulate waiting for hardware to report
	image.resize(w,h);
	image.zero();
	return true;
    }

    virtual int height() const {
	return h;
    }

    virtual int width() const {
	return w;
    }
};
\endcode

All this does is return blank images roughly every half second,
but it does indeed implement the IFrameGrabberImage interface.

We very nearly have a YARP device driver.  Sometimes we want
to be able to create devices flexibly, based on a configuration
file, or without having to worry about where their header file is.
For these purposes, YARP requires that:
\li All device drivers inherit from the "DeviceDriver" class.
\li All device drivers implement an <i>open</i> and <i>close</i> method.
\li Device drivers should be using no hardware resources before open is
    called or after close is called.
YARP in return will promise that <i>open</i> will be the first
method called after construction, and that if open returns false
no other methods will be called before destruction.
The <i>open</i> method takes a configuration object
which can contain arbitrary properties.

This is quite straightforward to do for our fake framegrabber:

\code
class FakeFrameGrabber : public IFrameGrabberImage,
			 public yarp::dev::DeviceDriver {
private:
    int w, int h;
public:
    FakeFrameGrabber() {
	h = w = 0;
    }

    bool open(int w, int h) {
	this->w = w;
	this->h = h;
	return w>0 && h>0;
    }

    virtual bool open(yarp::os::Searchable& config) {
	// extract width and height configuration, if present
	// otherwise use 128x128
	int desiredWidth = config.check("w",Value(128)).asInt32();
	int desiredHeight = config.check("h",Value(128)).asInt32();
	return open(desiredWidth,desiredHeight);
    }

    virtual bool close() {
	return true; // easy
    }

    virtual bool getImage(yarp::sig::ImageOf<yarp::sig::PixelRgb>& image) {
	Time::delay(0.5);  // simulate waiting for hardware to report
	image.resize(w,h);
	image.zero();
	return true;
    }

    virtual int height() const {
	return h;
    }

    virtual int width() const {
	return w;
    }
};
\endcode

Now we have a good YARP device driver (even if it is fake).
We've chosen to require that the width and height of images
be greater than zero, which seems reasonable.


\section note_devices_library Creating and configuring the new device

We can create, configure, and use our device directly, without
any bureaucracy:
\code
FakeFrameGrabber fakey;
fakey.open(640,480);
ImageOf<PixelRgb> img;
fakey.getImage(img);
...
\endcode

If we're smart, we'd make as much of our code as possible depend
just on the interface IFrameGrabberImage, so that we can reuse it
or substitute in a different framegrabber later:
\code
// creation and configuration -- depends on specific device type
FakeFrameGrabber fakey;
fakey.open(640,480);
IFrameGrabberImage& genericGrabber = fakey;
// from here on, we only care that our device implements IFrameGrabberImage
ImageOf<PixelRgb> img;
genericGrabber.getImage(img);
...
\endcode
This is a standard software engineering technique for minimizing unnecessary
coupling between modules.

Suppose we want to go further, and let the framegrabber
we use be controlled by a command line option.  So it could
either be our FakeFrameGrabber, or a real device like
DragonflyDeviceDriver or PicoloDeviceDriver (another framegrabber),
or RemoteFrameGrabber (a proxy for a framegrabber device on another
machine).

YARP comes with a helper for doing this.  It maintains a simple
database of the drivers you have compiled and available.
You can see this database by running "yarpdev",
which tells you something like:
\verbatim
...
Here are devices listed for your system:

Device <dragonfly>
   documented by the C++ class DragonflyDeviceDriver
   Wrapped for the network by <grabber>

Device <fakeFrameGrabber>
   documented by the C++ class FakeFrameGrabber
   Wrapped for the network by <grabber>

Device <grabber>
   documented by the C++ class ServerFrameGrabber
   Does not need a network wrapper.
...
\endverbatim
We see a "dragonfly" listing associated with the DragonflyDeviceDriver
class --
"dragonfly" is this devices <i>common name</i> to which it is referred to in
configuration files, command line options, etc..
There is also a "fakeFrameGrabber" listing associated with a FakeFrameGrabber
class -- this is in fact a more elaborate version of the fake framegrabber
we've been working on, for testing purposes.  We can ignore it for now.
There is also a "grabber" device listed, with is a network wrapper
that works for all framegrabber devices.

You can instantiate any device listed here from your code as follows:
\code
  #include <yarp/dev/PolyDriver.h>
  #include <yarp/dev/IFrameGrabberImage.h>
  #include <yarp/sig/Image.h>
  using yarp::dev::PolyDriver;
  using yarp::dev::IFrameGrabberImage;
  using yarp::sig::ImageOf;
  using yarp::sig::PixelRgb;
  ...
  PolyDriver dd("dragonfly");
  if (!dd.isValid()) {
    printf("Dragonfly not available\n");
    exit(1);
  }
  IFrameGrabberImage *grabber;
  dd.view(grabber);
  if (grabber!=NULL) {
    printf("*** Device can supply images\n");
    ImageOf<PixelRgb> img;
    if (grabber->getImage(img)) {
      printf("*** Got a %zux%zu image\n", img.width(), img.height());
    }
  }
\endcode
Just replace the name "dragonfly" with the device you want.

If we want to be able to create a FakeFrameGrabber through the
same mechanism, we need to add a <i>factory</i> for it to
the device driver database.  Here's how:
\code
DriverCreator *fakey_factory =
   new DriverCreatorOf<FakeFrameGrabber>("fakey","grabber","FakeFrameGrabber");
Drivers::factory().add(fakey_factory); // hand factory over to YARP
\endcode
The name "fakey" is an arbitrary common name we pick.
The name "grabber" gives a network wrapper for this device ("" if there
is none).
The class name "FakeFrameGrabber" is recorded to let the user know where
to look for documentation on this device.

Now we can do:
\code
  PolyDriver dd("fakey");
  IFrameGrabberImage *grabber;
  dd.view(grabber);
  if (grabber == nullptr) { exit(1); } // failed
  // from here on, we only care that our device implements IFrameGrabberImage
  ImageOf<PixelRgb> img;
  grabber->getImage(img);
  ...
\endcode

This form is calling FakeFrameGrabber::open without any
configuration information set up.  To pass in configuration options,
we do:
\code
  Property config("(device fakey) (w 640) (h 480)");
  PolyDriver dd(config);
  ...
\endcode

Once we've reached this point, some fun things become possible.
For example:
\code
  Property config("(device grabberDual) (subdevice fakey) (w 640) (h 480)");
  PolyDriver dd(config);
  ...
\endcode
This will create and configure a FakeFrameGrabber, then
wrap it up in a ServerFrameGrabber so that it can be accessed on
the network.

\subsection note_devices_list Find out available devices and their parameters

To have a full lost of devices and check their parameters follow the instruction at the page \ref yarpdev

More advanced topics: true nesting of device properties; calibration objects.

*/
