Sei sulla pagina 1di 93

UNIDAD IZTAPALAPA DIVISIN DE CIENCIAS BSICAS E INGENIERIA

DESARROLLO DE A P L I C A C I O N E S PA R A CONTROL Y MONITOREO DE DISPOSITIVOS REMOTOS


PA R A O B T E N E R E L T I T U L O D E L I C E N C I A D O E N C O M P U TA C I O N
PRESENTAN: CRISSTOMO BRAVO ENRIQUE ORTEGA TORRES ANA LILIA

____________________________ M en C. Omar L. Cabrera Jimnez Asesor

Mxico D. F. Julio 2007

Resumen: Este trabajo describe el entorno de control y monitoreo remoto de un Robot conectado al puerto paralelo de una PC. Este entorno, desarrollado en lenguaje Java permite enviar rdenes de movimientos y acciones que el robot es capaz de realizar de acuerdo al estado presente en el registro de datos del puerto conectado en una computadora Servidor y mas an, se tiene una estructura que permite lanzar programas residentes en la computadora remota mediante comandos en la computadora Cliente. De modo que esto nos permite incorporar nuevos programas o utilizar los que existen en el sistema para darle un conjunto escalable de funciones que el robot puede realizar; principalmente multimedia, controlados todos de manera remota independientemente de la red de que se disponga pero cuya disponibilidad debe estar garantizada. Esta versin ha sido probada sobre diferentes tecnologas de red como 802.11 y Bluetooth. Tambin se incluyen los resultados de las pruebas realizadas.

Indice Presentacin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Justificacin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1. Introduccin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2. Marco Terico. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.1 Programacin con sockets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2 Hilos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.3 Applets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.4 Ejemplo de construccin de un Applet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.5 Programacin del Puerto Paralelo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.6 Driver UserPort.sys . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.7 La API Genuts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3. Especificacin de requerimientos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.1 Estructura de las tramas de control del robot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2 Comunicacin entre cliente y servidor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.3 Plataforma de operacin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.4 Velocidad de respuesta . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.5 Control de programas remotos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.6 Interfaz grfica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4. Modelo de requerimientos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.1 Modelo de casos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.2 Modelo de interfaz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.3 Modelo de dominio del problema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5. Aplicacin desarrollada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.1 Descripcin general . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2 Diseo conceptual . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.3 Esquema general de comunicaciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.4 Diagramas de clases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6. Pruebas realizadas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 3 4 5 6 6 10 20 26 29 42 43 44 44 46 46 46 46 46 47 47 49 51 52 52 52 53 54 57

7. Recomendaciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 8. Conclusiones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 9. Referencias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 Anexo A. Cdigo fuente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A.1. Programa Joystick . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A.2. Programa Monitor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A.3. Programa controlador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A.4. Programa Sensor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 61 73 77 86

Presentacin Se desea desarrollar y evaluar aplicaciones de software para control y monitoreo de dispositivos electromecnicos mediante redes de computadoras conectadas con diferentes medios.

Justificacin El desarrollo de software ha sustituido en gran medida el proceso de desarrollo de hardware y esto, entre otras causas; ha hecho posible una disminucin en costos y rpido desarrollo de nuevas tecnologas. La posibilidad de sustituir dispositivos electrnicos por un entorno programable de amplias posibilidades como una PC permite libertades en el diseo de algoritmos y diferentes soluciones para el control de dispositivos remotos que de otro modo nos restringiran a un diseo, el cual una vez llevado a la etapa de pruebas puede ser modificado pero con el costo de adquirir nuevos dispositivos y adems con variaciones en las caractersticas elctricas de los dispositivos que deben ser consideradas por mnimas que estas sean. An cuando existen dispositivos programables como PICs y PLCs que nos permiten un avance en este sentido, la tecnologa de computadoras ha evolucionado notablemente al grado de contar con puertos de comunicacin como BlueTooth, puerto paralelo, serial, redes inalmbricas de alta velocidad y USB ademas de aplicaciones multimedia y todo esto con un funcionamiento eficiente probado en diferentes entornos. De este modo entramos a un campo que originalmente dio soluciones con un punto de vista puramente electrnico mediante radio control y circuitos combinatorios y secuenciales en conjunto con dispositivos programables, memorias EPROM etc. Aprovechamos ahora el avance en el campo de nuevas tecnologas de informacin y comunicacin para sustituir en gran medida la electrnica por el desarrollo de software, cambiando el laboratorio de electrnica por una computadora de escritorio y con un mnimo de interfaces electrnicas que incluso pueden ser modeladas por computadora.

Objetivos:

Analizar diferentes esquemas para el control y monitoreo remoto de dispositivos electromecnicos proponiendo el uso de diferentes algoritmos. Establecer diversos medios de comunicacin, los cuales permitan probar los programas de cmputo a desarrollar para el control y monitoreo de dispositivos electromecnicos. Construir diferentes esquemas de control y monitoreo remoto para dispositivos electromecncios implementando diferentes mecanismos de comunicacin. Programar diferentes algoritmos de control y monitoreo para dispositivos remotos conectados a una red de computadoras. Evaluar los resultados de diferentes pruebas de operacin del sistema de control y monitoreo desarrollado sobre diferentes medios y condiciones de operacin. Proponer algunas lneas de investigacin y mejoras a los equemas y algoritmos que se analicen basados en los resultados de sus pruebas de operacin.

1. INTRODUCCIN
Los avances en tecnologas de computo han tenido un mayor desarrollado en los ltimos aos a nivel mundial y se ha acentuado muchsimo ms en los pases del primer mundo, sin embargo en los pases en vas de desarrollo es necesario el desarrollo y la investigacin en este campo. En el caso de Mxico el avance tecnolgico se ha visto afectado al igual que en otros pases en vas de desarrollo por la carencia del factor humano suficientemente preparado para analizar, disear, producir, coordinar, manejar o mantener estas tecnologas. Esta necesidad y la oportunidad de participar en este tipo de proyectos, nos ha motivado a trabajar, para lograr el resultado que estamos presentando. El control de dispositivos remotos es un rea en la que se pueden encontrar una gran variedad de aplicaciones. El creciente desarrollo de internet y de redes locales, no solo nos da un medio a travs del cual podemos comunicarnos para este propsito, sino que adems nos permite incorporar nuevas tecnologas de acuerdo a necesidades especficas. Mas an, es tecnologa que se encuentra disponible ampliamente y que evoluciona proporcionando mejores caractersticas y mejor desempeo en poco tiempo. El esquema que presentaremos proporciona el control remoto especfico de un robot conectado al puerto paralelo de una computadora (servidor) desde otra estacin (cliente), comunicndose en un entorno de red local, convencional o inalmbrica; mediante el protocolo TCP/IP. Este esquema se puede aplicar para el control remoto de otros dispositivos que tengan una interfaz para conectarse al puerto paralelo con un mnimo de modificaciones al software desarrollado. El diseo permite desarrollar e incorporar nuevas aplicaciones, a ejecutarse en la estacin servidor, las cuales pueden ser invocadas remotamente desde la lnea de comandos del cliente, o bien utilizar programas ya disponibles en el servidor. En el cliente se cuenta con un monitor que recibe mensajes y los publica, estos mensajes pueden ser enviados por cualquier aplicacin actual en el servidor o que sea desarrollada a futuro. El servidor enva la salida de cualquier aplicacin invocada desde el cliente a este monitor lo que nos permite saber lo que se estn ejecutando. La programacin de esta aplicacin ha sido desarrollada en Java, lenguaje que nos permite independencia de plataforma para el programa cliente. Por otro lado Java nos proporciona diferentes conjuntos de clases que ya han sido programadas y satisfacen una amplia variedad de necesidades que al ser reutilizadas nos permiten un rpido avance en el desarrollo de la aplicacin. Dado que el servidor esta programado para interactuar con la lnea de comandos de MS-DOS, y adems utiliza bibliotecas de enlace dinmicas DLL para el control del puerto paralelo, este se ejecuta solo en plataforma Windows. Durante el desarrollo del proyecto se enfrentaron diferentes problemticas cuya solucin nos llev a la conclusin del trabajo que estamos presentando. Desde la eleccin del lenguaje de programacin que se contempl como la mejor opcin para resolver el problema de ejecucin independiente del sistema operativo, la capacidad de interactuar con otros programas desarrollados en lenguaje nativo C si se requiriera, la capacidad de invocar programas ejecutables, etc., hasta la forma en que Windows XP, NT o 2000 bloquean los puertos por cuestiones de seguridad y que dificultan su interaccin con el programador.

2. MARCO TERICO
Hemos agregado los conceptos fundamentales que han hecho posible el desarrollo de este trabajo. Omitimos conceptos bsicos de programacin orientada a objetos, dado que no es el objetivo el presentar un tratado extensivo sobre paradigmas de programacin. Aqu se muestra de forma general de conceptos que han sido considerados para el desarrollo de la aplicacin y para poder extender la misma. Iniciamos con los conceptos involucrados de la programacin en Java referentes a la manera en que se llevan a cabo las comunicaciones entre los diferentes programas o mdulos que conforman la aplicacin. Posteriormente presentamos la estructura del puerto paralelo con su programacin y finalmente se explica la teora que nos ayuda a resolver el problema de lectura/escritura en los puertos en entorno Windows que por razones de seguridad es restringido a los usuarios en versiones XP, 2000 y NT

2.1. Programacin con sockets


Para nadie es ya desconocida la necesidad existente de comunicacin de datos independientemente de la distancia que separe las estaciones a ambos extremos y, sobre todo, independientemente de la red en que estn localizadas. Desafortunadamente, la mayor parte de las redes son entidades independientes, establecidas para servir a las necesidades de un grupo nico. Lo que es ms, es imposible construir una red mundial con una nica tecnologa de hardware porque ninguna cumplira con las necesidades de todos los usuarios (algunos necesitaran grandes velocidades de comunicacin a corta distancia, mientras que otros desearan conectar computadoras a miles de kilmetros). Es por tanto necesario proporcionar procedimientos que permitan la interconexin de redes distintas, independiente de la tecnologa de hardware utilizada. Este tipo de problemas son los que se denominan internetworking (o interconexin de redes) y su solucin ha permitido extender las posibilidades de intercambio de informacin entre los distintos usuarios de distintas redes independientemente de su tecnologa y de su localizacin, a travs de la Internet (tambin llamada red de redes). La tecnologa Internet es un ejemplo de interconexin de sistemas abiertos. Se llama sistema abierto porque, al contrario que los sistemas de comunicaciones propietarios, las especificaciones estn al alcance del pblico. As, cualquiera puede construir el software necesario para comunicarse a travs de Internet. Adems, toda la tecnologa ha sido diseada para conseguir la comunicacin entre mquinas de diferentes arquitecturas, con distintos sistemas operativos y usando casi cualquier tipo de red. TCP/IP ha sido implementado en muchos y diferentes tipos de redes comerciales. Cada una de estas redes, dependiendo de su tecnologa y forma de funcionamiento, adapta el protocolo TCP/IP a sus caractersticas de una forma diferente. IP es un protocolo de red en el que los hosts cliente y servidor se identifican globalmente con la direccin IP, que consiste en octetos (32 bits) de la forma 156.35.14.2, donde parte de la direccin identifica a la red y parte al host dentro de esa red. No obstante, los programas utilizan usualmente direcciones del tipo hal.ugr.es que identifican al host y al dominio al que pertenece.

En la capa de transporte las entidades se identifican con el nmero de puerto (16 bits), que identifica el proceso dentro del host al que esta destinada o del que proviene la informacin. TCP/IP reserva una serie de puertos bien conocidos para las aplicaciones estndar (por ejemplo, 7 para el servidor de ECHO, 13 para el servidor de DAYTIME, 21 para el servidor FTP, 23 para el servidor TELNET y 25 para el servidor SMTP) y deja sin definir otros para las aplicaciones no estndares desarrolladas por los usuarios (advertencia: para aplicaciones de usuario se deben usar nmeros de puerto por encima de 1000 ya que los primeros estn reservados para root). La programacin de aplicaciones sobre TCP/IP se basa en el modelo cliente-servidor. Bsicamente, la idea consiste en que al iniciar un intercambio de informacin, una de las partes debe iniciar el dilogo (cliente) mientras que la otra debe estar indefinidamente preparada para recibir peticiones de establecimiento de dicho dilogo (servidor). Cada vez que un usuario cliente desee entablar un dilogo, primero deber contactar con el servidor, mandar una peticin y posteriormente esperar la respuesta. Los servidores pueden clasificarse atendiendo a si estn diseados para admitir mltiples conexiones simultneas (servidores concurrentes), por oposicin a los servidores que admiten una sola conexin por aplicacin ejecutada (llamados iterativos). Evidentemente, el diseo de estos ltimos ser mucho ms sencillo que el de los primeros. Otro concepto importante es la determinacin del tipo de interaccin entre el cliente y el servidor, que puede ser orientada a conexin o no orientada a conexin. Estas corresponden, respectivamente, con los dos protocolos caractersticos de la capa de transporte: TCP y UDP. TCP (orientado a conexin) garantiza toda la seguridad requerida para que la transmisin est libre de errores: verifica que todos los datos se reciben, automticamente retransmite aquellos que no fueron recibidos, garantiza que no hay errores de transmisin y adems, numera los datos para garantizar que se reciben en el mismo orden con el que fueron transmitidos. Igualmente, elimina los datos que por algn motivo aparecen repetidos, realiza un control de flujo para evitar que el emisor enve ms rpido de lo que el receptor puede consumir y, finalmente, informa a las aplicaciones (tanto al cliente como al servidor) si los niveles inferiores de red no pueden entablar la conexin. Por el contrario, UDP (no orientado a conexin) no introduce ningn procedimiento que garantice la seguridad de los datos transmitidos, siendo en este caso responsabilidad de las aplicaciones la realizacin de los procedimientos necesarios para subsanar cualquier tipo de error. En el desarrollo de aplicaciones sobre TCP/IP es imprescindible conocer como stas pueden intercambiar informacin con los niveles inferiores, es decir, conocer la interfaz con los protocolos TCP o UDP. Esta interfaz es bastante parecida al procedimiento de entrada/salida ordinario en el sistema operativo UNIX que, como se sabe, est basado en la secuencia abrir-leer/escribir-cerrar. En particular, la interfaz se basa en la definicin de un elemento abstracto denominado socket concepto muy similar a los descriptores de archivos usados en las operaciones convencionales de entrada-salida en UNIX. Recurdese que en las operaciones entrada/salida es necesario realizar la apertura del archivo antes de que la aplicacin pueda acceder a dicho archivo a travs del ente abstracto descriptor de archivo. En la interaccin de las aplicaciones con los protocolos TCP o UDP, es necesario que stas obtengan antes el descriptor o socket, y a partir de ese momento dichas aplicaciones intercambiarn informacin con el nivel inferior a travs del socket creado. Una vez creados, los sockets pueden ser usados por el servidor para esperar indefinidamente el establecimiento de una conexin (sockets pasivos) o, por el contrario, pueden ser usados por el cliente para iniciar la conexin (socket activos).

Todos los elementos necesarios para llevar a cabo comunicaciones utilizando los sockets de lenguajes Java se encuentran definidos en el paquete java.net. A continuacin revisaremos las clases contenidas en este y los conocimientos de programacin necesarios para la comunicacin en red.

2.1.1. La clase InetAddress Cualquier mquina conectada a Internet, lo que se conoce tambin como host, ha de tener una direccin de 32 bits, denominada direccin IP, que la identifica de forma nica, salvo ocasionales conflictos transitorios de direcciones. Por otra parte, dentro de un mismo host puede haber diferentes procesos comunicndose de manera independiente con otros procesos de otras mquinas, o incluso con diferentes threads (hilos) dentro de un mismo proceso en otra mquina. Por ejemplo, es frecuente que una computadora tenga establecidas simultneamente varias sesiones FTP con distintos servidores, y a la vez ste recibiendo correo mediante SMTP y leyendo news TNP. Lo que se hace para poner de acuerdo a las distintas entidades que se van a comunicar y repartir la informacin entre ellas es asignar a cada servicio un identificador, tambin de 32 bits, denominado nmero de puerto (port number), De esta forma, una conexin queda completamente especificada por los nmeros de puerto que emplean los interlocutores y las direcciones IP de las mquinas en que residen. Como alternativa a las direcciones IP, existen unos identificadores simblicos para las mquinas, basados en el servicio de nombre de dominio. De esta forma, podemos emplear nombre como xamanek.uam.mx o www.iztapalapa.uam.mx en vez de las direcciones IP de estos servidores. La clase InetAddress permite encapsular una direccin IP y su nombre de servidor correspondiente, de un modo que facilita su uso. Esta clase no tiene constructores accesibles para el cdigo de usuario, sino que para instanciarla hay que invocar a unos mtodos estticos especiales, denominados mtodos fbrica (factory methods). Existen tres de estos mtodos: getLocalHost(): devuelve un objeto InetAddress conteniendo la direccin de la mquina sobre la que se est ejecutando el programa. getByName(String nombre): devuelve un objeto InetAddress con la direccin de la mquina cuyo nombre se le pasa como parmetro. Si no se encuentra ninguna mquina con ese nombre, se produce una excepcin de tipo UnKnowHostException. getAllByNAme(String Nombre): devuelve un arreglo de objetos InetAddress conteniendo las direcciones de todas las mquinas que tienen el nombre pasado como parmetro. Si no se encuentra ninguna se produce una excepcin de tipo UNKnownHostException.

Adems de los mtodos fbrica que sirven para instanciar la clase, existen algunos mtodos normales (de instancia): getHostName(): devuelve un String que contiene el nombre de las mquina a la que corresponde la direccin. getAddress(): devuelve un arreglo de 4 bytes con la direccin IP. topString(): devuelve un String con el nombre y la direccin IP.

2.1.2. Sockets del lado del cliente El mecanismo de sockets se emplea para establecer una comunicacin bidireccional fiable entre dos procesos. Estos procesos pueden residir en la misma mquina o en mquinas diferentes conectadas en red. La creacin de un objeto de tipo Socket tambin establece la conexin. Se pueden utilizar los siguientes constructores: Socket(String host, int port): crea un socket que enlaza el host local con el host y el puerto especificados. Puede producir las excepciones UnkownHostException e IOException. Socket(InetAddress direccin, int port): anlogo al anterior, slo que en este caso el host se especifica pasando un objeto InetAddress. En caso de haber problemas se producir una excepcin de tipo IOException. Se pueden conocer en cualquier momento los atributos de un objeto de tipo Socket mediante los siguientes mtodos: getInetAddress(): devuelve un objeto InetAddress con la direccin del host remoto al que est conectado el socket. getPort(): devuelve el nmero de puerto al que est conectado el socket en el host remoto. getLocalPort(): devuelve el nmero del puerto local al que est conectado el socket. Una vez creado un socket, el envo y recepcin de datos a travs del mismo son exactamente iguales que la escritura y la lectura de los datos de un archivo. Para obtener y cerrar los streams de entrada y salida asociados al socket, se invocan los siguientes mtodos: getInputStream(): devuelve el objeto de tipo InputStream asociado con el socket. getOutputStream(): devuelve el objeto de tipo OutputStream asociado con el socket. close(): cierra tanto el stream de entrada como el de salida.

Con los streams obtenidos se pueden efectuar las operaciones que ya vimos en la seccin anterior. Si se produce algn problema durante las transmisin o la recepcin, como puede ser una prdida de conexin, se generar una excepcin IOException.

2.1.3. Sockets del lado del servidor Si se desea que un programa acte como servidor, es necesario algn mecanismo que permita esperar a recibir conexiones por tiempo indefinido. El hilo principal del servidor puede estar permanentemente en un bucle, dentro del cual se queda bloqueado esperando a que una mquina remota establezca una conexin con l. En el momento en que comienza a existir dicha conexin, el servidor queda desbloqueado y crea un hilo hijo que atiende al socket establecido con ese cliente concreto. Una vez hecho esto, el hilo principal vuelve a quedar en espera de la siguiente conexin y el hilo hijo atiende a las peticiones del cliente hasta que se cierra el socket que le enlaza con l, momento en el cual se autodestruye. Esta arquitectura permite conseguir de un modo muy sencillo un reparto de carga equitativo entre los clientes que intentan acceder al servicio. Para implementar esta funcionalidad se usa la clase ServerSocket, que admite los siguientes constructores: ServerSocket(int puerto): crea un ServerSocket sobre el puerto especificado. ServerSocket(int puerto, int timeout): crea un ServerSocket sobre el puerto especificado. En caso de que ese puerto est ocupado, espera un tiempo de hasta timeout milisegundos a que quede libre. En caso de no quedar libre en este tiempo, se produce una excepcin. Ambos constructores genera una excepcin IOException en caso de problemas. Para esperar a que un cliente llame y establezca una conexin, se invoca el mtodo accept(). Este mtodo deja bloqueado el thread que lo llama hasta que se produce la conexin. Una vez que sta queda establecida, la llamada a accept() devuelve un objeto de tipo Socket, que se puede usar para la comunicacin de la forma descrita en el apartado anterior.

