Driver para Control Intuitivo de Ratón por Force Feedback

Anuncio
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
Ingeniero Técnico en Informática de Sistemas
PROYECTO FIN DE CARRERA
Driver para Control Intuitivo de
Ratón por Force Feedback
Director: D. Juan Antonio Pérez-Campanero Atanasio
Autor: Ernesto Corral Messía de la Cerda
Madrid Junio 2010
Autorizada la entrega del proyecto del alumno:
Ernesto Corral Messía de la Cerda
EL DIRECTOR DEL PROYECTO
Juan Antonio Pérez-Campanero Atanasio
Fdo.: ........................ Fecha: ....../ ....../ ......
Vº Bº del Coordinador de Proyectos
David Contreras Bárcena
Fdo.: ........................ Fecha: ....../ ....../ ......
UNIVERSIDAD PONTIFICIA COMILLAS
ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA (ICAI)
Ingeniero Técnico en Informática de Sistemas
PROYECTO FIN DE CARRERA
Driver para Control Intuitivo de
Ratón por Force Feedback
Director: D. Juan Antonio Pérez-Campanero Atanasio
Autor: Ernesto Corral Messía de la Cerda
Madrid Junio 2010
Este proyecto está protegido mediante una licencia Creative Commons de
reconocimiento, sin propósitos comerciales y cuyas obras derivadas cumplan
a su vez estos requisitos.
http://creativecommons.org/licenses/by-nc-sa/3.0/es/
AGRADECIMIENTOS
AGRADECIMIENTOS
Quiero dar la gracias en primer lugar a Jaime, diseñador del hardware de
este dispositivo, ideólogo de este proyecto y sobre todo, amigo.
A Juan Antonio Pérez-Campanero, por dejarme hacer este proyecto con él, y
por el tiempo dedicado a este proyecto.
A mi madre, por la educación que me ha dado y su apoyo en los peores
momentos, tanto en la realización del proyecto como en el resto de la vida.
A mi padre, por enseñarme a juguetear con el ordenador y el camino de
autoexec.bat para poder hacer funcionar el PcFutbol 3.0 que me llevó hasta aquí.
Estés donde estés, si es que estás espero que estés orgulloso.
A la Monster School, muchos años juntos y muchas experiencias
compartidas, hemos pasado mucho juntos... ¡y lo que nos queda! Empezamos
siendo seis y el número ha ido aumentando durante el paso por la universidad.
Nos quedan muchas cosas por vivir juntos y espero que sigamos juntos por
muchos años. “All your cocos are belong to us”. A Leyre. A Ramón y todos los
que compartieron nuestra mesa en el Boomerang. A la gente de San Vicente,
Markés, Aratz, Migueloto, Yayo, Markitos, Ch1, Martits, Fabio, Pue, Lud, Carol,
Yaiza, Pazos, Epi, Balmori y el resto de la gentuza que nos juntamos allí. A la
gente de La Coruña que me acompañado durante tantos veranos y navidades,
Alfonso, Asis, Lino, Otero, Alex, y el resto de Coruñeses adictos al Playa que no
me llevan al Rush.
A Carlos Sierra, gracias por todo.
A todos lo compañeros con los que he compartido momentos más allá de las
aulas, Harek, Fishfeets (Cifu), Pablo, Raúl, Mario, Weezer, Antonio “Hegemón”,
Villa, David, Jorge, Javi, Ignatio, Diego, Luíh. Seguro que me dejo a muchos
pero ellos saben quienes son.
A los parroquianos del Rey Lagarto, especialmente a las Lagartonnas con las
que he compartido grandes momentos.
Al hardcore, sin esta música no habría soportado tantas horas de estudio y
vii
AGRADECIMIENTOS
delante del ordenador durante la carrera. Especialmente a la Taking Off Crew y al
Straight Edge, sin conocer este último no sé por donde podría haber llegado mi
vida, me ayudó mucho a encaminar mi vida.
Al resto de mi familia y en general a todo el mundo que ha pasado por mi
vida y me ha hecho ser lo que soy.
A todos los que me dejo y que deberían estar en esta lista, esto no es más
que un papel, donde os llevo de verdad es en el corazón.
viii
RESUMEN
RESUMEN
Debido al sistema actual para el manejo de maquinaria industrial y a la clara
tendencia al realismo en la industria de los videojuegos se decidió que se
desarrollaría un dispositivo que pudiera tanto mejorar el control de la maquinaria
industrial, especialmente brazos mecánicos, como mejorar la experiencia de juego
en videojuegos, especialmente los clasificados como First Person Shooter.
Por ello durante este proyecto se hablará del desarrollo de la parte del
software para una primera aproximación a un dispositivo completamente
funcional. La parte del hardware fue desarrollada por Jaime González-Arintero
durante los años 2008-2009. Se trata de un diseño de lo que sería un prototipo del
dispositivo. Con este desarrollo nacería lo que quedó en llamarse Proyecto
Rigodon.
El dispositivo consiste en la modificación de un ratón simple. A este se le
añadirían unos electroimanes que serían controlados por un circuito. Este circuito
haría que los electroimanes recibieran una tensión determinada que hiciera que se
pegasen a una alfombrilla de hierro sobre la que se apoyaría el ratón dificultando
así el movimiento.
Con las especificaciones que se daban debido al diseño del hardware se
decidió que el proyecto se dividiría en tres grandes módulos.
El primer módulo consistió en la necesidad de hacer un driver que facilitase
la implementación del ratón en caso de que se llegase a comercializar, de este
modo el dispositivo podría ser incluido en programas de una manera más general.
Además la realización de este módulo del proyecto ayudaría mucho a la
consecución de los objetivos marcados, así como a la realización de los siguientes
módulos.
A modo de aplicación para realizar pruebas y como forma de utilizar el
dispositivo con aplicaciones que no lo tengan implantado, se desarrolló una
aplicación para el control de los electroimanes. Esta aplicación tiene un interfaz
ix
RESUMEN
muy simple para que su manejo no necesite de aprendizaje.
Por último, como modo de demostrar las posibilidades del dispositivo se
adaptó el código fuente de un videojuego de forma que si se intentase vender a
una compañía, esta pudiera ver una demostración del dispositivo en acción.
Además se realizó un estudio de mercado en el que se llegó a la conclusión
de que con una campaña de publicidad adecuada a las necesidades del producto,
se podría tener una buena incursión en el mercado, ya que las industrias a las que
se pretende llevar este producto, están abiertas a mejoras tecnológicas.
x
ABSTRACT
ABSTRACT
Current systems for handle industrial machinery and the tendency to realism
in the videogames market led to developing a new device that can make better the
control of indrustial machinery, specialy mechanic arms,
and improve the
experience on videogames, especialy those known as First Person Shooters.
This project describes the development of the software for the first approach
to a funtional device. Hardware was developed by Jaime González-Arintero
during 2008 and 2009. It is the desingn of a prototype of a the device. The project
called Rigodon bornt with this development.
Device consists of modifying a simple mouse. Some electromagnets will be
added the mouse and will be controled by an electronic circuit. The circuit is used
to handle the tension that controls force that electromagnets uses to stick the
mouse and the metal plank under it, dificulting the movement of the mouse.
With conditions gave by the design of the hardware, project needed to be
divided in three big modules.
First module goes into the need of making a driver that makes easy device
implementation in case it will be commercialized, with a driver device could be
included in a simple way. The development of this first module will help with the
achievement of the project objetives and will help in the development of the next
modules.
As testing application and as control application for the device in
applications that don't have it implanted, an application that control
electromagnets was developed. This application has a very simple interface with
no learning needed.
To use as a demonstration of the posibilities the device, source code of a
videogame was adapted to show it to a company in case of trying to sell the
device.
A market research was executed, the conclusion was that with a good
xi
ABSTRACT
advertising campaign the device could be inserted into the market, due to
industries pointed by this proyect are opened to technologic improvements.
xii
ÍNDICE
1 INTRODUCCIÓN.............................................................6
1.1 Estado del arte....................................................................................8
1.1.1 Tableta gráfica.....................................................................8
1.1.2 Joystick...............................................................................9
1.1.3 Wiimote...............................................................................9
1.1.4 Novint Falcon...................................................................10
1.1.5 Nueva generación de ratones............................................11
1.1.6 Software............................................................................11
1.2 Rigodón.............................................................................................11
1.3 Motivación........................................................................................13
1.4 Objetivos...........................................................................................13
1.5 Requisitos de usuario.......................................................................14
1.6 Requisitos Software..........................................................................14
1.7 Análisis de requisitos........................................................................15
1.8 Metodología......................................................................................16
1.8.1 FASE1: Análisis................................................................17
1.8.2 FASE2: Diseño..................................................................18
1.8.3 FASE3: Implementación...................................................18
1.8.4 FASE4: Pruebas................................................................19
1.9 Planificación.....................................................................................19
2 DISEÑO DEL DRIVER...................................................22
2.1 Diseño de I/O....................................................................................22
2.1.1 Etapa1: Recepción y tratamiento de los datos..................24
2.1.2 Etapa2: Conversión digital-analógica...............................25
2.1.3 Etapa 3: Amplificación/buffer...........................................25
2.1.4 Etapa 4: Salida..................................................................26
2.2 UMDF y KMDF................................................................................26
2.2.1 Infraestructura de UMDF..................................................27
2.3 WinUSB.............................................................................................30
2.3.1 Install.inf...........................................................................31
2.3.2 Funciones en <winusb.h>.................................................31
2.4 Tecnología.........................................................................................32
3 DISEÑO DE LA APLICACIÓN DE CONTROL.........35
3.1 Componentes....................................................................................36
3.1.1 JSlider jFuerza..................................................................36
3.1.2 JTextField txtFuerza..........................................................36
3.2 JNI (Java Native Interface).............................................................36
3.3 Clase DriverCall.java.......................................................................37
3.4 Salida.................................................................................................37
3.5 DriverCall.c......................................................................................38
3.5.1 Java_DriverCall_driverCall..............................................38
3.5.2 GetWinUSBHandle...........................................................39
3.5.3 GetDeviceHandle .............................................................39
3.5.4 QueryDeviceEndpoints ....................................................39
3.5.5 WriteToBulkEndpoint ......................................................40
3.6 Tecnología.........................................................................................40
4 ADAPTACIÓN DE VIDEOJUEGO...............................42
4.1 Elección de videojuego.....................................................................42
4.2 Ingeniería inversa.............................................................................43
4.3 Adaptando el código.........................................................................44
4.4 Tecnología.........................................................................................45
5 CONCLUSIONES Y TRABAJOS FUTUROS..............47
6 ESTUDIO ECONÓMICO...............................................50
6.1 Estudio de mercado..........................................................................50
6.2 Presupuesto.......................................................................................51
7 BIBLIOGRAFÍA..............................................................54
7.1 Libros................................................................................................54
7.2 Links..................................................................................................54
8 ANEXOS...........................................................................56
Anexo A Ejemplo de fichero de instalación .inf...................................56
Anexo B DriverCall.c.............................................................................59
Anexo C Manual de instalación de winUSB........................................73
Anexo D Manual de la aplicación.........................................................74
Anexo E Librería rigodon.h..................................................................75
INTRODUCCIÓN
Parte1
INTRODUCCIÓN
5
INTRODUCCIÓN
1 INTRODUCCIÓN
En este capítulo se comentará como surgió la idea de realizar este proyecto,
también se comentará el estado de la tecnología que afecta al proyecto, así como
los motivos que llevaron a su realización, la problemática a la que se hizo frente,
una pequeña introducción al dispositivo sobre el que se trabaja, los objetivos a los
que se quiere llegar, la metodología utilizada para llegar a ellos y una la
planificación realizada para la conclusión de este proyecto.
La idea de realizar este proyecto surge a partir de una broma realizada en
una comida entre dos amigos en la que se sugirió que sería gracioso que al realizar
un movimiento de drag & drop con un fichero que “pesase” poco no hubiera
problema, pero que si se tratase de un fichero pesado, de por ejemplo de 2GB,
costase realizar el movimiento.
Al día siguiente uno de ellos se dio cuenta de que era posible hacerlo
mediante un ratón con electroimanes y una alfombrilla de hierro. Tras analizar las
aplicaciones que podía tener tanto en la industria como en el mundo de la
informática se pusieron manos a la obra.
Entre las aplicaciones encontradas para la idea inicial, las más interesantes
fueron el manejo de brazos mecánicos en la industria y el proporcionar realismo a
una industria que no para de aumentar, la industria del videojuego.
Cuando un operario utiliza un brazo mecánico, al operario le da igual lo que
transporte ese brazo, ya que el sistema tradicional utiliza un sistema de palancas.
La velocidad a la que se mueve ese brazo viene determinada por la tarea para la
que ese brazo mecánico está diseñado, por lo que ese brazo siempre se moverá a
esa velocidad incluso en el movimiento vacío de carga. Además, ¿qué pasa si se
quiere utilizar ese mismo brazo para realizar una tarea distinta? Surgiría un
problema ya que para poder cambiar la velocidad a la que se mueve ese brazo,
tendría que haber un técnico que lo modificara a nivel de hardware.
Las cifras de los últimos años dicen que en la industria audiovisual más del
50% de los ingresos vienen del mercado de los videojuegos. También vemos que
la tendencia es a conseguir un mayor realismo en los videojuegos, sobre todo en
6
INTRODUCCIÓN
los conocidos como first person shooters, aventuras en primera persona en las que
el jugador toma el papel de un mercenario o de un soldado. A la hora de ponerse a
jugar, el jugador medio dispone de una pantalla, un teclado y ratón, supóngase que
el usuario tiene que hacer de soldado, cada vez que tenga que utilizar un arma, al
tener siempre el mismo ratón, la sensación de usar un cuchillo o una pistola va a
ser la misma que la de utilizar un arma más grande como un lanza misiles o un
bazuca.
Figura 1.1: S.T.A.L.K.E.R., ejemplo de First Person Shooter.
Con este proyecto se pretende dar los primeros pasos para la creación de un
sistema de control que permita una fácil reconfiguración de algunos sistemas en la
industria. A la vez se ofrece una opción de un nuevo sistema de control que
pretende mejorar la experiencia en los videojuegos. Todo esto orientado a una
posible comercialización del producto, por lo tanto cuidando los costes para poder
tener un precio competitivo en el mercado.
7
INTRODUCCIÓN
1.1 Estado del arte
Actualmente la manera más extendida de controlar un ordenador es
mediante la combinación de teclado y ratón, aunque no existen alternativas para el
teclado, para controlar el cursor en un entorno gráfico si se presentan varias
opciones. Entre las más comunes se encontrarían la tableta gráfica y el joystick, y
un poco más infrecuente serían el Wiimote y el Novint Falcon Pistol.
1.1.1 Tableta gráfica
Este periférico consiste en una tableta que representa la pantalla, el
movimiento del cursor sobre la pantalla se realiza mediante un bolígrafo
especial que se desplaza por la pantalla.
Este dispositivo está preparado para diseñadores gráficos o
profesionales de la edición de imagen, es muy preciso y al manejarse como
si fuera un bolígrafo permite hacer trazos que no se pueden realizar con el
ratón. El problema de este tipo de dispositivo reside en el precio, ya que
adquirir una tableta gráfica de calidad media sería necesaria una inversión
de al menos 150€.
Figura 1.1.1.1: Wacom Bamboo. Ejemplo de tableta gráfica.
8
INTRODUCCIÓN
1.1.2 Joystick
Este dispositivo consiste en una palanca con dos o tres ejes.
Originalmente fue creado para el control de ciertas partes de una
aeronave pero en la actualidad este tipo de dispositivos se utiliza tanto para
manejar helicópteros y aviones, manejar grúas y brazos mecánicos y
controlar dispositivos teledirigidos (aeronaves, bombas guiadas, etc) como
para controlar un ordenador o una videoconsola.
En el último caso el uso del Joystick queda relegado a juegos en los
que se simula el control de un avión, un helicóptero, una nave espacial o
algún otro tipo de vehículo.
Figura 1.1.2.1: Logitech Freedom. Ejemplo de joystick de tres ejes.
1.1.3 Wiimote
Dispositivo
inalámbrico
dotado
de
infrarrojos,
bluetooth
y
acelerómetro. Mediante una combinación de estos elementos permite el
control del cursor como si de un puntero se tratara.
Desde el lanzamiento en 2006 de la consola Wii de Nintendo no se ha
parado de buscar funcionalidades para su controlador, desde como elemento
de apoyo en presentaciones, hasta como base de un posible manejo futuro
del 3D en los ordenadores. El problema como dispositivo es que exige una
9
INTRODUCCIÓN
distancia y, en caso de usarse para realizar un trabajo continuo, su uso
prolongado produce desgaste ya que no se utiliza en apoyo.
Figura 1.1.3.1: Wiimote.
1.1.4 Novint Falcon
Dispositivo a caballo entre el ratón y el joystick.
Dispone de tres servomotores unidos a unas ballestas que se unen en
una bola, mediante el manejo de estas se mueve el cursor. Está destinado a
juegos en 3D, además dispone de un dispositivo en forma de pistola
mediante el cual consigue más realismo. Los principales problemas son el
precio, el hecho de que estando en juego para apuntar hacia un lado tengas
que mover el dispositivo hacia el lado contrario y el tener que acostumbrarse
el usuario al manejo de un dispositivo extraño.
1.1.4.1: Novint Falcon con el dispositivo Pistol.
10
INTRODUCCIÓN
1.1.5 Nueva generación de ratones
En cuanto a ratones cabe destacar el intento por parte de Logitech con
la creación del G9.
Es un ratón que lleva una serie de contrapesos en su interior que
provoca una sensación se oposición ante movimientos bruscos del usuario.
Al funcionar mediante contrapesos, se trata de un sistema pasivo.
Figura 1.1.5.1: G9 de Logitech. Se pueden apreciar los contrapesos.
1.1.6 Software
En algunos videojuegos tratan la sensación de realismo mediante el
propio software.
Desde puntos de mira que se mueven a distinta velocidad dependiendo
del arma que lleves, hasta dificultad en el manejo de un coche después de
haber sufrido un accidente. Estas cosas ayudan, pero deberían de ir
complementados con algún hardware.
1.2 Rigodón
La propuesta de este proyecto es un ratón normal al que se le han añadido
cuatro electroimanes y una base de hierro sobre la que se apoya.
La idea de esta propuesta fue ser un dispositivo que engañase al cerebro con
la sensación de que se está moviendo objetos de distinto peso (a mayor peso del
11
INTRODUCCIÓN
objeto, mayor intensidad en los electroimanes y por lo tanto mayor dificultad de
movimiento). El coste del dispositivo es muy bajo en comparación con otros
productos, además es más versátil puesto que se puede aplicar a distintos campos
de la ingeniería ya nombrados en la introducción.
Figura 1.2.1: Esquema de Rigodón.
En la imagen [Figura 1.2.1] se puede ver como están situados los
electroimanes en el dispositivo. Del dispositivo salen tres cables, dos de ellos son
conectores a puertos USB, uno de ellos el del ratón original, el segundo, es el que
conecta el ordenador con el controlador de los electroimanes. En este proyecto
nos interesa la parte que maneja este cable, el driver escrito controla la
comunicación entre una aplicación y el microcontrolador de los electroimanes.
El tercer cable se encarga de la alimentación, cada electroimán para llegar a
la máxima potencia hay que aplicarle una intensidad de 12 voltios, por lo que con
los 5 que proporciona el USB no sería suficiente.
12
INTRODUCCIÓN
1.3 Motivación
Como se ha dicho en la introducción, tanto la industria en su más amplia
definición, como el mercado de los videojuegos en concreto, son mercados muy
amplios y con los que se puede negociar sobre la adquisición del dispositivo.
Por un lado se podrían ahorrar costes sustituyendo las palancas en la
industria por el ratón con force feedback. Supóngase una empresa dedicada al
tratamiento de residuos químicos, y por alguna razón esa planta se ve obligada a
tratar residuos orgánicos por un tiempo. Con las palancas se tendría que
reconfigurar la máquina, con el coste que supondría, tanto en tiempo como en
coste de la mano de obra del técnico. Con el ratón lo único que sería necesario
hacer, sería cambiar la fuerza que se realiza sobre el ratón, un trabajo que podría
hacer cualquier usuario, sin la necesidad de un técnico.
En el mercado de los videojuegos con un ratón simple todas las armas que
utilizan se utilizan igual, quedando como único diferenciador la velocidad a la que
se mueva el punto de mira, o el simulador del retroceso de las armas que son
controlados por software. Engañar al cerebro es fácil, y con solo poner una
diferenciación de fuerza real necesaria para mover el arma es suficiente para que
el usuario mejore su experiencia de juego, terminando con una sensación de
realismo mayor que con un ratón convencional.
También se encuentra una aplicación potencial al diseño gráfico. Sin lugar a
dudas lo mejor a la hora de ponerse a dibujar en un ordenador en una tableta
gráfica, pero hay un problema con estas, no todo el mundo se puede permitir
gastarse en una herramienta para dibujar al menos 150€. Por ello para el usuario
medio-bajo de programas de dibujo el ratón con force feedback es una buena
solución. El principal problema a la hora de dibujar es que el ratón se escapa y
estropea el trabajo ya realizado, este dispositivo pone una resistencia que hace que
no pueda pasar eso, además, no solo se está usando como periférico de dibujo,
también se usa como dispositivo de control del ordenador.
1.4 Objetivos
El alcance del proyecto se centra en el desarrollo del software necesario
para manejar un ratón especial, en concreto Rigodon, desarrollado en otro
13
INTRODUCCIÓN
proyecto, con el objetivo de ofrecer al usuario una sensación de realismo mayor
que el que tendría con el uso de un ratón comercial normal, tal y como se ha
descrito en el apartado anterior de motivación. En los apartados siguientes se
recogen las especificaciones requisitos, tanto del usuario como del software a
desarrollar, y el análisis de los mismos, obteniendo como resultado el conjunto de
funciones y aplicaciones a desarrollar para alcanzar dichos requisitos.
1.5 Requisitos de usuario
Dado el dispositivo hardware descrito en los apartados anteriores, se debe
hacer que funcione en un ordenador personal.
Dada la naturaleza del dispositivo, se decidió que el sistema operativo al que
debía ir dirigido debía ser Windows XP, en el siguiente punto se entrará más en
detalle en por qué la elección de Windows XP.
Es necesario desarrollar un software que controle el dispositivo. Mediante
este se podría controlar el dispositivo de forma que se pudiera usar en
aplicaciones que no lo tuvieran integrado, haciendo que así el dispositivo pueda
ser utilizado de manera inmediata, de forma que el usuario no tenga que esperar a
que los fabricantes lo adapten a cada uso.
También se deberá adaptar un programa para la utilización del dispositivo,
ya que se trata de un dispositivo cuya principal orientación es el ocio electrónico,
se decidió que el programa que se adaptaría sería un videojuego.
1.6 Requisitos Software
Los requisitos que debe cumplir el software que se vaya a desarrollar se
pueden resumir en cinco puntos:
Driver seguro: Cuando se escribe un driver la integridad del sistema
operativo se pone en juego, ya que el “programa”, una vez terminado, se ejecutará
en la memoria de kernel, es decir, en el núcleo del sistema operativo. Cuando esto
pasa, la aplicación accede a zonas de memoria reservadas para el sistema
operativo pudiendo provocar fallos que comprometan al sistema. Por esto, el que
el driver sea seguro es una prioridad.
Proyecto escalable: A la hora diseñar el dispositivo a parte de las
14
INTRODUCCIÓN
funcionalidades que se le dieron, se pensaron posibles actualizaciones y mejoras
para realizar en un futuro. Por eso, al diseñar el driver se debe hacer desde las
perspectiva de una posible ampliación.
Funcionamiento del driver en Windows XP: Aunque esta no sea la última
versión de Windows, Windows Vista se vio que era poco eficiente hasta el punto
que ya existe una nueva versión, el Windows 7. A la hora de realizar este
proyecto, Windows 7 está en su primera versión, es decir, hasta que Microsoft no
distribuya el Service Pack para Windows 7 se puede considerar al sistema
operativo una versión beta. Además, Windows XP es el sistema operativo más
extendido entre la gente que más juega. Por esto debe funcionar prioritariamente
en Windows XP.
Cabe decir que funcionando en XP, el driver debería funcionar tanto en
Vista como en 7.
Desarrollo de una aplicación de control: Se desarrollará una herramienta
sencilla para que el usuario pueda controlar el dispositivo.
Adaptación de un videojuego: Se modificará el código fuente de un
videojuego para comprobar la sensación de realismo obtenida. El videojuego
adaptado será el Doom, ya que tiene el código fuente liberado por sus creadores y
es antiguo, de forma que el código a tratar es menor que en otras opciones
barajadas como el Duke Nukem 3D.
1.7 Análisis de requisitos
Tras el análisis de los requisitos del apartado anterior, se ha tomado la
decisión de dividir el diseño en tres aplicaciones a desarrollar, tal y como se puede
ver en el diagrama de flujo de datos que se muestra a continuación:
Figura 1.7.1: DFD de los tres módulos que componen el proyecto.
15
INTRODUCCIÓN
A continuación se describe cada una de estas aplicaciones, y cuáles han sido
los condicionantes estudiados para tomar la decisión final:
1> Driver para controlar el ratón.
Esta función es la principal y más importante de todo el proyecto, ya que
condiciona el resto de desarrollos a realizar. Hay varias razones por las que se
decide hacer un driver. Se debía hacer funcionar un dispositivo desde dos
aplicaciones, por lo que había principalmente dos opciones, la primera desarrollar
un driver y utilizar las funciones creadas para manejarlo, la segunda era hacer
funcionar el dispositivo utilizando la API del lenguaje de programación que
tocase. Al tener que hacer funcionar el dispositivo en dos aplicaciones, la solución
más óptima era desarrollar el driver e invocarlo desde las aplicaciones. La
principal razón de la toma de esta decisión es que el dispositivo se quiere
comercializar, por lo que con el desarrollo de un driver, se puede presentar a las
empresas interesadas de forma que solo tengan que utilizar las funciones ofrecidas
por el driver para adaptar sus aplicaciones.
2>Aplicación de control.
Se desarrollará una aplicación de permitirá controlar y probar el dispositivo
desde la máquina desde la que se trabaja.
3>Interfaz para otras aplicaciones.
Se desarrollarán los procedimientos o rutinas necesarias para que se pueda
utilizar el dispositivo desde otras aplicaciones, ya sean nuevos programas a
desarrollar, o bien aplicaciones existentes que quieran utilizar el ratón.
1.8 Metodología
La metodología a utilizar es la metodología clásica o en cascada adaptada a
las necesidades de desarrollo de este proyecto.
Para ello se utilizaron las siguientes fases:
FASE0: Pre-análisis
FASE1: Análisis
FASE2: Diseño
FASE3: Implementación
FASE4: Pruebas
16
INTRODUCCIÓN
En la fase de pre-análisis se analizó la problemática general. En esta fase es
en la que se decidieron los tres módulos especificados en el apartado 1.4 de este
documento. Esta fase es la única que no se repitió, el resto de fases se repitió para
cada uno de los tres módulos que componen este proyecto, en las siguientes líneas
se aclarará qué se hizo en cada una de las fases para cada módulo.
Lo referente módulo del driver está explicado en detalle en el capítulo 2 de
este libro, así como todo lo referente a la aplicación de control y al videojuego se
puede ver en los puntos 3 y 4 de este documento respectivamente.
1.8.1 FASE1: Análisis
En el módulo correspondiente al diseño del driver se realizó un
estudio de las frameworks proporcionadas por Microsoft así como de la
posibilidades ya existentes que se ofrecían. A través de este análisis se
decidió la alternativa del uso de winUSB. Este análisis llevó muchos meses
del proyecto ya que la documentación es escasa y debido al tema, es algo
complicada de entender.
En lo que corresponde a la aplicación en el análisis se decidió que
debía de ser una aplicación muy simple en la que no hubiera necesidad de
un manual de instrucciones que ocupase más de una página, ya que como se
explicó en la introducción el dispositivo pretende ser una solución a las
complicadas configuraciones de los aparatos en la industria. La aplicación
enviará un char al driver, para ello podrá utilizar un slider o una caja de
texto. De está forma el usuario podrá controlar el dispositivo desde la
aplicación para su uso en aplicaciones no adaptadas a este.
En lo que al videojuego se refiere, la fase de análisis fue la más larga
de todas ya que se tuvieron que analizar más de 16MB de ficheros hasta que
se aislaron los ficheros a analizar y luego analizar más de 160 ficheros de
código hasta aislar las funciones que interactuaban con las armas.
Como se puede apreciar en los módulos del driver y del videojuego las
tareas a realizar fueron tareas muy duras a pesar de que el resultado sea algo
simple. Por supuesto, el resultado es tan simple debido al buen análisis
realizado en esta parte, esto hizo que el resto de las tareas fuesen más
llevaderas.
17
INTRODUCCIÓN
1.8.2 FASE2: Diseño
La fase del diseño de la parte del driver vino definida por las
necesidades del dispositivo por lo que las decisiones que se tomaron venían
de la propia naturaleza del dispositivo, por lo que el hecho de que se use en
forma de línea de comunicaciones viene condicionado por el dispositivo. La
única parte en la que hubo libertad fue a la hora de enviar un char de 8bits
en lugar del envío de una estructura de 4bits.
En el diseño de la aplicación de control habría dos partes, el diseño
gráfico y el diseño de la lógica, en lo que al diseño gráfico se refiere, tras un
análisis en el que primaba la simplicidad se decidió que para su manejo
intuitivo lo mejor sería un slider con el que cambiar la fuerza que debía
ejercer el dispositivo, este iría acompañado por un campo de texto en el que
poder cambiar la fuerza sin necesidad de seguir la progresión del slider.
En cuanto a la lógica, como el lenguaje elegido fue java, se decidió
que la forma de gestionarlo sería un jFrame que llevase todo el peso gráfico
de la aplicación con una clase que gestionase las llamadas a un interfaz
nativo que permitiese la comunicación con el sistema operativo.
En lo que al videojuego se refiere, el diseño estaba ya hecho por el
equipo que realizó el port del Doom, por lo que solamente se tomó la
decisión de abrir y cerrar la conexión con el dispositivo cada vez que se
necesitase, ya que se consideró más seguro que dejarla abierta y cerrarla al
terminar la ejecución del videojuego.
1.8.3 FASE3: Implementación
Tras la decisión del uso de winUSB, en la implementación de la parte
del driver se desarrollaron paquetes de instalación para el dispositivo para
todos las distribuciones de Windows desde Windows XP service pack 2. Así
como un manual de instalación del paquete que se encuentra en el ANEXO
C de este proyecto.
En la implementación de la aplicación, la parte gráfica fue muy rápida,
principal razón por la que se eligió java para desarrollarla, pero la carga
recaía en la creación del fichero .dll que comunicaría la aplicación con el
driver. Esta parte llevó bastante tiempo de realización principalmente debido
18
INTRODUCCIÓN
a problemas con el DDK de Microsoft.
En el videojuego, una vez localizadas la funciones sobre las que tratar
la implementación sería rápida debido a que tendría que realizar
exactamente las mismas rutinas que la aplicación, por lo que el código ya
estaba, solo había que crear una librería y añadirla al código desde donde se
realizarían las llamadas correspondientes.
1.8.4 FASE4: Pruebas
Todas las pruebas a realizar dependen del dispositivo que se trata de
implantar, como ya se dijo en la introducción la parte del dispositivo
depende del otro proyecto, por lo que hasta que el dispositivo no se
construya, la fase de pruebas quedará aplazada.
La batería de pruebas preparadas empezará por la prueba del
comportamiento del dispositivo en el ordenador, habrá pruebas de respuesta
del dispositivo en caso de desconectarlo durante la ejecución de la
aplicación y la conexión del dispositivo una vez iniciado la aplicación de
control. También se probará el videojuego forzando el cambio de arma en
las distintas situaciones en que este evento se puede dar.
1.9 Planificación
En el gráfico se puede ver la planificación dividida por cada módulo del
proyecto, como se puede ver durante el tiempo que dura cada módulo hay poco
solapamiento ya que cada módulo ayuda al desarrollo del siguiente.
Se puede ver que lo primero que se realizó fue el driver, con la realización
de esta primera parte se conseguiría que el resto del trabajo fuese más fácil. En el
proceso se usaron más de 6 meses en el análisis y la búsqueda de documentación
sobre el desarrollo de drivers para Windows, se alargó tanto por que la
información que existe es escasa y de dudosa procedencia, lo que hacía aun más
duro el proceso de análisis y diseño.
En lo que a la aplicación se refiere, se solapó con la parte del driver durante
el desarrollo de la interfaz gráfica de usuario y la lógica de gestión de eventos, el
resto de la aplicación no se pudo desarrollar hasta tener el driver en
funcionamiento.
19
INTRODUCCIÓN
El análisis de los ficheros correspondientes al código fuente del videojuego,
se inició a la vez que se desarrollaba la lógica de la aplicación, quedando una vez
terminada la aplicación la finalización del análisis y la introducción del código en
el código del ZDoom.
En paralelo a las fases se fue realizando la documentación, dejando la
finalización de esta para el último mes del proyecto.
2009
Driver
Aplicación
Videojuego
Documentación
OCTUBRE
NOVIEMBRE DICIEMBRE
Figura 1.7.1: Planificación para 2009.
2010
Driver
Aplicación
Videojuego
Documentación
ENERO
FEBRERO
MARZO
ABRIL
MAYO
JUNIO
Figura 1.7.2: Planificación para 2010.
20
DISEÑO DEL DRIVER
Parte2
DISEÑO DEL DRIVER
21
DISEÑO DEL DRIVER
2 DISEÑO DEL DRIVER
En este capítulo se explicará el proceso mediante el cual se desarrolló el
controlador del dispositivo, además, debido a la poca documentación existente
sobre el tema, se ha escrito de forma que sirva como guía de apoyo para
cualquiera que se disponga a desarrollar un driver para Windows.
Se necesita un driver para Windows capaz de comunicar las aplicaciones con
un dispositivo cuyas especificaciones técnicas están en el apartado 2.1, para ello
se realizó un estudio de las tecnologías que Microsoft ofrece a los desarrolladores
de drivers, apartados 2.2 y 2.3.
2.1 Diseño de I/O
El diseño del hardware es parte de otro proyecto [GONZ09] pero en lo que a
este proyecto atañe, el dispositivo está formado por un microcontrolador que
recibe una cadena binaria de ocho bits para controlar cuatro electroimanes y va
conectado a un ordenador por un puerto USB.
En principio la cadena que recibía el dispositivo era de cuatro bits, pero los
sistemas operativos direccionan a nivel de Byte y el tipo de dato mínimo usado
por C++ es el char (8bits) , por eso se cambió a ocho bits para no desperdiciar los
cuatro que quedarían sueltos. Con esta decisión el diseño se encaminó hacia uno
de los objetivos, la escalabilidad.
Los cuatro bits sobrantes en la primera versión son son utilizados, pero para
versiones posteriores, se pueden usar como un código que, por ejemplo, haga que
los electroimanes de la parte derecha estén apagados mientras los otros funcionan
con normalidad. Este tipo de acciones se han denominado “efectos”.
La aplicación solo necesita mandar la información, no recibe ninguna
información por parte del dispositivo por lo que se trata de una línea de
comunicación unidireccional.
Para dar una visión general del circuito se añade el esquema general del
circuito sacado del proyecto [GONZ09] y se añade una explicación general de
cada una de las etapas por las que la cadena enviada pasa para que al final los
22
DISEÑO DEL DRIVER
electroimanes del dispositivo se carguen.
Figura 2.1.1: Esquema del circuito del dispositivo dividido por etapas.
23
DISEÑO DEL DRIVER
2.1.1 Etapa1: Recepción y tratamiento de los datos
Figura 2.1.1.1: Etapa 1: Recepción y tratamiento de datos aislada.
Esta etapa es la encargada de recibir los datos, la parte más importante
de la etapa es el microcontrolador PIC16F84A, este recibe los datos en serie
del USB en el puerto RA0, y tiene el puerto RA1 ya preparado para en
versiones posteriores mandar información al ordenador que lo controle a
modo de mensajes de confirmación o alerta.
Dentro del micro, dependiendo del valor que se reciba se buscará en
una tabla la tensión necesaria correspondiente al valor que se reciba y se
enviará por medio del puerto RB en paralelo al conversor digital-analógico.
También contiene el reloj del circuito conectado al circuito en los
puestos de entrada y salida del reloj.
Se aprovechan los 5 voltios que provee el USB para alimentar el
microcontrolador y el LED que indica que el dispositivo recibe alimentación
tras pasar por un regulador de tensión.
24
DISEÑO DEL DRIVER
2.1.2 Etapa2: Conversión digital-analógica
Figura 2.1.2.1: Etapa2: Conversión digital-analógica aislada.
En esta etapa el conversor digital-analógico, DAC0808, recibe un
código de 8 bits es paralelo y los convierte en un valor entre 0 y 12 voltios
que se enviará a la siguiente etapa.
Este proceso se realiza en 150 ns.
2.1.3 Etapa 3: Amplificación/buffer
Figura 2.1.3.1: Etapa 3: Amplificación/buffer aislada.
Esta etapa sirve para aislar las etapas 1 y 2 de la etapa 4, ya que una
caída brusca de tensión en la etapa 4 podría dañar el resto del circuito.
Además al estar realizado con un amplificación operacional se podría
adaptar su uso a la amplificación en posibles desarrollos futuros.
25
DISEÑO DEL DRIVER
2.1.4 Etapa 4: Salida
Figura 2.1.4.1: Etapa 4: Salida aislada.
Cosiste en un transistor MOSFET que regula la tensión de los imanes
como si se tratase de uno solo, la corriente la recibe de la fuente de corriente
auxiliar, en este caso el dispositivo va conectado a la red eléctrica por medio
del cable de alimentación del dispositivo.
Es una visión general del circuito, si se desea entrar en más detalle
consúltese el proyecto “Control Intuitivo de Ratón por Force Feedback” de
donde se sacaron los gráficos que acompañan a esta explicación [GONZ09].
2.2 UMDF y KMDF
El modelo de la WDF (Windows Driver Foundation) provee dos frameworks
con las que trabajar según convenga al tipo de dispositivo para el que se esté
escribiendo el driver UMDF(User Mode Driver Framework) y KMDF (Kernel
Mode Driver Framework).
El sistema operativo Windows divide su memoria virtual en dos partes, User
Mode y Kernel Mode.
Todos los procesos que se ejecutan en Windows se ejecutan en modo usuario
(User Mode) excepto el proceso System. En modo usuario los procesos no pueden
26
DISEÑO DEL DRIVER
gestionar interrupciones ni tienen acceso directo al hardware, por lo que estos
procesos para comunicarse con un dispositivo físico necesitan de algo que haga de
pasarela, es el llamado reflector que se explica en la sección 2.2.1.
En Kernel Mode, los procesos tienen acceso directo al hardware, a la
memoria y pueden realizar llamadas al sistema, por esto y la posibilidad de
manejar la paginación de la memoria, la programación el modo Kernel es
peligrosa para la integridad del sistema.
Tras el estudio de ambas frameworks se llegó a la conclusión de que la
mejor opción era usar un UMDF, la principal razón fue que como la parte que se
quiere controlar es la parte de los cuatro electroimanes, no es necesaria la gestión
de interrupciones, por lo tanto lo que se necesita es una especie de línea de
comunicación entre el ordenador y el dispositivo. Esto se puede hacer usando
cualquiera de las dos frameworks, pero al escribir un UMDF se termina con uno
de los problemas principales de los drivers y a la vez uno de los objetivos del
proyecto, la estabilidad del sistema operativo. Al ser ejecutado en modo usuario,
es el sistema operativo el que se ocupa de gestionar todas las funciones del kernel
que se necesiten usar (memoria, paginación, etc) de forma que si el dispositivo
falla, en lugar de aparecer el famoso Blue Screen of Death, que fuerza a reiniciar
el sistema para recuperar la estabilidad poniendo en peligro toda la sesión de
trabajo y partes del sistema, simplemente el dispositivo dejaría de funcionar,
dejando que el sistema operativo siga funcionando sin problemas.
Con un KMDF se necesitan dos máquinas para poder comprobar los
posibles fallos de ejecución que pudiera tener, mientras que con el UMDF con una
sola máquina se pueden depurar esos errores, facilitando así el proceso de
depuración de errores.
2.2.1 Infraestructura de UMDF
Para hacer más fácil la comprensión de como funciona un driver
UMDF, se explicará apoyándose el la imagen a continuación [Figura
2.1.1.1], empezando desde la parte de la aplicación.
Application: Lo primero que ocurre es que la aplicación desde el
modo usuario invoca al driver, para ello se vale de las funciones
proporcionadas por Windows API.
27
DISEÑO DEL DRIVER
Windows API: Proporciona una serie de funciones que permiten la
comunicación entre las aplicaciones (Modo Usuario) y los Subsistemas del
Kernel (Modo Kernel).
Kernel Subsystems: Son pequeños subsistemas proporcionados por el
Kernel, tales como el I/O Manager o el Plug and Play Manager (PnP
Manager). Estos se valen de IRPs (I/O Request Packets) para comunicar las
peticiones al Reflector.
Figura 2.1.1.1: Infraestructura UMDF.
Reflector: Es el alma de la infraestructura de los UMDF. El objetivo
de una IRP debe de ser un KMDF device object, los cuales se encuentran en
Modo Kernel.
Los UMDF no pueden acceder al espacio de direccionamiento de
Modo Kernel, por eso se vale del Reflector, el Reflector es un driver KMDF
que representa a los drivers UMFD en el Modo Kernel. Además controla las
comunicaciones que recibe y envía el UMDF Host Procress, el cual está en
modo usuario.
28
DISEÑO DEL DRIVER
Para realizar estas funciones el reflector crea tres objetos: Up Device
Object, Down Device Object y Control Device Object.
Up Device Object: Es el encargado e recibir los IRPs del I/O
Manager y enviarlos al Host Process correspondiente para que los procese,
una vez procesadas las devuelve al I/O Manager.
Down Device Object: Se encarga de enviar a Lower Device Stack la
I/O Request ya procesada. También se comunica con el UMDF Host Process
para distintas cosas como puede ser crear una Device Interface.
Control Device Object: Maneja la comunicación entre el Reflector y
el UMFD Host Process que no tiene que ver con I/O Requests, como la
creación o la finalización de los Host Process.
UMDF Host Process: Es el encargado de cargar el driver y la librerías
Dll. Se encarga de la comunicación entre los drivers UMDF y el Reflector.
Dentro del UMDF Host Process se encuentra la UMDF Stack e
instancias de Framework.
UMDF Stack: Cada Driver UMDF está formado por varios drivers
del tipo Filter Driver o Function Driver, estos se colocan en una pila (UMDF
Stack), esta pila controla y procesa las I/O Requests.
Framework: Para cada Driver en la UMDF Stack hay asignada una
instancia de Framework. Se trata de una librería de sostiene el UMDF
Object Model y que comunica los drivers con el HostProcess.
Driver Manager: Maneja todos los UMDF Host Process en el
sistema, los crea, mantiene su estatus y los finaliza una vez no sean
necesarios.
Lower Device Stack: Se encarga del la comunicación con el
dispositivo. En el caso de este proyecto, se puede usar la Kernel Mode
Device Stack de Microsoft, ya que se trata de un dispositivo USB, pero en
algunos casos podría ser necesario la creación Lower Drivers por parte del
vendedor.
Device: El dispositivo receptor de la I/O Request.
29
DISEÑO DEL DRIVER
2.3 WinUSB
Desde la aparición de Windows Vista, la Windows Driver Foundation añadió
al DDK un driver llamado WinUSB.sys. Este driver facilita la creación de drivers
para dispositivos USB.
Es un driver KMDF, WinUSB.sys, que proporciona una librería, Winusb.dll,
que permite su uso desde aplicaciones como si se tratase de un driver UMDF.
WinUSB permite la adaptación de un driver existente a las necesidades de
un dispositivo específico mediante un fichero de instalación .inf (ver ANEXO A
para ver ejemplo). No es válido para cualquier dispositivo USB, tiene que cumplir
las siguientes condiciones:
- No soporta el tráfico isócrono.
- No puede acceder más de una aplicación a la vez.
El dispositivo cumple ambas condiciones, ya que el tráfico que necesitamos
para el dispositivo nunca debe ser isócrono, y por la naturaleza del dispositivo,
solo va a estar funcionando con una aplicación a la vez. Ya sea la de control o el
videojuego, no tiene sentido estar con las dos aplicaciones a la vez.
WinUSB funciona para cualquier sistema operativo Windows a partir de
Windows XP Service Pack 2, el problema es que para cada distribución de
Windows y cada bus de datos, el fichero de instalación y los instaladores que le
acompañan son distintos, para solucionar esto en el CD adjunto a este proyecto se
facilitan los distintos paquetes de instalación para cada distribución existente hasta
la fecha partiendo desde Windows XP Service Pack 2.
Este driver facilita mucho el trabajo a la hora de tener un driver operativo,
en la programación de la aplicación la diferencia es mínima. Solo se tiene que
escribir un poco más de código y usar las funciones que facilita la librería
<winusb.h>. Para ver un ejemplo de su funcionamiento ir al apartado 3.5 o al
ANEXO B para ver el código.
Esta fue la solución final que se dio a esta parte del proyecto, además de
estas razones, al usar un driver de Microsoft se puede dejar de lado como
problema la estabilidad del driver.
30
DISEÑO DEL DRIVER
2.3.1 Install.inf
Es el fichero de instalación de WinUSB. Ver ANEXO A para ver un
ejemplo.
Requiere una serie de campos entre los que destacan los que se tienen
que modificar para cada driver y para cada distribución:
ClassGUID: es el GUID, Globally Unique Identifier, que indica el
tipo de dispositivo que se va a usar.
DeviceInterfaceGUIDs: el GUID del dispositivo, es un numero
aleatorio que identifica al dispositivo en este caso el GUID elegido ha sido
AE5F20A3-09D7-4E62-B2F7-3D5172853709 y ha sido genera mediante la
aplicación proporcionada por guidgenerator.com.
CoInstallers_AddReg:
Aquí
se
añaden
los
coinstaladores
dependiendo de la distribución para la que se esté adaptando el fichero de
instalación.
El resto de las cosas se pueden dejar tal y como están para usar un
dispositivo del estilo del que maneja este proyecto, si algún dispositivo tiene
otras necesidades distintas se podrían modificar los campos.
2.3.2 Funciones en <winusb.h>
Winusb proporciona una serie de funciones que se pueden encontrar
en la página web de Microsoft para desarrolladores:
WinUsb_AbortPipe: Cancela todas las transferencias pendientes en
una pipe.
WinUsb_ControlTransfer: Transmite datos de control sobre un
endpoint de control por defecto.
WinUsb_FlushPipe: Descarta cualquier dato en una pipe.
WinUsb_Free: Libera los recursos reservados por WinUsb_Initialize.
WinUsb_GetAssociatedInterface: Guarda un controlador para un
interfaz asociado.
WinUsb_GetCurrentAlternateSetting: Devuelve el marco actual de
un interfaz alternativo para un interfaz.
WinUsb_GetDescriptor: Devuelve el descriptor que se pide.
WinUsb_GetOverlappedResult: Devuelve un HRESULT con la
31
DISEÑO DEL DRIVER
coincidencias.
WinUsb_GetPipePolicy: Devuelve la política de una pipe (endpoint).
WinUsb_GetPowerPolicy: Devuelve la política de uso de la energía
de un dispositivo.
WinUsb_Initialize: Crea una controlador de WinUsb para el
dispositivo especificado por un controlador de fichero.
WinUsb_QueryDeviceInformation: Consigue información sobre el
dispositivo físico asociado a un controlador de WinUSB.
WinUsb_QueryInterfaceSettings: Consigue el descriptor del interfaz
de un marco actual de un interfaz alternativo para un controlador de interfaz.
WinUsb_QueryPipe: Devuelve información sobre una pipe asociada
con un interfaz.
WinUsb_ReadPipe: Lee los datos en una pipe.
WinUsb_ResetPipe: Reinicia el interruptor de datos y limpia la
condición de atasco en una pipe.
WinUsb_SetCurrentAlternateSetting: Modifica el marco alternativo
de un interfaz.
WinUsb_SetPipePolicy: Modifica la política de una pipe (endpoint).
WinUsb_SetPowerPolicy: Modifica la política de uso de la energía
de un dispositivo.
WinUsb_WritePipe: Escribe los datos en una pipe.
Como funciones interesantes destacar WinUsb_WritePipe, es la
función mediante la cual envía datos una aplicación al driver y este al
dispositivo.
2.4 Tecnología
Para el la adaptación del driver se usó de Driver Development Kit. Este kit
es facilitado por Microsoft de manera gratuita siempre que se posea una licencia
válida de alguna de las distribuciones de Windows.
En este kit se proporcionan las frameworks necesarias para realizar tanto un
driver de modo usuario como uno de modo kernel. También se facilitan los
instaladores de WinUSB así como las librerías necesarias para su uso.
32
DISEÑO DEL DRIVER
El kit es descargable desde la página web de la Microsoft Development
Network [1].
33
DISEÑO DE LA APLICACIÓN DE CONTROL
Parte3
DISEÑO DE LA
APLICACIÓN DE
CONTROL
34
DISEÑO DE LA APLICACIÓN DE CONTROL
3 DISEÑO DE LA APLICACIÓN DE CONTROL
En este capítulo se tratará el diseño de la aplicación que el usuario utilizará a
modo de panel de control del dispositivo, durante la sección se entrará en detalle
en la interfaz de usuario, en cómo se usa en la aplicación la Java Native Interface,
así como en el programa a implementar que comunica la aplicación con el
dispositivo.
La aplicación de control es una aplicación de usuario con interfaz simple, en
la que se podrá modificar la fuerza que deberá hacer el dispositivo.
Para la realización de la aplicación se utiliza eclipse con su framework para
el lenguaje de programación Java.
Esta aplicación se desarrolla para que se pueda modificar la fuerza del
dispositivo y se pueda usar en aplicaciones en las que no está integrado, es decir,
si un usuario quiere fijar una fuerza determinada para usar alguna herramienta de
dibujo, este puede fijarla en la aplicación y luego seguir trabajando en la
herramienta de dibujo.
Figura 3.1.1: Aplicación de prueba al iniciar y al modificar uno de los valores.
35
DISEÑO DE LA APLICACIÓN DE CONTROL
3.1 Componentes
La aplicación [Figura 3.1.1]está compuesta principalmente por un JTextField
y un JSlider, dando así la posibilidad de cambiar la fuerza del dispositivo de dos
maneras distintas.
3.1.1 JSlider jFuerza
Este es el principal componente gráfico de la aplicación ya que
pretende ser el principal controlador. Comprende el intervalo desde cero
hasta quince, ambos incluidos.
La modificación es progresiva, para llegar de dos a siete tiene que
pasar por el tres, el cuatro, el cinco y el seis.
Cuando se modifica jFuerza el campo de texto txtFuerza también se
modifica de forma que siempre habrá el mismo valor en los dos campos.
Al mover la posición de la fuerza en el jSlider se crea una instancia de
la clase DriverCall.java que se encarga de comunicar con el driver.
3.1.2 JTextField txtFuerza
Es la alternativa a jFuerza, se usará si se quiere un salto no progresivo.
Al modificar este campo, jFuerza se actualiza de la misma manera que
se ha explicado en la sección anterior.
Al igual que pasaba con el jSlider, cuando se modifica la fuerza en el
campo, se crea una instancia de la clase DriverCall.java que se encarga de
comunicar con el driver.
3.2 JNI (Java Native Interface)
La elección de Java como lenguaje de desarrollo para la aplicación se debió
a que era un lenguaje conocido y a que el desarrollo de la interfaz de usuario sería
muy rápido.
El problema era que Java no puede comunicarse directamente con el driver,
por lo que se usó la librería JNI que provee Java, mediante ella se puede ejecutar
código C desde una aplicación Java. Para esto se usaron Test.java, como clase
Java que controla el flujo de la aplicación mediante la interfaz gráfica;
DriverCall.c, es un fichero que contiene el código de invocación del driver; y
36
DISEÑO DE LA APLICACIÓN DE CONTROL
DriverCall.h, es la librería que utiliza JNI, para ejecutar DriverCall.c como si
formase parte de Test.java. Para ello Test.java se apoya en la clase DriverCall.java
que se explica en el punto 3.3.
Como se ve en la imagen [Figura 3.1.2], mediante JNI, Test.java se
comunica con el driver enviándole una fuerza previamente introducía por el
usuario, mediante el jSlider o el jTextField, el driver recibe esa información, la
procesa y se la envía al dispositivo.
Figura 3.2.1: Diagrama de funcionamiento de la aplicación.
3.3 Clase DriverCall.java
Esta clase es invocada desde Test.java.
A partir de esta clase se crea la librería DriverCall.h, que es usada
posteriormente en DriverCall.c para crear el .dll que usa la aplicación para invocar
las funciones de escritura en el driver.
La razón de usar esta clase es que para lanzar la llamada a la función nativa
hay que crear una instancia de la clase que la define, por lo que si se crea una
nueva instancia de Test.java, se abriría otra jFrame con el mismo contenido que la
primera cada vez que se cambie la fuerza.
3.4 Salida
En la salida de la aplicación se debe realizar una última llamada al driver
que deja la fuerza a cero.
Tal y como está diseñada la aplicación, es necesaria esta llamada ya que si
37
DISEÑO DE LA APLICACIÓN DE CONTROL
no se realiza, el dispositivo seguiría ejerciendo fuerza hasta que se reiniciase la
aplicación y se pusiera a cero. Con esta última llamada, se realiza una especie de
proceso de limpieza que dejaría al dispositivo funcionar como un ratón estándar.
3.5 DriverCall.c
Es ejecutada desde la aplicación mediante JNI. Para ver el código completo
de DriverCall.c consúltese ANEXO B.
Todas la funciones excepto Java_DriverCall_driverCall, devuelven un
BOOL que se usa de control en la función principal.
3.5.1 Java_DriverCall_driverCall
Es la función principal, desde esta se controla la llamada al resto de las
funciones.
Recibe datos desde Test.java, pero lo interesante es el jint i que se
recibe. La función convierte i en envio, un char que se será el que se envíe al
dispositivo.
Para poder enviarlo antes se tiene que crear un fichero que maneja el
driver, crear un pipe que enlace con el dispositivo y por último, enviar el
char.
Para realizar esta conversión se utiliza un switch() sobre el jint i, la
razón de la conversión mediante switch es la incompatibilidad de tipos de
datos, ya que jint es un entero de 32 bits, mientras que la variable en la que
se quiere meter es un char que en el lenguaje de programación C es una
variable de 8 bits. Para evitar esta incompatibilidad se usa el switch de modo
que se para cada valor entre 0 y 15 se mete ese mismo valor en el char. Lo
que se mete en realidad son los valores hexadecimales de 0 a 15 de forma
que cuando se envíen al dispositivo el microcontrolador de este pueda
interpretarlos como debe.
Por último esta función cerrará el fichero de control mediante las
funciones CloseHandle y WinUsb_Free, la segunda contenida en winusb.h.
CloseHandle(hDeviceHandle);
WinUsb_Free(hWinUSBHandle);
38
DISEÑO DE LA APLICACIÓN DE CONTROL
Por último devuelve el control a Test.java.
3.5.2 GetWinUSBHandle
Para abrir el fichero que maneja WinUSB, se necesita la función
CreateFile, está función se usa únicamente para conseguir la interfaz de
control de WinUSB.
Para esto, lo que hace esta función es invocar a la función
GetDeviceHandle. Donde se modifica phWinUSBHandle, declarada en la
función principal.
3.5.3 GetDeviceHandle
Es la que definitivamente crea el fichero que controla WinUSB.
Esto lo hace después de pasar un protocolo que facilita Microsoft, en
este protocolo se hacen una serie de comprobaciones, una vez pasadas todas
por fin se ejecuta la función CreateFile.
*hDeviceHandle
=
CreateFile
(lpDevicePath,
GENERIC_WRITE,FILE_SHARE_WRITE,NULL,
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
Se puede ver en la función que se ha abierto únicamente en modo
escritura ya que el dispositivo no necesita las operaciones de lectura.
Además debe ser invocada antes de llamar a GetWinUSBHandle, ya
que el valor que se pasa WinUSBHandle a esta en hDeviceHandle es el que
se consigue tras una llama a esta función.
3.5.4 QueryDeviceEndpoints
Una vez conseguido el fichero para manejar el driver, lo siguiente es
abrir una línea de comunicaciones.
En esta función, básicamente lo que se hace es conseguir un
identificador (pipeid) del end point sobre el que hay que escribir.
39
DISEÑO DE LA APLICACIÓN DE CONTROL
3.5.5 WriteToBulkEndpoint
Esta función es la hace la escritura.
En ella se define un tamaño de buffer, que es este caso el del tamaño
de un char. Y ese buffer es el que se pasa al driver por medio de la función
después de llenarlo con la variable envío. Para ello se usa la función
WinUsb_WritePipe que es proporcionada en winusb.h para mandar el
contenido del buffer al pipe que apunta a nuestro end point:
bResult = WinUsb_WritePipe(hDeviceHandle, *pID,
szBuffer, cbSize, &cbSent, 0);
Después devolverá el control a la función principal donde se cerrará el
fichero que maneja el Driver.
3.6 Tecnología
La aplicación se divide en dos partes, la parte gráfica y la parte lógica, que
es la que llama al driver.
Para la parte gráfica se utilizó el lenguaje de programación Java y Eclipse
Galileo como framework de este. La elección de estos se debe a que se habían
utilizado de antemano y facilitaban un desarrollo muy rápido del GUI.
Para la lógica se usó el lenguaje de programación C y como framework el
Microsoft Visual Estudio Express Edition, ya que este a parte de trabajar con C
nos permitiría trabajar con C++ en otras partes del proyecto.
Podría haberse utilizado la misma framework para ambos lenguajes, pero
ambas herramientas son gratuitas por lo que no incrementan el coste del proyecto
y facilitan la abstracción al tener frameworks distintos para cada lenguaje.
40
ADAPTACIÓN DE VIDEOJUEGO
Parte4
ADAPTACIÓN DE
VIDEOJUEGO
41
ADAPTACIÓN DE VIDEOJUEGO
4 ADAPTACIÓN DE VIDEOJUEGO
Durante este capítulo se explicará como se adaptó un videojuego a su uso
con el ratón, desde como fue la elección del videojuego, hasta como se inyectó el
código concerniente al manejo del driver en el código proporcionado por el
equipo de desarrollo del port del Doom para Windows ZDoom.
Ante la intención de entrar en el mercado de los videojuegos se decidió que
se debía adaptar un videojuego del tipo FPS (First-Person Shooter), de forma que
se pudiera hacer una demostración. Ya que se trataba de una versión de
demostración no comercializable, solo se trataría en el aspecto de las armas, sin
entrar en la parte de dificultar el movimiento cuando cambias a un entorno
distinto como puede ser el agua.
4.1 Elección de videojuego
A la hora de elegir qué videojuego adaptar, se realizó un búsqueda de
códigos de videojuegos que habían sido liberados, tras una primera criba,
quedaron dos opciones, el Doom y el Duke Nukem 3D.
Con un análisis relativamente rápido se llegó a la conclusión definitiva de
que el videojuego a tratar debía ser el Doom. La principal razón de esta elección
fue la diferente carga de trabajo que suponía cada uno, ya que el código del Doom,
al ser uno de los primeros First Person Shooters, era mucho más reducido que el
del Duke Nukem 3D.
En la decisión también tomó parte la nostalgia y los recuerdos del tiempo
gastado durante la infancia, por parte de los creadores del dispositivo, jugando al
Doom.
El código que liberó IDSoftware estaba preparado para entornos Linux, por
lo que para adaptar se usó un port para Windows de este juego llamado ZDoom.
En este port se encuentran todos los juegos que utilizan el motor del Doom (Doom
engine), como por ejemplo Hexen, Heretic, Doom 2 y por supuesto el Doom que
es el que atañe a este proyecto.
42
ADAPTACIÓN DE VIDEOJUEGO
4.2 Ingeniería inversa
La ingeniería inversa consiste en el estudio de una tecnología existente hasta
comprender el funcionamiento del dispositivo sobre el que se está realizando el
estudio. En este caso al tratar con un videojuego, el proceso de ingeniería inversa
se realizaría sobre el código fuente liberado por IDSoftware y distribuido por el
equipo del ZDoom en lugar de sobre un dispositivo.
En una primera fase se analizaron los ficheros para aislar el código común a
todos los videjuegos y el código del Doom en un már de ficheros de más de
16MB. Una vez aislada esa parte del código, quedaron ciento cincuenta y cuatro
ficheros entre librerías y código de C++.
Estos ficheros se analizaron hasta que se aisló un solo fichero que manejaba
el cambio de armas, el fichero p_pspr.cpp.
Dentro de este fichero se localizó la función sobre la que se trabajaría,
A_WeaponReady.
DEFINE_ACTION_FUNCTION(AInventory, A_WeaponReady) {
player_t *player = self->player; AWeapon *weapon;
if (NULL == player) { return; }
weapon = player->ReadyWeapon;
/*
Llamadas a las funciones
*/
if (NULL == weapon) { return; }
//
Change
player
from
>InStateSequence(self->state,
attack
state
if
(self-
self->MissileState)
||
self->InStateSequence(self->state, self->MeleeState)) {
static_cast<APlayerPawn *>(self)->PlayIdle (); }
// Play ready sound, if any. if (weapon->ReadySound
&&
player->psprites[ps_weapon].state
==
weapon43
ADAPTACIÓN DE VIDEOJUEGO
>FindState(NAME_Ready)) { if (!(weapon->WeaponFlags &
WIF_READYSNDHALF) || pr_wpnreadysnd() < 128) { S_Sound
(self,
CHAN_WEAPON,
weapon->ReadySound,
1,
ATTN_NORM); } }
// Prepare for bobbing and firing action. player>cheats
|=
CF_WEAPONREADY;
>psprites[ps_weapon].sx
=
0;
playerplayer-
>psprites[ps_weapon].sy = WEAPONTOP; }
Se ha marcado como código comentado el lugar donde se incluiría la
llamada a las funciones.
4.3 Adaptando el código
Una vez localizadas las funciones, se realizó el mismo proceso que en
DriverCall.c explicado en el apartado 3.5 de este documento.
Había dos opciones: crear el fichero de control en el inicio de la ejecución y
cerrarlo al finalizar la partida; o abrir y cerrar cada vez que se realizase un cambio
de arma.
Se decidió la segunda opción porque se vio mejor que la primera, ya que
aunque la eficiencia de realizar el proceso cada cambio de arma era menor, era
mucho más respetuoso con la memoria, ya que la libera cuando ya deja de ser
necesaria. Teniendo en cuenta que en juego real no cambias de arma todo el rato,
se decidió que se llamaría a la rutina de la misma manera que en DriverCall.c cada
vez que se cambie el arma.
Para esto se realizó una librería con las funciones necesarias de llamada, de
forma que solo incluyéndose en el código se pudiesen llamar sin ensuciar el
código proporcionado.
#include “rigodon.h”
Rigodon.h es el nombre que recibió la librería utilizada en la realización de
44
ADAPTACIÓN DE VIDEOJUEGO
este proceso. Además se tuvieron que incluir las librerías y tipos de datos
especiales que se usan en las funciones que realizan el proceso de escritura en el
driver.
4.4 Tecnología
Como recurso principal para esta parte del proyecto se utilizó el código
fuente del port del Doom llamado ZDoom [2]. ZDoom contiene una clausula en su
web que permite distribuir el videojuego siempre que sea de manera gratuita.
El código del ZDoom es un código C++, por lo que para su tratamiento y
modificación se utilizo el framework Microsoft Visual Estudio Express Edition.
45
CONCLUSIONES Y TRABAJOS FUTUROS
Parte5
CONCLUSIONES Y
TRABAJOS FUTUROS
46
CONCLUSIONES Y TRABAJOS FUTUROS
5 CONCLUSIONES Y TRABAJOS FUTUROS
En este capítulo se comentarán las dificultades y las conclusiones a las que
se llegó durante el desarrollo de este proyecto, así como las posibilidades de
trabajo que aparecen con la consecución de este proyecto.
Cuando se encara el desarrollo de un driver de las características del de este
proyecto, se debe tener en cuenta que la mayoría del tiempo del proyecto se va
consumir en el análisis y el diseño del controlador, quedando la programación
prácticamente en un segundo plano.
Una de las cosas que se infravalora a la hora de la programación son los
comentarios, la importancia se ve cuando se tiene que modificar un código ajeno.
Un código bien comentado puede ahorrar muchísimo trabajo a los que tengan que
venir después a trabajar con el código.
Cuando se decidió hacer este proyecto, parecía un desarrollo sencillo, pero
según se profundiza en él se encuentran matices en los que se ve que, aún siendo
un proyecto para un prototipo simple de control de electroimanes, se puede
complicar hasta extremos insospechados. Usando exactamente la misma
tecnología, se pueden sustituir los imanes por servomotores e implantarlos en un
joystick, se podrían llevar a un nivel superior periféricos hoy en día casi en
desuso.
No se pueden olvidar los 4 bits que no se llegan a utilizar de la cadena que
se manda al dispositivo, con una adaptación sencilla y una modificación de la
alfombrilla de hierro sobre la que se apoya se podría llegar a una segunda versión
del dispositivo en la que se añadiesen efectos. Por ejemplo dejando solo ciertos
puntos de la plancha con hierro (suficientes para que la sensación fuerza siquiera
siendo potente) y que ante algún evento del juego solo un electroimán puesto a la
máxima potencia dificultase ciertos giros (un pinchazo mientras conduces un
vehículo por ejemplo).
Además en los periféricos para ordenador actuales se puede apreciar la falta
de complementos que ya están disponibles actualmente en las consolas de
videojuegos, como pueden ser la vibración o un giróscopo, que bien adaptados
podría ser un gran avance; solo hay que imaginarse el poder cambiar la
47
CONCLUSIONES Y TRABAJOS FUTUROS
orientación de una textura en un programa de tratamiento de imágenes con un
simple giro de muñeca.
Tampoco se puede dejar de lado una de las motivaciones principales de la
realización de este proyecto, el manejo de brazos mecánicos en la industria, se
podría realizar una aplicación que funcionase como interfaz más compleja entre el
operario y la máquina.
El desarrollo del videojuego se ha dejado un como demostración simple y el
dispositivo solo interactúa con las armas, por lo que la adaptación completa de un
videojuego o la creación de un videojuego en el que se explote en el dispositivo
sería una idea para un proyecto en el futuro.
Se puede apreciar un amplio abanico de posibilidades a partir de una idea
relativamente básica.
Por supuesto, el principal trabajo futuro será la comercialización del
dispositivo, ya que es una de la principales motivaciones de este.
48
ESTUDIO ECONÓMICO
Parte6
ESTUDIO
ECONÓMICO
49
ESTUDIO ECONÓMICO
6 ESTUDIO ECONÓMICO
En este capítulo se incluye un pequeño análisis de los mercados a los que va
dirigido el dispositivo, así como el presupuesto del proyecto desglosado por
secciones de trabajo y coste de las horas/hombre.
6.1 Estudio de mercado
Como se trata de un proyecto nuevo, es difícil saber como puede reaccionar
el mercado. Tanto el la industria, como la informática en general, en concreto en
sector de los videojuegos, están abiertos a mejoras tecnológicas.
Por un lado están los brazos mecánicos que maneja la industria. Estos tienen
deficiencias en el tanto en control manual, dejado en manos del control numérico
la mayoría de tareas, como a la hora del reciclaje de estos, ya que para un cambio
de tarea, deben cambiar la configuración directamente en la máquina.
Por el otro lado están la informática y los videojuegos. En la informática
general el dispositivo iría dirigido al usuario amateur de programas profesionales,
para los programas de diseño gráfico como FreeHand o Photoshop, o programas
de dibujo de planos como Autocad que requieren gran precisión en ciertos
momentos, ya existen tabletas gráficas que cubren las necesidades de
profesionales dispuestos a gastarse lo que cuesta una tableta gráfica con el fin de
mejorar su trabajo. Pero el usuario que diseña o hace planos por afición no
necesitará tanta precisión ni estará dispuesto a gastar ese dinero. Ese sector sería
el que habría que abordar en lo que a la informática general se refiere.
En cuanto al mercado de los videojuegos se puede decir que es todavía más
incierto si cabe. Por un lado está el hecho de que mueve más del 50% del ocio
audiovisual, como ejemplo, en diciembre de 2009, el juego Call of Duty Modern
Warfare 2 hizo más dinero que la taquillera película Avatar. Pero por el otro lado
muchos jugadores no buscan realismo en un dispositivo si no eficiencia, estos son
los jugadores de juegos online, que buscan ser más rápidos y mejores que el
contrario. El sector de usuarios al que tendría que dirigirse es a los jugadores que
buscan calidad gráfica y gran interacción con el entorno, realismo al fin y al cabo.
La competencia en el mercado de los videojuegos es muy grande y no se
50
ESTUDIO ECONÓMICO
rige por el criterio del precio, ya que los grandes fanáticos de los videojuegos
están dispuestos a gastar mucho dinero en periféricos que mejoren la experiencia
de juego.
El coste de construir un solo dispositivo se calcula en 32,21€, pero una vez
iniciada la producción en cadena y la compra de elementos al por mayor, se
calcula que no pasaría de los 15€. Comercializándolo a 35€ se estaría sacando un
133% de beneficio y se estaría muy por debajo del precio de los periféricos
orientados a profesionales de los que se ha hablado antes.
Si al precio se le añade una buena campaña publicitaria, se considera que el
dispositivo tiene una posibilidades de éxito bastante altas.
6.2 Presupuesto
El presupuesto fue analizado desde un punto de vista humano, es decir, el
coste de las personas en cada fase del proyecto. Esto es así porque no se ha
necesitado ninguna inversión en software o hardware que no estuviera adquirido
de antemano ya que la herramienta principal (WDK) se facilita a cualquier usuario
con una licencia de Windows. El resto se realizo con aplicaciones gratuitas y open
source, como Visual C++ Xpress Edition o Eclipse Galileo.
El presupuesto queda desglosado en las siguientes tablas [Figuras de 6.1 a
6.3]]:
Tiempo dedicado (horas)
DIRECCIÓN
ANÁLISIS
DISEÑO
DESARROLLO
DOCUMENTACIÓN
TOTAL
Driver
10
50
30
33
15
138
Aplicación
3
7
8
15
10
43
Videojuego
3
20
5
10
8
46
Total
16
77
43
58
33
227
Figura 6.1: Horas de trabajo por grupo de trabajo y sección del proyecto.
TITULACIÓN
COSTE €/h
Director de proyecto
Analista
Programador
60,00 €
40,00 €
30,00 €
Figura 6.2: Coste por hora de trabajo dependiendo del puesto.
51
ESTUDIO ECONÓMICO
SECCIÓN
DIRECCIÓN
ANÁLISIS Y DISEÑO
DESARROLLO
DOCUMENTACIÓN
TOTAL
COSTE €/h
960,00 €
4.800,00 €
990,00 €
1.320,00 €
8.070,00 €
Figura 6.3: Coste desglosado por secciones y total.
Cabe aclarar que las horas de documentación están valoradas como horas de
analistas, al igual que las de Análisis y Diseño, que al ser consideradas como fases
que se llegan a solapar, se han puesto como una misma sección en el coste
desglosado por secciones [Figura 6.3].
Las horas de documentación son muchas debido a que la información
disponible sobre drivers para Windows es escasa y en su mayoría está en
publicaciones de pago y en inglés, por esto a la hora de documentar se ha
invertido mucho tiempo en intentar que este proyecto sirva también de guía para
el desarrollo de un driver.
Además, el coste por hora de los programadores está por encima del
habitual, esto es porque la programación de un driver requiere mayor calidad en la
programación que una simple aplicación de escritorio.
52
BIBLIOGRAFÍA
Parte7
BIBLIOGRAFÍA
53
BIBLIOGRAFÍA
7 BIBLIOGRAFÍA
7.1 Libros
[GONZ09] González-Arintero Berziano, Jaime. “Control Intuitivo de Ratón
por Force Feedback”. Universidad Pontificia de Comillas, UPCO,
2009.
[ORWI07]
Orwick, Penny y Smith, Guy.“Developing Drivers with the
Windows® Driver Foundation”. Microsoft Press; 1 edition (April
25, 2007).
[ONEY02] Oney, Walter. “Programming the Microsoft Windows Driver
Model”. Microsoft Press; 2nd edition (December 16, 2002).
7.2 Links
[1]
http://msdn.Microsoft.com
[2]
http://zdoom.org
[3]
http://java.sun.com/
[4]
http://java.sun.com/javase/6/docs/technotes/guides/jni/
54
ANEXOS
Parte8
ANEXOS
55
ANEXOS
8 ANEXOS
Anexo A Ejemplo de fichero de instalación .inf
[Version]
Signature = "$Windows NT$"
Class = MyDeviceClass
ClassGuid={78A1C341-4539-11d3-B88D-00C04FAD5171}
Provider = %ProviderName%
CatalogFile=MyCatFile.cat
;==================Class section==================
[ClassInstall32]
Addreg=MyDeviceClassReg
[MyDeviceClassReg]
HKR,,,0,%ClassName%
HKR,,Icon,,-1
; ========Manufacturer/Models sections=========
[Manufacturer]
%ProviderName% = MyDevice_WinUSB,NTx86,NTamd64,NTia64
[MyDevice_WinUSB.NTx86]
%USB\MyDevice.DeviceDesc%=
USB_Install, USB\VID_0547&PID_1002
[MyDevice_WinUSB.NTamd64]
%USB\MyDevice.DeviceDesc%=
USB_Install, USB\VID_0547&PID_1002
56
ANEXOS
[MyDevice_WinUSB.NTia64]
%USB\MyDevice.DeviceDesc%=
USB_Install,USB\VID_0547&PID_1002
;===================Installation===================
;[1]
[USB_Install]
Include=winusb.inf
Needs=WINUSB.NT
;[2]
[USB_Install.Services]
Include=winusb.inf
AddService=WinUSB,0x00000002,WinUSB_ServiceInstall
;[3]
[WinUSB_ServiceInstall]
DisplayName
= %WinUSB_SvcDesc%
ServiceType
= 1
StartType
= 3
ErrorControl
= 1
ServiceBinary
= %12%\winusb.sys
;[4]
[USB_Install.Wdf]
KmdfService=WINUSB, WinUsb_Install
[WinUSB_Install]
KmdfLibraryVersion=1.9
;[5]
57
ANEXOS
[USB_Install.HW]
AddReg=Dev_AddReg
[Dev_AddReg]
HKR,,DeviceInterfaceGUIDs,0x10000,"{AE5F20A3-09D7-4E62B2F7-3D5172853709}"
;[6]
[USB_Install.CoInstallers]
AddReg=CoInstallers_AddReg
CopyFiles=CoInstallers_CopyFiles
[CoInstallers_AddReg]
HKR,,CoInstallers32,0x00010000,"WdfCoInstaller01009.dll
,WdfCoInstaller","WinUSBCoInstaller2.dll"
[CoInstallers_CopyFiles]
WinUSBCoInstaller2.dll
WdfCoInstaller01009.dll
[DestinationDirs]
CoInstallers_CopyFiles=11
;=================SourceMediaSection===============
;[7]
[SourceDisksNames]
1 = %DISK_NAME%,,,\i386
2 = %DISK_NAME%,,,\amd64
3 = %DISK_NAME%,,,\ia64
[SourceDisksFiles.x86]
58
ANEXOS
WinUSBCoInstaller2.dll=1
WdfCoInstaller01009.dll=1
[SourceDisksFiles.NTamd64]
WinUSBCoInstaller2.dll=2
WdfCoInstaller01009.dll=2
[SourceDisksFiles.ia64]
WinUSBCoInstaller2.dll=3
WdfCoInstaller01009.dll=3
; =================== Strings ===================
[Strings]
ProviderName="MyWinUsbTest"
USB\MyDevice.DeviceDesc="Test using WinUSB only"
WinUSB_SvcDesc="WinUSB Test"
DISK_NAME="My Install Disk"
ClassName="MyDeviceClass"
Anexo B DriverCall.c
#include <jni.h>
#include "DriverCall.h"
#include "E:\windows\VisualC++\VC\include\stdio.h"
//#include "SAL.h"
// Include Windows headers
#include "E:\WinDDK\7600.16385.0\inc\api\windows.h"
#include <tchar.h>
#include "E:\WinDDK\7600.16385.0\inc\api\strsafe.h"
// Include WinUSB headers
#include <winusb.h>
59
ANEXOS
#include "E:\WinDDK\7600.16385.0\inc\api\Usb100.h"
#include "E:\WinDDK\7600.16385.0\inc\api\Setupapi.h"
// Linked libraries
#pragma comment (lib ,
"E:\WinDDK\7600.16385.0\lib\wxp\i386\setupapi.lib" )
#pragma comment (lib ,
"E:\WinDDK\7600.16385.0\lib\wlh\i386\winusb.lib" )
//Estructura del pipe
struct PIPE_ID
{
UCHAR
PipeInId;
UCHAR
PipeOutId;
};
// GUID tiene que ser igual que el del fichero.inf
static const GUID OSR_DEVICE_INTERFACE =
{ 0xae5f20a3, 0x09d7, 0x4e62, {0xb2, 0xf7, 0x3d, 0x51,
0x72, 0x85, 0x37, 0x09}};
JNIEXPORT void JNICALL Java_DriverCall_driverCall
(JNIEnv *je, jobject jo, jint i)
{
//printf("Aquí debería ir un write o fwrite al driver
guayser\n");
GUID guidDeviceInterface = OSR_DEVICE_INTERFACE;
BOOL bResult = TRUE;
PIPE_ID PipeID;
HANDLE hDeviceHandle = INVALID_HANDLE_VALUE;
WINUSB_INTERFACE_HANDLE hWinUSBHandle =
INVALID_HANDLE_VALUE;
60
ANEXOS
//UCHAR DeviceSpeed;
ULONG cbSize = 0;
//char que se envía
char envio = 0;
//convierto i a char
switch(i)
{
case 1: envio = 1;
break;
case 2: envio = 2;
break;
case 3: envio = 3;
break;
case 4: envio = 4;
break;
case 5: envio = 5;
break;
case 6: envio = 6;
break;
case 7: envio = 7;
break;
case 8: envio = 8;
break;
case 9: envio = 9;
break;
case 10: envio = 10;
break;
case 11: envio = 11;
break;
case 12: envio = 12;
61
ANEXOS
break;
case 13: envio = 13;
break;
case 14: envio = 14;
break;
case 15: envio = 15;
break;
case 0: envio = 0;
break;
default: envio = 0;
break;
}
//Llamada para conseguir un handle para pasarlo en la
siguiente función
GetDeviceHandle (guidDeviceInterface, &hDeviceHandle);
if(!bResult)
{
goto done;
}
//Llamada para crear fichero que controle winusb
bResult = GetWinUSBHandle(hDeviceHandle,
&hWinUSBHandle);
if(!bResult)
{
goto done;
}
//Llamo para crear pipe con el dispositivo
62
ANEXOS
bResult = QueryDeviceEndpoints(hWinUSBHandle, &PipeID);
if(!bResult)
{
goto done;
}
//Escribo en el driver
WriteToBulkEndpoint(hDeviceHandle,&pID,&cbSize, envio);
if(!bResult)
{
goto done;
}
done:
CloseHandle(hDeviceHandle);
WinUsb_Free(hWinUSBHandle);
}
/*
CREA FICHERO PARA MANEJAR WinUSB DRIVER para Rigodón
*/
BOOL GetDeviceHandle (GUID guidDeviceInterface, PHANDLE
hDeviceHandle)
{
if (guidDeviceInterface==GUID_NULL)
{
return FALSE;
}
BOOL bResult = TRUE;
HDEVINFO hDeviceInfo;
SP_DEVINFO_DATA DeviceInfoData;
SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
PSP_DEVICE_INTERFACE_DETAIL_DATA
pInterfaceDetailData = NULL;
ULONG requiredLength=0;
63
ANEXOS
LPTSTR lpDevicePath = NULL;
DWORD index = 0;
// Get information about all the installed devices
for the specified
// device interface class.
hDeviceInfo =
SetupDiGetClassDevs(&guidDeviceInterface,NULL,NULL,DIGC
F_PRESENT|DIGCF_DEVICEINTERFACE);
if (hDeviceInfo == INVALID_HANDLE_VALUE)
{
// ERROR
printf("Error SetupDiGetClassDevs: %d.\n",
GetLastError());
goto done;
}
//Enumerate all the device interfaces in the device
information set.
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
for (index = 0; SetupDiEnumDeviceInfo(hDeviceInfo,
index, &DeviceInfoData); index++)
{
//Reset for this iteration
if (lpDevicePath)
{
LocalFree(lpDevicePath);
}
64
ANEXOS
if (pInterfaceDetailData)
{
LocalFree(pInterfaceDetailData);
}
deviceInterfaceData.cbSize =
sizeof(SP_INTERFACE_DEVICE_DATA);
//Get information about the device interface.
bResult =
SetupDiEnumDeviceInterfaces(hDeviceInfo,&DeviceInfoData
,&guidDeviceInterface,index,&deviceInterfaceData);
// Check if last item
if (GetLastError () == ERROR_NO_MORE_ITEMS)
{
break;
}
//Check for some other error
if (!bResult)
{
printf("Error SetupDiEnumDeviceInterfaces:
%d.\n", GetLastError());
goto done;
}
//Interface data is returned in
SP_DEVICE_INTERFACE_DETAIL_DATA
//which we need to allocate, so we have to call
this function twice.
//First to get the size so that we know how
65
ANEXOS
much to allocate
//Second, the actual call with the allocated
buffer
bResult =
SetupDiGetDeviceInterfaceDetail(hDeviceInfo,&deviceInte
rfaceData,NULL, 0,&requiredLength,NULL);
//Check for some other error
if (!bResult)
{
if
((ERROR_INSUFFICIENT_BUFFER==GetLastError()) &&
(requiredLength>0))
{
//we got the size, allocate buffer
pInterfaceDetailData =
(PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LPTR,
requiredLength);
if (!pInterfaceDetailData)
{
// ERROR
printf("Error allocating memory for
the device detail buffer.\n");
goto done;
}
}
else
{
printf("Error
SetupDiEnumDeviceInterfaces: %d.\n", GetLastError());
goto done;
}
66
ANEXOS
}
//get the interface detailed data
pInterfaceDetailData->cbSize =
sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
//Now call it with the correct size and
allocated buffer
bResult =
SetupDiGetDeviceInterfaceDetail(hDeviceInfo,&deviceInte
rfaceData,pInterfaceDetailData,requiredLength,
NULL,
&DeviceInfoData);
//Check for some other error
if (!bResult)
{
printf("Error
SetupDiGetDeviceInterfaceDetail: %d.\n",
GetLastError());
goto done;
}
//copy device path
size_t nLength = wcslen (pInterfaceDetailData>DevicePath) + 1;
lpDevicePath = (TCHAR *) LocalAlloc (LPTR,
nLength * sizeof(TCHAR));
StringCchCopy(lpDevicePath, nLength,
pInterfaceDetailData->DevicePath);
lpDevicePath[nLength-1] = 0;
67
ANEXOS
printf("Device path:
%s\n", lpDevicePath);
}
if (!lpDevicePath)
{
//Error.
printf("Error %d.", GetLastError());
goto done;
}
//Open the device
*hDeviceHandle = CreateFile
(lpDevicePath,GENERIC_WRITE,FILE_SHARE_WRITE,NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
if (*hDeviceHandle == INVALID_HANDLE_VALUE)
{
//Error.
printf("Error %d.", GetLastError());
goto done;
}
done:
LocalFree(lpDevicePath);
LocalFree(pInterfaceDetailData);
bResult =
SetupDiDestroyDeviceInfoList(hDeviceInfo);
return bResult;
}
/*
PARA MANEJAR WIN USB, LLAMA A GETDEVICEHANDLE PARA ELLO
68
ANEXOS
*/
BOOL GetWinUSBHandle(HANDLE hDeviceHandle,
PWINUSB_INTERFACE_HANDLE phWinUSBHandle)
{
if (hDeviceHandle == INVALID_HANDLE_VALUE)
{
return FALSE;
}
BOOL bResult = WinUsb_Initialize(hDeviceHandle,
phWinUSBHandle);
if(!bResult)
{
//Error.
printf("WinUsb_Initialize Error %d.",
GetLastError());
return FALSE;
}
return bResult;
}
/*
Encola los descriptores
*/
BOOL QueryDeviceEndpoints (WINUSB_INTERFACE_HANDLE
hDeviceHandle, PIPE_ID* pipeid)
{
if (hDeviceHandle==INVALID_HANDLE_VALUE)
{
return FALSE;
}
BOOL bResult = TRUE;
USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
69
ANEXOS
ZeroMemory(&InterfaceDescriptor,
sizeof(USB_INTERFACE_DESCRIPTOR));
WINUSB_PIPE_INFORMATION
Pipe;
ZeroMemory(&Pipe, sizeof(WINUSB_PIPE_INFORMATION));
bResult =
WinUsb_QueryInterfaceSettings(hDeviceHandle, 0,
&InterfaceDescriptor);
if (bResult)
{
for (int index = 0; index <
InterfaceDescriptor.bNumEndpoints; index++)
{
bResult = WinUsb_QueryPipe(hDeviceHandle,
0, index, &Pipe);
if (bResult)
{
if (Pipe.PipeType ==
UsbdPipeTypeControl)
{
printf("Endpoint index: %d Pipe
type: Control Pipe ID: %d.\n", index, Pipe.PipeType,
Pipe.PipeId);
}
if (Pipe.PipeType ==
UsbdPipeTypeIsochronous)
{
printf("Endpoint index: %d Pipe
type: Isochronous Pipe ID: %d.\n", index,
Pipe.PipeType, Pipe.PipeId);
}
if (Pipe.PipeType == UsbdPipeTypeBulk)
70
ANEXOS
{
if
(USB_ENDPOINT_DIRECTION_IN(Pipe.PipeId))
{
printf("Endpoint index: %d Pipe
type: Bulk Pipe ID: %c.\n", index, Pipe.PipeType,
Pipe.PipeId);
pipeid->PipeInId = Pipe.PipeId;
}
if
(USB_ENDPOINT_DIRECTION_OUT(Pipe.PipeId))
{
printf("Endpoint index: %d Pipe
type: Bulk Pipe ID: %c.\n", index, Pipe.PipeType,
Pipe.PipeId);
pipeid->PipeOutId =
Pipe.PipeId;
}
}
if (Pipe.PipeType ==
UsbdPipeTypeInterrupt)
{
printf("Endpoint index: %d Pipe
type: Interrupt Pipe ID: %d.\n", index, Pipe.PipeType,
Pipe.PipeId);
}
}
else
{
continue;
}
}
71
ANEXOS
}
done:
return bResult;
}
/*
ESCRIBE SOBRE EL DRIVER
*/
BOOL WriteToBulkEndpoint(WINUSB_INTERFACE_HANDLE
hDeviceHandle, UCHAR* pID, ULONG* pcbWritten, char
envio)
{
if (hDeviceHandle==INVALID_HANDLE_VALUE || !pID
|| !pcbWritten)
{
return FALSE;
}
BOOL bResult = TRUE;
//Tamaño de Buffer de 1 char()
UCHAR szBuffer[] = &envio;
ULONG cbSize = strlen(szBuffer);
ULONG cbSent = 0;
bResult = WinUsb_WritePipe(hDeviceHandle, *pID,
szBuffer, cbSize, &cbSent, 0);
if(!bResult)
{
goto done;
}
printf("Wrote to pipe %d: %s \nActual data
transferred: %d.\n", *pID, szBuffer, cbSent);
*pcbWritten = cbSent;
72
ANEXOS
done:
return bResult;
}
Anexo C Manual de instalación de winUSB
Para la instalación de WinUSB en su equipo, primero debe coger el paquete
de instalación correspondiente a las necesidades de su equipo. Para distiguirlos
cada paque tiene un nombre con el formato <Nombre de la distribución de
windows><xXX>.rar por ejemplo para la instalación en Windows XP service
pack 2 en un equipo x86. El paquete de instalación necesario sería uno con el
nombre XPx86.rar.
Una vez localizado el paquete lo debe descomprimir en su escritorio.
Una vez hecho esto, debe acceder a la carpeta, localizar el fichero install.inf
y situar el cursor sobre él. Pulse, con el botón secundario del ratón y pinche en
instalar.
La instalación debería haberse completando con éxito.
73
ANEXOS
Anexo D Manual de la aplicación
Para iniciar la ejecución de la aplicación debe tener instalado el Java
Runtime Environment, si no es así descárguelo desde http://java.sun.com/.
Una vez instalado JRE, solo debe hacer doble click sobre el fichero Rigodon
Enforcer.jar para lanzar la aplicación.
Con la aplicación abierta tiene dos maneras de comunicarse con el
dispositivo, la primera es a partir del slider, sitúese por encima o por debajo de la
posición de la marca en la barra y haga click, esto moverá el indicador hacia
arriba o hacia abajo respectivamente.
Si prefiere realizar un cambio que no sea gradual, escriba un número entre 0
y 15 en el campo de texto y pulse enter. Esto enviará al dispositivo la fuerza
introducida en el campo de texto.
Para terminar la ejecución pulsar el icono de la “x” en la parte superior
izquierda, mediante esta acción el dispositivo pasará a tener fuerza 0 dejando así
que pueda trabajar libremente con el resto de aplicaciones.
74
ANEXOS
Anexo E Librería rigodon.h
#include <stdio.h>
//#include "SAL.h"
// Include Windows headers
#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
// Include WinUSB headers
#include <winusb.h>
#include <Usb100.h>
#include <Setupapi.h>
// Linked libraries
#pragma comment (lib ,
"E:\WinDDK\7600.16385.0\lib\wxp\i386\setupapi.lib" )
#pragma comment (lib ,
"E:\WinDDK\7600.16385.0\lib\wlh\i386\winusb.lib" )
75
ANEXOS
//Estructura del pipe
struct PIPE_ID
{
UCHAR
PipeInId;
UCHAR
PipeOutId;
};
// GUID tiene que ser igual que el del fichero.inf
static const GUID OSR_DEVICE_INTERFACE =
{ 0xae5f20a3, 0x09d7, 0x4e62, {0xb2, 0xf7, 0x3d, 0x51,
0x72, 0x85, 0x37, 0x09}};
//Prototipos de función
BOOL GetDeviceHandle (GUID, PHANDLE);
BOOL GetWinUSBHandle(HANDLE, PWINUSB_INTERFACE_HANDLE);
BOOL QueryDeviceEndpoints (WINUSB_INTERFACE_HANDLE,
PIPE_ID*);
76
ANEXOS
BOOL WriteToBulkEndpoint(WINUSB_INTERFACE_HANDLE,
UCHAR*, ULONG*, char);
77
Descargar