## page was renamed from Robotica/RomaaPlayerDriver #acl BecariosGrupo:read,write,revert All:read #acl Default All:read = Estructura del driver = == Declaración de la clase RomaaDriver == {{{ 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 }; }}} == Métodos virtuales == * '''Setup:''' Realiza funciones de inicialización especificas del dispositivo por ej. abrir y configurar un puerto de comunicación serie; también ejecuta el ''thread'' del driver. El método ''Setup()'' es llamado cada vez que un cliente se ''subscribe'' al driver. * '''Shutdown:''' Es el opuesto al método ''Setup()''. ''Shutdown()'' asegura la terminación de dispositivos como por ej. cerrar un puerto de comunicación serie; también detiene el ''thread'' del driver. * '''ProcessMessage:''' Este método se invoca con cada mensaje entrante al servidor y ofrece la posibilidad de enviar una respuesta ''publicando'' un mensaje utilizando la función miembro pública ''Publish()''. * '''Main:''' Es la función principal del ''thread'' del dispositivo, donde se incluyen todas las interacciones con el dispositivo. == Registro del driver en el servidor e inicialización == El ''server player'' inicia el plug-in driver llamando a '''player_driver_init''' (función en C), esta función llama a {{{RomaaDriver_Register}}}. {{{ extern "C" { int player_driver_init( DriverTable* table ) { RomaaDriver_Register( table ); return(0); } } }}} '''RomaaDriver_Register''' agrega el driver a una tabla de drivers del ''player server'' llamando a {{{RomaaDriver_Init}}}. {{{ void RomaaDriver_Register( DriverTable* table ) { table->AddDriver( "romaadriver", RomaaDriver_Init ); } }}} '''RomaaDriver_Init''' crea un nuevo objeto ''RomaaDriver'' y devuelve un puntero al driver. {{{ Driver* RomaaDriver_Init( ConfigFile* cf, int section ) { // Create and return a new instance of this driver return ( (Driver*)(new RomaaDriver( cf, section )) ); } }}} Una vez creado el objeto ''RomaaDriver'' se ejecuta el constructor, este carga datos del archivo de configuración (*.cfg) del ''player server''. 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 '''una única''' interfaz, en este caso ''position2d'' ([[http://playerstage.sourceforge.net/doc/Player-2.1.0/player/group__interfaces.html | ver]] listado de interfaces definidas en Player). {{{ 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; } }}} El [[http://playerstage.sourceforge.net/doc/Player-2.1.0/player/classDriver.html#f54e042eca17926aca9c6e62a9b160fc | prototipo]] de la clase '''Driver''' es {{{ Driver (ConfigFile *cf, int section, bool overwrite_cmds, size_t queue_maxlen, int interf) }}} Las funciones '''RomaaDriver_Init''' y '''RomaaDriver_Register''' son funciones declaradas fuera de la clase así pueden ser invocada sin ningún contexto de objeto. == Secuencia del server == Al ejecutar el servidor player mediante ={{{player romaa.cfg}}}=, 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. 1. trying to load /home/gfpp/programas/romaa_player_driver/./libromaadriver... 1. success 1. invoking player_driver_init()... 1. %RED%- !RomaaDriver _Register%ENDCOLOR% 1. success 1. %RED%- !RomaaDriver _Init%ENDCOLOR% 1. %RED%- !RomaaDriver::RomaaDriver%ENDCOLOR% 1. listening on 6665 1. Added file watch 4 1. Added file watch 5 1. Listening on ports: 6665 1. Added file watch 6 1. accepted TCP client 0 on port 6665, fd 6 1. %RED%- !RomaaDriver::Setup%ENDCOLOR% 1. romaadriver initialising... 1. %BLUE%Connecting at ...%ENDCOLOR% 1. %BLUE%serial dev: /dev/ttyS1%ENDCOLOR% 1. %BLUE%baudrate: 38400%ENDCOLOR% 1. %BLUE%romaadriver ready%ENDCOLOR% 1. %RED%- !RomaaDriver::Main%ENDCOLOR% 1. %RED%- !RomaaDriver::ProcessMessage%ENDCOLOR% 1. closing TCP connection to client 0 on port 6665 1. %RED%- !RomaaDriver::Shutdown%ENDCOLOR% 1. Shuting romaadriver down 1. %BLUE%romaadriver has been shutdown%ENDCOLOR% 1. Quitting. 1. %RED%- !RomaaDriver::~RomaaDriver%ENDCOLOR% Se destacan algunos puntos importantes * '''1''' se carga el driver {{{libromaadriver}}} * '''12''' se ejecuta un programa cliente ( ={{{playerv}}}=) * '''22''' se desconecta el cliente * '''26''' se termina la ejecución del servidor == Constructor == En el contructor se lee el archivo de configuración (*.cfg) y se definen las interfaces utilizadas. ([[http://playerstage.sourceforge.net/doc/Player-2.1.0/player/classConfigFile.html | ver]] Configuration file class). En el caso de '''una única''' interfaz ''position2d'' para el control de motores y odometria seria {{{ RomaaDriver::RomaaDriver(ConfigFile* cf, int section) : Driver(cf, section, false, PLAYER_MSGQUEUE_DEFAULT_MAXLEN, PLAYER_POSITION2D_CODE) // Read an option from the configuration file this->tty_dev = cf->ReadString(section, "port", "/dev/ttyS0"); this->baudrate = cf->ReadInt(section, "baudrate", 38400); return; } }}} Si el driver provee de múltiples interfaces se utiliza el siguiente constructor {{{ RomaaDriver::RomaaDriver(ConfigFile* cf, int section) : Driver(cf, section) }}} Y se deben agregar las interfaces explicitamente {{{ player_devaddr_t position_addr; if ( cf->ReadDeviceAddr( &position_addr, section, "provides", PLAYER_POSITION2D_CODE, -1, NULL) == 0 ) { if ( this->AddInterface( position_addr ) != 0 ) { this->SetError(-1); return; } } }}} == Main == 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 ''while(true)'' o ''for(;;)''. La función Main tiene que llamar unas pocas funciones específicas: * '''pthread_testcancel:''' Verifica si el thread fue terminado (killed). La función saldrá del loop y ejecutara la el método ''Shutdown''. * '''ProcessMessage:''' Es una llamada a Player que llamará la función ''ProcessMessage()'' del plugin con cada mensaje esperando en la cola de mensajes. * '''usleep:''' Es un comando de ''sleep'' para liberar los recursos utilizados por el driver. La función ''Main'' es donde se debería leer información de los dispositivos, formatear los datos especificos para un interfaz y publicarlos a Player.