2.2. Hilos
2.2.1. Programas de flujo nico Un programa de flujo nico o mono-hilado utiliza un nico flujo de control (thread) para controlar su ejecucin. Pues muchos programas no necesitan la potencia o utilidad de mltiples flujos de control. Por ejemplo, en el siguiente cdigo:

10

public class HolaMundo { static public void main( String args[] ) { System.out.println( "Hola Mundo!" ); } } Aqu, cuando se llama a main(), la aplicacin imprime el mensaje y termina. Esto ocurre dentro de un nico hilo de ejecucin (thread). Debido a que la mayor parte de los entornos operativos no solan ofrecer un soporte razonable para mltiples hilos de control, los lenguajes de programacin tradicionales, tales como C++, no incorporaron mecanismos para describir de manera elegante situaciones de este tipo. La sincronizacin entre las mltiples partes de un programa se llevaba a cabo mediante un ciclo infinito. Estos entornos son de tipo sncrono, gestionados por sucesos. Entornos tales como el de Macintosh de Apple, Windows de Microsoft y X11/Motif fueron diseados en torno al modelo de bucle de suceso.

2.2.2 Programas de flujo mltiple En el ejemplo anterior Hola mundo, no se ve el hilo de ejecucin que corre el programa. Sin embargo, Java posibilita la creacin y control de hilos de ejecucin explcitamente. La utilizacin de hilos (threads) en Java, permite una enorme flexibilidad a los programadores a la hora de plantearse el desarrollo de aplicaciones. La simplicidad para crear, configurar y ejecutar hilos, permite que se puedan implementar aplicaciones portables y robustas, lo cual no es posible con otros lenguajes de tercera generacin. Los navegadores utilizan diferentes hilos ejecutndose en paralelo para realizar varias tareas, "aparentemente" concurrentemente. Por ejemplo, en muchas pginas Web, se puede desplazar la pgina e ir leyendo el texto antes de que todas las imgenes estn presentes en la pantalla. En este caso, el navegador est obteniendo las imgenes en un hilo de ejecucin y soportando el desplazamiento de la pgina en otro hilo. Las aplicaciones multihilo utilizan muchos contextos de ejecucin para cumplir su trabajo. Hacen uso del hecho de que muchas tareas contienen subtareas distintas e independientes. Se puede utilizar un hilo de ejecucin para cada subtarea. Mientras que los programas de flujo nico pueden realizar su tarea ejecutando las subtareas secuencialmente, un programa multihilo permite que cada thread comience y termine tan pronto como sea posible. Este comportamiento presenta una mejor respuesta a la entrada en tiempo real. Vamos a modificar el programa de saludo creando tres hilos de ejecucin individuales, que imprimen cada uno de ellos su propio mensaje de saludo, MultiHola.java:

