<?xml version="1.0" encoding="utf-8"?><!DOCTYPE article  PUBLIC '-//OASIS//DTD DocBook XML V4.4//EN'  'http://www.docbook.org/xml/4.4/docbookx.dtd'><article><articleinfo><title>Robotica/PlayerStageRoMAA/PlayerDriverRoMAA1/DriverStruct</title><revhistory><revision><revnumber>3</revnumber><date>2011-04-20 22:03:12</date><authorinitials>GonzaloPerezPaina</authorinitials><revremark>organización de la wiki</revremark></revision><revision><revnumber>2</revnumber><date>2010-06-05 22:54:35</date><authorinitials>GonzaloPerezPaina</authorinitials></revision></revhistory></articleinfo><section><title>Estructura del driver</title><section><title>Declaración de la clase RomaaDriver</title><screen><![CDATA[ 1 class RomaaDriver : public Driver
 2 {
 3   public:
 4     RomaaDriver( ConfigFile* cf, int section );
 5     ~RomaaDriver();
 6     
 7     // Must implement the following methods
 8     virtual int Setup();
 9     virtual int Shutdown();
10     
11     // This method will be invoked on each incoming message
12     virtual int ProcessMessage( QueuePointer& resp_queue,
13         player_msghdr* hdr,
14         void* data );
15         
16   protected:
17   private:
18   
19     // Main function for device thread
20     virtual void Main(); 
21 };]]></screen></section><section><title>Métodos virtuales</title><itemizedlist><listitem><para><emphasis role="strong">Setup:</emphasis> Realiza funciones de inicialización especificas del dispositivo por ej. abrir y configurar un puerto de comunicación serie; también ejecuta el <emphasis>thread</emphasis> del driver. El método <emphasis>Setup()</emphasis> es llamado cada vez que un cliente se <emphasis>subscribe</emphasis> al driver.  </para></listitem><listitem><para><emphasis role="strong">Shutdown:</emphasis> Es el opuesto al método <emphasis>Setup()</emphasis>. <emphasis>Shutdown()</emphasis> asegura la terminación de dispositivos como por ej. cerrar un puerto de comunicación serie; también detiene el <emphasis>thread</emphasis> del driver.  </para></listitem><listitem><para><emphasis role="strong"><ulink url="https://ciii.frc.utn.edu.ar/wiki/Robotica/PlayerStageRoMAA/PlayerDriverRoMAA1/DriverStruct/wiki/ProcessMessage#">ProcessMessage</ulink>:</emphasis> Este método se invoca con cada mensaje entrante al servidor y ofrece la posibilidad de enviar una respuesta <emphasis>publicando</emphasis> un mensaje utilizando la función miembro pública <emphasis>Publish()</emphasis>.  </para></listitem><listitem><para><emphasis role="strong">Main:</emphasis> Es la función principal del <emphasis>thread</emphasis> del dispositivo, donde se incluyen todas las interacciones con el dispositivo.  </para></listitem></itemizedlist></section><section><title>Registro del driver en el servidor e inicialización</title><para>El <emphasis>server player</emphasis> inicia el plug-in driver llamando a <emphasis role="strong">player_driver_init</emphasis> (función en C), esta función llama a <code>RomaaDriver_Register</code>. </para><screen><![CDATA[extern "C" 
{
  int player_driver_init( DriverTable* table )
  {
    RomaaDriver_Register( table );
    return(0);
  }
}]]></screen><para><emphasis role="strong"><ulink url="https://ciii.frc.utn.edu.ar/wiki/Robotica/PlayerStageRoMAA/PlayerDriverRoMAA1/DriverStruct/wiki/RomaaDriver#">RomaaDriver</ulink>_Register</emphasis> agrega el driver a una tabla de drivers del <emphasis>player server</emphasis> llamando a <code>RomaaDriver_Init</code>. </para><screen><![CDATA[void RomaaDriver_Register( DriverTable* table )
{
  table->AddDriver( "romaadriver", RomaaDriver_Init );
}]]></screen><para><emphasis role="strong"><ulink url="https://ciii.frc.utn.edu.ar/wiki/Robotica/PlayerStageRoMAA/PlayerDriverRoMAA1/DriverStruct/wiki/RomaaDriver#">RomaaDriver</ulink>_Init</emphasis> crea un nuevo objeto <emphasis><ulink url="https://ciii.frc.utn.edu.ar/wiki/Robotica/PlayerStageRoMAA/PlayerDriverRoMAA1/DriverStruct/wiki/RomaaDriver#">RomaaDriver</ulink></emphasis> y devuelve un puntero al driver. </para><screen><![CDATA[Driver* RomaaDriver_Init( ConfigFile* cf,
    int section )
{
  // Create and return a new instance of this driver
  return ( (Driver*)(new RomaaDriver( cf, section )) );
}]]></screen><para>Una vez creado el objeto <emphasis><ulink url="https://ciii.frc.utn.edu.ar/wiki/Robotica/PlayerStageRoMAA/PlayerDriverRoMAA1/DriverStruct/wiki/RomaaDriver#">RomaaDriver</ulink></emphasis> se ejecuta el constructor, este carga datos del archivo de configuración (*.cfg) del <emphasis>player server</emphasis>.  En el siguiente código utiliza un inicializador de constructor para inicializar los miembros datos con los parámetros pasados. Este constructor se utiliza para <emphasis role="strong">una única</emphasis> interfaz, en este caso <emphasis>position2d</emphasis> (<ulink url="http://playerstage.sourceforge.net/doc/Player-2.1.0/player/group__interfaces.html">ver</ulink> listado de interfaces definidas en Player). </para><screen><![CDATA[RomaaDriver::RomaaDriver(ConfigFile* cf, int section)
  : Driver(cf, section, false, PLAYER_MSGQUEUE_DEFAULT_MAXLEN,
                     PLAYER_POSITION2D_CODE)
{
  // Read an option from the configuration file
  return;
}]]></screen><para>El <ulink url="http://playerstage.sourceforge.net/doc/Player-2.1.0/player/classDriver.html#f54e042eca17926aca9c6e62a9b160fc">prototipo</ulink> de la clase <emphasis role="strong">Driver</emphasis> es </para><screen><![CDATA[   Driver (ConfigFile *cf, int section, bool overwrite_cmds, size_t queue_maxlen, int interf)]]></screen><para>Las funciones <emphasis role="strong"><ulink url="https://ciii.frc.utn.edu.ar/wiki/Robotica/PlayerStageRoMAA/PlayerDriverRoMAA1/DriverStruct/wiki/RomaaDriver#">RomaaDriver</ulink>_Init</emphasis> y <emphasis role="strong"><ulink url="https://ciii.frc.utn.edu.ar/wiki/Robotica/PlayerStageRoMAA/PlayerDriverRoMAA1/DriverStruct/wiki/RomaaDriver#">RomaaDriver</ulink>_Register</emphasis> son funciones declaradas fuera de la clase así pueden ser invocada sin ningún contexto de objeto. </para></section><section><title>Secuencia del server</title><para>Al ejecutar el servidor player mediante =<code>player romaa.cfg</code>=, se imprime lo siguiente en pantalla, donde en color negro se muestran los mensaje del server player, en %RED%rojo%ENDCOLOR% ejecución de métodos y %BLUE%azul%ENDCOLOR% mensajes del driver. </para><orderedlist numeration="arabic"><listitem><para>trying to load /home/gfpp/programas/romaa_player_driver/./libromaadriver...  </para></listitem><listitem><para>success  </para></listitem><listitem><para>invoking player_driver_init()...  </para></listitem><listitem><para>%RED%- RomaaDriver _Register%ENDCOLOR%  </para></listitem><listitem><para>success  </para></listitem><listitem><para>%RED%- RomaaDriver _Init%ENDCOLOR%  </para></listitem><listitem><para>%RED%- RomaaDriver::<ulink url="https://ciii.frc.utn.edu.ar/wiki/Robotica/PlayerStageRoMAA/PlayerDriverRoMAA1/DriverStruct/wiki/RomaaDriver#">RomaaDriver</ulink>%ENDCOLOR%  </para></listitem><listitem><para>listening on 6665  </para></listitem><listitem><para>Added file watch 4  </para></listitem><listitem><para>Added file watch 5  </para></listitem><listitem><para>Listening on ports: 6665  </para></listitem><listitem><para>Added file watch 6  </para></listitem><listitem><para>accepted TCP client 0 on port 6665, fd 6  </para></listitem><listitem><para>%RED%- RomaaDriver::Setup%ENDCOLOR%  </para></listitem><listitem><para>romaadriver initialising...  </para></listitem><listitem><para>%BLUE%Connecting at ...%ENDCOLOR%  </para></listitem><listitem><para>%BLUE%serial dev: /dev/ttyS1%ENDCOLOR%  </para></listitem><listitem><para>%BLUE%baudrate: 38400%ENDCOLOR%  </para></listitem><listitem><para>%BLUE%romaadriver ready%ENDCOLOR%  </para></listitem><listitem><para>%RED%- RomaaDriver::Main%ENDCOLOR%  </para></listitem><listitem><para>%RED%- RomaaDriver::<ulink url="https://ciii.frc.utn.edu.ar/wiki/Robotica/PlayerStageRoMAA/PlayerDriverRoMAA1/DriverStruct/wiki/ProcessMessage#">ProcessMessage</ulink>%ENDCOLOR%  </para></listitem><listitem><para>closing TCP connection to client 0 on port 6665  </para></listitem><listitem><para>%RED%- RomaaDriver::Shutdown%ENDCOLOR%  </para></listitem><listitem><para>Shuting romaadriver down  </para></listitem><listitem><para>%BLUE%romaadriver has been shutdown%ENDCOLOR%  </para></listitem><listitem><para>Quitting.  </para></listitem><listitem><para>%RED%- RomaaDriver::~<ulink url="https://ciii.frc.utn.edu.ar/wiki/Robotica/PlayerStageRoMAA/PlayerDriverRoMAA1/DriverStruct/wiki/RomaaDriver#">RomaaDriver</ulink>%ENDCOLOR%  </para></listitem></orderedlist><para>Se destacan algunos puntos importantes </para><itemizedlist><listitem><para><emphasis role="strong">1</emphasis> se carga el driver <code>libromaadriver</code>  </para></listitem><listitem><para><emphasis role="strong">12</emphasis> se ejecuta un programa cliente ( =<code>playerv</code>=)  </para></listitem><listitem><para><emphasis role="strong">22</emphasis> se desconecta el cliente  </para></listitem><listitem><para><emphasis role="strong">26</emphasis> se termina la ejecución del servidor  </para></listitem></itemizedlist></section><section><title>Constructor</title><para>En el contructor se lee el archivo de configuración (*.cfg) y se definen las interfaces utilizadas. (<ulink url="http://playerstage.sourceforge.net/doc/Player-2.1.0/player/classConfigFile.html">ver</ulink> Configuration file class). </para><para>En el caso de <emphasis role="strong">una única</emphasis> interfaz <emphasis>position2d</emphasis> para el control de motores y odometria seria </para><screen><![CDATA[RomaaDriver::RomaaDriver(ConfigFile* cf, int section)
  : Driver(cf, section, false, PLAYER_MSGQUEUE_DEFAULT_MAXLEN, 
    PLAYER_POSITION2D_CODE)
]]><![CDATA[
  // Read an option from the configuration file
  this->tty_dev = cf->ReadString(section, "port", "/dev/ttyS0");
  this->baudrate = cf->ReadInt(section, "baudrate", 38400);
]]><![CDATA[
  return;
}]]></screen><para>Si el driver provee de múltiples interfaces se utiliza el siguiente constructor </para><screen><![CDATA[RomaaDriver::RomaaDriver(ConfigFile* cf, int section) : Driver(cf, section)]]></screen><para>Y se deben agregar las interfaces explicitamente </para><screen><![CDATA[  player_devaddr_t   position_addr;
]]><![CDATA[
  if ( cf->ReadDeviceAddr( &position_addr, section, "provides",    
                          PLAYER_POSITION2D_CODE, -1, NULL) == 0 )    
  {    
    if ( this->AddInterface( position_addr ) != 0 )    
    {    
      this->SetError(-1);    
      return;    
    }    
  }    ]]></screen></section><section><title>Main</title><para>La función Main en el núcleo del plugin driver que se ejecuta en un thread, esto significa que este corre en paralelo con otros drivers. La mayor parte de la función Main esta contenida en un loop <emphasis>while(true)</emphasis> o <emphasis>for(;;)</emphasis>. La función Main tiene que llamar unas pocas funciones específicas: </para><itemizedlist><listitem><para><emphasis role="strong">pthread_testcancel:</emphasis> Verifica si el thread fue terminado (killed). La función saldrá del loop y ejecutara la el método <emphasis>Shutdown</emphasis>.  </para></listitem><listitem><para><emphasis role="strong"><ulink url="https://ciii.frc.utn.edu.ar/wiki/Robotica/PlayerStageRoMAA/PlayerDriverRoMAA1/DriverStruct/wiki/ProcessMessage#">ProcessMessage</ulink>:</emphasis> Es una llamada a Player que llamará la función <emphasis><ulink url="https://ciii.frc.utn.edu.ar/wiki/Robotica/PlayerStageRoMAA/PlayerDriverRoMAA1/DriverStruct/wiki/ProcessMessage#">ProcessMessage</ulink>()</emphasis> del plugin con cada mensaje esperando en la cola de mensajes.  </para></listitem><listitem><para><emphasis role="strong">usleep:</emphasis> Es un comando de <emphasis>sleep</emphasis> para liberar los recursos utilizados por el driver.  </para></listitem></itemizedlist><para>La función <emphasis>Main</emphasis> es donde se debería leer información de los dispositivos, formatear los datos especificos para un interfaz y publicarlos a Player. </para></section></section></article>