class TestTh extends Thread { private String nombre; private int retardo;

11

// Constructor para almacenar nombre y retardo public TestTh( String s,int d ) { nombre = s; retardo = d; } // El metodo run() es similar al main(), pero para // threads. Cuando run() termina el thread muere public void run() { // Retrasamos la ejecucin el tiempo especificado try { sleep( retardo ); } catch( InterruptedException e ) { ; } // Ahora imprimimos el nombre System.out.println( "Hola Mundo! "+nombre+" "+retardo ); } }

public class MultiHola { public static void main( String args[] ) { TestTh t1,t2,t3; // t1 t2 t3 Creamos los threads = new TestTh( "Thread 1",(int)(Math.random()*2000) ); = new TestTh( "Thread 2",(int)(Math.random()*2000) ); = new TestTh( "Thread 3",(int)(Math.random()*2000) );

// Arrancamos los threads t1.start(); t2.start(); t3.start(); } }

2.2.3. La clase Thread Es la clase que encapsula todo el control necesario sobre los hilos de ejecucin (threads) y para ello se sirve de los mtodos que se exponen en las secciones siguientes.

2.2.3.1 Mtodos de Clase Estos son los mtodos estticos que deben llamarse de manera directa en la clase Thread.

12

currentThread() Este mtodo devuelve el objeto thread que representa al hilo de ejecucin que se est ejecutando actualmente. yield() Este mtodo hace que el intrprete cambie de contexto entre el hilo actual y el siguiente hilo ejecutable disponible. Es una manera de asegurar que los hilos de menor prioridad no sufran inanicin. sleep( long ) El mtodo sleep() provoca que el intrprete ponga al hilo en curso a dormir durante el nmero de milisegundos que se indiquen en el parmetro de invocacin. Una vez transcurridos esos milisegundos, dicho hilo volver a estar disponible para su ejecucin.

2.2.3.2 Mtodos de Instancia Presentamos solo algunos de los mtodos de la clase Thread, los cuales utilizaremos constantemente dada su importancia. start() Este mtodo indica al intrprete de Java que cree un contexto del hilo del sistema y comience a ejecutarlo. A continuacin, el mtodo run() de este hilo ser invocado en el nuevo contexto del hilo. Hay que tener precaucin de no llamar al mtodo start() ms de una vez sobre un hilo determinado. run() El mtodo run() constituye el cuerpo de un hilo en ejecucin. Este es el nico mtodo del interfaz Runnable. Es llamado por el mtodo start() despus de que el hilo apropiado del sistema se haya inicializado. Siempre que el mtodo run() devuelva el control, el hilo actual se detendr. stop() Este mtodo provoca que el hilo se detenga de manera inmediata. A menudo constituye una manera brusca de detener un hilo, especialmente si este mtodo se ejecuta sobre el hilo en curso. En tal caso, la lnea inmediatamente posterior a la llamada al mtodo stop() no llega a ejecutarse jams, pues el contexto del hilo muere antes de que stop() devuelva el control. Una forma ms elegante de detener un hilo es utilizar alguna variable que ocasione que el mtodo run() termine de manera ordenada. En realidad, nunca se debera recurrir al uso de este mtodo. suspend() El mtodo suspend() toma el hilo y provoca que se detenga su ejecucin. Si la ejecucin de un hilo se suspende, puede llamarse a resume() sobre el mismo hilo para lograr que vuelva a ejecutarse.

13

resume() El mtodo resume() se utiliza para revivir un hilo suspendido. No hay garantas de que el hilo comience a ejecutarse inmediatamente, ya que puede haber un hilo de mayor prioridad en ejecucin actualmente, pero resume() ocasiona que el hilo vuelva a ser un candidato a ser ejecutado. setPriority( int ) El mtodo setPriority() asigna al hilo la prioridad indicada por el valor pasado como parmetro. Hay bastantes constantes predefinidas para la prioridad, definidas en la clase Thread, tales como MIN_PRIORITY, NORM_PRIORITY y MAX_PRIORITY, que toman los valores 1, 5 y 10, respectivamente. getPriority() Este mtodo devuelve la prioridad del hilo de ejecucin en curso, comprendido entre uno y diez. setName( String ) Este mtodo permite identificar al hilo con un nombre mnemnico. De esta manera se facilita la depuracin de programas multihilo. Este nombre aparecer en todas las lneas de trazado que se muestran cada vez que el intrprete Java imprime excepciones no capturadas. getName() Este mtodo devuelve el valor actual, de tipo cadena, asignado como nombre al hilo en ejecucin mediante setName(). 2.2.4. Creacin de un Thread Hay dos modos de conseguir hilos de ejecucin (threads) en Java. Una es implementando la interfaz Runnable, la otra es extender la clase Thread. La implementacin de la interfaz Runnable es la forma habitual de crear hilos. Las interfaces proporcionan al programador una forma de agrupar el trabajo, se utilizan para disear los requerimientos comunes. La interfaz define el trabajo y la clase, o clases, que implementan la interfaz para realizar ese trabajo Es importante distinguir las diferencias entre una clase y una interfaz. Primero, una interfaz solamente puede contener mtodos abstractos y/o variables estticas y finales (constantes). Las clases, por otro lado, pueden implementar mtodos y contener variables que no sean constantes. Segundo, una interfaz no puede implementar cualquier mtodo. Una clase que implemente una interfaz debe implementar todos los mtodos definidos en ese interfaz. Una interfaz tiene la posibilidad de poder extenderse de otras interfaces y, al contrario que las clases, puede extenderse de mltiples interfaces. Adems, una interfaz no puede ser instanciada con el operador new; por ejemplo, la siguiente sentencia no est permitida: Runnable a = new Runnable(); // No se permite

14

El primer mtodo de crear un hilo de ejecucin es simplemente extender la clase Thread: class MiThread extends Thread { public void run() { . . . } } El ejemplo anterior crea una nueva clase MiThread que extiende la clase Thread y sobrescribe el mtodo Thread.run() por su propia implementacin. El mtodo run() es donde se realizar todo el trabajo de la clase. Extendiendo la clase Thread, se pueden heredar los mtodos y variables de la clase padre. En este caso, solamente se puede extender o derivar una vez de la clase padre. Esta limitacin de Java puede ser superada a travs de la implementacin de Runnable: public class MiThread implements Runnable { Thread t; public void run() { // Ejecucin del thread una vez creado } } En este caso necesitamos crear una instancia de Thread antes de que el sistema pueda ejecutar el proceso como un hilo. Adems, el mtodo abstracto run() est definido en la interfaz Runnable y tiene que ser implementado. La nica diferencia entre los dos mtodos es que este ltimo es mucho ms flexible. En el ejemplo anterior, todava est la oportunidad de extender la clase MiThread, si fuese necesario. La mayora de las clases creadas que necesiten ejecutarse como un hilo, implementarn el interfaz Runnable, ya que probablemente extendern alguna de su funcionalidad a otras clases. No se debe pensar que la interfaz Runnable est haciendo alguna cosa cuando la tarea se est ejecutando, solamente contiene mtodos abstractos. package java.lang; public interface Runnable { public abstract void run() ; } Como se ve, una interfaz slo proporciona un diseo para las clases que vayan a ser implementadas. En el caso de Runnable, obliga a la definicin del mtodo run(), por lo tanto, la mayor parte del trabajo se hace en la clase Thread. Las siguientes lneas de cdigo explican esto. public class Thread implements Runnable { ... public void run() { if( tarea != null ) tarea.run() ; } } ...
}

15

De este segmento de cdigo se desprende que la clase Thread tambin implemente la interfaz Runnable. tarea.run() se asegura de que la clase con que trabaja (la clase que va a ejecutarse como un hilo) no sea nula y ejecuta el mtodo run() de esa clase. Cuando esto suceda, el mtodo run() de la clase har que corra como un hilo. A continuacin se presenta un ejemplo que implementa la interfaz Runnable para crear un programa multihilo. class javaMultiHilo { static public void main( String args[] ) { Thread hiloA = new Thread( new MiHilo(),"hiloA" ); Thread hiloB = new Thread( new MiHilo(),"hiloB" ); hiloA.start(); hiloB.start(); try { Thread.currentThread().sleep( 1000 ); }catch( InterruptedException e ){} System.out.println( Thread.currentThread() ); hiloA.stop(); hiloB.stop(); } } class NoHaceNada { // Esta clase existe solamente para que sea heredada por la clase // MiHilo, para evitar que esta clase sea capaz de heredar la clase // Thread, y se pueda implementar el interfaz Runnable en su // lugar } class MiHilo extends NoHaceNada implements Runnable { public void run() { // Presenta en pantalla informacin sobre este hilo en particular System.out.println( Thread.currentThread() ); } } Como se puede observar, el programa define una clase MiHilo que extiende a la clase NoHaceNada e implementa el interfaz Runnable. Se redefine el mtodo run() en la clase MiHilo para presentar informacin sobre el hilo. La nica razn de extender la clase NoHaceNada es proporcionar un ejemplo de situacin en que haya que extender alguna otra clase, adems de implementar el interfaz. En el ejemplo javaMultiHilo2.java muestra el mismo programa bsicamente, pero en este caso extendiendo la clase Thread, en lugar de implementar el interfaz Runnable para crear el programa multihilo.

16

class javaMultiHilo2 { static public void main( String args[] ) { Thread hiloA = new Thread( new MiHilo(),"hiloA" ); Thread hiloB = new Thread( new MiHilo(),"hiloB" ); hiloA.start(); hiloB.start(); try { Thread.currentThread().sleep( 1000 ); }catch( InterruptedException e ){} System.out.println( Thread.currentThread() ); hiloA.stop(); hiloB.stop(); } }

class MiHilo extends Thread { public void run() { // Presenta en pantalla informacin sobre este hilo en particular System.out.println( Thread.currentThread() ); } } En ese caso, la nueva clase MiHilo extiende la clase Thread y no implementa el interfaz Runnable directamente (la clase Thread implementa el interfaz Runnable, por lo que indirectamente MiHilo tambin est implementando ese interfaz). El resto del programa es similar al anterior. Y todava se puede presentar un ejemplo ms simple, utilizando un constructor de la clase Thread que no necesita parmetros, tal como se presenta en el ejemplo javaMultiHilo3.java. En los ejemplos anteriores, el constructor utilizado para Thread necesitaba dos parmetros, el primero un objeto de cualquier clase que implemente el interfaz Runnable y el segundo una cadena que indica el nombre del hilo (este nombre es independiente del nombre de la variable que referencia al objeto Thread).

class javaMultiHilo3 { static public void main( String args[] ) { Thread hiloA = new MiHilo(); Thread hiloB = new MiHilo(); hiloA.start(); hiloB.start(); try { Thread.currentThread().sleep( 1000 ); }catch( InterruptedException e ){}

17

System.out.println( Thread.currentThread() ); // Se detiene la ejecucin de los dos hilos hiloA.stop(); hiloB.stop(); } }

class MiHilo extends Thread { public void run() { System.out.println( Thread.currentThread() ); } } Las sentencias en este ejemplo para instanciar objetos Thread, son mucho menos complejas, siendo el programa, en esencia, el mismo de los ejemplos anteriores. 2.2.5. Arranque de un Thread Las aplicaciones ejecutan main() tras arrancar. Esta es la razn de que main() sea el lugar natural para crear y arrancar otros hilos. La lnea de cdigo: t1 = new TestTh( "Thread 1",(int)(Math.random()*2000) ); crea un nuevo hilo de ejecucin. Los dos argumentos representan el nombre del hilo y el tiempo que se desea que espere antes de imprimir el mensaje. Al tener control directo sobre los hilos, hay que arrancarlos explcitamente. En el ejemplo con: t1.start(); start(), en realidad es un mtodo oculto en el hilo de ejecucin que llama a run(). 2.2.6. Manipulacin de un Thread Si todo fue bien en la creacin del hilo, t1 debera contener un thread vlido, que controlaremos en el mtodo run(). Una vez dentro de run(), se pueden comenzar las sentencias de ejecucin como en otros programas. run() sirve como rutina main() para los hilos; cuando run() termina, tambin lo hace el hilo. Todo lo que se quiera que haga el hilo de ejecucin ha de estar dentro de run(), por eso cuando se dice que un mtodo es Runnable, es obligatorio escribir un mtodo run(). En este ejemplo, se intenta inmediatamente esperar durante una cantidad de tiempo aleatoria (pasada a travs del constructor): sleep( retardo );

18

El mtodo sleep() simplemente le dice al hilo de ejecucin que duerma durante los milisegundos especificados. Se debera utilizar sleep() cuando se pretenda retrasar la ejecucin del hilo. sleep() no consume recursos del sistema mientras el hilo duerme. De esta forma otros hilos pueden seguir funcionando. Una vez hecho el retardo, se imprime el mensaje "Hola Mundo!" con el nombre del hilo y el retardo. 2.2.7. Suspensin de un Thread Puede resultar til suspender la ejecucin de un hilo sin marcar un lmite de tiempo. Si, por ejemplo, est construyendo un applet con un hilo de animacin, seguramente se querr permitir al usuario la opcin de detener la animacin hasta que quiera continuar. No se trata de terminar la animacin, sino desactivarla. Para este tipo de control de los hilos de ejecucin se puede utilizar el mtodo suspend(). t1.suspend(); Este mtodo no detiene la ejecucin permanentemente. El hilo es suspendido indefinidamente y para volver a activarlo de nuevo se necesita realizar una invocacin al mtodo resume(): t1.resume(); 2.2.8. Parada de un Thread El ltimo elemento de control que se necesita sobre los hilos de ejecucin es el mtodo stop(). Se utiliza para terminar la ejecucin de un hilo: t1.stop(); Esta llamada no destruye el hilo, sino que detiene su ejecucin. La ejecucin no se puede reanudar ya con t1.start(). Cuando se liberen las variables que se usan en el hilo, el objeto Thread (creado con new) quedar marcado para eliminarlo y el garbage collector se encargar de liberar la memoria que utilizaba. En el ejemplo, no se necesita detener explcitamente el hilo de ejecucin. Simplemente se le deja terminar. Los programas ms complejos necesitarn un control sobre cada uno de los hilos que lancen, el mtodo stop() puede utilizarse en esas situaciones. Si se necesita, se puede comprobar si un hilo est vivo o no; considerando vivo un hilo que ha comenzado y no ha sido detenido. t1.isAlive(); Este mtodo devolver true en caso de que el hilo t1 est vivo, es decir, ya se haya llamado a su mtodo run() y no haya sido parado con un stop() ni haya terminado el mtodo run() en su ejecucin. En el ejemplo no hay problemas de realizar una parada incondicional, al estar todos los hilos vivos. Pero si a un hilo de ejecucin, que puede no estar vivo, se le invoca su mtodo stop(), se generar una excepcin. En este caso, en los que el estado del hilo no puede conocerse de antemano es donde se requiere el uso del mtodo isAlive().

19

2.3. APPLETS
2.3.1. Introduccin a los applets Los applets son programas que se incluyen en las pginas Web. Los applets son ejecutados en la mquina cliente, con lo que no existe un exceso de carga del servidor o saturacin del ancho de banda. Permiten cargar a travs de la red una aplicacin portable que se ejecuta en el navegador. Para que esto ocurra tan slo hace falta que el navegador sea capaz de interpretar Java. A las pginas que contienen applets se las denomina pginas Java-Powered. Las applets pueden ser visualizadas con la herramienta appletviewer, incluido en el JDK de Java. Los applets no son exactamente aplicaciones Java, ya que presentan las siguientes diferencias respecto a las aplicaciones normales Java:

Se cargan mediante un navegador, no siendo lanzados por el intrprete Java. Son cargados a travs de la red por medio de pginas HTML y no residen en el disco duro de la mquina que los ejecuta. Poseen un ciclo de vida diferente; mientras que una aplicacin se lanza una vez, un applet se arranca (inicia) cada vez que el usuario recarga la pgina en la que se encuentra dicho applet. Tienen menos derechos que una aplicacin clsica, por razones de seguridad. De modo predeterminado en el puesto que los ejecuta no pueden ni leer ni escribir archivos, ni lanzar programas, ni cargar DLLs. Slo pueden comunicarse con el servidor Web en que se encuentra la pgina Web que las contiene.

2.3.2. Consideraciones sobre la seguridad en los applets Como ya se ha dicho los applets tienen una serie de restricciones de programacin que los hacen "seguros". Estas restricciones de seguridad son especialmente importantes, ya que evitarn que se cargue por error un applet que destruya datos de la mquina, que obtenga informacin restringida, o que produzca otros daos inesperados. Los applets no dejan de ser "ejecutables" que funcionan dentro de una aplicacin, como puede ser un visualizador de pginas Web (browser). Este ejecutable puede obtenerse de una red, lo que significa que hay cdigo posiblemente no fiable que se ejecuta dentro de la aplicacin. Java tiene muchas restricciones de seguridad que minimizan el riesgo de la ejecucin de applets, pero estas tambin limitan a los programadores de applets en su capacidad de programacin. El modelo de seguridad para los applets en Java lo trata como cdigo no fiable ejecutndose dentro de un entorno fiable. Por ejemplo, cuando un usuario instala una copia de un navegador Web en una mquina cree que su cdigo ser funcional en el entorno. Normalmente los usuarios tienen cuidado de qu instalan cuando proviene de una red. Un applet, por el contrario, se carga desde la red sin ninguna comprobacin de su fiabilidad. El lenguaje Java y los applets son escritos para que eviten applets no fiables.

20

Estas restricciones son implementadas para verificar que los cdigos de byte de las clases de los applets, no rompen las reglas bsicas del lenguaje ni las restricciones de acceso en tiempo de ejecucin. Slo cuando las mismas son satisfechas se le permite a la applet ejecutar su cdigo. Cuando se ejecuta, se le marca para sealar que se encuentra dentro del intrprete. Esta marca permite a las clases de tiempo de ejecucin determinar cundo a una fraccin del cdigo se le permite invocar a cierto mtodo. Por ejemplo, un applet est restringido en los hosts en los que se puede abrir una conexin de red o en un conjunto de URLs a las que puede acceder. En su conjunto estas restricciones constituyen una poltica de seguridad. En el futuro, Java tendr polticas ms ricas, incluyendo algunas que usen encriptacin y autentificacin para permitir a los applets una mayor capacidad. La actual poltica de seguridad afecta a los recursos que un applet puede usar, cuyos principales puntos son:

Los accesos que pueden realizar los applets a los archivos son restringidos. En particular escribir y/o leer en archivos no ser una capacidad estndar que se pueda realizar en los navegadores que soporten applets de Java. Las conexiones de red sern restringidas a conectar solo con el host del que proviene el applet. Un applet no es capaz de usar ningn mtodo que pueda resultar en una ejecucin arbitraria, cdigo no revisado o ambos. Esto incluye mtodos que ejecuten programas arbitrarios (mtodos nativos) as como la carga de bibliotecas dinmicas.

Se anticipa en cualquier caso que en el futuro los modelos de seguridad permitirn a las applets autentificadas superar estas restricciones.

21

2.3.3. LA CLASE APPLET 2.3.3.1 Situacin de la clase Applet en la API de Java La clase Applet Java, de la cual han de heredar todos los programas Java que vayan a actuar como applets, es la nica clase que contiene el paquete java.applet de la API de Java. Esta clase hereda de Object (como todas las clases Java), pero adems hereda de Component y Container, que son dos clases del paquete grfico AWT. Esto ya perfila las posibilidades grficas de este tipo de aplicaciones Java. 2.3.3.2 Mtodos del ciclo de vida Como ya se ha indicado un applet no tiene un ciclo de vida tan "sencillo" como el de una aplicacin, que simplemente se ejecuta hasta que finaliza su mtodo main(). La siguiente figura representa el ciclo de vida de un applet:

Fig 3.1 Ciclo de vida de un applet Cada crculo representa una fase en el ciclo de vida del applet. Las flechas representan transiciones y el texto representa la accin que causa la transicin. Cada fase est marcada con una invocacin a un mtodo del applet:

void init(); Es invocado cuando se carga el applet. Aqu se suelen introducir las iniciaciones que el applet necesite. void start(); Es invocado cuando el applet, despus de haber sido cargado, ha sido parado (cambio de pgina Web, minimizacin del navegador,...), y de nuevo activado (vuelta a la pgina, restauracin del navegador,...). Se informa al applet que tiene que empezar su funcionamiento. void stop(); Es invocado para informar al applet que debe detener su ejecucin. As un applet que utilice threads, debera detenerlos en el cdigo de este mtodo. void destroy(); Es invocado para informar al applet que su espacio est siendo solicitado por el sistema, es decir el usuario abandona el navegador. El applet debe aprovechar este momento para liberar o destruir los recursos que est utilizando. void paint(); Es invocado cada vez que hay que el navegador redibuja el applet.

22

Al crear un applet no es necesario implementar todos estos mtodos. Cuando un navegador carga una pgina Web que contiene un applet, suele mostrar en su parte inferior un mensaje como: initializing... starting... Esto indica que el applet, se est cargando: 1. Una instancia de la clase applet es creada. 2. El applet es iniciado, mediante su mtodo init(). 3. El applet empieza a ejecutarse, mediante su mtodo start(). Cuando el usuario se encuentra con una pgina Web, que contiene un applet y salta a otra pgina, entonces el applet se detiene invocando a su mtodo stop(). Si el usuario retorna a la pgina donde reside el applet, ste vuelve a ejecutarse nuevamente invocando a su mtodo start(). Cuando el usuario sale del navegador el applet tiene un tiempo para finalizar su ejecucin y hacer una limpieza final, mediante el mtodo destroy(). 2.3.3.3 La clase URL Una URL (Uniform Resource Locator) es una direccin de Internet. Cada recurso (archivo, pgina Web, imagen...) tiene uno propio. En Java existe una clase denominada URL que modela esta clase de objetos. La clase URL pertenece al paquete java.net, y tiene una cierta importancia en el desarrollo de los applets, puesto que muchos de los mtodos de la clase Applet la utilizan para acceder a determinado recurso de Internet o para identificarse. Podemos especificar un URL de manera absoluta:

URL URLabsoluto = new URL("http://www.host.com/dir/fich.htm");


O bien podemos especificar un URL de manera relativa:

URL URLhost = new URL("http://www.Javasoft.com/"); URL URLrelativo = new URL( URLhost, "dir/fich.htm");
Ambos ejemplos corresponderan al URL "http://www.host.com/dir/fich.htm".

23

2.3.3.4 Inclusin de un applet en una pgina Web Para incluir un applet en una pgina Web, una vez compilado el applet, debe incluirse entre el cdigo HTML de la pgina Web una etiqueta <APPLET>, e indispensablemente los siguientes tres parmetros: code: Especifica el URL del archivo de clase Java (*.class) que contiene el applet. width: Especifica la anchura inicial del applet (en pixels). heigth: Especifica la altura inicial del applet (en pixels). Adems, de la etiqueta inicial, un applet puede tener parmetros que se especificarn mediante etiquetas <PARAM>, y bsicamente contener dos parmetros: name: Indica el nombre del parmetro del applet al que esta etiqueta hace referencia. value: Establece este valor al parmetro indicado en name de la misma etiqueta. As un ejemplo de esto sera:
<applet code="AppletDiagonal.class" width=200 height=200> <param name=Parametro1 value=Valor1> <param name=Parametro2 value=Valor2> </applet>

En este ejemplo el applet puede entender los parmetros Parametro1 y Parametro2, mediante los mtodos que se describen posteriormente, y se obtendra Valor1 y Valor2 respectivamente. Se observa que adems de la etiqueta <applet> en el cdigo HTML tambin aparece una etiqueta </applet>. Esto sucede porque HTML es un lenguaje, en el que casi todas las etiquetas de inicio de elemento (<etiq>) tienen una etiqueta de fin (</etiq>).

2.3.3.5 Obtencin de los parmetros de un applet Cuando se incluye un applet en una pgina Web se utiliza la etiqueta HTML <applet>. Las etiquetas HTML permiten utilizar parmetros, y la etiqueta <applet> hace lo propio, permitiendo al applet recibir parmetros de ejecucin, tal y como una aplicacin los recibe en el parmetro s (un vector de cadenas) de su mtodo main(String[] s). Los siguientes mtodos se utilizan para extraer informacin de los parmetros que recibi el applet cuando fue llamado mediante cdigo HTML:

URL getDocumentBase(); Devuelve el URL del documento que contiene el applet. URL getCodeBase(); Devuelve el URL del applet. String getParameter(String name); Devuelve el valor de un parmetro (etiquetas <param>) que aparece en el documento HTML.

Tenemos la llamada a un applet, con el siguiente cdigo HTML:

24

<applet code="AppletParam.class" width=50 height=50> <param name=Color value="red"> </applet>

Una llamada en este applet al mtodo getParameter("Color") devolver "red". 2.3.3.6 Obtencin de informacin sobre un applet Algunos mtodos se utilizan para comunicar informacin o mostrar mensajes en la pantalla referentes al applet:

boolean isActive(); Comprueba si el applet est activo. void showStatus(String status); Muestra una cadena del estado en la pantalla. String getAppletInfo(); Devuelve informacin relativa al applet como el autor, Copyright o versin. String[ ][ ] getParameterInfo(); Devuelve un vector que describe algn parmetro especfico del applet. Cada elemento en el vector es un vector de tres cadenas que tienen la forma: {nombre, tipo, comentario}.

Un ejemplo de como definir este mtodo para un applet que permita un solo parmetro, color, sera:
public String[][] getParameterInfo() { String info[][] = { {"Color","String","foreground color"} }; return info; }

2.3.3.7 Manipulacin del entorno de un applet Algunos applets pueden afectar al entorno en que estn ejecutndose. Para ello se utilizan los mtodos:

AppletContext getAppletContext(); Devuelve un AppletContext, que permite al applet afectar a su entorno de ejecucin. void resize( int ancho, int largo); Solicita que se modifique el tamao del applet. Tambin permite recibir un nico parmetro Dimension. Locale getLocale(); Devuelve el valor Locale del applet si este fue establecido. void setStub( AppletStub s ); Establece el stub de este applet.

2.3.3.8 Soporte multimedia La clase Applet tambin incluye mtodos para trabajar con imgenes y archivos de sonido de Internet mediante la utilizacin de URLs. Para ello implementa los mtodos:

Image getImage(URL u, String s); Obtiene una imagen de un URL u que ser absoluto si no se especifica una ruta relativa s. AudioClip getAudioClip(URL u, String s); Obtiene un clip de sonido de un URL u que ser absoluto si no se especifica una ruta relativa s.

25

void play(URL ur1, String name); Ejecuta directamente un archivo de sonido de un URL u que ser absoluto si no se especifica una ruta relativa s. static audioClip newAudioClip(URL u); Obtiene un nuevo archivo de sonido del URL u.

Mediante el uso adecuado de varios de estos mtodos se pueden combinar sonidos e imgenes para conseguir efectos espectaculares.

2.4. EJEMPLO DE CONSTRUCCIN DE UN APPLET 2.4.1 Cdigo Para crear un applet normalmente ser necesario importar al menos las bibliotecas java.awt.* y java.applet.*. La clase que represente al applet se debe declarar como una subclase de la clase Applet, para poder sobrescribir los mtodos de la clase Applet. Siempre conviene sobrescribir al menos el mtodo paint() que ser llamado por los navegadores que soporten applets para mostrarles por pantalla. Vamos a construir un applet denominada AppletDiagonal que simplemente dibuje una lnea diagonal. Un posible cdigo sera:
import java.awt.*; import java.applet.*; public class AppletDiagonal extends Applet { public void paint(Graphics g) { g.setColor( Color.red ); g.drawLine(0, 0, getWidth(), getHeight() ); } }

A continuacin se describe el funcionamiento de este cdigo: 1. El mtodo paint() recibe un objeto de la clase Graphics. La clase Graphics, incluida en el paquete AWT, contiene mtodos para mostrar varios tipos de grficos. 2. Mediante el mtodo setColor() de la clase Graphics se establece el color de primer plano a rojo, que es uno de los colores predefinidos de la clase Color. 3. Por ltimo, mediante drawLine() se dibuja una lnea dadas las coordenadas de su esquina superior izquierda y de la inferior derecha. En este caso se indican la esquina superior izquierda del applet mediante las coordenadas (0,0), y la esquina inferior derecha se obtiene mediante dos mtodos de la clase Dimension (getWidth(), getHeight() ). 2.4.2 Ejecucin Para ejecutar el applet, una vez compilado el archivo, se introduce la llamada al applet en una pgina Web (por ejemplo AppletDiagonal.htm), introduciendo entre su cdigo HTML lo siguiente:

26

<applet code="AppletDiagonal.class" width=200 height=200> </applet>

Cuando se cargue esta pgina Web en un navegador compatible con Java o mediante el visualizador de applets (appletviewer) se ver algo como:

Fig. 4.1: Applet "Lnea" Se podra dibujar un rectngulo con cambiar la lnea de cdigo de drawLine() por otra que llamase al mtodo drawRect():
g.drawRect(10, 10, r.width 20, r.height 20);

2.4.3 Creacin de una aplicacin que utilice un applet (AWT)


A continuacin usaremos AWT para crear una aplicacin que de un resultado igual que la ejecucin del "applet Lnea". Ser una aplicacin que crear un Frame de AWT para incluir el applet que ya fue creado. El main() de la aplicacin slo crear un objeto de este tipo (indicndole altura y anchura, como hacamos en el applet mediante los parmetros de la etiqueta HTML). El cdigo fuente de la aplicacin sera el siguiente:
import java.awt.*; import java.awt.event.*; class FrameLinea extends Frame { private AppletDiagonal unApplet; // Se mostrar public static void main( String[] s ) { new FrameLinea( 200, 230 ); }

27

public FrameLinea( int ancho, int largo ) { super(); // Constructor de Component // Se aade un oyente que cerrara la aplicacin addWindowListener( new OyenteLinea() ); // Se crea una applet de diagonal unApplet=new AppletDiagonal(); unApplet.init(); unApplet.start(); // Se mete la applet en frame add( unApplet ); setSize(ancho,largo); // ajusta frame setVisible(true); // muestra frame } // Clase anidada class OyenteLinea extends WindowAdapter { // Sobreescribo el mtodo de "cuando se cierra ventana" public void windowClosing(WindowEvent e) { unApplet.stop(); unApplet.destroy(); System.exit(0); } } }

Se crea un Frame en el que se incluye el applet unApplet que ser de la clase AppletDiagonal, creado anteriormente. Lo que hace la aplicacin es crear un oyente de la clase OyenteLinea, que ser el encargado de capturar el evento de cerrar la ventana del Frame. En el constructor se inicia el applet (init() y start()) y se aade al Frame mediante el mtodo add() de la clase Container (Frame es hija de Container). Por ltimo se establece el tamao del Frame (recibido por parmetro) mediante setSize() y por ltimo se muestra el Frame que ya tiene en su interior el applet (setVisible()). Cuando se cierra la ventana, el OyenteLinea se encarga de cerrar el applet, mediante stop() y destroy(), y de finalizar la aplicacin mediante System.exit().

2.4.4 Creacin de una aplicacin que utilice el applet (Swing) Esta misma aplicacin se puede crear utilizando Swing con solo cambiar las siguientes cosas: 1. Se debe incluir la biblioteca de Swing:
import javax.swing.*;

2. Se deben cambiar los nombres de la clase Frame de AWT por la clase JFrame de Swing.

28

3. Se crea un contentPane mediante un objeto JPanel, justo antes de llamar al oyente:


setContentPane( new JPanel() );

4. Para aadir el applet se debe agregar al contentPane:


getContentPane().add( unaApplet );

2.5. Programacin del Puerto Paralelo


El puerto paralelo se apega al estndar IEEE 1284 liberado en 1994 y que define 4 modos de operacin soportados an en la actualidad: 1. Puerto Paralelo Estndar (SPP) 2. Puerto Paralelo PS/2 (Bidireccional) 3. Puerto Paralelo Mejorado (EPP) 4. Puerto Paralelo con Capacidades Extendidas (ECP). La mayora de las computadoras personales recientes, tanto de escritorio como porttiles, presentan por omisin una configuracin del puerto paralelo en dos direcciones de datos (bidireccional) para cualquier sistema operativo. Los sistemas operativos menos recientes, hablando de Windows 98 y anteriores, tambin son capaces de soportar este tipo de esquema para recibir y enviar datos por el puerto de impresin, siempre y cuando se configure manualmente dicha caracterstica, preferentemente desde el SETUP. En esta seccin se discutir el modo de operacin bidireccional. Para el anlisis mostrado se consideran dos vertientes: la programacin del puerto bajo el modo MS DOS (Microsoft Disk Operating System Sistema Operativo en Disco), y como segunda derivacin, la programacin en Modo Windows. En ambos casos se revisan interfaces unidireccionales y bidireccionales. 2.5.1 Programacin del Puerto Paralelo en Modo MS - DOS. El modo MS- DOS es vlido en Windows 98 y versiones anteriores (Windows 95, Windows 3.1, etc.). En esta condicin es posible escribir directamente a los registros del puerto. 2.5.1.1 Puerto Paralelo Unidireccional. Considerando el modo de una sola direccin, comnmente llamado Puerto Paralelo Estndar (SPP), existen tres direcciones consecutivas asociadas con un puerto paralelo; estas direcciones pertenecen al registro de datos (Data Register), el registro de estado (Status Register) y el registro de control (Control Register). Se le denomina direccin base a la que indica la propia del registro de datos, por lo general 0x378; as se tendra para el registro de estado la direccin inmediata siguiente 0x379 y para el registro de control la direccin 0x37A Existen alternativas diferentes para encontrar la direccin de los puertos, debido a que puede cambiar dependiendo de la arquitectura y organizacin interna de la PC. Es posible acceder directamente al panel de control de Windows y verificar el sistema; dentro de los recursos hardware se encuentra el administrador de dispositivos. El puerto paralelo se utiliza para la conexin de impresoras, por lo que aparecen etiquetados como LPT1, LPT2, LPT3 LPT4, segn las caractersticas de la PC.

29

Es importante recordar que en el modo estndar, el puerto de datos slo es de salida, de ah que se le conozca como unidireccional, y es de 8 bits. El puerto de estado es de slo entrada con 5 bits referidos en el conector y el propio de control tiene 4 bits de slo salida. En resumen, tenemos que en las porttiles, se tiende a encaminar todos los perifricos hacia USB, eliminando en algunos casos el puerto paralelo y el puerto de juegos; as como la unidad de disco flexible, obligando a que sta sea externa, o bien, utilizar la alternativa del Disco Compacto de este modo se tienen 12 lneas de salida (de las cuales, 3 son de tipo activa bajo) y slo 5 de entrada (con una sola lnea de tipo activo bajo), tal y como se aprecia en la figura 1.a. El puerto paralelo utiliza un conector hembra clase D de 25 pines (DB-25), definido como TIPO A por el estndar IEEE 1284 En las figuras 1.a y 1.b, se aprecia la distribucin fsica de los pines en el conector DB-25. Para fines de anlisis, se considera que los tres registros del puerto son de 8 bits, por lo que se tiene un orden significativo que es necesario respetar cuando se forma una palabra de configuracin, por ejemplo, en el caso del registro de estado, se tiene disponible a partir del bit 4 y hasta el bit 8 (S7, S6, S5, S4, S3), los dems estn comprometidos o reservados para otros propsitos. De acuerdo al diagrama interno aproximado mostrado en la figura 1.b, el bit ms significativo del registro de estado (S7), trabaja con lgica negativa y est fsicamente ubicado en el pin 11 del conector. Si se requiere leer una palabra de entrada a travs de este registro, es importante considerar con qu lgica funciona cada pin.

El registro de control, para fines prcticos en el diseo de interfaces en modo estndar, es slo de salida y utiliza los primeros cuatro bits (C3, C2, C1, C0) del registro, los restantes cuatro estn reservados. En este registro, los bits C3, C1 y C0, trabajan con lgica invertida y estn localizados fsicamente en los pines 17, 14 y 1 del conector. Como ya se coment con anterioridad, los ocho bits del registro de datos se utilizan slo como salidas y todos trabajan con lgica positiva, ubicndose en orden significativo del pin 2 al pin 9 del conector, tal y como se aprecia en la figura 1.a. El siguiente programa escrito en Lenguaje C, muestra de manera sencilla cmo se envan y reciben datos. El circuito secuenciador de la figura 2 se activa con el botn externo conectado al bit 4 del registro de estado (S3), ubicado fsicamente en el pin 15 del conector.

30

/*Se incluyen las bibliotecas generales, No se utilizan todas en este ejemplo*/ #include <stdio.h> #include <stdlib.h> #include <conio.h> #include <dos.h> void main(void) { int entrada; /*Datos de la secuencia, en decimal*/ int leds[9] = {0,1,2,4,8,16,32,64,128}; int i; while(1) { entrada = inportb(0x379); /*Si el bit S3 est en 0, el botn est presionado*/ if (((entrada)&0x08)==0) { for(i = 0; i < 9; i++) { /*Recorre uno a uno los bits de izquierda a derecha*/ outport(0x378,leds[i]); sleep(1); } } else outportb(0x378,0x00); /*Si el botn no es presionado, los LEDs se apagan*/ }
}

Las conexiones bsicas requieren los pines 2, 3, 4, 5, 6, 7, 8 y 9 del conector como D0, D1, D2, D3, D4, D5, D6 Y D7 del registro de datos, por lo que se conectarn leds tal y como lo indica el diagrama siguiente (figura 2). Para la conexin del botn de activacin se utilizar el pin 15 del conector. Se recomienda utilizar una fuente externa de 5 volts y acoplar las tierras.

31

Como ya se indic con anterioridad, este programa slo funciona en modo MS- DOS. Para que funcione tambin sobre sistemas operativos superiores a Windows 98, es necesaria una biblioteca de enlace dinmico (dll) que declare nuevas funciones para acceder al puerto paralelo, esta cuestin se detallar ms tarde en este mismo documento. 2.5.1.2 Puerto Paralelo Bidireccional. En algunas aplicaciones prcticas se requieren ms lneas de entrada que las disponibles en el puerto de estado; por ejemplo, leer los 8 bits de un convertidor analgico digital paralelo o interactuar con una pantalla de LCD. Dado que las entradas del puerto de estado estn restringidas a slo 5 bits, es necesario adecuar el programa escrito hacia una lgica de multiplexaje que lea un dato de 4 bits, se almacene en una localidad de memoria y despus de un tiempo se lea la otra parte del dato, pensando en una entrada de 8 bits ms. Es admisible configurar el puerto de datos para que sus ocho pines puedan ser tambin entradas. Esto se logra accediendo al puerto de control y cambiando el bit nmero 6 del registro de un estado natural bajo a un estado alto. Cuando C5 est a 0 lgico, las 8 lneas del puerto de datos son salidas y cuando C5 est a 1 lgico, se comportan como entradas. La figura 3, muestra la disposicin fsica de los pines del registro del puerto de control. Considerando una direccin base 378H para el puerto de datos, se lista el siguiente fragmento en Lenguaje C para explicar de manera ms concreta la idea anterior. { unsigned int Valor, temp; outportb(0x37A, 0x20); Valor=inport(0x378); printf ("Valor Ledo: %u \n", Valor); getch(); } Obsrvese que en la primera instruccin outportb(0x37A, 0x20) se escribe al puerto de control con la direccin 0x37A un valor hexadecimal 0x20, traducido a binario de 8 bits como 00100000, especificando que el bit nmero 6 se establece a un nivel lgico alto por lo que el puerto de datos (0x378) est configurado como entrada. En la siguiente instruccin Valor=inport(0x378) se leen las 8 lneas de datos y se asignan a una variable sin signo previamente definida. Como ejemplo prctico, se considera un ADC0804 supervisado a travs del puerto paralelo en modo bidireccional, como lo expone el diagrama de la figura 4. En este caso no se expone a detalle el funcionamiento del convertidor por lo que se recomienda consultar la hoja de especificaciones del dispositivo. Para este diseo en particular, la entrada analgica a convertir proviene directamente de una resistencia variable; sin embargo, sta se puede sustituir (con las adecuaciones necesarias) por algn sensor, por ejemplo, un dispositivo LM35 para concebir un termmetro digital.

32

Para las seales de control WR y RD, se consideran los bits 2 y 0, respectivamente del puerto de control (0x37A). Como ya se mencion, C5 es el bit que permite configurar el puerto de datos como entrada o como salida, por lo que no tiene un pin exterior. En el programa en Lenguaje C listado a continuacin, se decidi utilizar C2 para Write y C0 para Read del ADC. Fsicamente, y con referencia a la figura 3, C2 est asignado al pin 16 del conector y C0 al pin 1 del mismo. Ntese que el hardware interno del puerto de control especifica que el pin 1 del conector tiene lgica negativa, por lo que se debe considerar este aspecto en el momento de generar las seales de escritura y lectura. Para leer el bit correspondiente a la seal INTR que indica el fin de la conversin del ADC, se utiliza el bit S3 del puerto de estado (0x379), ubicado en el pin 15 del conector. Para capturar un dato convertido, se predispone utilizar los 8 bits del puerto de datos (0x378) conectados de manera tradicional del menos significativo al ms significativo; en otras palabras, DB0 corresponder al D0 del puerto (pin 2), DB1 a D1 (pin 3) y as, sucesivamente, hasta DB7 que corresponder a D7 (pin 9). Al principio del programa listado se solicita el nmero de muestras a convertir (cuntas veces se repetir el programa). Es una manera sencilla de terminar el programa despus de n lecturas. Tambin es posible asignar una tecla para salir. Se recomiendan pocas muestras cuando el delay es de un valor alto. /* ADC0804 por el puerto paralelo 8-bits utilizando modo bidireccional (ECP).*/ #include <stdio.h> #include <dos.h> main() { unsigned int pdatos, pestado, pcontrol, temp, dato_leido; int contador, muestra; pdatos=0x378; pestado=pdatos+1; pcontrol=pdatos+2;

33

/*permite restaurar el valor original del puerto*/ temp=inportb(pcontrol); clrscr(); /* "muestra" indica el nmero de lecturas que deseas realizar*/ for (muestra=0; muestra<50; muestra++) { /* Comienza la conversin poniendo en bajo "write" y manteniendo C5 en alto para la bidireccionalidad. Posteriormente pondremos en alto "write" para eshabilitarlo; as se genera el pulso negativo para accionar "write"*/ outportb(pcontrol, 0x20); delay(10000); outportb(pcontrol, 0x24); /* Espera hasta que la conversin haya concluido recibiendo el bit INTR proveniente del ADC*/ /* "contador" permite terminar el programa despus de 256 ciclos si no se ha conectado el ADC al puerto*/ contador=0; do { contador++; } while (((inportb(pestado) & 0x08)==0) && (contador!=256)); if (contador==256) printf ("No hay convertidor!!!\n"); else { delay(10000); /*Es posible omitir el retardo*/ outportb(pcontrol, 0x25); delay(10000); dato_leido=inportb(pdatos); outportb(pcontrol, 0x24); clrscr(); printf ("ADC value:%i",dato_leido); /* nicamente espera por una tecla, una vez que concluy el programa*/ getch(); } } /*restaura puerto de control a su valor original*/ outportb(pcontrol, temp); return 0; } De igual forma que en el modo unidireccional, este cdigo funciona correctamente slo en modo MS-DOS. 2.5.2. Programacin del Puerto Paralelo en Modo Windows Windows NT, 2000 y XP no permiten manejar el puerto paralelo en modo MS-DOS, como suceda con las versiones anteriores de este mismo sistema operativo. Para solucionar este inconveniente, dando acceso a puerto en cualquier versin de Windows (en modo Windows) se requieren bibliotecas de enlace dinmico (dll) que se compilan en algn lenguaje de alto nivel que las soporte y stas gestionan ante el sistema operativo el manejo del puerto.

34

Una biblioteca dll se disea, por lo general, en C++ y se utiliza en lenguajes de alto nivel como el mismo C++, Delphi o Java, entre otros. A continuacin tenemos el empleo de un archivo dll para crear interfaces en Visual Basic 6.0. Ninguno de los compiladores para Windows ha incluido un componente para el manejo de puertos en forma general slo para comunicaciones e impresin. La ventaja que tiene Visual. Basic sobre otros lenguajes es la facilidad de su entorno. La biblioteca io.dll se descarga gratuitamente de http://www.geekhideout.com y se copia al directorio ubicado en C:/Windows/System32/. En Internet existen disponibles otras bibliotecas similares; la que aqu se indica se ha probado con xito en todos los diseos presentados en esta seccin. El siguiente paso consiste en crear un proyecto estndar en Visual Basic y adicionar un mdulo que incluya los prototipos de la dll para Visual Basic, listados en la misma pgina web de donde se descarg la dll (referirse a la Tabla 1). Tabla 1. Prototipos de io.dll a escribirse en un mdulo de Visual Basic.
Public Declare Sub PortOut Lib "IO.DLL" (ByVal Port As Integer, ByVal Data As Byte) Public Declare Sub PortWordOut Lib "IO.DLL" (ByVal Port As Integer, ByVal Data As Integer) Public Declare Sub PortDWordOut Lib "IO.DLL" (ByVal Port As Integer, ByVal Data As Long) Public Declare Function PortIn Lib "IO.DLL" (ByVal Port As Integer) As Byte Public Declare Function PortWordIn Lib "IO.DLL" (ByVal Port As Integer) As Integer Public Declare Function PortDWordIn Lib "IO.DLL" (ByVal Port As Integer) As Long Public Declare Sub SetPortBit Lib "IO.DLL" (ByVal Port As Integer, ByVal Bit As Byte) Public Declare Sub ClrPortBit Lib "IO.DLL" (ByVal Port As Integer, ByVal Bit As Byte) Public Declare Sub NotPortBit Lib "IO.DLL" (ByVal Port As Integer, ByVal Bit As Byte) Public Declare Function GetPortBit Lib "IO.DLL" (ByVal Port As Integer, ByVal Bit As Byte) As Boolean Public Declare Function RightPortShift Lib "IO.DLL" (ByVal Port As Integer, ByVal Val As Boolean) As Boolean Public Declare Function LeftPortShift Lib "IO.DLL" (ByVal Port As Integer, ByVal Val As Boolean) As Boolean Public Declare Function IsDriverInstalled Lib "IO.DLL" () As Boolean

Lo anterior se logra activando la opcin del men Proyecto y seleccionando Adicionar Mdulo. En el espacio de edicin del mismo mdulo se escriben los prototipos de la Tabla 1. Para salvar el proyecto completo se requiere nombrar primeramente la Forma, despus el Proyecto y finalmente el Mdulo. Obsrvese la pantalla de la figura 1. Bsicamente y en correspondencia con los prototipos del dll, se tienen 13 funciones para manejo del puerto paralelo, nos enfocaremos slo a cuatro: PortOut, PortIn, SetPortBit y ClrPortBit. Las dos primeras permiten enviar y recibir respectivamente un byte por puerto indicado. SetPortBit y ClrPortBit, manipulan slo un bit del registro implicado, ya sea para establecerlo o para limpiarlo.

35

Figura 5. Pantalla de diseo en Visual Basic 6.0, adicionando un mdulo.

2.5.2.1. Programacin Unidireccional en Visual Basic Considerando el mismo ejemplo en modo estndar propuesto por el diagrama de la figura 2; en Visual Basic no se cuentan con las instrucciones Sleep ni Delay, propias de C, por lo que para temporizar se requiere un Timer sincronizado en milisegundos. La pantalla mostrada en la figura 6, es la que se utiliz para concretar el secuenciador de ejemplo. Una vez creado el proyecto, y despus de haber adicionado el mdulo de declaraciones de la dll, se procede a colocar una caja de texto (TextBox) que por omisin llevar el nombre Text1. Despus se colocar debajo de la caja una etiqueta (Label) que por default est referida como Label1. Dentro de las propiedades de este objeto se debe buscar la que se refiere a Caption (Texto de etiqueta) y escribir Valor enviado al puerto. Se coloca un botn de accin (CommandBotton) que por omisin se llamar Command1. Dentro de sus propiedades, y en Caption, se escribe Inicio. Por ltimo, se inserta un Timer, con el nombre Timer1. Este objeto slo se visualiza en tiempo de diseo, es decir, en la aplicacin ejecutable no se ver.

Figura 6. Pantalla en tiempo de diseo para el secuenciador.

36

En el editor de la forma (View Code) se copia el cdigo siguiente y se presiona el botn Run para ejecutar la aplicacin.
Option Explicit 'Programa que enva y recibe datos del puerto Dim i As Integer 'paralelo de la PC. Se utiliza io.dll. Dim ValorIn As Byte Dim Compara As Byte Private Sub Form_Load() 'no hagas nada, cuando se abra la aplicacin End Sub Private Sub Command1_Click() 'Cuando se presione el botn "Inicia" While (1) 'se valida el comienzo del programita Comienza Wend End Sub Sub Comienza() ValorIn = PortIn(&H379) 'Lee puerto de datos Compara = ValorIn And &H8 'Comprobamos que s3 est a cero (Botn presionado) If Compara = 0 Then escribe_pto 'Rutina del secuenciador Else Text1.Text = "Presiona el botn" 'No est presionado el botn End If End Sub Sub escribe_pto() PortOut &H378, 0 For i = 0 To 7 'Inicia ciclo para establecer (poner a 1) el bit Espera 0.5 'correspondiente SetPortBit &H378, i Text1.Text = 2 ^ i Next i End Sub Sub Espera(t As Double) 'Rutina de tiempo Timer1.Interval = t * 1000 'Milisegundos Timer1.Enabled = True 'Habilitamos timer Do While Timer1.Enabled DoEvents Loop End Sub Private Sub Timer1_Timer() 'Habilitacin del timer1, relacionada Timer1.Enabled = False 'con la rutina Espera End Sub Private Sub Form_OKClick() 'Salir de la aplicacin App.End End Sub

El siguiente cdigo, diseado para una interfaz en modo unidireccional, permite enviar un dato escrito en la caja de texto correspondiente a Enviar dato directamente al puerto de datos (0x378). Tambin es posible leer un dato del puerto de estado (0x379) en la caja de texto correspondiente a Leer dato. La pantalla en tiempo de diseo se muestra en la figura 7.

37

Option Explicit 'Programa que enva y recibe datos del puerto Private Sub Form_Load() 'Condiciones al momento de abrir la aplicacin PortOut &H378, 0 'Limpia el puerto de datos End Sub Private Sub Command1_Click() 'Al hacer click en el botn Command1 ("Enva") Dim dato_out As Variant 'Dato a escribir en la caja de texto en decimal dato_out = datoout.Text PortOut &H378, dato_out 'Limpia puerto End Sub Private Sub Command2_Click() 'Al hacer click en el botn Command2 ("Lee Puerto") Dim ValorIn As Byte 'El resultado se asignar a la variable ValorIn ValorIn = PortIn(&H379) dato_in.Text = ValorIn & " , est en decimal" End Sub Private Sub Form_OKClick() 'Salir de la aplicacin App.End End Sub

Figura 7. Interfaz unidireccional de propsito general.

2.5.2.2 Programacin Bidireccional en Visual Basic Para la programacin bidireccional del puerto de datos se sigue la misma lgica descrita en los programas en Lenguaje C anteriores, es decir, se establece el bit 6 (C5) del puerto de control para que el registro de datos acepte un byte proveniente del exterior y se limpia el mismo bit si se desea que el registro de datos sea slo de salida. Retomando la interfaz para monitorear el ADC0804, algunos autores desestiman utilizar todas las seales del ADC. Con una frecuencia mucho menor que los 8KHz naturales del dispositivo, es posible obtener circuitos ms simples como el denominado Free Running que propone utilizar un inversor hacia RD de la seal WR, obligando a que RD siempre sea el complemento de WR y viceversa (ver figura 8). El inversor se puede implementar dentro de cdigo, y dado que la frecuencia de trabajo para reportar lecturas se considera lenta, es posible omitir la espera de la respuesta de la seal INTR.

38

Se recomienda reestablecer el puerto de control a su estado original, antes de salir de la aplicacin. La preparacin del puerto desde el SETUP es fundamental para que funcione correctamente este programa.

Figura 8. Conexin Free Runnig para el ADC0804.

El siguiente cdigo en Visual Basic muestra la solucin propuesta. Obsrvese que slo se enva la seal de reloj por el puerto de control, a la vez que se reciben de forma paralela los 8 bits del ADC por el puerto de datos de la PC.

Option Explicit 'Programa que recibe datos de un ADC0804 Dim DatoPuerto As Byte 'con conexiones mnimas Free Running Dim Temporal As Byte 'Modo del puerto paralelo: ECP (Bidireccional) Private Sub Form_Load() 'Limpia puerto de datos al cargar la aplicacin PortOut &H378, 0 End Sub Private Sub Command1_Click() 'Con el botn "Inicio" Temporal = PortIn(&H37A) 'Almacena el valor del puerto de control While (1) 'se valida el comienzo de la adquisicin Comienza Wend End Sub Private Sub Command2_Click() 'Botn "Restaurar Puerto" PortOut &H37A, Temporal 'Regresa a la configuracin original pto. de control PortOut &H378, 0 'Limpia nuevamente el puerto de datos; detiene programa End Sub Sub Comienza() PortOut &H37A, &H20 'Configura C5, bidireccional y genera flanco negativo Espera 0.5 'Rutina de espera (1/2 segundo) PortOut &H37A, &H24 'Mantiene bidireccionalidad y genera flanco positivo Espera 0.5 DatoPuerto = PortIn(&H378) 'Lee puerto de datos y escribe equivalente en Volts Text1.Text = DatoPuerto * 0.0196 & " Volts" '255 binario = 5 Volts analgicos End Sub Sub Espera(t As Double) 'Rutina de tiempo Timer1.Interval = t * 1000 'Milisegundos

39

Timer1.Enabled = True 'Habilitamos timer Do While Timer1.Enabled DoEvents Loop End Sub Private Sub Timer1_Timer() 'Habilitacin del timer1, relacionada Timer1.Enabled = False 'con la rutina Espera End Sub Private Sub Form_OKClick() 'Salir de la aplicacin App.End End Sub

Las siguientes figuras, 9a y 9b, muestran de manera respectiva, las pantallas correspondientes al tiempo de diseo y al tiempo de ejecucin de la interfaz en dos direcciones para el ADC0804. Particularmente en 9b se aprecia el resultado arrojado por la aplicacin para un dato de 25510 equivalente a 5 Volts, enviado por el ADC trabajando sobre Windows XP.

2.5.2.3 Programacin del Puerto Paralelo en Java La programacin del puerto paralelo en Java se vuelve muy sencilla una vez que se disponen de clases o paquetes diseados para este fin. Esta es la gran ventaja de la programacin orientada a objetos en la cual, si alguien ya dise una clase que contemple los mtodos para lectura o escritura del puerto paralelo, solo hay que utilizarla creando un objeto de dicha clase. De este modo se cuenta con varias clases de comunicacin con el puerto paralelo, una de ellas es la clase ParallelPort perteneciente al package parport el cual se encuentra fcilmente en la red con el cdigo disponible para las adecuaciones que se crean convenientes si esto es necesario. De modo que solo hay que importar el paquete parport dentro del proyecto y crear un objeto de la clase correspondiente, a travs del cual se puede escribir o leer del puerto paralelo. A continuacin se muestra el cdigo en Java que corresponde a la clase ParralellPort
package parport;

40

public class ParallelPort { /** La direccion base del puerto (e.g. 0x378 es la direccion base para LPT1) */ private int portBase;

/** Para construir un objeto de la clase ParallelPort, * se necesita la direccion base del puerto */ public ParallelPort (int portBase) { this.portBase = portBase; } /** * * * * * * * * * * * * * * * * * * */ Lee un byte de los pines del registro de ESTADO del puerto paralelo. El byte leido contiene 5 bits validos, que corresponden a los 5 bits de entrada del registro de ESTADO del puerto paralelo (El registro de ESTADO se encuentra en "portBase + 1", e.g. la direccion del registro de ESTADO para LPT1 es 0x379). La siguiente tabla muestra el contenido del byte: Bit | Pin # | Estado de impresora | Invertido -----+-------+----------------------+----------7 | ~11 | Busy | Si 6 | 10 | Acknowledge | 5 | 12 | Out of paper | 4 | 13 | Selected | 3 | 15 | I/O error | Note que el Pin 11 esta invertido, esto significa que una entrada "Alto" en el pin es un 0 en el bit 7 y una entrada "Bajo" significa 1 en bit 7

public int read () { return ParallelPort.readOneByte (this.portBase+1); } /** * * * * * * * * * * * * * * * * */ Escribe un byte al registro de DATOS del puerto paralelo. El byte es escrito a los pines de DATOS del puerto. Los pines de datos se localizan en la direccion base del puerto (e.g. La direccion del registro de DATOS para LPT1 es 0x378). La siguiente tabla muestra como es escrito el byte Bit | Pin # | DATOS de impresora -----+-------+-------------7 | 9 | DATA 7 6 | 8 | DATA 6 5 | 7 | DATA 5 4 | 6 | DATA 4 3 | 5 | DATA 3 2 | 4 | DATA 2 1 | 3 | DATA 1 0 | 2 | DATA 0

public void write (int oneByte) { ParallelPort.writeOneByte (this.portBase, oneByte); }

41

/** Lee un byte de la direccion especificada. * (normalmente la direccion es el registro de ESTADO del puerto) */ public static native int readOneByte (int address); /** Escribe un byte a la direccion especificada * (normalmente la direccion es el registro de DATOS del puerto) */ public static native void writeOneByte (int address, int oneByte); static { System.loadLibrary("parport"); } }

Una manera de utilizar esta en un programa se muestra a continuacin en el siguiente segmento:


import parport.ParallelPort;

. . .
public void run( ) { try { int valorDeSalida; ParallelPort lpt1 = new ParallelPort(0x378); //Puerto de datos valorDeSalida = 255; // los 8 bits en 1 lpt1.write(valorDeSalida); // escribe byte al puerto paralelo

2.6. Driver UserPort.sys


UserPort.sys es un driver del kernell para Windows 2000/NT que proporciona a los programas en modo usuario acceso a los puertos de entrada/salida. Esto permite a los programas ejecutables normales accesar al hardware directamente como se hace en sistemas operativos como Windows 95/ 98/Me. Este driver no funciona en Windows 95/98/Me y no hay necesidad de utilizarlo en estos sistemas operativos. El driver puede ser utilizado para los siguientes propsitos: a) Ejecutar software en Windows 2000/NT/XP que normalmente solo funciona en Windows 95/98/Me. b) Accesar fcilmente a hardware conectado al puerto paralelo y otros puertos de entrada/salida mediante programas ejecutndose en modo usuario. Se puede utilizar este driver para operaciones de escritura y lectura del puerto paralelo, dndole el acceso al archivo UserPort.sys y efectuando otros pasos como se ejemplifica en el cdigo en C++ de programa UserPort.exe, el cual se anexa. Si se desea puede hacer simplemente lo siguiente: Copiar UserPort.SYS a %WINDIR%\SYSTEM32\DRIVERS y ejecutar el programa UserPort.exe que permite utilizar este driver para abrir los puertos que usted indique. De este modo puede ejecutar los programas que normalmente solo funcionaran en Windows 95/98/Me y que utilizan los puertos de entrada/salida.

42

Descripcin tcnica: El driver da a los programas en modo usuario acceso a los puertos seleccionados cambiando el IOPM (I/O Permission Map) de los procesadores x86 la figura muestra el funcionamiento del driver, para una descripcin detallada consulte los manuales de procesadores INTEL

El tamao original del TSS (Task State Segment) es 0x20ab y el driver cambia a 0x2135. El offset por defecto del IOPM es 0x20ad. Y este valor es reescrito por el Sistema Operativo en cada cambio de tarea a ejecutar. El offset del IOPM debe por lo tanto ser cambiado con la funcin Ke386IoSetAccessProcess, la cual establece el offset del IOPM a 0x88. El AllProcessesIOPM es escrito a 0x20ad porque este es el valor por defecto para todos los procesos y el ThroughCreateFileIOPM es escrito con 0x88 porque la funcin Ke386IoSetAccessProcess establece el offset del IOPM a 0x88. La funcin Ke386IoSetAccessProcess es llamada cuando un programa en modo usuario abre el archivo \\.\UserPort. El driver carga los dos IOPMs de: HKEY_LOCAL_MACHINE\Software\UserPort\AllProcessesIOPM HKEY_LOCAL_MACHINE\Software\UserPort\ThroughCreateFileIOPM Nota El driver esta influenciado e inspirado en un artculo escrito por Dale Roberts 8/30/95 publicado en mayo de 1996 por el Dr. Dobbs Journal, vese www.ddj.com.

2.7. La API Genuts


La API Genuts proporciona un marco para desarrollo de juegos de manera consistente en Java. Contiene una biblioteca con clases que principalmente fueron desarrolladas para la concepcin de juegos, incluyendo funciones para manipulacin y deteccin de colisiones. Adicionalmente, proporciona un nivel de abstraccin para algunos juegos relacionados con la API de Java, que incluyen manipulacin de imgenes y manejo de eventos. Su objetivo principal es: Juegos Web Telfonos mviles PDAs La API Genuts es compatible con Java 1.1, Java 2 y Java Me (MID P 1.0).

43

3. ESPECIFICACION DE REQUERIMIENTOS 3.1. Estructura de las tramas de control del robot


Al momento de iniciar este anlisis se dispone de una interfaz en hardware que se conecta entre el puerto paralelo de la computadora servidor y el robot, esta interfaz proporciona la potencia necesaria a la entrada del robot que consiste de un registro de 8 bits en el cual la parte alta corresponde a las seales que controlan mediante un circuito combinatorio, los movimientos del robot: adelante, atrs, izquierda, derecha, sus posiciones intermedias y alto. Cada bit de la parte baja del registro corresponde a una seal que controla los movimientos independientes del brazo izquierdo, brazo derecho, cabeza con movimiento vertical y cabeza con movimiento horizontal. La aplicacin a desarrollar debe ser capaz de enviar desde el cliente la cadena de bits correspondiente al servidor, para que esta se enve al puerto paralelo y sea recibido por la interfaz de acuerdo al movimiento que se desea que realice el robot. Esta descripcin ha sido especificada desde el diseo del robot y se describe en la siguiente tabla:

m0 m1 m2 m3 m4 m5 m6 m7 m8 m9 m10 m11 m12 m13 m14 m15

S1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1

S2 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1

S3 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1

S4 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1

CONDICION
Todos los switches cerrados 3 switches cerrados 3 switches cerrados 2 switches opuestos cerrados 3 switches cerrados Esquina S1 y S3 cerrados Esquina S1 y S4 cerrados S1 cerrado 3 switches cerrados Esquina S2 y S3 cerrados Esquina S2 y S4 cerrados S2 cerrado 2 switches opuestos cerrados S3 cerrado S4 cerrado Todos los switches abiertos

OBSERVACION
IMPOSIBLE IMPOSIBLE IMPOSIBLE IMPOSIBLE IMPOSIBLE VUELTA IZQ - ADELANTE PIVOTE VUELTA DER - ADELANTE PIVOTE ADELANTE IMPOSIBLE VUELTA - IZQ ATRS PIVOTE VUELTA DER - ATRS PIVOTE ATRS IMPOSIBLE VUELTA - IZQ VUELTA - DER POSICION NORMAL

Donde las variables S1, S2, S3, y S4 corresponden a las zonas que abarcara un Joystick con la siguiente descripcin:

44

Las condiciones descritas las interpretan 4 motores con los que cuenta el robot para desarrollar su dinmica de movimiento. Los estados en los que se encuentren operando estos motores de manera combinada generan las siguientes funciones:
MOTOR FUNCION 0 0 DETENIDO 0 1 ATRS 1 0 ADELANTE 1 1 DETENIDO

De modo que la tabla inicial puede ser expresada como se muestra a continuacin:
S1 m0 m1 m2 m3 m4 m5 m6 m7 m8 m9 m10 m11 m12 m13 m14 m15 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 S2 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 S3 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 S4 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 MDA MDB MIA * * * * * 1 B 1 * C 0 0 * 1 0 0 * * * * * 0 B 0 * C 1 1 * 0 1 0 * * * * * A 1 1 * 0 D 0 * 0 1 0 MIB * * * * * A 0 0 * 1 D 1 * 1 0 0

MD = MOTOR DERECHO MI = MOTOR IZQUIERDO

De este modo las cadenas de bits que se deben enviar al puerto paralelo para los diferentes movimientos son:
VUELTA IZQ ADELANTE PIVOTE VUELTA DER ADELANTE PIVOTE ADELANTE VUELTA IZQ ATRS PIVOTE VUELTA DER ATRS PIVOTE ATRS VUELTA IZQ VUELTA DER POSICION NORMAL

1 B 1 C 0 0 1 0 0

0 B 0 C 1 1 0 1 0

A 1 1 0 D 0 0 1 0

A 0 0 1 D 1 1 0 0 (A, B, C, D) {0, 1}

45

Adems de las seales independientes para controlar los brazos y cabeza del robot como ya se mencion anteriormente. La cadena enviada entre cliente y servidor puede tener una estructura diferente, pero se requiere que la cadena enviada a la interfaz con el robot cumpla las especificaciones descritas en las tablas anteriores, dado que la lgica combinatoria del circuito que controla al robot est diseada en base a estas tablas.

3.2 Comunicacin entre cliente y servidor


Se requiere que las aplicaciones desarrolladas se ejecuten independientemente de la red de que se disponga, siempre que sea empleado el protocolo TCP/IP. Para ello solo se deben especificar las direcciones IPs de cliente y servidor as como los puertos correspondientes en la aplicacin a desarrollar. Se debe tomar como hiptesis que la calidad de servicio de la red est garantizada. Una vez establecida la red su conexin no ser interrumpida y los paquetes que se envan o reciben no tendrn prdidas.

3.3. Plataforma de operacin


La aplicacin debe ejecutarse en ambiente Windows sin restricciones en la versin de que se disponga como Windows 98, Me, 2000, NT o XP. Se resalta la caracterstica de seguridad de Windows 2000, NT y XP que bloquea el acceso a los puertos, ya sea para lectura o escritura por lo que los programas desarrollados deben considerar dicha caracterstica para que esto no sea un problema para los usuarios de la aplicacin.

3.4. Velocidad de respuesta


La aplicacin estar enviando paquetes de datos constantemente y a su vez en versiones posteriores, ser capaz de recibir multimedia como puede ser la transmisin de audio y video, por lo que se desea que la aplicacin maneje de manera eficiente el envo de paquetes de control sin saturar el canal, para permitir que las aplicaciones futuras funcionen eficientemente. As se debe minimizar el tamao y la cantidad de paquetes a enviar. La aplicacin debe responder de manera rpida y no consumir demasiados recursos de cmputo.

3.5. Control de programas remotos


Se desea la ejecucin de programas de manera remota con una terminal o mediante el uso de una aplicacin adicional con el fin llevar a cabo la reproduccin multimedia en el lado del servidor y tener control desde el cliente. As tambin se puede iniciar la ejecucin de programas o terminacin de estos desde el cliente en cualquier momento y esto debe ser con procesos ligeros que no sobrecarguen los recursos utilizados por cada programa, de modo que se pudiera hacer lenta la ejecucin de los programas en el servidor, repercutiendo en un desempeo pobre de las aplicaciones.

3.6. Interfaz grfica


Se desea el uso de un Joystick Virtual y se recomienda el uso de un applet para el diseo del mismo.

46

4. Modelo de Requerimientos 4.1. Modelo de Casos


El siguiente diagrama muestra los casos de uso ms relevantes del sistema

Estos se describen a continuacin:

Caso de uso: Enviar Movimiento Precondiciones: La conexin con el servidor se encuentra establecida. Postcondiciones: La conexin con el servidor contina establecida y el estado del registro de datos en el servidor se ha actualizado Paso Descripcin 1 El usuario mueve el mouse, coloca el puntero dentro del rea del joystick y hace click sobre un punto de la misma, entra arrastrando el puntero de una regin a otra o bien habilita o deshabilita una casilla de verificacin. El programa cliente redibuja la palanca del joystick creando la apariencia de movimiento hacia el punto sobre el que se coloca el puntero mientras el botn izquierdo del mouse es presionado y se encuentra dentro del rea del joystick. El programa cliente reconoce un cambio de regin en la que ahora se encuentra colocada la palanca del joystick, o bien reconoce si una casilla de verificacin fue habilitada/deshabilitada y enva el paquete de informacin correspondiente, desde el cliente al servidor; con la instruccin del movimiento a realizar. El programa servidor recibe la instruccin, la interpreta y enva el valor numrico que corresponde al puerto paralelo para ser ledo por la interfaz del robot.

47

5 6

Se repite desde el paso 1 al 4 hasta que el botn izquierdo del mouse es liberado. Si no cambia de regin solo se repiten los pasos 1 y 2. Fin de caso de uso

Caso de uso: Ejecutar Comando Precondiciones: La conexin con el servidor se encuentra establecida. Postcondiciones: La conexin con el servidor contina establecida.

Paso Descripcin 1 2 3 4 5 El usuario escribe un comando en la lnea de comandos del programa cliente y presiona Enter o Aceptar. El programa cliente limpia el cuadro de texto, empaqueta el comando y lo enva al servidor. El programa servidor reconoce que se trata de un comando y lo ejecuta. El programa servidor realiza el caso de uso Enviar mensaje de estatus Fin de caso de uso

Caso de uso: Enviar mensaje de estatus Precondiciones: El monitor esta en disponibilidad de aceptar una nueva conexin. Postcondiciones: Se cierra la conexin con el monitor.

Paso Descripcin 1 2 3 4 5 6 El programa servidor guarda la salida de ejecucin del comando ejecutado, se comunica con el monitor y solicita establecer la conexin. El monitor acepta la conexin. El servidor enva el mensaje con la salida al monitor en la computadora cliente. El programa monitor recibe el mensaje y lo despliega en pantalla. El programa monitor cierra su conexin y queda en posibilidad de recibir otro mensaje. Fin de caso de uso.

Caso de uso: Iniciar Monitor Precondiciones: La computadora cliente y la computadora servidor se encuentran en red. Postcondiciones: El monitor esta listo para aceptar cualquier conexin.

Paso Descripcin 1 El usuario inicia el servicio de monitoreo haciendo click en aceptar con el nmero de puerto correspondiente ya capturado en el cuadro de texto indicado para ese fin. 2 El monitor se encuentra en una condicin de aceptar cualquier conexin que se solicite. 3 Fin de caso de uso.

48

4.2. Modelo de Interfaz


No hay navegacin entre pantallas. La pantalla de Control Remoto es redibujada para crear la apariencia de movimiento del joystick y su botn Conectar/Desconectar cambia de mensaje de acuerdo al estado en el que se encuentre. 4.2.1 Pantallas en el lado del Cliente:

Pantalla Control Remoto


Permite controlar los movimientos del robot

Pantalla de servicio de monitoreo remoto


Permite visualizar el resultado de ejecucin de los programas ejecutndose remotamente, as como los mensajes de lectura del puerto paralelo que detecta el Sensor ejecutndose el Servidor

49

4.2.2. Pantallas en el lado del servidor:

Pantalla de Controlador del Robot


Esta es la aplicacin del servidor que se pone en servicio para que se pueda establecer comunicacin desde el cliente y que recibe las rdenes del joystick para transmitirlas a la interfaz del robot a travs del puerto paralelo principalmente.

Pantalla de Sensor de escritura en el Puerto Paralelo


Permite poner en marcha el servicio de lectura del Puerto paralelo adems de monitorear localmente el estado del mismo.

50

4.3. Modelo de Dominio del Problema


4.3.1 Diagramas de Secuencia Los diagramas de Secuencia muestran una interaccin ordenada segn la secuencia temporal de eventos. El eje vertical representa el tiempo, y en el eje horizontal se colocan los objetos y actores participantes en la interaccin, sin un orden prefijado. Cada objeto o actor tiene una lnea vertical, y los mensajes se representan mediante flechas entre los distintos objetos. El tiempo fluye de arriba abajo. Los diagramas de secuencia mostrados estn simplificados para mostrar las interacciones principales que se desean entre cada objeto.

4.3.1.1 Caso de Uso Enviar Movimiento


Joystick Cliente Servidor LPT1

El usuario mueve el Joystick o activa un movimiento

Se redibuja Joystick en Pantalla

Se empaqueta el moviento a enviar Se pasa el paquete al objeto Cliente El cliente envia el paquete por la red al servidor Se obtiene el dato a escribir en el puerto y se lo pasa LPT1

Se escribe en el puerto paralelo

4.3.1.2 Caso de Uso Enviar Comando

Joystick

Cliente

Monitor

Servidor

HiloLanzador

Se inicia servicio de monitoreo El usuario escribe un comando y presiona enter o enviar Se empaqueta el comando a enviar

Se pasa el paquete al objeto Cliente

El cliente envia el paquete por la red al servidor

Se crea un hilo para atender peticin

Ejecuta comando

Se envia salida de ejecucin del comando o programa

51

5. APLICACIN DESARROLLADA
5.1. Descripcin general El sistema que estamos presentando consta de cuatro programas: dos en el lado del Servidor y dos en el lado del Cliente. Este conjunto de mdulos, permite controlar al robot conectado en el puerto paralelo en el lado del servidor, adems proporciona acceso a programas instalados en la estacin en el lado del Servidor, as como monitoreo mediante una terminal que recibe la salida de los programas ejecutados remotamente; los cuales pueden ser invocados por lnea de comandos desde el cliente. Esta terminal de monitoreo tambin puede recibir los mensajes que son enviados a la misma, desde alguna otra aplicacin que los enve a la direccin y puerto correspondientes, tal como lo hace un programa sensor que lee el registro de estado del puerto paralelo reportando cualquier cambio en este. De este modo se pueden incorporar sensores al robot que reporten alguna condicin y esta sea enviada al programa monitor. Una vez establecida la red, conectado el robot al puerto paralelo e instalados cliente y servidor, se tiene la siguiente arquitectura.

Fig V-1

5.2. Diseo conceptual El sistema desarrollado esta conformado por 4 programas independientes pero que se comunican entre si. En el lado del cliente: 1. Joystick 2. Monitor En el lado del servidor: 3. Controlador 4. Sensor

52

El Programa Joystick se comunica con el Programa Controlador envindole cadenas que contienen la informacin a procesar por este ltimo, pudindose tratar de instrucciones de control del robot, o bien comandos (programas) a ejecutar. El controlador crea un hilo por cada peticin de un comando o programa a ejecutar y las salidas son manejadas por nuevos hilos ya sean resultados de la ejecucin o mensajes de error. Se utiliza este esquema con el fin de garantizar que el servidor siga atendiendo nuevas peticiones de manera eficiente, sin bloquearse por algn error en la ejecucin del comando. Si no fuera de esta manera se tendra el problema de retardo para el control del robot al estar esperando el mensaje de respuesta generado por cada vez que se enva un comando o seal de control del robot. Existe por ello un programa de monitoreo que recibe las salidas que obtiene cada hilo que es generado por el Servidor, adems de recibir el status del programa Sensor. Si hubiera algn problema con la ejecucin de un hilo o con el tiempo en que tarda en terminar su ejecucin, en el peor caso se puede reiniciar el monitor, sin perder el manejo del robot. Esta idea permite escalar el funcionamiento global de las aplicaciones que pudieran incorporarse y ser invocadas de manera remota y monitoreadas incluso si se agregan sensores enlazados con programas que se comuniquen a su vez con nuevos programas en el modelo cliente/servidor.

5.3. Esquema general de comunicaciones

Robot

Seales de control del robot Cliente Sensor

Servidor

P1

Monitor Pi

P2

Hilos generados por cada invocacin de programas o comandos desde el cliente

Fig V-2

53

El programa cliente (Joystick) se comunica con el servidor (Controlador), el cual genera hilos que a su vez se comunican con el Programa Monitor. El programa Servidor enva las seales de control correspondientes al puerto Paralelo, segn lo solicite el programa Cliente. El programa Sensor monitorea constantemente el registro de estado por si ha cambiado su valor, el cual puede ser modificado con un voltaje de 0 o 5 Volts directamente en alguno de los pines que corresponden al registro de estado del puerto paralelo. Si este ha cambiado se manda la informacin correspondiente al programa Monitor.

5.4. Diagramas de Clases


5.4.1 Programa Joystick El Programa Joystick es en si, un llamado a la clase principal (con el mtodo main) la cual instancia diferentes clases y estas a su vez otras tal como se muestra en el diagrama de clases siguiente. Se muestran solo los mtodos y atributos ms ilustrativos de cada clase, para detalles precisos consultar el cdigo en Java presentado en la seccin VI. Los mtodos que se ilustran nos dan una idea del funcionamiento de todo el programa.

LanzadorDeApplet run() close()

crea Joystick dirIPTextBox ptoTextBox com.gnuts.gameui Joystick() mueveBola() mouseClicked() mouseEntered() mouseExited() mousePressed() mouseReleased() enviaComando() enviaMovimiento() Cliente utiliza cliente() envia() cerrarSocket()

utiliza

Package gnuts.jar

Fig V-3. Clases del Programa Control Remoto

La clase Joystick que es un Applet es instanciada por la clase LanzadorDeApplet, la cual monta el Applet sobre un Frame para poder ser visualizado sin navegador. Adems la clase Cliente es la encargada de establecer la comunicacin con el Servidor y enviar las instrucciones a ejecutar correspondientes.

54

Se hace uso del paquete gnuts.jar, el cual fue creado para desarrollar juegos para computadora y posee un conjunto muy amplio de clases para estos propsitos incluyendo manejo de audio. En nuestro caso es empleada para el desarrollo del Joystick virtual que controla al robot. Los mtodos de esta clase se pueden dividir en aquellos que reconocen una accin del mouse dentro del rea del Joystick virtual, el mtodo mueveBola que redibuja la palanca del Joystick apoyado en las clases del paquete gnuts y las clases que se encargan de empaquetar la informacin para el servidor y solicitar su transmisin. Estos ltimos apoyndose en la clase cliente quien es la que establece la comunicacin con el servidor y enva los paquetes correspondientes. Si por alguna razn se deseara que esta aplicacin sea operada desde un navegador, se cuenta prcticamente con todo el proyecto para que esto sea llevado a cabo, ya que todas las clases visuales son extendidas de un applet y solo faltara modificar algunos valores para darle la presentacin adecuada.

5.4.2. Programa Monitor Consta de las clases que se muestran en el siguiente diagrama, la clase VentanaDeMonitoreo abre un socket para aceptar conexiones del Servidor y recibir las cadenas de mensajes que conforman la salida de los programas ejecutados remotamente, esta es instanciada por la clase LanzadorDeApplet que monta el applet sobre un Frame. Adems se utilizan hilos para atender cada uno de los mensajes que son enviados desde el servidor. La Clase VentanaDeMonitoreo crea un hilo que se queda en espera de una nueva conexin por la que se recibir el mensaje a publicar e inmediatamente se crea un nuevo hilo en espera de una nueva conexin. Al terminar de publicarse la informacin el hilo es terminado. Esto permite que la aplicacin trabaje de manera continua sin bloqueos o saturacin por la atencin de diversos mensajes.

LanzadorDeApplet run() close() crea

VentanaDeMonitoreo ptoTextLabel textArea ventanaDeMonitoreo() init() main()

HiloM utiliza hiloM() run()

Cada mensaje que llega es atendido por un nuevo hilo

Fig V-4. Clase del programa Monitor

55

5.4.3. Programa Controlador Consta de 7 clases como se muestra en la figura siguiente. La clase VentanaControlador que es instanciada por la clase LanzadorDeApplet es quien se encarga de iniciar al controlador, una vez creado un objeto de esta clase, se tiene un proceso al que se conecta el Joystick a travs de un socket y por este se reciben los paquetes con las instrucciones o comandos correspondientes, el paquete es analizado y si se trata de un movimiento se hace uso de la clase ParallelPort para escribir el valor correspondiente en el puerto paralelo. Si el paquete recibido corresponde a la ejecucin de un comando, entonces se instancia a la clase LanzadorDOS, la cual recibe el comando a ejecutar y a travs del programa cmd.exe o command.com (segn la versin del sistema operativo) este lo ejecuta recibiendo los parmetros correspondientes. Si la invocacin del comando o programa genera una respuesta, esta es enviada con ayuda de la clase Transmisor. Cada comando o mensaje es manejado por un hilo mediante la clase HiloMensajero. La estructura general de cada clase se muestra en el siguiente diagrama.
LanzadorDOS lanzadorDOS() HiloMensajero run() hiloMensajero()

LanzadorDeApplet run() close()

crea

crea utiliza

VentanaControlador ventanaControlador() init() main() utiliza

Controlador controlador() lanza() run() utiliza Transmisor transmisor()

utiliza

ParallelPort read() write()

Fig V-5 Clases del Programa Manejador

5.4.4. Programa Sensor

Una vez credo un objeto de la clase LectorLPT1 se monitorea el registro de estado del puerto paralelo con ayuda de la clase ParallelPort y si hay un cambio se enva un mensaje al monitor con ayuda de la clase Transmisor. La clase VentanaSensor permite adems ver el estado del puerto ya que se muestra este a travs de la misma. La estructura de este programa se muestra a continuacin.

56

LanzadorDeApplet run() close()

crea

VentanaSensor ventanaSensor() init() main() utiliza

LectorLPT1 lectorLPT1() run() utiliza Transmisor transmisor()

utiliza

ParallelPort read() write()

6.. PRUEBAS REALIZADAS


Entre las pruebas realizadas enlistamos las siguientes con las observaciones sealadas. Pruebas con red garantizada La respuesta del envo de comandos es satisfactoria, las instrucciones son recibidas sin retrasos aparentes no obstante los cambios de comando se enven continuamente en intervalos de tiempo cortos. El applet que dibuja el Joystick es pintado eficientemente sin retrasos aparentes Prueba de control al perder la red El robot permanece con el ltimo comando enviado y no se puede retomar el control. De este modo la red local debe estar garantizada como ya se haba considerado. Pruebas en diferentes Sistema Operativos La aplicacin se instala y opera correctamente en diferentes sistemas operativos Windows (win 95, Win 98, Win Me, Win 2000 y Windows XP La necesidad de utilizar la ventana de lnea de comandos de manera virtual para ejecutar comandos remotamente hace lenta la ejecucin de los mismos en el servidor por lo que se recomienda que este cuente con una memoria RAM superior a 512 MB y un procesador superior a 1.7GHz.

57

7. RECOMENDACIONES
El presente trabajo puede ser mejorado en varios aspectos, estas observaciones son el resultado de probar con este producto y haber obtenido resultados satisfactorios, con lo que se pueden pasar a considerar aspectos no tan prioritarios; pero que mejoran la calidad de la aplicacin as como su mantenimiento y expansin. Se sugiere plantear una solucin distinta al uso de sockets dada la complejidad de sincronizacin de los mismos sobre todo si se van a enviar diferentes tipos de paquetes. El esquema de control mediante el puerto paralelo funciona adecuadamente para las velocidades de respuesta de los dispositivos controlados remotamente. Sin embargo se propone un avance en este sentido con el uso del Puerto USB dada su tendencia a sustituir otros puertos de comunicaciones como el puerto serie o paralelo. Se propone el desarrollo de un sensor de red para casos en los que la red no est garantizada y de este modo ejecutar una instruccin de paro cuando esto ocurra, de tal modo que no se pierda el control del robot a pesar de la posibilidad de perder la red.

58

8. CONCLUSIONES
El desarrollo de aplicaciones bajo el protocolo TCP/IP para control y monitoreo de dispositivos remotos en ambiente de red nos brinda la seguridad de que estas seguirn funcionando con las nuevas tecnologas dado que se desarrollan bajo este estndar. El uso de sockets nos permite el envo de datos proporcionando nicamente un nmero de puerto y la direccin IP del servidor. De manera transparente, ya sea que se tenga una red convencional o inalmbrica. Java como lenguaje de programacin nos proporciona independencia de la plataforma en la que se ejecutan las aplicaciones generadas. Adems el desarrollo de clases nos permite su reutilizacin, logrando mejorar las mismas con nuevos mtodos o bien avanzar en los detalles o caractersticas particulares de la aplicacin. De modo que se aprovechan las caractersticas de la programacin orientada a objetos y se logran mayores avances en menor tiempo con mejor calidad. El uso hilos para repartir tareas que pueden ser realizadas concurrentemente con otras que el procesador o los procesadores deban realizar, nos permite un mejor desempeo de la aplicacin siempre que se usen adecuadamente. Sin embargo, pueden generar problemas de sincronizacin si el orden de ejecucin es importante y un hilo toma ms tiempo en ejecutarse de lo que se esperaba. El uso de hilos para optimizar el envi de seales al puerto paralelo fue descartado dado que se requiere de un orden estricto en la secuencia de instrucciones a realizar. No obstante result adecuado para mejorar el rendimiento y la velocidad de respuesta del servidor dado que las tareas de diferente naturaleza y ejecucin espordica pueden ser llevadas a cabo de manera independiente y su respuesta no es crtica en orden y tiempo. Optimizar el cdigo generado resulta esencial en la parte del programa que enva instrucciones mediante el joystick al puerto paralelo, ya que el movimiento de este genera una seal cada vez que cambia de posicin, por lo que en un barrido de una posicin a otra se podran estar generando demasiadas instrucciones en un intervalo de tiempo muy corto. El uso de computadoras para el control remoto de aplicaciones nos da grandes ventajas como lo es la disponibilidad de perifricos, puertos de comunicaciones, programas existentes y programas que an no han sido desarrollados pero que pueden ser incorporados. Adems de todas las tecnologas que sern desarrolladas en los prximos aos. El uso del puerto Paralelo facilita la comunicacin con dispositivos externos, sin embargo la tendencia es la de migrar nuevo hardware y equipo a controlar hacia el uso de Puertos de alta velocidad como USB. De modo que un siguiente paso ser el de realizar esta conversin. La arquitectura del sistema desarrollado, permitir modificar fcilmente el cdigo si as se requiere, sustituyendo nicamente la clase ParallelPort por la que corresponda para la comunicacin con el puerto USB as como el diseo o uso del driver correspondiente en cuanto a software se refiere. La capacidad de invocar programas o comandos de manera remota en el servidor nos ayuda a incorporar elementos multimedia en las aplicaciones, dado el soporte que proporciona la computadora haciendo la funcin de servidor, a la que se conecta el dispositivo a controlar. Adems nos permite el monitoreo de los procesos en ejecucin. Si se desean agregar sensores para monitoreo del robot, estos pueden comunicar su estado mediante nuevos sockets entre los dos equipos con nuevos programas que se deben desarrollar. Finalmente podemos decir que se cuenta con una arquitectura de software para control y monitoreo de dispositivos remotos que es escalable e independiente de plataforma, bajo un ambiente de red, fcilmente adaptable al control de otros dispositivos.

59

9. REFERENCIAS
[1] Eckel Bruce. Piensa en Java. Pearson educacin (2002) [2] Programming the Parallel Port: Interfacing the PC for Data Acquisition & Process Control. Dhananjay V. Gadre. Ed. CMP Books, 1999. [3]. http://www.doc.ic.ac.uk/~ih/doc/par/ : Interfacing to the IBM-PC Parallel Printer Port. [ONLINE] (Mayo 2005) [4] http://www.lvr.com/parport.htm: Parallel Port Central [ONLINE] (Mayo, 2005) [5] http://www.geekhideout.com. (Mayo 2005) [6] http://algoval.essex.ac.uk/cec2005/race/apps/UserPort.zip (Junio 2005) [7]. http://www.genuts.com/api. (Junio 2005) [8]. Herrera Lozada. J.C. Interfaces para el puerto paralelo de la PC, en modo bidireccional. CIDETEC IPN) [9]. http://soft0.upc.es/pc/sockets [ONLINE], (Junio 2005) [10]. www.ddj.com [ONLINE]

60

ANEXO A. CODIGO FUENTE


A continuacin se proporciona el cdigo fuente de las clases desarrolladas.

A.1. Programa Joystick


/* package cliente; import java.net.*; import java.io.*; /** * Clase que crea un socket cliente, establece la conexin y lee los datos * del servidor, escribindolos en pantalla. */ Archivo: ClienteRobot.java */

public class ClienteRobot { Socket socket; BufferedReader lectorDeSocket; PrintWriter escritorDeSocket; boolean bandera = true; ClienteRobot(String dir_ip, String puerto) { try { socket = new Socket(dir_ip,Integer.valueOf(puerto).intValue()); } catch(Exception exc) { System.out.println("No se pudo establecer la conexion"); } }

public boolean envia(String comando){ bandera = true; try { escritorDeSocket = new PrintWriter(socket.getOutputStream(),true); escritorDeSocket.println(comando); } catch(Exception exc) { System.out.println("No hay comunicacion con el Servidor"); bandera = false; } return bandera; }

public void cerrarSocket(){ try { socket.close(); } catch(Exception exc) { System.out.println("Socket cerrado"); } } }

61

/*

Archivo: Joystick.java

*/

/* Se utiliza clase com.gnuts.gameui para Joystick * Mas informacin en: The Genuts Project - http://www.genuts.com * Version 2006 */ package cliente; import import import import javax.swing.*; java.awt.*; java.awt.event.*; com.genuts.gameui.*;

/** * Applet: Joystick y Linea de comandos para control remoto de Robot y computadora */ public class Joystick extends JApplet implements MouseListener, MouseMotionListener { PlayField f; int int int int int int int int int int xb, yb; d; w, h; p; xc, yc; L; s; H; xc2, yc2; region = 0;

// La parte alta de la cadena es logica inversa al diseo original del hardware StringBuffer cadenaDeControl = new StringBuffer("00000000"); ClienteRobot cliente; private private private private private private private private private private private private private private private JButton setButton = new JButton(); JLabel dirIPLabel = new JLabel(); JTextField dirIPTextField = new JTextField(); JLabel ptoLabel = new JLabel(); JTextField ptoTextField = new JTextField(); JTextField commandTextField = new JTextField(""); JLabel avisos = new JLabel(); JButton enviarButton = new JButton(); JButton salirButton = new JButton(); JLabel shellLabel = new JLabel(); JLabel JCheckBox JCheckBox JCheckBox JCheckBox checkGroupLabel = new JLabel("Activar:"); brazoIzqCB = new JCheckBox(" B. Izquierdo"); brazoDerCB = new JCheckBox(" B. Derecho"); cabezaNoCB = new JCheckBox(" NO - Cabeza"); cabezaSiCB = new JCheckBox(" SI - Cabeza"); // ESTADO INICIAL

private void enviaComando(String comando, String mensajeEnPantalla) { if(!comando.equals("")){ cliente.envia(comando); System.out.println(mensajeEnPantalla); } }

62

private void enviaMovimiento(int xs, int ys) { // Regiones: // Se envia movimiento de Robot segun zona del Joystick // (solo si hubo una modificacion de la cadena a enviar) // // // // // // // // // // // // s1 0 0 0 1 1 1 1 1 1 s2 1 1 1 0 0 0 1 1 1 s3 0 1 1 0 1 1 0 1 1 s4 1 0 1 1 0 1 1 0 1 MDA MDB MIA MIB 1 0 A A B B 1 0 1 0 1 0 C C 0 1 0 1 D D 0 1 0 1 1 0 0 1 0 1 1 0 0 0 0 0

4 | 3 | 2 5 | 0 | 1 6 | 7 | 8

m5 m6 m7 m9 m10 m11 m12 m13 m14 m15

REGION OBSERVACION 4 VUELTA IZQ-ADE PIVOTE 2 VUELTA DER-ADE PIVOTE 3 ADELANTE 6 8 7 5 1 0 VUELTA IZQ-ATR PIVOTE VUELTA DER-ATR PIVOTE ATRAS VUELTA IZQ VUELTA DERECHA POSICION NORMAL

// EN EL CLIENTE SE USARAN LOS 4 BITS MDA MDB MIA y MIB PARA // CONTROLAR LOS 2 MOTORES DEL ROBOT QUE RESPONDEN DE ACUERDO A LA // SIG TABLA // // // // // MOTOR 0 0 0 1 1 0 1 1 FUNCION DETENIDO ATRAS ADELANTE DETENIDO

MD = MOTOR DERECHO (A o B) MI = MOTOR IZQUIERDO (A o B)

// ESTRUCTURA DE cadenaDeControl: |BI|BD|NO|SI|MDA|MDB|MIA|MIB| if(xs > w*9/14){ if(ys > h*9/14) {if(region != 8 ) { cadenaDeControl.setCharAt(4,'0'); cadenaDeControl.setCharAt(5,'1'); cadenaDeControl.setCharAt(6,'1'); cadenaDeControl.setCharAt(7,'1'); enviaComando("#lud "+cadenaDeControl,"VUELTA DER-ATRAS PIVOTE"); region = 8;} // SE SABE EN QUE REGION ESTA PARA NO REPETIR } // ENVIOS SIN NECESIDAD else if(ys > h*5/14) {if(region != 1){ cadenaDeControl.setCharAt(4,'0'); cadenaDeControl.setCharAt(5,'1'); cadenaDeControl.setCharAt(6,'1'); cadenaDeControl.setCharAt(7,'0'); enviaComando("#lud "+cadenaDeControl,"VUELTA DER"); region = 1;} } else {if(region != 2){ cadenaDeControl.setCharAt(4,'1'); cadenaDeControl.setCharAt(5,'1'); cadenaDeControl.setCharAt(6,'1'); cadenaDeControl.setCharAt(7,'0'); enviaComando("#lud "+cadenaDeControl,"VUELTA DER-ADELANTE PIVOTE"); region = 2;} } } else if(xs > w*5/14){ if(ys > h*9/14) {if(region != 7){ cadenaDeControl.setCharAt(4,'0'); cadenaDeControl.setCharAt(5,'1'); cadenaDeControl.setCharAt(6,'0'); cadenaDeControl.setCharAt(7,'1'); enviaComando("#lud "+cadenaDeControl,"ATRAS"); region = 7;} }

63

else if(ys > h*5/14) {if(region != 0){ cadenaDeControl.setCharAt(4,'0'); cadenaDeControl.setCharAt(5,'0'); cadenaDeControl.setCharAt(6,'0'); cadenaDeControl.setCharAt(7,'0'); enviaComando("#lud "+cadenaDeControl,"ALTO"); region = 0;} } else {if(region != 3){ cadenaDeControl.setCharAt(4,'1'); cadenaDeControl.setCharAt(5,'0'); cadenaDeControl.setCharAt(6,'1'); cadenaDeControl.setCharAt(7,'0'); enviaComando("#lud "+cadenaDeControl,"ADELANTE"); region = 3;} } } else{ if(ys > h*9/14) {if(region != 6){ cadenaDeControl.setCharAt(4,'1'); cadenaDeControl.setCharAt(5,'1'); cadenaDeControl.setCharAt(6,'0'); cadenaDeControl.setCharAt(7,'1'); enviaComando("#lud "+cadenaDeControl,"VUELTA IZQ-ATRAS PIVOTE"); region = 6;} } else if(ys > h*5/14) {if(region != 5){ cadenaDeControl.setCharAt(4,'1'); cadenaDeControl.setCharAt(5,'0'); cadenaDeControl.setCharAt(6,'0'); cadenaDeControl.setCharAt(7,'1'); enviaComando("#lud "+cadenaDeControl,"VUELTA-IZQ"); region = 5;} } else {if(region != 4){ cadenaDeControl.setCharAt(4,'1'); cadenaDeControl.setCharAt(5,'0'); cadenaDeControl.setCharAt(6,'1'); cadenaDeControl.setCharAt(7,'1'); enviaComando("#lud "+cadenaDeControl,"VUELTA IZQ-ADELANTE PIVOTE"); region = 4;} } } } class DetectorEnter implements ActionListener { //Accion a realizar al presionar ENTER public void actionPerformed(ActionEvent e) { if(commandTextField.getText()!= ""){ enviaComando(commandTextField.getText(),"Enviar comando por shell"); commandTextField.setText(""); } else avisos.setText("Escriba comando y Presione ENTER"); } } public void init() { commandTextField.disable(); commandTextField.setBackground(new Color(225,225,225)); //Gris claro Container cp = getContentPane();

64

//Listeners para botones, Check Group y Enter commandTextField.addActionListener(new DetectorEnter()); brazoIzqCB.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if(brazoIzqCB.isSelected()){ cadenaDeControl.setCharAt(0,'1'); enviaComando("#lud "+cadenaDeControl,"Brazo Izquierdo Activado"); } else { cadenaDeControl.setCharAt(0,'0'); enviaComando("#lud "+cadenaDeControl,"Brazo Izquierdo Desactivado"); } avisos.setText("Listo..."); } });

brazoDerCB.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if(brazoDerCB.isSelected()){ cadenaDeControl.setCharAt(1,'1'); enviaComando("#lud "+cadenaDeControl,"Brazo Derecho Activado"); } else { cadenaDeControl.setCharAt(1,'0'); enviaComando("#lud "+cadenaDeControl,"Brazo Derecho Desactivado"); } avisos.setText("Listo..."); } });

cabezaNoCB.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if(cabezaNoCB.isSelected()){ cadenaDeControl.setCharAt(2,'1'); enviaComando("#lud "+cadenaDeControl,"NO Cabeza Activado"); } else { cadenaDeControl.setCharAt(2,'0'); enviaComando("#lud "+cadenaDeControl,"NO Cabeza Desactivado"); } avisos.setText("Listo..."); } });

cabezaSiCB.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if(cabezaSiCB.isSelected()){ cadenaDeControl.setCharAt(3,'1'); enviaComando("#lud "+cadenaDeControl,"SI Cabeza Activado"); } else { cadenaDeControl.setCharAt(3,'0'); enviaComando("#lud "+cadenaDeControl,"SI Cabeza Desactivado"); } avisos.setText("Listo..."); } });

65

salirButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if(setButton.getText()!="Desconectar"){ stop(); destroy(); LanzadorDeApplet.cerrar(); } else{ avisos.setText("Si desea salir Desconectese"); } } });

enviarButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if(commandTextField.getText()!= ""){ enviaComando(commandTextField.getText(),"Boton Enviar comando Presionado"); commandTextField.setText(""); } else { avisos.setText("Escriba un comando..."); } } });

setButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { if(setButton.getText()=="Conectar"){ //falta validar por return correcto cliente = new ClienteRobot(dirIPTextField.getText(),ptoTextField.getText()); if(cliente.envia("#lud "+cadenaDeControl)==true){ dirIPTextField.disable(); ptoTextField.disable(); commandTextField.enable(); dirIPTextField.setBackground(new Color(225,225,225)); ptoTextField.setBackground(new Color(225,225,225)); commandTextField.setBackground(java.awt.Color.white); setButton.setText("Desconectar"); avisos.setText("Listo..."); brazoIzqCB.setEnabled(true); brazoDerCB.setEnabled(true); cabezaNoCB.setEnabled(true); cabezaSiCB.setEnabled(true); enviarButton.setEnabled(true); f.setEnabled(true); System.out.println("Conexion Establecida"); }else{ avisos.setText("No se puede establecer la conexion"); System.out.println("No se puede establecer la conexion"); } System.out.println("Boton Conectar Presionado"); } else { cliente.cerrarSocket(); dirIPTextField.setBackground(java.awt.Color.white); ptoTextField.setBackground(java.awt.Color.white); commandTextField.setBackground(new Color(225,225,225)); //aqui dirIPTextField.enable(); ptoTextField.enable(); commandTextField.disable(); setButton.setText("Conectar"); avisos.setText("Establezca IP y Puerto ....."); brazoIzqCB.setEnabled(false);

66

brazoDerCB.setEnabled(false); cabezaNoCB.setEnabled(false); cabezaSiCB.setEnabled(false); enviarButton.setEnabled(false); f.setEnabled(false); System.out.println("Boton Desconectar Presionado - Desconectado"); } } });

/* ++++++++++++++++++++++ Posiciones de controles y texto ++++++++++++++++++++++++ */ cp.setLayout(null); brazoIzqCB.setEnabled(false); brazoDerCB.setEnabled(false); cabezaNoCB.setEnabled(false); cabezaSiCB.setEnabled(false); enviarButton.setEnabled(false); // Botones etc.. cp.add(setButton); setButton.setBounds(270, 24, 90, 25); setButton.setText("Conectar"); setButton.setFont(new java.awt.Font("Dialog", java.awt.Font.PLAIN, 9)); cp.add(dirIPLabel); dirIPLabel.setBounds(20, 30, 33, 20); dirIPLabel.setText("Dir. IP"); dirIPLabel.setFont(new java.awt.Font("Dialog", java.awt.Font.PLAIN, 10)); cp.add(ptoLabel); ptoLabel.setBounds(168, 30, 33, 20); ptoLabel.setText("Puerto"); ptoLabel.setFont(new java.awt.Font("Dialog", java.awt.Font.PLAIN, 10)); cp.add(avisos); avisos.setBounds(22, 275, 170, 15); avisos.setText("Cargando Joystick..."); avisos.setForeground(Color.red); avisos.setFont(new java.awt.Font("Dialog", java.awt.Font.ITALIC, 10)); cp.add(shellLabel); shellLabel.setBounds(20, 225, 139, 15); shellLabel.setText("Linea de Comandos"); shellLabel.setFont(new java.awt.Font("Dialog", java.awt.Font.PLAIN, 10)); cp.add(dirIPTextField); dirIPTextField.setBounds(55, 25, 99, 25); dirIPTextField.setText(""); cp.add(ptoTextField); ptoTextField.setBounds(203, 25, 52, 25); ptoTextField.setText("8086"); cp.add(commandTextField); commandTextField.setBounds(20, 245, 167, 25); commandTextField.setText(""); cp.add(enviarButton); enviarButton.setBounds(205, 245, 69, 25); enviarButton.setText("Enviar"); enviarButton.setFont(new java.awt.Font("Dialog", java.awt.Font.PLAIN, 10));

67

cp.add(salirButton); salirButton.setBounds(290, 245, 69, 25); salirButton.setText("Salir"); salirButton.setFont(new java.awt.Font("Dialog", java.awt.Font.PLAIN, 10)); cp.add(checkGroupLabel); cp.add(brazoIzqCB); cp.add(brazoDerCB); cp.add(cabezaNoCB); cp.add(cabezaSiCB); checkGroupLabel.setBounds(250,60,110,20); brazoIzqCB.setBounds(250,90,110,20); brazoDerCB.setBounds(250,125,110,20); cabezaNoCB.setBounds(250,160,110,20); cabezaSiCB.setBounds(250,195,110,20); checkGroupLabel.setFont(new java.awt.Font("Dialog", java.awt.Font.BOLD, 11)); brazoIzqCB.setFont(new java.awt.Font("Dialog", java.awt.Font.BOLD, 11)); brazoDerCB.setFont(new java.awt.Font("Dialog", java.awt.Font.BOLD, 11)); cabezaNoCB.setFont(new java.awt.Font("Dialog", java.awt.Font.BOLD, 11)); cabezaSiCB.setFont(new java.awt.Font("Dialog", java.awt.Font.BOLD, 11)); checkGroupLabel.setForeground(java.awt.Color.darkGray); brazoIzqCB.setForeground(java.awt.Color.darkGray); brazoDerCB.setForeground(java.awt.Color.darkGray); cabezaNoCB.setForeground(java.awt.Color.darkGray); cabezaSiCB.setForeground(java.awt.Color.darkGray);

// Creacion de Joystick // anchura y altura w = getSize().width - getSize().width/2; h = getSize().height - getSize().height/2; // profundidad p = (int)(Math.min(w,h)*0.05); // diametro de la bolita d = (int)(Math.min(w,h)*0.35); // ancho del palito s = d/3; // centro xc = (w-p)/2; yc = (h-p)/2; // altura de la bolita H = p*2; // centro xc2 = xc-H; yc2 = yc-H; // radio de accion L = Math.min(w,h)/2-d/2-H-p; // iniciar movimiento de la bolita xb = xc-H; yb = yc-H;

68

f = new PlayField(w,h) { public void paintPlayField(Graphics g) { // Zona de joystick g.setColor(Color.white); g.fillRect(0,0,w,h); // caja g.setColor(new Color(204,204,204)); g.fillRect(0+w/4,0+h/4,w-p-w/2,h-p-h/2); g.setColor(new Color(102,102,102)); int tx1[] = {w-p-w/4,w-w/4,w-w/4,w-p-w/4}; int ty1[] = {0+h/4,p+h/4,h-h/4,h-p-h/4}; g.fillPolygon(tx1, ty1, 4); g.setColor(new Color(153,153,153)); int tx2[] = {0+w/4,w-p-w/4,w-w/4,p+w/4}; int ty2[] = {h-p-h/4,h-p-h/4,h-h/4,h-h/4}; g.fillPolygon(tx2, ty2, 4); // palito g.setColor(new Color(102,102,102)); g.fillOval(xc-s/2,yc-s/2,s,s); drawThickLine(g, xc, yc, xb, yb, s); // bolita g.setColor(new Color(99,174,203)); g.fillOval(xb-d/2,yb-d/2,d,d); // efecto de 3D de bolita g.setColor(Color.white); g.fillOval(xb-d/4,yb-d/4,d/6,d/6); } }; f.setSleepTime(1000/25); f.setDisplayManager(null); f.addMouseListener(this); f.addMouseMotionListener(this); //Area de Joystick cp.add(f); f.setBounds(27, 68, 184, 144); avisos.setText("Establezca IP y Puerto..."); avisos.setForeground(Color.black); f.setEnabled(false); }

public void start() { f.setPause(false); } public void stop() { f.stop(); } public void mouseClicked(MouseEvent e) { //System.out.println("Mouse clicked"); enviaMovimiento(e.getX(),e.getY()); }

69

public void mouseEntered(MouseEvent e) { avisos.setText("Listo..."); //System.out.println("Mouse entra"); //showStatus(getAppletInfo()); } public void mouseExited(MouseEvent e) { //System.out.println("Mouse sale"); //showStatus(""); } public String getAppletInfo() { return "Control Remoto"; } public void mousePressed(MouseEvent e) { //System.out.println("Mouse Presionado y moviendo bola"); mueveBola(e.getX(),e.getY()); //enviaMovimiento(e.getX(),e.getY()); } void mueveBola(int nx, int ny) { xb = nx; yb = ny; // xb y yb estan en un cuadrado LxL if (xb > xc2+L) xb = xc2+L; else if (xb < xc2-L) xb = xc2-L; if (yb > yc2+L) yb = yc2+L; else if (yb < yc2-L) yb = yc2-L; f.repaint(); } public void mouseReleased(MouseEvent e) { //System.out.println("Mouse liberado y moviendo bola"); mueveBola(xc2,yc2); } public void mouseDragged(MouseEvent e) { //System.out.println("Mouse arrastrado y mover bola"); enviaMovimiento(e.getX(),e.getY()); mueveBola(e.getX(),e.getY()); } public void mouseMoved(MouseEvent e) { //System.out.println("Mouse movido"); // Nada... } /** * Referencias: Real's HowTo, http://www.rgagnon.com/ */ public void drawThickLine(Graphics g, int x1, int y1, int x2, int y2, int paloLong) { // Linea (es un poligono) int dX = x2 - x1; int dY = y2 - y1;

70

// longitud de la linea double longitud = Math.sqrt(dX * dX + dY * dY); double escala = (double)(paloLong) / (2 * longitud); // X y double double ddx += ddy += int dx int dy Y se incrementan... ddx = -escala * (double)dY; ddy = escala * (double)dX; (ddx > 0) ? 0.5 : -0.5; (ddy > 0) ? 0.5 : -0.5; = (int)ddx; = (int)ddy;

// Puntos en las esquinas... int xPoints[] = new int[4]; int yPoints[] = new int[4]; xPoints[0] xPoints[1] xPoints[2] xPoints[3] = = = = x1 x1 x2 x2 + + dx; dx; dx; dx; yPoints[0] yPoints[1] yPoints[2] yPoints[3] = = = = y1 y1 y2 y2 + + dy; dy; dy; dy;

g.fillPolygon(xPoints, yPoints, 4); } public static void main(String[] args) { LanzadorDeApplet.run(new Joystick(), 385, 330, "Robot - Control Remoto"); } }

71

/* * Archivo LanzadorDeApplet.java Creado: 19 de Junio de 2005 * * Clase que agrega un applet a un Frame para poder visualizarlo * sin navegador y desde la linea de comandos * */ package cliente; /** * @author * @author * @author * @author * @author * * @author * @author * */

Ignacio Andrs Snchez Enrique Crisstomo Bravo Ana Lilia Ortega Torres Ivn Olaf Vivas Trejo Erik Torres Ramrez - Responsable de Proyecto: M. en C. Omar Cabrera UAM - Iztapalapa

import javax.swing.*; import java.awt.event.*; import java.applet.*; public class LanzadorDeApplet { static JFrame frame = null; public static void setupClosing(JFrame frame) { frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); } public static void run(Applet applet, int width, int height, String mensaje) { frame = new JFrame(mensaje); setupClosing(frame); frame.getContentPane().add(applet); frame.setSize(width, height); frame.setVisible(true); applet.init(); applet.start(); } public static void cerrar(){ frame.dispose(); } }

72

A.2. Programa Monitor


/* package principal; import import import import javax.swing.*; java.awt.*; java.awt.event.*; javax.swing.border.*; Archivo: VentanaDeMonitoreo.java */

public class VentanaDeMonitoreo extends JApplet { private JLabel ptoLabel = new JLabel(); private JLabel titulo = new JLabel("Informacin del Servidor:"); public JTextField ptoTextField = new JTextField(); private JLabel avisos = new JLabel(); String nueva_linea = ""; // cadena que recibe informacion en tiempo real int i = 0; JButton conectarBtn = new JButton("Iniciar"), limpiarBtn = new JButton("Limpiar"), salirBtn = new JButton("Salir"); public JTextArea txtArea = new JTextArea("", 10, 10); JScrollPane scPanel = new JScrollPane(txtArea, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); //Iniciar class B1L implements ActionListener { public void actionPerformed(ActionEvent e) { //new HiloM(ptoTextField, txtArea); //* HiloM hilito = new HiloM(ptoTextField, txtArea); //hilito.run(); //hilito.setDaemon(true); //hilito.run(); //*/ conectarBtn.setToolTipText("El servidor ya esta habilitado"); ptoTextField.disable(); conectarBtn.disable(); conectarBtn.setEnabled(false); } } //Limpiar class B2L implements ActionListener { public void actionPerformed(ActionEvent e) { nueva_linea = null; txtArea.setText("Servicio de Monitoreo"); avisos.setForeground(Color.blue); avisos.setText("Listo..."); } }

73

public void init() { Container cp = getContentPane(); cp.setLayout(null); Border brd = BorderFactory.createMatteBorder(1, 1, 1, 1, Color.black); scPanel.setBorder(brd); cp.add(ptoLabel); ptoLabel.setBounds(180, 30, 40, 20); ptoLabel.setText("Puerto:"); ptoLabel.setFont(new java.awt.Font("Dialog", java.awt.Font.BOLD, 11)); cp.add(ptoTextField); ptoTextField.setBounds(230, 25, 50, 25); ptoTextField.setText("8080"); cp.add(titulo); titulo.setBounds(35, 60, 170, 15); titulo.setFont(new java.awt.Font("Dialog", java.awt.Font.BOLD, 11)); cp.add(avisos); avisos.setBounds(35, 300, 170, 15); avisos.setText("Listo..."); avisos.setForeground(Color.red); avisos.setFont(new java.awt.Font("Dialog", java.awt.Font.ITALIC, 10)); conectarBtn.addActionListener(new B1L()); cp.add(conectarBtn); conectarBtn.setBounds(307, 25, 90, 25); conectarBtn.setToolTipText("Iniciar Monitor"); limpiarBtn.addActionListener(new B2L()); cp.add(limpiarBtn); limpiarBtn.setBounds(90, 270, 90, 25); limpiarBtn.setToolTipText("Limpiar Area de Texto"); cp.add(salirBtn); salirBtn.setBounds(250, 270, 90, 25); salirBtn.setToolTipText("Haga click si desea terminar"); salirBtn.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { stop(); destroy(); LanzadorDeApplet.cerrar(); } });

cp.add(scPanel); scPanel.setBounds(32, 90, 365, 160); //txtArea.setText(""); txtArea.setFont(new java.awt.Font("Dialog", java.awt.Font.PLAIN, 11)); txtArea.setEditable(false); } public static void main(String[] args) { LanzadorDeApplet.run(new VentanaDeMonitoreo(), 440, 360,"SERVICIO DE MONITOREO REMOTO"); } }

74

/* package principal; import import import import import import import java.io.BufferedReader; java.io.IOException; java.io.InputStreamReader; java.net.ServerSocket; java.net.Socket; javax.swing.JTextArea; javax.swing.JTextField;

Archivo: HiloM.java

*/

class HiloM extends Thread{ String valor = ""; JTextArea myArea; public HiloM(JTextField puerto,JTextArea area) { valor = puerto.getText(); myArea = area; setDaemon(true); start(); } public void run() { String textCache = "Bienvenido al servicio de Monitoreo"; textCache = "Servicio de Monitoreo Iniciado"; try { ServerSocket serverSocket = new ServerSocket(Integer.valueOf(valor).intValue()); myArea.setText(textCache); while(true){ Socket incoming = serverSocket.accept(); try { BufferedReader in = new BufferedReader( new InputStreamReader( incoming.getInputStream() )); //Lee por el socket String newline = in.readLine(); textCache = textCache + "\n" +newline; //concatena con nueva linea myArea.setText(textCache); myArea.setCaretPosition(myArea.getDocument().getLength()); int idealSize = 5000; int maxExcess = 3000; int excess = myArea.getDocument().getLength() - idealSize; if (excess >= maxExcess) { myArea.replaceRange("", 0, excess); } System.out.println(newline); } catch(Exception exc) { System.out.println("Error en la conexion"); } yield(); } } catch (NumberFormatException e) { e.printStackTrace(); } catch (IOException e) { } } }

75

/* * Archivo LanzadorDeApplet.java Creado: 15 de Julio, 2005 * * Clase que agrega un applet a un Frame para poder visualizarlo * sin navegador y desde la linea de comandos * */ package principal; /** * @author Ignacio Andrs Snchez * @author Ana Lilia Ortega Torres */ import javax.swing.*; import java.awt.event.*; import java.applet.*; public class LanzadorDeApplet { static JFrame frame = null; public static void setupClosing(JFrame frame) { frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); } public static void run(Applet applet, int width, int height, String mensajeTitulo) { frame = new JFrame(mensajeTitulo); setupClosing(frame); frame.getContentPane().add(applet); frame.setSize(width, height); applet.init(); applet.start(); frame.setVisible(true); } public static void cerrar(){ frame.dispose(); } }

76

A.3. Programa Controlador


/* Archivo: VentanaControlador.java */

package servidor; import java.awt.Color; import java.awt.Container; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.BorderFactory; import javax.swing.JApplet; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.border.Border; public class VentanaControlador extends JApplet { private JLabel ptoLabel = new JLabel(); private JLabel pto2Label = new JLabel(); private JLabel ipLabel = new JLabel(); private JLabel titulo = new JLabel("Informacin de control:"); public JTextField ptoTextField = new JTextField(); public JTextField pto2TextField = new JTextField(); public JTextField ipTextField = new JTextField(); private JLabel avisos = new JLabel(); String nueva_linea = ""; // cadena que recibe informacion en tiempo real int i = 0; JButton conectarBtn = new JButton("Iniciar"), limpiarBtn = new JButton("Limpiar"), salirBtn = new JButton("Salir"); public JTextArea txtArea = new JTextArea("", 10, 10); JScrollPane scPanel = new JScrollPane(txtArea, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); //Iniciar class B1L implements ActionListener { public void actionPerformed(ActionEvent e) { Controlador oDemonio = new Controlador(ipTextField,ptoTextField,pto2TextField, txtArea); ptoTextField.setEnabled(false); pto2TextField.setEnabled(false); ipTextField.setEnabled(false); conectarBtn.setEnabled(false); conectarBtn.setToolTipText("Servidor listo"); } } //Limpiar class B2L implements ActionListener { public void actionPerformed(ActionEvent e) { nueva_linea = null; txtArea.setText(""); avisos.setForeground(Color.blue); avisos.setText("Listo..."); } }

77

public void init() { Container cp = getContentPane(); cp.setLayout(null); Border brd = BorderFactory.createMatteBorder(1, 1, 1, 1, Color.black); scPanel.setBorder(brd); cp.add(ptoLabel); ptoLabel.setBounds(32, 28, 120, 20); ptoLabel.setText("Puerto de Monitoreo:"); ptoLabel.setFont(new java.awt.Font("Dialog", java.awt.Font.BOLD, 11)); cp.add(pto2Label); pto2Label.setBounds(240, 28, 120, 20); pto2Label.setText("Puerto de Joystick:"); pto2Label.setFont(new java.awt.Font("Dialog", java.awt.Font.BOLD, 11)); cp.add(ptoTextField); ptoTextField.setBounds(160, 25, 45, 25); ptoTextField.setText("8080"); cp.add(pto2TextField); pto2TextField.setBounds(356, 25, 45, 25); pto2TextField.setText("8086"); cp.add(ipLabel); ipLabel.setBounds(32, 68, 65, 20); ipLabel.setText("IP cliente:"); ipLabel.setFont(new java.awt.Font("Dialog", java.awt.Font.BOLD, 11)); cp.add(ipTextField); ipTextField.setBounds(95, 65, 135, 25); ipTextField.setText(""); conectarBtn.addActionListener(new B1L()); cp.add(conectarBtn); conectarBtn.setBounds(265, 65, 100, 25); conectarBtn.setToolTipText("Iniciar Servicio"); cp.add(titulo); titulo.setBounds(35, 105, 170, 15); titulo.setFont(new java.awt.Font("Dialog", java.awt.Font.BOLD, 11)); cp.add(avisos); avisos.setBounds(35, 310, 170, 15); avisos.setText("Listo..."); avisos.setForeground(Color.red); avisos.setFont(new java.awt.Font("Dialog", java.awt.Font.ITALIC, 10)); limpiarBtn.addActionListener(new B2L()); cp.add(limpiarBtn); limpiarBtn.setBounds(80, 280, 100, 25); limpiarBtn.setToolTipText("Limpiar Area de Informacin de Control"); cp.add(salirBtn); salirBtn.setBounds(265, 280, 100, 25); salirBtn.setToolTipText("Haga click si desea terminar la aplicacin"); salirBtn.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { stop(); destroy(); LanzadorDeApplet.cerrar(); } });

78

cp.add(scPanel); scPanel.setBounds(32, 130, 370, 130); txtArea.setFont(new java.awt.Font("Dialog", java.awt.Font.PLAIN, 11)); txtArea.setEditable(false); } public static void main(String[] args) { LanzadorDeApplet.run(new VentanaControlador(), 440, 365); } }

/*

Archivo : Controlador.java

*/

package servidor; import import import import import import java.net.*; parport.ParallelPort; java.io.*; javax.swing.JTextArea; javax.swing.JTextField; coordinador.tareas.extras.*;

public class Controlador extends Thread { public static String dirIPCliente = ""; public static String puerto2 = "8080";//Pto de monitor public static boolean hayComunicacion = true; public static int valor; JTextArea myArea;

public Controlador(JTextField ip,JTextField ptoM,JTextField ptoJ,JTextArea area) { dirIPCliente = ip.getText(); puerto2 = ptoM.getText(); valor = Integer.valueOf(ptoJ.getText()).intValue(); myArea = area; setDaemon(true); start(); }

private static void lanza(String sentencia) //sentencia { LanzadorDOS lanzador = new LanzadorDOS(sentencia); } public void run() { ServerSocket serverSocket = null; try { serverSocket = new ServerSocket(valor); myArea.setText("Servidor atendiendo peticiones..." + "\n"); ParallelPort lpt1 = new ParallelPort(0x378); Socket incoming = serverSocket.accept();//bajar? char [] arreglo = {'0','0','0','0','0','0','0','0'}; int valorDeSalida, i,j,potencia;

79

while(true)

try { BufferedReader lectorBufferDeEntrada = new BufferedReader(new InputStreamReader(incoming.getInputStream())); PrintWriter escritorDeSalida = new PrintWriter(incoming.getOutputStream(), true); //Lee el comando por el socket String comando = lectorBufferDeEntrada.readLine(); if(comando == null) { myArea.append("Esperando Conexion..." + "\n"); incoming = serverSocket.accept(); } else { myArea.append("Comando recibido: " +comando + "\n"); if(comando.startsWith("#l")==true) { comando.getChars(5,13,arreglo,0); valorDeSalida = 0; for(i=0;i<8;i++){ // Se calcula el entero que corresponde a cadena potencia = 1; for(j=0;j<i;j++){ potencia = potencia * 2; } //la cadena original contiene la subcadena de bits a enviar al if(comando.charAt(i+5)=='1'){ //puerto a partir de la posicion 5 valorDeSalida = valorDeSalida | potencia; } } lpt1.write(valorDeSalida); // escribe byte al puerto paralelo myArea.append("Escritura en el Puerto Paralelo: " + valorDeSalida + "\n"); } else { //Se lanza el programa que corre en DOS con sus parametros lanza(comando); } } // Se posiciona al final de el area de texto: myArea.setCaretPosition(myArea.getDocument().getLength()); // limita el tamano del texto int idealSize = 5000; int maxExcess = 3000; int excess = myArea.getDocument().getLength() - idealSize; if (excess >= maxExcess) { myArea.replaceRange("", 0, excess); } } catch(Exception exc) {System.out.println("Error! - " + exc.toString()); } } } catch(Exception exc) {System.out.println("El Numero de Puerto No fue ingresado correctamente!");} } }

80

/* package servidor; import java.net.*; import java.io.*; public class Transmisor { Socket socket; PrintWriter writer;

Archivo: Transmisor.java

*/

public Transmisor(String dir_ip, String puerto, String cadena) { boolean exito = true; try { socket = new Socket(dir_ip, Integer.valueOf(puerto).intValue()); writer = new PrintWriter(socket.getOutputStream(), true); try { writer.println(cadena); } catch (Exception exc) { System.out.println("Error! No se pueden enviar datos"); Controlador.hayComunicacion = false; } try { socket.close(); } catch (Exception exc) { System.out.println("No se cerro la comunicacion de manera normal"); } } catch (Exception exc) { System.out.println("Aun no existe Monitor disponible en la direccion y puerto especificados!"); Controlador.hayComunicacion = false; } } }

81

/* * Archivo LanzadorDeApplet.java Creado: 19 de Junio de 2005 * * Clase que agrega un applet a un Frame para poder visualizarlo * sin navegador y desde la linea de comandos * */ package cliente; /** * @author * @author * @author * @author * @author * * @author * @author * */

Ignacio Andrs Snchez Enrique Crisstomo Bravo Ana Lilia Ortega Torres Ivn Olaf Vivas Trejo Erik Torres Ramrez - Responsable de Proyecto: M. en C. Omar Cabrera UAM - Iztapalapa

import javax.swing.*; import java.awt.event.*; import java.applet.*; public class LanzadorDeApplet { static JFrame frame = null; public static void setupClosing(JFrame frame) { frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); } public static void run(Applet applet, int width, int height) { frame = new JFrame("CONTROLADOR DEL ROBOT"); setupClosing(frame); frame.getContentPane().add(applet); frame.setSize(width, height); applet.init(); applet.start(); frame.setVisible(true); } public static void cerrar(){ frame.dispose(); } }

82

/*

Archivo: ParallelPort.java

*/

package parport; public class ParallelPort { /** The port base address (e.g. 0x378 is base address for LPT1) */ private int portBase; /** To cunstruct a ParallelPort object, * you need the port base address */ public ParallelPort (int portBase) { this.portBase = portBase; } /** Reads one byte from the STATUS pins of the parallel port. * * The byte read contains 5 valid bits, corresponing to 5 pins of input * from the STATUS pins of the parallel port (the STATUS is located * at "portBase + 1", e.g. the STATUS address for LPT1 is 0x379). * * This diagram shows the content of the byte: * * Bit | Pin # | Printer Status | Inverted * -----+-------+-----------------+----------* 7 | ~11 | Busy | Yes * 6 | 10 | Acknowledge | * 5 | 12 | Out of paper | * 4 | 13 | Selected | * 3 | 15 | I/O error | * * Note that Pin 11 is inverted, this means that "Hi" input on pin * means 0 on bit 7, "Low" input on pin means 1 on bit 7. */ public int read () { return ParallelPort.readOneByte (this.portBase+1); } /** * * * * * * * * * * * * * * * * */ Writes one byte to the DATA pins of parallel port. The byte is written to the DATA pins of the port. The DATA pins are located at the base address of the port (e.g. DATA address for LPT1 is 0x378). This diagram shows how the byte is written: Bit | Pin # | Printer DATA -----+-------+-------------7 | 9 | DATA 7 6 | 8 | DATA 6 5 | 7 | DATA 5 4 | 6 | DATA 4 3 | 5 | DATA 3 2 | 4 | DATA 2 1 | 3 | DATA 1 0 | 2 | DATA 0

83

public void write (int oneByte) { ParallelPort.writeOneByte (this.portBase, oneByte); } /** Reads one byte from the specified address. * (normally the address is the STATUS pins of the port) */ public static native int readOneByte (int address); /** Writes one byte to the specified address * (normally the address is the DATA pins of the port) */ public static native void writeOneByte (int address, int oneByte); static { System.loadLibrary("parport"); } }

/*

Archivo: HiloMensajero.java

*/

package coordinador.tareas.extras; import java.io.*; import servidor.Controlador; import servidor.Transmisor; public class HiloMensajero extends Thread{ InputStream is; String type; HiloMensajero(InputStream is, String type) { this.is = is; this.type = type; } public void run() { try { InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); String line=null; while ( (line = br.readLine()) != null){ System.out.println(type + ">" + line); Transmisor s = new Transmisor(Controlador.dirIPCliente,Controlador.puerto2,type + ">" + line); } } catch (IOException ioe) { ioe.printStackTrace(); } } }

84

/*

Archivo LanzadorDOS.java

*/

package coordinador.tareas.extras; public class LanzadorDOS { public LanzadorDOS(String programaXLanzar) { //programaXLanzar (incluir parametros) entre comillas // El programa DOS a lanzar no debe esperar interaccion try { String sistemaOperativo = System.getProperty("os.name" ); String[] sentencia = new String[3]; //Para ver nombre de OS donde se ejecuta //System.out.println(sistemaOperativo); if( sistemaOperativo.equals( "Windows 95" )|| sistemaOperativo.equals( "Windows 98" )||sistemaOperativo.equals( "Windows Me" )) { sentencia[0] = "command.com" ; sentencia[1] = "/C" ; sentencia[2] = programaXLanzar; } else if(sistemaOperativo.equals( "Windows NT" )|| sistemaOperativo.equals( "Windows XP" )||sistemaOperativo.equals( "Windows 2000" ))// Win XP, NT y 2000 { sentencia[0] = "cmd.exe" ; sentencia[1] = "/C" ; sentencia[2] = programaXLanzar; } else { System.out.println("Sistema Operativo No Soportado "); System.exit(1); }

Runtime rt = Runtime.getRuntime(); System.out.println("Ejecutando " + sentencia[0] + " " + sentencia[1] + " " + sentencia[2]); Process proc = rt.exec(sentencia);// // Hilo para manejar algun mensaje de error y reportarlo al cliente HiloMensajero hiloDeError = new HiloMensajero(proc.getErrorStream(), "ERROR"); // Hilo para manejar la salida y reportarla al cliente HiloMensajero hiloDeSalidas = new HiloMensajero(proc.getInputStream(), "..\\"); // Se encargan de lo indicado hiloDeError.start(); hiloDeSalidas.start(); // Valor de retorno de llamada al programa MS-DOS int valorSalida = proc.waitFor(); System.out.println("Valor De Retorno: " + valorSalida); } catch (Throwable t) { t.printStackTrace(); } } }

85

A.4. Programa Sensor


/* package servidor; import import import import javax.swing.*; java.awt.*; java.awt.event.*; javax.swing.border.*; Archivo: VentanaSensor.java */

public class VentanaSensor extends JApplet { private JLabel private JLabel private JLabel tituloPrincipal = new JLabel(); ptoLabel = new JLabel(); ipLabel = new JLabel();

private JLabel titulo = new JLabel("Informacin del SENSOR:"); public JTextField ptoTextField = new JTextField(); public JTextField ipTextField = new JTextField(); private JLabel avisos = new JLabel(); String nueva_linea = ""; // cadena que recibe informacion en tiempo real int i = 0; JButton conectarBtn = new JButton("Iniciar"), limpiarBtn = new JButton("Limpiar"), salirBtn = new JButton("Salir"); public JTextArea txtArea = new JTextArea("", 10, 10); JScrollPane scPanel = new JScrollPane(txtArea, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); //Iniciar class B1L implements ActionListener { public void actionPerformed(ActionEvent e) { LectorLPT1 oSensor = new LectorLPT1(ipTextField,ptoTextField, txtArea); ptoTextField.setEnabled(false); ipTextField.setEnabled(false); conectarBtn.setEnabled(false); conectarBtn.setToolTipText("SENSOR FUNCIONANDO"); } } //Limpiar class B2L implements ActionListener { public void actionPerformed(ActionEvent e) { nueva_linea = null; txtArea.setText("Servicio de SENSOR"); avisos.setForeground(Color.blue); avisos.setText("Listo..."); } } public void init() { Container cp = getContentPane(); cp.setLayout(null); Border brd = BorderFactory.createMatteBorder(1, 1, 1, 1, Color.black); scPanel.setBorder(brd);

86

cp.add(ipLabel); ipLabel.setBounds(32, 30, 60, 20); ipLabel.setText("IP cliente:"); ipLabel.setFont(new java.awt.Font("Dialog", java.awt.Font.BOLD, 11)); cp.add(ipTextField); ipTextField.setBounds(90, 25, 99, 25); ipTextField.setText(""); cp.add(ptoLabel); ptoLabel.setBounds(202, 30, 50, 20); ptoLabel.setText("Puerto:"); ptoLabel.setFont(new java.awt.Font("Dialog", java.awt.Font.BOLD, 11)); cp.add(ptoTextField); ptoTextField.setBounds(247, 25, 52, 25); ptoTextField.setText("8080"); conectarBtn.addActionListener(new B1L()); cp.add(conectarBtn); conectarBtn.setBounds(320, 25, 90, 25); conectarBtn.setToolTipText("Iniciar SENSOR");

cp.add(titulo); titulo.setBounds(35, 70, 170, 15); titulo.setFont(new java.awt.Font("Dialog", java.awt.Font.BOLD, 11)); cp.add(avisos); avisos.setBounds(35, 300, 170, 15); avisos.setText("Listo..."); avisos.setForeground(Color.red); avisos.setFont(new java.awt.Font("Dialog", java.awt.Font.ITALIC, 10)); limpiarBtn.addActionListener(new B2L()); cp.add(limpiarBtn); limpiarBtn.setBounds(90, 280, 90, 25); limpiarBtn.setToolTipText("Limpiar Area de Texto"); cp.add(salirBtn); salirBtn.setBounds(260, 280, 90, 25); salirBtn.setToolTipText("Haga click si desea terminar"); salirBtn.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { stop(); destroy(); LanzadorDeApplet.cerrar(); } });

cp.add(scPanel); scPanel.setBounds(32, 95, 385, 160); txtArea.setFont(new java.awt.Font("Dialog", java.awt.Font.PLAIN, 11)); txtArea.setEditable(false); } public static void main(String[] args) { LanzadorDeApplet.run(new VentanaSensor(), 450, 365,"LECTURA EN PUERTO PARALELO"); } }

87

/* package servidor; import javax.swing.JTextArea; import javax.swing.JTextField; import parport.ParallelPort; import servidor.Transmisor;

Archivo: LectorLPT1.java

*/

class LectorLPT1 extends Thread{ String dirIPCliente; String puerto2; JTextArea myArea; public LectorLPT1(JTextField dirIPc, JTextField pto,JTextArea area) { dirIPCliente = dirIPc.getText(); puerto2 = pto.getText(); //Puerto de Monitoreo default = 8080 myArea = area; setDaemon(true); start(); } public void run() { try { ParallelPort lpt1 = new ParallelPort(0x378); // Direccion Base = 378, // PtoControl = 378h+2 = 37Ah try { Transmisor z = new Transmisor(dirIPCliente,puerto2,"Se habilito escritura para Sensores del Robot"); } catch(Exception exc) {System.out.println("Error! - " + exc.toString()); } int valorLeido = 0; int valorAnterior; String textCache = "Servicio de Sensor en Puerto Paralelo"; while(true) { valorAnterior = valorLeido; valorLeido = lpt1.read(); if(valorLeido != valorAnterior) { System.out.println("Valor de codigo de Sensores leido: " +valorLeido +"\n"); Transmisor s = new Transmisor(dirIPCliente,puerto2,"Status = " + valorLeido); } textCache = textCache +"Valor de lectura:" +valorLeido +"\n"; //concatena myArea.setText(textCache); //posiciona al final de JTextArea: myArea.setCaretPosition(myArea.getDocument().getLength()); // restringe el tamano del texto int idealSize = 3000; int maxExcess = 2000; int excess = myArea.getDocument().getLength() - idealSize; if (excess >= maxExcess) { myArea.replaceRange("", 0, excess); } Thread.sleep(1000);//El muestreo ocurre cada 1 segundo yield(); }//fin de ciclo while infinito } catch(Exception exc) {System.out.println("Error!");} System.out.println("Programa Terminado"); } }

88

/* package servidor; import java.net.*; import java.io.*;

Archivo: Transmisor.java

*/

public class Transmisor { Socket socket; PrintWriter writer;

public Transmisor(String dir_ip, String puerto, String cadena) { boolean exito = true; try { socket = new Socket(dir_ip, Integer.valueOf(puerto).intValue()); writer = new PrintWriter(socket.getOutputStream(), true); try { writer.println(cadena); } catch (Exception exc) { System.out.println("Error! No se pueden enviar datos"); } try { socket.close(); } catch (Exception exc) { System.out.println("No se cerro la comunicacion de manera normal"); } } catch (Exception exc) { System.out.println("No existe Monitor o Falta indicar IP como Parametro"); } } }

89

/* * Archivo LanzadorDeApplet.java * Clase que agrega un applet a un Frame para poder visualizarlo * sin navegador y desde la linea de comandos * */ package servidor; import javax.swing.*; import java.awt.event.*; import java.applet.*; public class LanzadorDeApplet { static JFrame frame = null; public static void setupClosing(JFrame frame) { frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); } public static void run(Applet applet, int width, int height, String mensaje) { frame = new JFrame(mensaje); setupClosing(frame); frame.getContentPane().add(applet); frame.setSize(width, height); applet.init(); applet.start(); frame.setVisible(true); } public static void cerrar(){ frame.dispose(); } }

/* package parport; public class ParallelPort {

Archivo: ParalellPort.java

*/

/** La direccion base del puerto (e.g. 0x378 es la direccion base para LPT1) */ private int portBase;

/** Para construir un objeto de la clase ParallelPort, * se necesita la direccion base del puerto */ public ParallelPort (int portBase) { this.portBase = portBase; } /** * * * * * Lee un byte de los pines del registro de ESTADO del puerto paralelo. El byte leido contiene 5 bits validos, que corresponden a los 5 bits de entrada del registro de ESTADO del puerto paralelo (El registro de ESTADO se encuentra en "portBase + 1", e.g. la direccion del registro de ESTADO para LPT1 es 0x379).

90

* * * * * * * * * * * * * */

La siguiente tabla muestra el contenido del byte: Bit | Pin # | Estado de impresora | Invertido -----+-------+----------------------+----------7 | ~11 | Busy | Si 6 | 10 | Acknowledge | 5 | 12 | Out of paper | 4 | 13 | Selected | 3 | 15 | I/O error | Note que el Pin 11 esta invertido, esto significa que una entrada "Alto" en el pin es un 0 en el bit 7 y una entrada "Bajo" significa 1 en bit 7

public int read () { return ParallelPort.readOneByte (this.portBase+1); }

/** * * * * * * * * * * * * * * * * */

Escribe un byte al registro de DATOS del puerto paralelo. El byte es escrito a los pines de DATOS del puerto. Los pines de datos se localizan en la direccion base del puerto (e.g. La direccion del registro de DATOS para LPT1 es 0x378). La siguiente tabla muestra como es escrito el byte Bit | Pin # | DATOS de impresora -----+-------+-------------7 | 9 | DATA 7 6 | 8 | DATA 6 5 | 7 | DATA 5 4 | 6 | DATA 4 3 | 5 | DATA 3 2 | 4 | DATA 2 1 | 3 | DATA 1 0 | 2 | DATA 0

public void write (int oneByte) { ParallelPort.writeOneByte (this.portBase, oneByte); } /** Lee un byte de la direccion especificada. * (normalmente la direccion es el registro de ESTADO del puerto) */ public static native int readOneByte (int address); /** Escribe un byte a la direccion especificada * (normalmente la direccion es el registro de DATOS del puerto) */ public static native void writeOneByte (int address, int oneByte); static { System.loadLibrary("parport"); }

91

92

Potrebbero piacerti anche