Download diseño y realización de un sistema on board diagnostics (obd-ii)
Document related concepts
no text concepts found
Transcript
DISEÑO Y REALIZACIÓN DE UN SISTEMA ON BOARD DIAGNOSTICS (OBD-II) ALUMNO: OSCAR RAYO MANSILLA DIRECTOR: JORDI SELLARÈS GONZÁLEZ 4 DE JUNIO DE 2009 2 ÍNDICE 1. Introducción 5 1.1. Justificación del proyecto…………………………………………5 1.2. Antecedentes…………………………………………………………..6 1.3. Objetivos………………………………………………………………..10 1.4. Alcance del proyecto………………………………………………11 1.5. Descripción general del proyecto……………………………12 1.5.1. Descripción básica del hardware……………..12 1.5.2. Descripción básica del software………….…..13 2. Diseños realizados 14 2.1. Metodología utilizada……………………………………………14 2.2. Recursos utilizados………………………………………………..16 2.3. Descripción del diseño del modem interface………….21 2.4. Descripción del diseño del programador JDM2…......25 2.5. Modificaciones del diseño del modem…………………..29 2.6. Diseño de la aplicación de prueba en C++………………37 2.7. Diseño de la aplicación de prueba en JAVA…………….40 2.8. Diseño de la aplicación gráfica diseñada en JAVA.....46 3 3. Resultados 52 3.1. Ámbito de utilización…………………………………………….52 3.2. Validación de los diseños……………………………………….52 3.3. Descripción del funcionamiento…………………………….54 3.4. Aplicaciones del proyecto………………………………………66 4. Comentarios finales 67 4.1. Plan de trabajo……………………………………………………………67 4.2. Lista de materiales………………………………………………………68 4.3. Presupuesto………………………………………………………………..70 4.4. Objetivos logrados………………………………………………………71 4.5. Conclusiones……………………………………………………………….71 4.6. Mejoras futuras…………………………………………………………..72 5. Bibliografía 73 6. Anexo 74 4 1. Introducción 1.1. Justificación del proyecto La motivación principal de este proyecto es llegar a poder diseñar un sistema con el que poder diagnosticar las posibles averías de cualquier vehículo sin tener que recurrir a los costosos servicios oficiales. Normalmente cuando se nos avería el coche siempre tenemos que acabar recurriendo a los talleres de reparación de los cuales dispone el fabricante de nuestro vehículo, y aunque desconocemos cuales son los medios de los que disponen para diagnosticar la avería, si sabemos que existe un herramienta que conectándola al vehículo averigua el problema al instante. Esto se debe a que estas marcas tan famosas equipan nuestros coches con sistemas electrónicos capaces de gestionar toda la mecánica y electricidad de que dispone, sin más ayuda que la de un modulo electrónico. En realidad estos módulos no son más que una pequeña computadora a la cual si se conoce su funcionamiento se puede acceder aunque su fabricante intente taparlo, cosa que no les es posible ya que desde hace ya bastantes años están obligados a implementar un estándar de autodiagnóstico llamado “OBD-II”, que se hizo público a consecuencia de las grandes emisiones contaminantes a las que estamos expuestos, implantando así un mecanismo de control de estas. Estos módulos son el objetivo de este proyecto, ya que en el momento que podamos comunicarnos con ellos podremos saber que le ocurre a nuestro coche y por tanto cuando tengamos que acudir al taller nosotros sabremos, en parte, si nos están estafando, cosa que lamentablemente a veces pasa. 5 1.2. Antecedentes OBD (On Board Diagnostics) es un sistema de diagnóstico a bordo en vehículos (coches y camiones). Actualmente se emplea OBD-II (Estados Unidos), EOBD (Europa), y JOBD (Japón) estándar que aportan un control casi completo del motor y otros dispositivos del vehículo. OBD II es la abreviatura de On Board Diagnostics (Diagnóstico de Abordo) II, la segunda generación de los requerimientos del equipamiento autodiagnosticable de abordo de los Estados Unidos de América. Las características de autodiagnóstico de a bordo están incorporadas en el hardware y el software de la computadora de abordo de un vehículo para monitorear prácticamente todos los componentes que pueden afectar las emisiones. Cada componente es monitoreado por una rutina de diagnóstico para verificar si está funcionando perfectamente. Si se detecta un problema o una falla, el sistema de OBD II ilumina una lámpara de advertencia en el cuadro de instrumentos para avisarle al conductor. La lámpara de advertencia normalmente lleva la inscripción "Check Engine" o "Service Engine Soon". El sistema también guarda informaciones importantes sobre la falla detectada para que un mecánico pueda encontrar y resolver el problema. En los Estados Unidos de América, todos los vehículos de pasajeros y los camiones de gasolina y combustibles alternos a partir de 1996 deben contar con sistemas de OBD II, al igual que todos los vehículos de pasajeros y camiones de diesel a partir de 1997, en Europa a partir del año 2001 se obliga implantar el estándar EOBD. Además, un pequeño número de vehículos de gas fueron equipados con sistemas de OBD II. Por tanto la pregunta ahora es, ¿qué fue OBD I? OBD I fue la primera regulación de OBD que obligaba a los productores a instalar un sistema de monitoreo de algunos de los componentes controladores de emisiones en automóviles. Obligatorios en todos los vehículos a partir de 1991, los sistemas de OBD I no eran tan efectivos porque solamente monitoreaban algunos de los componentes relacionados con las emisiones, y no eran calibrados para un nivel específico de emisiones. Y además, ¿qué es EOBD? EOBD es la abreviatura de European On Board Diagnostics (Diagnóstico de a Bordo Europeo), la variación europea de OBD II. Una de las diferencias es que no se monitorean las evaporaciones del depósito. Sin embargo, EOBD es un sistema mucho más sofisticado que OBD II ya que usa "mapas" de las entradas a 6 los sensores expectadas basados en las condiciones de operación del motor, y los componentes se adaptan al sistema calibrándose empíricamente. Esto significa que los repuestos necesitan ser de alta calidad y específicos para el vehículo y modelo. Todos los estándares antes mencionados implementan varios modos de trabajo, es decir, según la parte de información a la que queramos acceder necesitamos utilizar un modo diferente, dentro de cada uno de ellos podemos usar un abanico de parámetros muy amplio. Los modos de trabajo más extendidos son los siguientes: Modo 01: Se utiliza para determinar qué información del modulo electrónico (ECU) está a disposición de la herramienta de exploración. Modo 02: Muestra los llamados en este contexto “Freeze Frame Data”, es decir, capturas puntuales de información que ha ido almacenado la ECU. Modo 03: Lista los posibles fallos producidos en la mecánica mediante códigos de error identificativos (DTC). Modo 04: Se utiliza para borrar los códigos de error almacenados (DTC) y los datos “Freeze Frame Data”. Modo 05: Muestra los valores tomados a los sensores de oxigeno y los resultados de los test que les ha realizado de forma autónoma la ECU. Modo 06: Se usa para obtener los resultados de los test realizados por la ECU al sistema de monitoreo no continuo. Existe normalmente un valor mínimo, máximo y actual de cada uno de los test. Modo 07: Se usa para solicitar resultados al sistema de control permanente. Este modo lo suelen utilizar los técnicos después de una reparación del vehículo, y después de borrar la información de diagnóstico para ver los resultados de las pruebas después de un solo ciclo de conducción, determinando si la reparación ha solucionado el problema. Sólo hay tres monitores continuos identificados: combustible, fallo de encendido, e integridad de los componentes. En este proyecto solo se va ha hacer uso del modo 01, 03 y 04, aunque teniendo en cuenta que el modo 01 dispone de más de 60 PID’s diferentes, no es poco el trabajo a desarrollar. 7 Actualmente ya existen muchas herramientas y software disponible para poder llevar a cabo la inspección de un vehículo dotado de OBD-II. Existen muchos tipos de herramientas distintas, pero principalmente la gran diferencia entre ellas es si pueden o no trabajar de forma autónoma, es decir, si necesitan o no ser ejecutadas en un ordenador personal bajo un sistema operativo. Como ejemplo podemos encontrarnos el software llamado ScanMaster, el cual se puede utilizar de forma completa previo pago de una pequeña cantidad de dinero: 8 También podemos encontrar el software ScanTool.net, el cual ha sido de mucha utilidad para este proyecto ya que en una de sus versiones ofrece el código fuente con el que fue diseñado: Estos programas están diseñados para trabajar junto con el microcontrolador ELM327, es decir, necesitan de este elemento intermedio entre el PC y el vehículo. Existen en el mercado muchos modelos de interface disponibles en el mercado, pero todas se basan en este micro. A continuación podemos ver algunos ejemplos: Interface ELM327 9 Interface ELM327 Interface ELM327 con Bluetooth En las imágenes vemos que los modelos tienen diferentes formas y diferentes métodos de conexión, ya que en uno de los casos se realiza por “bluetooth”, pero su funcionamiento respecto al estándar OBD-II es idéntico. 1.3. Objetivos Este proyecto abarca una pequeña parte del complejo campo de la autodiagnosis en la automoción, y por tanto no pretende crear un sistema que pueda substituir a las avanzadas herramientas de las que dispone cualquier servicio de manteniendo, ya que el estándar OBD-II, aun siendo de libre acceso, comprende modos de trabajo de los cuales no se tiene información en este proyecto. Mucha de la documentación que engloba al OBD-II está disponible previo pago a las respectivas empresas que lo han diseñado y estandarizado, como es el caso de la Sociedad Americana de Ingenieros (SAE) o la Organización Internacional para la Estandarización (ISO). Aun no disponiendo de toda la información deseada los objetivos de este proyecto son bastante ambiciosos y se pueden listar como sigue: Conseguir una comunicación estable con cualquier centralita electrónica (ECU) de cualquier vehículo equipado con OBD-II. Conseguir desarrollar una aplicación portable a cualquier sistema operativo y plataforma utilizando lenguaje JAVA y la estructura de programación “por capas”. 10 Realizar mejoras en el hardware ya existente en el mercado a partir del cual se construirá nuestra interface. Demostrar que con la información disponible en la red, es posible acceder a los sistemas de control que implementan los fabricantes de automóviles en sus vehículos. 1.4. Alcance del proyecto El alcance de este proyecto incluye la creación de un sistema que implementa una parte de las grandes posibilidades que ofrece el OBD-II, pudiéndose usar como una herramienta orientativa a la hora de diagnosticar una posible avería. Este sistema utiliza por un lado un modem interface que adecua las señales procedentes de la centralita electrónica que se encuentra en el vehículo (ECU), a las señales que necesita un puerto USB de cualquier ordenador. A partir de aquí, un software de control gestionara toda la información recibida. Muchos de los métodos de diagnostico existentes utilizan este planteamiento pero ninguno de ellos, por lo menos oficialmente, utiliza una aplicación desarrollada en JAVA que, por lo tanto, permita ejecutarse en la mayoría de los sistemas operativos existentes, incluyendo el famoso Linux y además en diferentes tipos de plataformas. Para desarrollar el hardware se utilizaran diseños de interfaces ya existentes a partir de los cuales se creará la que se utilizara en este proyecto, es decir, se recapitularan los esquemas eléctricos de los que se dispongan y sobre el PCB elegido se añadirán las posibles mejoras que pudieran aportar otros diseños. Esta parte del trabajo también conlleva la construcción y puesta en marcha de un programador de microcontroladores, necesario para implementar el firmware a partir del cual el micro utilizado en la interface funcionará. Po otro lado el software ha desarrollar tiene un papel igual o más importante, ya que para conseguir diseñar la aplicación de control sobre el modem interface, se necesitan realizar los primeros programas de prueba que servirán para constatar las bases del funcionamiento de la última y definitiva aplicación que interactuará con el modem. Este último programa constará de diferentes apartados y opciones en un entorno visual que mostrará los resultados de una forma fácilmente comprensible dejando así todo el proceso de cálculo en segundo plano. 11 1.5. Descripción general del proyecto En este proyecto como se ha ido comentado a lo largo de este documento se pretende elaborar un sistema capaz de comunicarse con la electrónica que gestiona cualquiera de los vehículos dotados con el estándar OBD-II, y para llevarlo acabo ha sido necesario trabajar sobre diferentes aspectos que están involucrados en el proceso de comunicación. Por tanto principalmente existen dos partes importantes a diferenciar en el desarrollo de este proyecto: La parte que engloba el hardware necesario, que nos es más que un modem interface que hace de intérprete entre la centralita electrónica del automóvil (ECU), y el puerto USB de un ordenador personal. La parte que engloba el software, que se refiere a la aplicación que funcionará en el PC y que gestionará el modem interface a partir de los datos que se vallan recibiendo y enviando atreves del puerto USB. 1.5.1 Descripción básica del hardware (Modem interface) Para diseñar el modem interface se recurrió a diseños ya existentes y de libre disposición en la red, con el fin de conseguir construir una interface que aportase las mejoras que de forma individual cada diseño implementa. Esta interface contiene como elemento principal un microcontrolador (PIC18F2550) que es el encargado de gestionar la comunicación entre los dos periféricos en cuestión, es decir, recoge la información que obtiene del puerto USB y la interpreta según el protocolo en que se esté comunicando con la ECU. Esto se debe a que el estándar OBD-II implementa 4 posibles protocolos en su capa física, SAEJ1850PWM, ISO 9141/14230, J1850 VPW, ISO 15765 (CAN). Para que el micro pueda realizar estas funciones se dispone además de un firmware que implementa las capacidades antes descritas, lo que lleva por tanto a realizar su grabación en el micro, y además a la construcción de un programador con el cual realizar este proceso. Otro aspecto importante a resaltar es la necesidad de construir un cable específico para realizar la conexión entre la ECU y la interface durante las primeras pruebas, ya que las centralitas electrónicas disponen de un conector exclusivo para este uso, y por tanto es muy difícil de encontrar en el mercado material compatible. 12 1.5.2 Descripción básica del software (Interface Visual) Para realizar la aplicación que gestionará el modem y todos los datos que serán enviados y recibidos a través de él, se deben realizar primero unos pasos previos para poder familiarizarse con las rutinas que deberemos utilizar. Como inicio de este proceso se debe comenzar por averiguar cuál es el mecanismo que siguen otras aplicaciones que ya implementan este mecanismo, y para poder hacerlo existe una aplicación, mencionada anteriormente (ScanTool), que ofrece el código fuente mediante lenguaje C++. A través de este código es posible extraer las rutinas básicas con las que se realiza la comunicación con el micro y la ECU, esto permite que nosotros mismos realicemos un programa de prueba con el que observar cual es la estructura básica que debemos seguir. Debido a que el objetivo es realizar el software utilizando JAVA, ya que nos permitirá hacer portable nuestro trabajo a diferentes plataformas, el programa anterior no es aun suficiente para poder afrontar la implementación de la aplicación definitiva, y por tanto es necesario realizar otro programa de prueba que contenga la misma estructura que el anterior pero con código JAVA. Para poder llevar a cabo este objetivo es necesario utilizar la librería “RXTXcomm” como librería nativa para realizar las comunicaciones por los puertos serie, ya que los medios que ofrece la “API” de Java respecto a este tipo de comunicaciones están obsoletos. Una vez sabemos utilizar los recursos existentes de Java, se puede empezar a desarrollar el software que nos ofrecerá las opciones y características que queremos implementar en la aplicación definitiva. El objetivo es que el programa pueda permitirnos, a través de una interface visual, realizar las siguientes tareas: Opciones para poder configurar los parámetros del puerto serie según convenga. Opciones para poder seleccionar los protocolos de comunicación que sean necesarios según el vehículo. Realizar lectura de códigos de error que pueda tener almacenados la centralita electrónica del automóvil. Realizar lecturas a tiempo real de los datos que aportan los diferentes sensores del motor del vehículo, rpm, velocidad, carga del motor, etc. Disponer de una consola de texto que monitoree el puerto serie refrescando su contenido según el estado del tráfico de datos entre el PC y el modem interface. 13 2. Diseños 2.1. Metodología utilizada Durante el desarrollo de este proyecto se ha seguido en parte la filosofía de la ingeniería inversa para alcanzar algunos de los objetivos, aunque también se han seguido las pautas de diseños anteriores de disponibilidad libre que realizan las mismas funciones, ya que encontrar cual es el camino que se sigue para realizar los procesos adecuadamente en un sector tan cerrado tecnológicamente como el del automóvil puede llegar a ser muy desesperante. Este proyecto consta principalmente de un parte de software y otra de hardware. En lo que hace referencia a la parte física, es decir, el hardware, se ha utilizado un diseño de libre uso disponible en la red, a partir del cual se construye básicamente la interface. Este aparato también se comercializa actualmente con el nombre de ALLProAdapter por la empresa OBDDiag.net y es una versión compatible de otra interface llamada ELM327, que originalmente es utilizada por muchos software disponibles de pago, y del cual también se disponen de los diseños electrónicos, los cuales también se han aprovechado para realizar el diseño final de la circuitería del modem interface basado en el PIC18F2550. El primer paso ha sido comprobar que los programas que existen como antecedentes funcionen correctamente sobre el hardware montado. De esta manera se tiene la garantía de que el hardware (interface con PIC18F2550 con conexión USB), funciona correctamente y de que los programas en los que nos basaremos para la realización del proyecto son funcionales. De no ser así, podríamos basarnos en herramientas que no serian útiles. Una vez verificados estos puntos, el primer objetivo siempre ha sido conseguir efectuar algún tipo de comunicación con el dispositivo (PIC18F2550) desde el PC, ya que uno de los problemas comunes a todos los dispositivos de este tipo es conocer la forma de comunicarse desde el nivel más básico, es decir, constatar que el micro controlador reacciona o contesta de alguna manera delante de un estimulo producido mediante una línea de comunicaciones digital. Existe un software para el diagnostico de vehículos llamado ScanTool.net, que en una de sus versiones ofrece el código fuente, muy útil para el propósito de este proyecto. Este programa ha sido, para este proyecto, la base para poder iniciar la búsqueda de los pasos que se siguen a la hora de realizar una comunicación desde el PC hasta la centralita electrónica del vehículo, atreves del puerto de comunicaciones serie. 14 Además del software de control y el hardware a controlar hay que tener en cuenta que los microcontroladores necesitan un “driver” para que el sistema operativo que lo gestiona pueda controlarlo. Dado que el PIC18F2550 lo fabrica la compañía Microchip, se pensó en que posiblemente esta proporcionara su “driver”, y aunque así es, lo proporciona mediante la instalación de un paquete de herramientas llamado “USB Framework package”, el cual obliga a instalar además del driver muchas otras utilidades que en principio no son necesarias para este caso. La empresa que ofrece libremente la información para montar la interface, OBDDiag.net, también proporciona el driver que se necesita, en forma de fichero INF, y es suficiente para que Windows XP o Vista la detecte sin problemas. También se pudo averiguar que en otros sistemas operativos, como por ejemplo Linux, este microcontrolador está contemplado y en las mismas distribuciones de Linux ya se incorpora el “driver” necesario. Por tanto, después de montar la interface y verificar su funcionamiento mediante el software ya existente, se procedió a intentar una comunicación utilizando recursos propios, es decir, sin recurrir a la funcionalidad de los programas anteriores. Utilizando el código fuente antes mencionado, el cual se basa en C++, se diseño un programa de prueba que conseguía comunicarse de forma básica con el microcontrolador, pero que aportó mucha información para realizar el proyecto. Una vez lograda la comunicación se procedió a intentar obtener el mismo resultado pero utilizando la plataforma Java. Básicamente el programa de prueba en este caso tiene la misma estructura que en C++, pero utilizando los recursos de los que dispone Java. El paso más importante aquí fue encontrar que métodos utiliza Java para comunicarse con el puerto Serie, y aunque los que proporciona Sun Microsystems, empresa diseñadora de esta plataforma de programación, están obsoletos, no fue difícil encontrar otros actualizados y perfectamente compatibles con su máquina virtual. Esta funcionalidad la proporciona el paquete RXTXcomm junto con la instalación de la maquina virtual de Java. Como último objetivo se planteó realizar un software que ofreciese muchas más funcionalidades de configuración sobre la interface, utilizando un entorno grafico y mucho mas intuitivo. Este software engloba toda la capacidad de comunicación de los programas anteriores pero añadiendo todo el potencial que ofrece un entorno visual diseñado con java, lo cual dota al programa de muchas opciones de configuración y operatibilidad sobre la interface y por tanto sobre la centralita electrónica de cualquier vehículo, que, al fin y al cabo, es lo que se pretende controlar. 15 2.1 Recursos utilizados Para realizar este proyecto se han utilizado recursos de diferente tipo según si nos referimos a la parte de software o a la de hardware, pero siempre recurriendo como fuente principal de información a la que se dispone en la red. Para montar la interface se recurrió a la web OBDDiag.net, donde se describen todos los materiales, software, firmware del micro y diseño del PCB necesarios para construirla. Paralelamente también se sacó información de la web ELM Electronics, donde mediante los datasheet que ofrecen (ELM327DS.pdf y ELM320DS.pdf), describen como fabricar un interface para conectarse a la centralita electrónica (ECU) de cualquier vehículo utilizando los microcontroladores que ellos suministran. El datasheet ELM327DS, es el documento que expone todas las posibles ordenes y respuestas que se reciben y envían al modem interface ELM327 y por tanto también al microcontrolador que se utiliza en este proyecto, ya que este incorpora un firmware compatible que contiene la misma estructura básica que el original, el ELM327. En el siguiente listado se pueden ver todos los posibles comandos que el ELM327 implementa, y por tanto, aunque no todos los comandos que utiliza la interface utilizada en este proyecto: 16 17 A continuación podemos ver uno de los esquemas eléctricos que aporta ELM Electronics, utilizando su microcontrolador más famoso, el antes mencionado ELM327, el cual utilizan muchas interfaces del mercado, ya que es capaz de manejar y gestionar los protocolos de comunicación más utilizados en el estándar OBD-II: Detalle del esquema eléctrico de un intérprete de OBD a RS232 18 Para realizar el software de control se utilizo como base de inicio el software que proporciona la empresa ScanTool.net, la cual ofrece en una de sus versiones su código fuente. Este código fuente se trató con el tan extendido programa de desarrollo DEV-C++, y posteriormente también se desarrollaron con él los primeros diseños de prueba con los se empezó la comunicación con la interface. Una vez se empezó a programar utilizando la plataforma JAVA y su máquina virtual, la cual está disponible en la web de Sun Microsystems y se puede descargar mediante el paquete JDK 6 Update 13, se pasó a utilizar otra herramienta para programar con este lenguaje llamada Eclipse en su versión 3.2.2, y fue muy útil para desarrollar el entorno gráfico del que dispone el software de control que se ha creado en este proyecto. Un recurso muy importante también fue toda la información que se aporta en RXTX.org, donde se explica el funcionamiento de la librería RXTXcomm.jar, que es la que se utiliza en JAVA para manejar los puertos serie. En esta web se ofrecen claros ejemplos de cómo utilizar y configurar los métodos de los que se dispone, en especial haciendo hincapié en uno de ellos que será adjuntado en el anexo del proyecto. 19 Por otro lado para poder entender cómo funcionan los protocolos de comunicación que utiliza el estándar OBDII (On Borad Diagnostics II), se extrajo mucha información de la enciclopedia libre Wikipedia, donde en uno de sus documentos (OBD-II PIDs), explica cuales y como son los formatos de trama de datos que utiliza este estándar, además de documentos como (ASCII), que detalla las equivalencias del código ascii entre valores decimales y hexadecimal. Detalle de equivalencias código ASCII Detalle de la información aportada en el documento OBD PID’s 20 2.3. Descripción del diseño del modem interface La primera parte del proyecto que se empezó a diseñar y construir es el modem interface que se utiliza como aparato para interconectar el PC con la centralita electrónica del vehículo. Este aparato consta de tres partes a diferenciar, el cable USB que comunica el PC con el modem, el cable OBD-II que comunica la centralita electrónica del vehículo con el modem y el modem propiamente dicho. En los cables no hubo ningún proceso de montaje, se podían comprar ya hechos, pero si se intento fabricar el del conector OBD-II, ya que es difícil encontrarlos en los comercios especializados, pero se acabó desechando por su poca durabilidad ya que después de unas pocas pruebas empezó a deteriorarse. Cable OBD-II a DB9 hembra Cable USB tipo A-B En la siguiente tabla se puede apreciar la correspondencia entre los pines del conector OBD-II y el DB9: OBD-II 16 PIN(Macho) DB9 PIN(Hembra) (J2850 BUS+) 2 7 (Chassis Ground) 4 1+2 (Signal Ground) 5 1+2 (CAN High J-2284) 6 3 (ISO 9141-2 K Line) 7 4 (J2850 BUS- ) 10 6 (CAN Low J-2284) 14 5 (ISO 9141-2 L Line) 15 8 (Battery Power) 16 9 21 Por tanto el trabajo importante aquí estaba en la fabricación del modem. Para poder construirlo se acudió a una tienda especializada donde disponían de todos los componentes electrónicos necesarios, los cuales se procedieron a instalar en el PCB creado a partir del siguiente “layout” de doble cara: 22 Este aparato contempla la posibilidad de utilizar 4 protocolos de comunicación distintos a nivel de capa física, ya que a lo largo de los años las diferentes centralitas electrónicas que montan los fabricantes de vehículos así lo han dispuesto, aunque a partir del año 2004, en Europa, la mayoría de fabricantes empezaron a implementar solo el protocolo CAN Bus. Cualquiera de los vehículos fabricados en EE.UU. a partir del 1996, fueron obligados a disponer de un puerto OBD2, y en Europa a partir del año 2001, también se obligo a implantar este tipo de conexión. La norma OBD2 comprende cuatro protocolos de comunicación distintos: ISO 9141/14230 J1850 PWM J1850 VPW ISO 15765 (CAN) VPW (Variable Pulse Width) fue originalmente introducido por General Motors, mientras que PWM (Pulse Width Modulation) pertenece al grupo Ford. ISO 9141 y la posterior encarnación ISO 14230 (AKA Keyword 2000) es el que la mayoría de vehículos europeos y asiáticos utilizaban. Todos los nuevos modelos a partir 2007/2008 sólo pueden implementar el protocolo CAN Bus. La siguiente imagen es la de un conector típico OBD2 de 16 pines instalado en cualquier vehículo: Según el protocolo de comunicación que utilice el vehículo los pines habilitados en el conector serán diferentes. El protocolo ISO 9141/14230 utiliza los pines 6 y 15, el protocolo J1850 PWM utiliza el 2 y el 10, el protocolo J1850 VPW utiliza solo el pin 2, y el protocolo ISO 15765 (CAN), el pin 6 y 14. Todos los protocolos utilizan como fuente de alimentación los pines 4 y 5 (masa chasis y masa señal respectivamente), y el pin 16 (+12V). 23 Para entender el funcionamiento interno del modem habría que empezar por describir las partes de las que se compone su circuitería. En la siguiente imagen se puede observar el esquema eléctrico de la interface: En el esquema se observa que el microcontrolador utilizado es el PIC18F2455, pero por dificultades a la hora de adquirirlo se optó por el PIC18F2550, que es perfectamente compatible además de aportar un poco mas de memoria. Este micro es el encargado de gestionar todo los componentes periféricos del circuito y de mantener la comunicación entre ellos, es decir, recibe la información procedente del puerto USB al que está conectado, la transfiere a los elementos del circuito que proceda y viceversa, ya que la comunicación es bidireccional. La parte del circuito que se ocupa de manejar el protocolo CAN BUS, son los integrados MCP2515 y MCP2551, el integrado MC33290 maneja el protocolo ISO9141/14230 junto con Q3, J1850 VPW está controlado por MC33390 y el par de Mosfets (Q2 P-channel y Q1 N-channel) controlan el bus J1850PWM junto un comparador interno del PIC18F2550 y las resistencias R4 y R5 que crean la señal diferencial de la entrada del PWM. 24 2.4 Descripción del diseño del programador JDM2 Después de la explicación anterior es obvio deducir que el elemento más importante aquí es el microcontrolador PIC18F2550, pero por si solo no tiene ninguna funcionalidad a no ser que se le introduzca el firmware adecuado, por esta razón se tuvo que construir exclusivamente para este fin un programador compatible con el protocolo ICSP (In-Circuit Serial Programming). Este tipo de programador, llamado JDM2, es muy famoso en la red ya que se construye con pocos componentes e implementa el estándar ICSP que es el que ofrece la empresa Microchip para poder introducir los firmwares en los microcontroladores que ellos fabrican. El esquema eléctrico del programador es de fácil adquisición en cualquier web de electrónica y se representa con el siguiente esquema: 25 El circuito se montó en una placa de baquelita específica para realizar prototipos, y se siguió el siguiente “layout”: Detalle del programador JDM2 en su parte superior Detalle del programador JDM2 en su parte inferior (lado soldadura) 26 Además del programador necesitamos poder conectarlo a una PC que disponga de puerto serie, ya que a través de este puerto se comunicará con el software que enviará el firmware al micro. La aplicación que se utilizó para programar el microcontrolador fue “PICPgm Develop. Programer” que es un software gratuito y de fácil manejo; solo hay que seleccionar el archivo que contenga el firmware y una vez cargado cliquear en la opción de gravado. Siguiendo el “datasheet” del microcontrolador se conectó al programador según el siguiente detalle: Los pines detallados en la imagen son los que utiliza el programador JDM2 y por tanto el estándar ICSP, para comunicarse con el PIC. Vemos que además de los pines de comunicación (MCLR, PGC y PGD), también utiliza el puerto serie para alimentarse mediante los pines 8 y 19 para masa, y el 20 para los +5 V necesarios. El pin 26 (PGM), no está implementado en el programador ya que este solo se utiliza en el caso que se realice una programación en modo “LowVoltage ICSP”, y en este caso se realiza en modo “High-Voltage ICSP”. 27 La conexión realizada para proceder a programar el micro fue la siguiente: En la imagen podemos ver como el cableado procedente del programador está etiquetado con el nombre de los pines a los cuales debe ser conectado. Alrededor del micro hay un cable que puentea dos pines, esto se debe a que el microcontrolador necesita dos puntos de masa. Por otro lado vemos como el cable procedente del puerto serie está conectado en su el respectivo conector DB9. También vemos que el programador está dotado de un diodo “led” de color rojo, el cual es de suma utilidad a la hora de detectar alguna anomalía en el proceso de gravado. 28 2.5 Modificaciones del diseño del modem Una vez se había montado la interface y se procedió a comprobar su correcto funcionamiento con software ya existente, se observó que funcionaba correctamente en todos los vehículos chequeados los cuales utilizaban diferentes protocolos de comunicación, exceptuando uno de los casos que no se obtenía respuesta de su centralita electrónica. Se sospechó que posiblemente la interface no funcionaba correctamente y se procedió a analizar con un osciloscopio las señales que producía respecto al protocolo J1850PWM. Para realizar las mediciones se tuvo recurrir a un osciloscopio digital con una capacidad de muestro de hasta 1GHz, herramienta que aseguraba el visionado más que correcto de la señal, ya que además esta era de tipo no periódica y por tanto con un osciloscopio analógico es prácticamente imposible capturarla. El resultado fue el siguiente: Resultado de la trama enviada a través del pin 2 (BUS+) del conector OBD-II Resultado del trama enviada a través del pin 10 (BUS-) del conector OBD-II 29 Para entender el resultado de estas graficas es preciso hacer una descripción del comportamiento de la capa física del protocolo j1850PWM. Este protocolo dispone de dos líneas de comunicación, el BUS+ y BUS-, y se caracteriza por utilizar la modulación del ancho de pulso (PWM) como mecanismo de codificación de bits. El periodo de cada bit tiene una duración de 24 µs y su estado se expresa de la siguiente forma: Un bit=1, se representa con un estado activo de 8us dentro de un periodo. Un bit=0, se representa con un estado activo de 16us dentro de un periodo. El BUS+ está activo cuando toma el valor de 5v. El BUS- está activo cuando toma el valor de 0v. Por tanto se deduce que en estado de reposo el BUS+ se encuentra a 0 V y el BUS- a 5 V, a medida que se van enviando los bits los buses van cambiando de estado quedando siempre entre ellos con tensiones invertidas, lo que se traduce en un mecanismo de protección contra interferencias exteriores. Hecha esta explicación podemos darnos cuenta de que la gráfica que representa el BUS+ desvela un pequeño problema eléctrico, ya que mientras que el BUSreacciona rápidamente colocándose a 0 V, el BUS+ nunca llega a lograr los 5 V, quedándose siempre en los 4,4 V aproximadamente. Aunque este no sería un problema para realizar la comunicación satisfactoriamente según las especificaciones del protocolo SAEJ1850PWM, ya que se encuentra dentro de los márgenes eléctricos permitidos, se procedió a modificar la electrónica que se ocupa de implementar esta codificación. 30 En el esquema eléctrico observamos que los encargados de ajustar estas tensiones son los Mosfets Q1 y Q2 (Q2 P-channel y Q1 N-channel) junto con las resistencias R7 y R6. Partiendo de otro diseño disponible en la red que implementa el mismo protocolo, se cambiaron los Mosfets por transistores PNP y NPN (PNP->2N3906 y NPN->2N3904) y las resistencias R6 y R7 de 22kΩ por resistencias de 2K7 Ω. Además se incorporaron resistencias de protección a las bases de los transistores de 1KΩ. Por tanto la modificación resultaría según el siguiente esquema: 31 Debido a que se constató que el problema no venia causado por el hardware se empezó a investigar si podía venir dado por errores en las tramas enviadas. Según el estándar J1850 PWM el formato de trama es el siguiente: A partir de los documentos que explican las características de este protocolo se averiguo que las diferentes partes de la trama tienen las siguientes funciones: SOF: Start of frame Header Field: Son los encargados de especificar mediante 3 bytes los siguientes parámetros: El primer byte especifica el modo en que se van a comunicar la centralita con la interface, y según el documento SAE J2178 este byte de cabecera se denomina de tipo mapeado, eso significa que cada bit tiene un significado. Los 8 bit se identifican así: BIT 7 6 5 4 3 2 1 0 ID P P P H K Y Z Z Los tres más significativos (7, 6 y 5) indican la prioridad del mensaje y puede tomar los siguientes valores: Bit 7 Bit 6 Bit 5 0 0 0 0 0 0 1 1 0 1 0 2 0 1 1 3 1 0 0 4 1 0 1 5 1 1 0 6 1 1 1 7 Prioridad máxima Prioridad mínima 32 El bit 4 (H) indica si la cabecera es de 3 bytes o uno: H=0 Tres bytes H=1 Un byte El bit 3 (K) indica si se utiliza "In-Frame response" ? : K=0 Requerido K=1 No requerido El bit 2 (Y) indica si la dirección usada es física o funcional: Y=0 Funcional Y=1 Física Los bit 0 y 1 (Z, Z) se usan junto con K e Y para definir el tipo de mensaje: Msg. KKYZ Respuesta(K) Dirección(Y) Tipo de mensaje 0 0000 Requerido Funcional “Function” 1 0001 Requerido Funcional “Broadcast” 2 0010 Requerido Funcional “Function Query” 3 0011 Requerido Funcional “Function Read” 4 0100 Requerido Física “Nodo a Nodo” 5 0101 Requerido Física “Reservado-MFG” 6 0110 Requerido Física “Reservado-SAE” 7 0111 No requerido Física “Reservado-MFG” 8 1000 No requerido Funcional “Function Command/Status” 9 1001 No requerido Funcional “Funcion Request/Query” 10 1010 No requerido Funcional “FunctionExt.Command/Status” 11 1011 No requerido Funcional “Function Ext. Request/Query” 12 1100 No requerido Física “Nodo a Nodo” 13 1101 No requerido Física “Reservado-MFG” 14 1110 No requerido Física “No disponible” 15 1111 No requerido Física “Reservado-MFG” 33 El segundo byte representa a la dirección de memoria elegida que identifica a la centralita (ECU). El tercer byte representa a la dirección de memoria elegida que identifica a la interface o herramienta de chequeo. Data Field: Es la información que se quiere hacer llegar al micro de la ECU. CRC: Chequeo de redundancia cíclica de la trama. Conociendo ya la estructura de este protocolo se pensó que una solución al problema sería modificar los “Header Field” ya que posiblemente no serian los adecuados. A partir de aquí se procedió a averiguar cuáles eran los que utilizaba nuestra interface, y esto se consiguió mediante el comando “ATH1”, el cual le indica al modem que muestre las cabeceras (Headers) de todas las tramas, después observando una de las tramas se vio que la cabecera utilizada por defecto era 6A 61 F1. En el documento antes mencionado (J2178), se indicaba que esta cabecera es generalmente la más utilizada en muchas de las centralitas que implementan el protocolo J1850PWM, pero también hacía referencia a otra posible cabecera a utilizar, que era E4 10 F1. La cabecera 6A 61 F1 especifica el uso de 0x61 (01100001) como primer byte que significa prioridad 3, tres bytes de cabecera, tipo de mensaje 2, usando dirección funcional que es el segundo byte de la cabecera, es decir, 0x6A. La cabecera E4 10 F1 especifica el uso de 0xE4 (11100100) como primer byte que indica prioridad 7 (mínima), tres bytes de cabecera, tipo de mensaje 4, con dirección física y nodo a nodo. En principio para proceder a cambiar las cabeceras se dispone del comando “ATSH”, pero por causas aún desconocidas no era reconocido por nuestra interface, a pesar de que en el firmware del microcontrolador se vio que estaba implementado, mediante un software para editar ficheros de este tipo. Utilizando este mismo software (Hex Workshop Hex Editor), se intento averiguar donde se encontraban los bytes que definían las cabeceras en cuestión, y después de una búsqueda muy extensa se encontraron y modificaron con los nuevos valores. 34 En la siguiente captura podemos observar el fragmento de código donde se encontraban estos datos, fue un tarea laboriosa ya que este fichero solo contiene tramas hexadecimales, y es el resultado de la compilación de un código fuente al que no se tenía acceso. :103C70000350E66EE66A00010028BC6F000E0120CA :103C8000BD6FBCC0E6FFBDC0E6FF040E0024BE6FE2 :103C9000000E0120BF6FBEC0E6FFBFC0E6FFDDEC37 :103CA0001EF046E90028E96E000E0120EA6E6A0E59 :103CB000EF6E020E0024E96E000E0120EA6E610E26 :103CC000EF6E030E0024E96E000E0120EA6EF10E85 :103CD000EF6E0001030EBC6F00EBE9FF01EBEAFFA2 :103CE000BC51EF2642E9E7CFD9FF1200D9CFE6FF5A Además de reemplazar estos bytes también se tuvo que recalcular el “checksum” de cada línea modificada ya que este cambiaba, y el resultado fue el siguiente: :103C70000350E66EE66A00010028BC6F000E0120CA :103C8000BD6FBCC0E6FFBDC0E6FF040E0024BE6FE2 :103C9000000E0120BF6FBEC0E6FFBFC0E6FFDDEC37 :103CA0001EF046E90028E96E000E0120EA6EE40EBA :103CB000EF6E020E0024E96E000E0120EA6E100E77 :103CC000EF6E030E0024E96E000E0120EA6EF10E85 :103CD000EF6E0001030EBC6F00EBE9FF01EBEAFFA2 :103CE000BC51EF2642E9E7CFD9FF1200D9CFE6FF5A Con el firmware ya modificado se procedió a volver reescribirlo en el microcontrolador utilizando el programador antes descrito. Una vez preparada la interface se volvió a intentar la comunicación con la centralita en cuestión que nos daba problemas. El resultado fue muy interesante ya que esta vez si nos contestó pero de la forma no esperada. La trama enviada fue la siguiente: E4 10 F1 01 00 0A Y su respuesta: C4 F1 10 7F 01 01 00 00 11 41 El dato a resaltar es el 7F 01, que indica respuesta negativa, es decir, según el documento J2178 una respuesta negativa significa que la centralita electrónica no dispone de información sobre el modo de trabajo requerido, que es el “Modo 01”. 35 El estándar OBD-II contempla varios modos de trabajo, entre ellos el modo 01, modo 03, modo 07, modo 04, modo 09, modo 22 y bastantes más. Cada uno de ellos se ocupa de una parte de la información que puede aportar la ECU. El modo más extendido entre todas las centralitas es el modo 01. Cada modo además especifica sus parámetros PID (Parameter ID), en caso del modo 01 uno puede ser el parámetro 00, que es el que se utiliza en nuestro caso. Este parámetro sirve para decirle a la ECU que nos muestre cuales son los PID que pueden ser utilizados en este modo de entre los PID que se encuentran numerados del 1 al 20. Después de consultar nuevamente el documento J2178 se averiguó que cuando el modo 01 no está disponible en la centralita lo más probable es que se implementara en su lugar el modo 22. Este fue el final de la investigación ya que el modo 22 utiliza una longitud de trama más larga que el 01, cosa para la cual nuestro hardware (el microcontrolador de la interface), no está preparado, ya que no se implemento en su firmware esta funcionalidad. 36 2.6 Diseño de la aplicación de prueba en C++ Hasta ahora se ha explicado el diseño utilizado para crear la parte de hardware de la que se compone el proyecto, pero anteriormente se ha hecho referencia también a la parte de software que es la que tiene más peso y elaboración. El desarrollo del software se empezó a elaborar a partir del software libre ScanTool.net, que en una de sus versiones ofrece el código fuente. Utilizando la herramienta Dev-C++ y este código, el cual se basa en C++, se localizaron los métodos y funciones que se sospechaban eran los responsables de mantener la comunicación mediante el puerto serie. El primer paso fue averiguar cuál era la función que realizaba las operaciones necesarias para realizar las comunicaciones con el PIC. Tras encontrarla y incorporarla a un programa de prueba, se procedió a compilar la función, tras esto el mismo compilador mencionaba cuales eran las funciones y variables que llamaba este método para poder comunicarse, y por lo tanto poder buscarlas en el código anterior para reunirlas en el programa de prueba. Una vez que se tenían todas las funciones y variables en el mismo fichero se podía compilar el código sin obtener errores, averiguando así cómo se comportaba el hilo de ejecución. Después de saber cuál era la rutina de ejecución, se sacaron todas las órdenes o variables que no son imprescindibles por realizar una comunicación básica, dejando la clase reducida al máximo para tener una visión simple del proceso comunicación dejando a la vista claramente las funciones necesarias. Finalmente el programa de prueba podía realizar la comunicación enviando órdenes al PIC (atz, 0100, etc...) obteniendo los mensajes enviados y los recibos con una visualización por consola. A continuación aparece el código del programa de prueba: 37 38 Este programa utiliza la librería “allegro” como base, un librería muy utilizada para desarrollar videojuegos, y por tanto era necesario indicarle al compilador que la cargase con “-lalleg”, aunque también necesita cargar la librería “iostream” y la “winalleg”, necesaria si se trabaja en Windows. Las funciones implementadas son: main(): Arranca el hilo de ejecución. init(): Carga las librerías y abre el puerto. deinit(): Descarga las librerías y cierra el puerto. read_comport(): Lee el puerto serie. open_comport(): Abre el puerto serie. 39 close_commport(): Cierra el puerto serie. send_command(): Escribe en el puerto serie. 2.7. Diseño de la aplicación de prueba en JAVA El segundo diseño se centra en la elaboración de otro programa de prueba a partir de lenguaje JAVA, ya que era necesario averiguar las capacidades de este lenguaje a la hora de comunicarse con el puerto serie. Como primer apunte se ha de decir que se utilizó el IDE para programar en Java Eclipse. Para poder comunicarse con el puerto serie es necesario incluir las librerías adecuadas en el paquete de la API de java instalada en el PC, es decir, en el paquete autoinstalable “JDK-JRE” que ofrece gratuitamente Sun Microsystems, ya que este no incluye librerías con esta funcionalidad. Para este fin existe una librería llamada RXTXcomm, disponible en www.RXTX.org, que mediante métodos nativos dota a Java de la capacidad para comunicarse con el puerto serie y paralelo, y además puede utilizarse en cualquier sistema operativo, haciendo hincapié en Windows, ya que aunque Sun ofrece una API para este fin (Javacomm), no da soporte para este sistema operativo, quedándose ya esta API obsoleta y aconsejando RXTXcomm. Descargando y descomprimiendo el “zip” donde se incluyen los ficheros necesarios de RXTX, debemos de copiar RXTXcomm.jar en la ruta c:\Archivos de programa\Java\jre\lib\ext, rxtxSerial.dll y rxtxParallel.dll en c:\Archivos de programa\Java\jre\bin. Si en lugar de Windows nos encontramos en Linux las rutas donde situar los ficheros es diferente. En Linux debemos de copiar RXTXcomm.jar en /usr/lib/jvm/jre/lib/ext, los archivos librxtParallel.so y librxtxSerial.so hay que copiarlos en /usr/lib/jvm/jre/lib/i386 si el sistema es de 32 bits. Con esto el compilador ya tendrá las librerías disponibles y podremos utilizarla en el código que programemos. RXTX.org dispone de una web donde se explica el funcionamiento de la librería y sus métodos, además ofrece ejemplos claros de cómo ponerla en marcha. 40 El programa de prueba que se elaboró en esta fase del proyecto fue el siguiente: import import import import import import import import import import gnu.io.CommPortIdentifier; gnu.io.NoSuchPortException; gnu.io.PortInUseException; gnu.io.SerialPort; gnu.io.UnsupportedCommOperationException; java.io.IOException; java.io.InputStream; java.io.OutputStream; java.util.Date; java.util.Enumeration; public class Principal { CommPortIdentifier idpuerto; String NombrePuerto; String ordre="atz"; String stringRebut; SerialPort port; OutputStream DadesEscriu; InputStream FluxDades; Date temps,temps2; StringBuffer respuesta; public Principal(){} public void conectar(){ int j=0; for(Enumeration i=CommPortIdentifier.getPortIdentifiers();i.hasMoreElements();){ idpuerto = (CommPortIdentifier) i.nextElement(); System.out.print(j++ +". " + idpuerto.getName()+"\n"); //Se examinan todos los puertos disponibles } try { idpuerto.getPortIdentifier("COM2"); port = ( SerialPort )idpuerto.open("VisualOBD",2000); port.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); //Se abre el puerto seleccionado } catch (PortInUseException e) { e.printStackTrace(); System.out.println("Puerto en uso."); } catch (NoSuchPortException e) { e.printStackTrace(); System.out.println(e); } catch (UnsupportedCommOperationException e) { e.printStackTrace(); System.out.println(e); } } 41 public void enviar(){ temps=new Date(); int data; try { DadesEscriu = port.getOutputStream(); for(int i=0;i<ordre.length();i++){ data= ordre.codePointAt(i); System.out.println(data); DadesEscriu.write(data);//Se escribe en el Puerto serie if((i+1) == ordre.length()){ DadesEscriu.write(13); //Solamente necessita el retorno de carro, //sin el salto de linea. } } System.out.println("Enviat atz:"); } catch (IOException e) { e.printStackTrace(); System.out.println(e); } } public void recibir(){ respuesta=new StringBuffer(); while((timer()-temps.getTime())<3000){} char z; int reb=0; try { FluxDades = port.getInputStream(); while(reb>-1){ reb=FluxDades.read();//Se lee el Puerto serie z=(char) reb; respuesta.append(z); } System.out.println(respuesta);//Se imprime la respuesta por consola port.close(); } catch (IOException e) { e.printStackTrace(); System.out.println(e); } } public static void main(String[] args) { Principal prin=new Principal(); prin.conectar(); prin.enviar(); prin.recibir(); } public long timer(){ temps2 = new Date(); return temps2.getTime(); } } 42 Estructuralmente el programa se asemeja al diseño en C++, y por tanto implementa métodos funcionalmente muy parecidos: public static void main(): Método que inicia la ejecución del programa. public void Conectar(): Establece la conexión con el puerto serie indicado. public void Enviar(): Escribe la trama de datos a enviar en el puerto serie. public void recibir(): Lee la trama de datos recibida del puerto serie. Public long timer(): Método que realiza la espera necesaria a la respuesta del puerto. Tanto en JAVA como en C++, el tratamiento de las tramas digitales recibidas y enviadas en el puerto serie se traducen en valores decimales según el código ASCII, a partir de su equivalente en binario y posteriormente en hexadecimal. Unos ejemplos de trama de datos y su tratamiento sería el siguiente: Comando a enviar: ”atz”-> equivalencia código ASCII:”97,116,122” Este comando sirve para hacer un “reset” del micro. Se le añade a la trama el retorno de carro para indicar fin de trama: “atz\r”->código ASCII:”97,116,122,13” y el método write() de la clase SerialPort la envía al puerto serie. Trama recibida del puerto serie atreves del método read() de la clase SerialPort: 97,116,122,13,10,69,76,77,51,50,55,32,118,49,46,49,32,99,111,109,112, 97,116,105,98,108,101,13,10,62,-1 Equivalencia de la trama según el código ASCII: atz ELM327 v1.1 compatible El último número (-1), indica que no se está recibiendo ningún dato, y sirve como referencia para saber que la trama ha finalizado, además el micro marca el fin de la trama con el numero 62 ( equivalente a “>”). 43 Comando a enviar: ”01 0C”-> equivalencia código ASCII:” 48,49,48,67” Este comando sirve para pedirle a la centralita electrónica del vehículo (ECU), a cuantas revoluciones por minuto (rpm), está girando el motor. Se le añade a la trama el retorno de carro para indicar fin de trama: “01 0C\r”->código ASCII:” 48,49,48,67,13” y el método write() de la clase SerialPort la envía al puerto serie. Posteriormente cuando la interface la ha recibido esta la envía a la ECU según el siguiente formato de trama si el protocolo a utilizar es J1850 PWM: SOF: Start Of Frame Header Field: 6A 61 F1 Data Field: 01 0C (Comando que se ha especificado antes) CRC: 0A EOF: End Of Frame La ECU contesta con la siguiente trama y la interface la recoge para enviarla al puerto serie: 6A F1 61 41 0C 0B 88 0A -> Respuesta ECU 01 0C -> Respuesta 6A F1 61 41 0C 0B 88 0A Interface Se puede observar que la interface le añade a la trama el comando solicitado Trama recibida del puerto serie atreves del método read() de la clase SerialPort: 48,49,48,67,13,10,54,65,70,49,54,49,52,49,48,67,48,66,56,56,48,65,13,1 0,62,-1 44 Por tanto en la respuesta obtenida podemos diferenciar que: 01 0C: Comando requerido 6A F1 61: Cabecera de la trama(Especifica direcciones de memoria, prioridades, tipo de conexión, etc..) 41 0C: Confirmación de que se ha contestado al comando requerido sumando 40 a 01, quedando 41 0C. 0B 88: El dato que interesa para calcular las rpm. Según el documento OBD Pid’s anteriormente mencionado, si pasamos a decimal estos valores quedando en 11 y 136, y aplicamos esta fórmula (( A ⋅ 256) + B ) = (11 ⋅ 256) + 136 = 738 , obtenemos las revoluciones por 4 4 minuto del motor a tiempo real. 0A: Chequeo de redundancia cíclica de la trama (CRC). 45 2.5. Diseño de la aplicación grafica diseñada en JAVA El diseño final y definitivo de este proyecto consistía en realizar un software multiplataforma diseñado mediante la conocida estructura de programación “por capas”, para poder unir de forma correcta toda la capacidad de comunicación que se había conseguido en los programas de prueba anteriores con la necesidad de ofrecer muchas más opciones, entorno grafico y el potencial que aporta un entorno visual diseñado con JAVA, lo cual dota al programa de muchas posibilidades de configuración y operatibilidad sobre la interface y por tanto sobre la centralita electrónica de cualquier vehículo. Este software intenta ser compatible con cualquier plataforma que disponga de una conexión USB o RS-232, de ahí su implementación mediante JAVA, pero debido a que para realizar las comunicaciones con dichos puertos se ha utilizado un librería nativa (RXTXcomm.jar), es posible que existan algunas incompatibilidades de un plataforma a otra, cosa que se debería consultar en la web de RXTXcomm. Básicamente el programa ofrece cinco apartados bien diferenciados: La pantalla principal de inicio: Es la ventana que vemos cuando inicia el programa, en ella realizamos y vemos las operaciones principales, como son realizar la conexión/desconexión con la interface y siempre viendo en una consola de texto los datos que se están enviando y recibiendo a tiempo real. La opción de configuración del puerto: En esta sección del programa podemos configurar todos los parámetros necesarios del puerto serie, para poder realizar una conexión. La opción de selección del protocolo de comunicación: Esta funcionalidad del programa permite que el usuario pueda elegir manualmente el protocolo con el que se quiere comunicar con la ECU de su vehículo. La opción de Lectura de códigos de error: Esta opción ofrece la posibilidad de poder averiguar si nuestro vehículo ha sufrido o sufre algún fallo técnico, a través de la obtención de un código identificativo que especifica la avería y que proporciona la ECU. La opción de mediciones a tiempo real: Esta parte del programa proporciona información de los diferentes sensores de los que dispone el motor de nuestro vehículo, mostrando datos como la temperatura, velocidad, revoluciones por minuto, cantidad de aire absorbido, etc.… 46 Para realizar el software se utilizó la estructura de programación por capas: capa de datos, capa de dominio y capa de presentación. Cada capa tiene una función dentro del programa y una serie de clases que cumplen con la función que se les ha asignado. A continuación se explica la función y clases que contiene cada capa: 1. Capa de Datos: Es la encargada de gestionar todas las tramas de datos que se intercambian la computadora y la interface. Su objetivo es recoger ya sean datos recibidos o enviados, adecuarlos y tratarlos para poder o bien mandárselos a la interface a través del puerto serie o recibirlos y mandárselos a las capas superiores. En esta capa podemos encontrar las siguientes clases: Clase Conexión: Es la encargada de encapsular todos los atributos de los que se compone una conexión que se realiza atreves del puerto serie: velocidad, dataBits, stopBits, paridad, nombrePuerto, protocolo. Clase ControladorConexión: Contiene todos los métodos necesarios para realizar la conexión, contiene mucha de la estructura conseguida en los programas de prueba. Clase lecturaTXTErrores: Clase que permite acceder a archivos de tipo “TXT”, con el objetivo de que el programa disponga de una memoria permanente. Alguna de las funcionalidades de las que dispone el software necesita cotejar la información que recibe con la que dispone para poder reconocerla, como es el caso de la lectura de los códigos de error. Clase MuestraIDs: Captura los identificadores de trama del protocolo CAN Bus. 2. Capa de Dominio: Es la encargada de hacer de intermediario entre la capa de datos y la inmediatamente superior a la de dominio, que en este caso es la de presentación. Ofrece la capacidad de trabajo de la capa de datos, de una forma mucho más accesible para sus capas superiores. En esta capa encontramos la clase ControladorDominioConexión, la cual contiene todos los métodos necesarios para manejar todas las clases que se encuentran en la capa de datos. 47 Capa de Presentación: Esta capa se encarga de gestionar toda la parte visual del programa y contiene todas las clases y controladores necesarios para poder llevar a cabo esta tarea. Concretamente estas son las clases que contiene: ControladorPrincipal y VistaPrincipal: Gestionan la carga de todas las demás clases de la capa de presentación y proporcionan las operaciones básicas del programa, como son poder iniciar o detener un conexión con la interface y seleccionar las diferentes opciones del programa. ControladorErrores y VistaCodigosError: Estas clases se ocupan de gestionar la presentación en pantalla de los códigos de error proporcionados por la ECU. ControladorMediciones y VistaMediciones: Se ocupan de gestionar la presentación en pantalla de los datos referentes a valores que proporcionan los sensores del vehículo, tales como temperatura, velocidad, revoluciones por minuto, cantidad de aire absorbido, etc.… ControladorProtocolo y VistaProtocolo: Gestionan la presentación en pantalla de las opciones disponibles a la hora de seleccionar un protocolo de comunicación. ControladorPSerie y VistaConfiguración: Presentan en pantalla todas las opciones que requiere el puerto serie para ser configurado. Además permiten realizar una búsqueda de estos. Por lo extenso del código de este último programa, se incorporará al final del proyecto como documento adjunto. En esta aplicación la clase más importante y difícil de desarrollar es la clase ControladorConexion, ya que es la que capacita al software de la capacidad de utilizar varios hilos de ejecución. Esta clase implementa la interface “Runnable” con su respectivo método “Run()”, el cual está en permanente escucha a los mensajes que se envían desde el puerto serie, y por tanto permite liberar al hilo principal para poder realizar otras funciones simultáneamente. Otra de las clases que implementa un nuevo hilo de ejecución es la clase ControladorMediciones, la cual se encarga de mostrar los datos de la lectura a tiempo real de los diferentes sensores de los que dispone la centralita en el vehículo. Por tanto en la aplicación trabajan 3 hilos de ejecución: Hilo principal: Se mantiene a la espera para realizar las funciones que reclame el usuario. Hilo de la clase ControladorConexion: Escucha permanentemente el puerto serie consiguiendo así no perder ningún posible dato y una velocidad de respuesta mucho más alta. Hilo de la clase ControladorMediciones: Refresca constantemente en pantalla los datos que va recibiendo el método run() de la clase ControladorConexión. 48 Cuando se procedió a probar el software sobre diferentes sistemas operativos con la intención de asegurar su funcionalidad, ventaja que tiene JAVA sobre otros lenguajes ya que utiliza una maquina virtual, se observó que en Windows funcionaba correctamente ya que sobre este se había realizado la programación, pero sobre Linux se obtuvo un resultado inesperado. Se observó que en Linux el programa arrancaba y funcionaba de forma correcta, pero en el momento que se procedía a desconectarlo del puerto serie el programa quedaba totalmente bloqueado. Después de muchas pruebas se averiguó que las librerías nativas “RXTXcomm.jar” que utiliza esta aplicación se comportaban de diferente forma según el sistema operativo en el que estuviéramos trabajando. El problema se encontraba en el método run() de la clase ControladorConexión(), ya que este utiliza la clase SerialPort constantemente para escuchar el puerto serie. Observando el siguiente fragmento de código podemos hacernos una idea de la situación: public void run(){ boolean datos=false; String tramaRecibida; Thread thisThread = Thread.currentThread(); while(hilo == thisThread){ char z; int longitudTrama=0; int reb=0; try { datosRecibidos = port.getInputStream(); while((reb=datosRecibidos.read())>-1){ z=(char) reb; if(reb==62){ break; } if(reb!=-1){ tramaRecibidaInicial.append(z); } } DestruirHilo=true; } catch (IOException e1) { estado("No response."); } Vemos que la línea subrayada, “datosRecibidos.read()”, es la orden que se encarga de acceder al puerto y cuando el hilo de ejecución llega a ella en Windows la lee una vez y sigue su transcurso dentro del método “run()” hasta el siguiente ciclo de bucle donde lo volvería a leer, pero en Linux no sucede los mismo, el hilo de ejecución se detiene en esta línea esperando un nuevo mensaje del puerto y por tanto bloqueando su posible cierre desde el hilo principal, es decir, como el hilo que se ejecuta en “run()” nunca libera al objeto “port”, cuando accedemos al mismo objeto desde el hilo principal de la clase este provoca un bloqueo de la aplicación ya que nunca tendrá permiso para cerrarlo. Esto se solucionó enviando un mensaje cualquiera al puerto y cambiando en el mismo instante la condición del bucle “while”(hilo=null), para que el hilo de run() saliese de su estado de escucha y acabara extinguiéndose ya que la condición del bucle ya no se cumplía. 49 Como aporte final a esta aplicación se procedió a empaquetarla en un archivo “.jar”, lo que facilita mucho su puesta en marcha y portabilidad a cualquier otra plataforma o sistema operativo. Pero uno de los inconvenientes que presentaba esta aplicación era que para poder comunicarse con los puertos de comunicación necesitaba la librería nativa “RXTXcomm”, y por tanto, esta no viene incluida en las librerías de la maquina virtual que se instala por defecto, lo que obliga a tener que instalarla manualmente. Para cualquier persona que esté familiarizada con la programación no resulta ser un problema, pero si para alguien que solo quiera hacer unas cuantas pruebas. La solución fue crear una carpeta donde se introduciría el archivo “JAR”, los archivos adjuntos necesarios como los “JPG” y “TXT”, y otra carpeta donde incluiríamos la librería nativa “RXTXcomm”. Además de lo anterior se crearon dos archivos ejecutables (RunLinux.sh y RunWindows.bat), que se utilizan según en el sistema operativo en el que estemos. La carpeta se llama VisualOBDJar y contiene los siguientes archivos: VisualOBD.jar: Archivo comprimido que contiene todo el código de la aplicación. RunLinux.sh: Archivo ejecutable para Linux. RunWindows.bat: Archivo ejecutable para Windows. VisualOBD4_1 y AboutVisualOBD: Archivos de tipo “JPG”. CodigodErrores.txt: Archivo de texto utilizado como base de datos. Leeme.txt: Archivo de texto que contiene una breve explicación de cómo arrancar el software. lib: Carpeta que contiene la librería nativa “RXTXcomm” con los respectivos archivos “rxtxParallel.dll”, “rxtxSerial.dll”, “librxtxSerial.so”, y “librxtxParallel.so” necesarios para realizar su carga en el sistema operativo través de la máquina virtual. 50 Para poder realizar la carga de la librería nativa correctamente se tuvo que modificar el archivo MANIFEST que contiene el paquete VisualOBD.jar quedando de la siguiente forma: Y a los archivos RunWindows.bat y RunLinux.sh se les introdujo los siguientes comandos: 51 3. Resultados 3.1. Ámbito de utilización Este proyecto se basa en un sistema para el chequeo del estado técnico de cualquiera de los vehículos que actualmente se comercializan o se han comercializado desde 1996 en EEUU y 2001 en Europa, y por tanto su ámbito de utilización se puede extender bastante, incluso como pequeña herramienta para los profesionales del sector o para cualquier persona que disponga de un vehículo dotado con el sistema On Board Diagnostics-II (OBD-II), que tenga interés en indagar sobre el estado de su automóvil. Esta herramienta podría ser muy útil, por ejemplo, para un pequeño taller mecánico donde su presupuesto para adquirir un aparato de diagnostico es reducido, y utilizando el sistema descrito aquí podría solucionarle muchos problemas sin tener que hacer un gran desembolso económico. Actualmente todos los vehículos de cualquiera de los fabricantes, están obligados por ley a implementar este estándar, como un mecanismo que facilite a todo el sector del mantenimiento, el rápido diagnostico de las averías, lo que garantiza que el sistema que se ha desarrollado será útil en un ámbito muy extenso. También hay que decir que es necesario que el usuario tenga un mínimo de conocimientos sobre la materia para comprender los resultados que muestra el programa de diagnostico durante el chequeo del vehículo, lo que quizás hace que se reduzca en parte el ámbito de uso. Por otro lado en este proyecto se profundiza bastante en el tratamiento de las comunicaciones realizadas a través del puerto serie utilizando los lenguajes C++ y JAVA, información que puede ser muy útil en todo aquel ámbito que necesite de esta conexión. 3.2. Validación de los diseños Una vez terminado el proceso de diseño, el siguiente paso ha sido validar el proyecto realizando pruebas en diferentes vehículos de diferentes marcas, teniendo la certeza de que estos estaban equipados con estándar OBD-II. Cada modelo chequeado disponía de un protocolo de comunicación diferente a nivel de capa física, con lo que se conseguía comprobar que todos los protocolos que implementa la interface funcionan. 52 Las pruebas realizadas se realizaron con éxito en los siguientes coches: Citroen C3 1.4 HDI: Fabricado en 2004 Equipado con OBD-II y implementa el protocolo ISO 14230-4 KWP2000 Seat Toledo 1.9 TDI: Fabricado en 2001 Equipado con OBD-II y implementa el protocolo ISO 9141-2 VolksWagen Golf 1.9 TDI: Fabricado en 2002 Equipado con OBD-II y implementa el protocolo ISO 9141-2 Audi A3 1.9 TDI: Fabricado en 2001 Equipado con OBD-II y implementa el protocolo ISO 9141-2 Toyota Prius (Motor hibrido) Fabricado en 2006 Equipado con OBD-II y implementa el protocolo ISO 15765-4 CAN BUS Seat Leon 1.9 TDI: Fabricado en 2008 Equipado con OBD-II y implementa el protocolo ISO 15765-4 CAN BUS Ford Focus TDDi: Fabricado en 2002 Equipado con OBD-II y implementa el protocolo SAE J1850PWM Opel Astra 1.6i: Fabricado en 2001 Equipado con OBD-II y implementa el protocolo SAE J1850VPW Opel Astra 2.0 DTI: Fabricado en 2003 Equipado con OBD-II y implementa el protocolo ISO 9141-2 Ford Escort 1.8 TD: Fabricado en 1998, equipado con OBD-II, implementa el protocolo SAE J1850PWM, pero no es compatible con nuestro trabajo por incorporar un modo de trabajo (Modo 22) no contemplado en el proyecto por su poco uso. 53 3.3. Descripción del funcionamiento A continuación se describen los pasos a seguir para poner en marcha el sistema a la hora hacer un chequeo sobre un vehículo. El primer paso es localizar en el coche el conector OBD-II, ya que cada modelo lo puede incorporar en un lugar diferente. Una vez localizado debemos conectar nuestro cable OBD-II el cual proviene de nuestra interface. Disponiendo de un ordenador portátil o de uno de sobremesa cercano al lugar donde estemos trabajando, conectamos la interface al puerto USB. El montaje sería el siguiente si se realiza en un Citroen C3 del año 2004, ya que con respecto a otro modelo puede variar la localización del conector OBD-II. 54 A partir de aquí podemos arrancar nuestro PC, una vez cargado el sistema operativo entramos dentro de la carpeta que contiene el software del proyecto llamada VisualOBDJar. En esta carpeta encontramos dos archivos ejecutables, el RunLinux.sh y RunWindows.bat, los cuales serán utilizamos según en el sistema operativo en que estemos trabajando. En este caso arrancamos RunWindows.bat y nos aparecerá el siguiente entorno visual: 55 El siguiente paso es realizar la conexión, y para ello debemos arrancar el motor del coche, seleccionar los parámetros de configuración del puerto serie (Options->Serial Port Configuration): Cliqueando en “Search for available ports” obtendremos un lista de los puertos que tenemos disponibles. Posteriormente en la parte superior seleccionaremos el puerto en el que esté conectada la interface, y modificaremos los demás parámetros según sea necesario. Después solo queda cliquear en “Apply” para confirmar los cambios. 56 Ahora debemos seleccionar el protocolo de comunicación (Options>Communication protocol configuration). En el caso de no conocer el protocolo que se va utilizar, el sistema lo detectará automáticamente: Vemos que podemos seleccionar el protocolo de comunicación o dejar seleccionada la opción “Automatic detection of communication protocol”, para que sea autodetectado. Esta sección también nos proporciona la posibilidad de modificar las cabeceras de las tramas que se van a enviar. Cada opción (Priority, ECU Addres, Tool address) se corresponde con un byte dentro de la trama, esto aumenta las posibilidades de éxito en el momento de conectarse con la ECU, ya que aunque muchos modelos de centralitas se comunican de la misma forma, necesitan que se les especifique este parámetro y por tanto modificar el que se envía por defecto. 57 El siguiente paso es iniciar la conexión cliqueando en “Connect”, si el proceso se ha realizado con éxito obtendremos la siguiente respuesta: Observamos que en la consola de texto nos aparecen los comandos “0100”->”41 00 98 1B 00 11” y “0100”->”86 F1 10 41 00 98 1B 00 11”, lo que quiere decir que se ha realizado la conexión correctamente y que la ECU contestó adecuadamente informando de los PID’s (Parameter ID’s) que tiene disponibles para ser inspeccionados. 58 En caso de que la conexión con la ECU sea fallida este sería el resultado: Observamos que en la consola de texto se nos comunica que en los comandos “0100”->”Unable to connect”, no hubo respuesta ya que la captura se trata de un simple prueba sin conexión a la ECU. Los demás comandos “AT”, son contestados correctamente porque son datos procedentes únicamente de la interface, es decir, solo incumben a parámetros que tienen que ver con el microcontrolador de la interface sin tener en cuenta a la ECU. 59 Ahora podemos ver un ejemplo de la información que nos daría el programa en el caso de que el vehículo tuviera almacenados 4 códigos de error indicando así que se han producido estos fallos técnicos. Para acceder a esta información solo hay que cliquear en “Read error codes”, estando por supuesto el sistema correctamente conectado a la ECU: Este es un ejemplo simulado por eso en la consola de texto seguimos obteniendo un resultado negativo cuando se envían los comandos “0100”,”0101” y “03”. El programa nos indica si la luz de chequeo MIL (Malfunction Indicator Light) situada en el cuadro de mandos, está encendida y cuantos códigos de error tiene almacenados la ECU. Además se detallan cuales son los códigos de error y una descripción del significado de estos. Si además quisiéramos borrar estas fallas almacenadas en la memoria de la centralita, tendríamos que cliquear en “Clear error codes”, y nos aparecería una advertencia de seguridad que nos avisaría del paso que vamos a realizar, ya que si borramos esta información accidentalmente no la podríamos recuperarla. 60 Otra funcionalidad del programa es la lectura de datos a tiempo real de los sensores que tiene instalados el motor. La cantidad de información que podemos obtener, depende de la ECU, ya que según el modelo de esta, puede ofrecer más o menos datos de los sensores que gestiona en la mecánica del motor. Un ejemplo sería el siguiente: En la imagen se observan por un lado los datos que se van recibiendo en formato numérico, es decir, carga del motor, temperatura del refrigerante, revoluciones por minuto, velocidad actual, temperatura y cantidad de aire absorbido MAF (Mass Air Flow), y en la consola de texto se observan los mismos datos pero en formato hexadecimal, que es como la interface los va enviando a nuestro software. Esta última característica nos permite localizar rápidamente cualquier incidencia en el proceso de transferencia de datos o en el procesamiento de la centralita electrónica ya que de no ser así sería mucho más difícil detectar el problema. 61 En esta captura se observan más datos aportados por la ECU: Se puede observar que se nos proporciona información sobre la cantidad de kilómetros que hemos circulado con algún problema técnico indicado con la luz de chequeo MIL (Malfunction Indicator Lamp) encendida. Otro dato importante es el de la presión que hay en el circuito de inyección de combustible en estado de motor a ralentí, proporcionada por la bomba inyectora a los cilindros. Parece un dato desproporcionado ya que 22070Kpa equivalen a 220,7 bar de presión, pero teniendo en cuenta que la tecnología hoy utilizada puede llegar hasta los 2000 bar en el régimen de motor más alto, es bastante aceptable. 62 En esta otra imagen se observan las mismas lecturas pero realizadas a un régimen de motor más alto, se ha pasado de estar en 751rpm a 1613. Observamos que la temperatura de refrigerante es menor que en la captura anterior, esto se debe a que se tomaron los datos anteriormente. Lo importante a señalar es que además de ver cambios en la rpm, también los hay en “MAF Air Flow Rate” ya que el motor necesita absorber más aire. En “Calculated engine load value” los datos también varían, este dato nos informa sobre la carga a la que está sometido el motor en ese preciso momento con respecto a la carga total que podría soportar, y aunque lo lógico sería que aumentase a mas revoluciones el resultado es todo lo contrario, disminuye. Esto se debe a que aunque el motor gira a más vueltas, este no debe ejercer ningún esfuerzo ya que se encuentra parado y por tanto no encuentra ninguna fuerza contraria al sentido de giro. 63 Una imagen muy determinante para constatar que las lecturas son correctas es la siguiente: Observamos que el cuenta revoluciones del panel de instrumentos del vehículo, está marcando alrededor de las 1500 rpm, dato que se confirma observando la pantalla del ordenador portátil donde aparece una lectura de 1510 rpm. Se observa también que hay coincidencia en la velocidad, que es de 0 km/h ya que nos encontrábamos parados. 64 Hasta ahora el software se ha presentado funcionando bajo sistema operativo Windows XP, pero también es capaz de funcionar en otros sistemas operativos, como por ejemplo Linux. En la siguiente imagen podemos apreciarlo: En la imagen vemos funcionar el software diseñado en este proyecto bajo sistema operativo Linux, concretamente en la distribución Ubuntu en su versión 8.04, con la maquina virtual de JAVA instalada. Respecto a Linux hay que hacer una pequeña aclaración sobre la detección de los puertos serie. En este sistema operativo los puertos serie se suelen identificar con nombres como “ttyS0”, “ttyACM0” o “ttyUSB0”, a diferencia de los COM1, COM2, COM3, etc., de Windows y además se ubican en un carpeta llamada “/dev”. Por tanto cuando arrancamos el programa en Linux seleccionamos una de estas opciones y no tendremos ningún problema si nuestra interface se conecta directamente al puerto RS-232, ya que la detectará como /dev/ttySO, que es la referencia de dispositivo que siempre es detectada de forma correcta. 65 Muchas de las interface compatibles utilizan el puerto USB, como es nuestro caso, y en Windows las detecta también como puerto COM y no encontramos problemas, pero en Linux estas interface son detectadas como /dev/ttyACM0, y aquí es donde podemos tener impedimentos, porque este error viene causado por la librería nativa RXTXcomm, la cual no contempla este tipo de puertos. Para poder solucionarlo podemos ejecutar la siguiente línea de comando en un terminal de Linux, con la intención de hacer un linkado simbólico de la interface “/dev/ttyACM0” con una referencia que si reconozca la librería, por ejemplo “/dev/ttyS0”: >ln -sf /dev/ttyS0 /dev/ttyACM0 Después de ejecutar este comando podremos seleccionar el dispositivo “ttyS0” como si se tratase de “ttyACM0”, y la comunicación se realizará sin ningún tipo de problema. 3.4. Aplicaciones del proyecto Como se ha ido viendo durante todo el desarrollo de la memoria, las aplicaciones de este sistema de diagnosis son bastante obvias. El sistema diseñado es aplicable al chequeo del estado técnico de cualquiera de los vehículos que actualmente se comercializan o se han comercializado desde el año 1996 en EEUU y 2001 en Europa. Es a partir de estas fechas cuando se obligó a los fabricantes a implantar el estándar OBD-II, y aunque anteriormente los vehículos también estaban equipados con un sistema de este tipo precisamente llamado OBD, es decir, el mismo sistema pero en su primera versión, este no estaba estandarizado entre todos los fabricantes y por tanto cada uno de ellos implementaba sus propios mecanismos para realizar la auto diagnosis de sus modelos, lo que lleva a descartar este proyecto en aplicaciones referentes a este tipo de vehículos. Por tanto como ejemplo este sistema se puede aplicar en las labores de manteniendo de cualquier profesional del sector que se encuentre con uno de los vehículos mencionados anteriormente averiado y que después de su reparación verifique con esta herramienta si el problema se ha subsanado correctamente asegurándose de que la ECU no devuelve ningún código de error o de que el sensor en cuestión ofrece unas lecturas correctas según especificaciones del fabricante. 66 Otro ejemplo podría ser el que se da normalmente cuando cualquier poseedor de un vehículo con OBD-II observa que en el cuadro de instrumentos se le ha encendido una luz llamada “Check Engine” y se pregunta el porqué de este fallo. En lugar de recurrir al servicio de mantenimiento inmediatamente podemos proceder a realizar una lectura de “Codigos de Error” obteniendo el posible código que nos describirá brevemente a que se debe el problema. Otra de las facetas en las que se puede incluir este sistema es entre aquellas personas que por puro placer o interés quieren conectarse con su automóvil para observar los datos que la centralita electrónica les puede ofrecer, con fines de simple curiosidad. Como vemos esta herramienta, aunque no está dotada de todo el potencial posible que ofrece el OBD-II, si aporta una funcionalidad muy útil entre los posibles usuarios interesados por la mecánica. 4. Comentarios finales 4.1 Plan de trabajo El plan de trabajo de este proyecto se ha ido desarrollando según los siguientes puntos: 1. Conseguir todos los componentes y materiales electrónicos necesarios para construir el modem interface y el programador de PICs. 2. Montar la interface y el programador según el PCB y esquemas eléctricos especificados en el proyecto. 3. Montar un cable OBD-II para ser utilizado provisionalmente durante las primeras pruebas. 4. Comprobar el correcto funcionamiento de la interface y familiarizarse con los comandos “AT” que permiten configurar el microcontrolador PIC18F2550. 5. Instalar en un ordenador portátil los sistemas operativos WindowsXP y Linux Ubuntu 8.04 con la respectiva maquina virtual de JAVA. 6. Instalar software compatible con la interface para comprobar su correcto funcionamiento. 67 7. Conectar la interface a diferentes vehículos para asegurar su funcionalidad. 8. Programar aplicaciones de prueba en C++ y Java. 9. Programar aplicación utilizando JAVA con un entorno visual lo suficientemente potente que permita gobernar la interface y la centralita electrónica de forma estable. 10. Verificar el correcto funcionamiento de la aplicación sobre la interface mediante pruebas. 11. Verificar el correcto funcionamiento de la aplicación sobre la centralita electrónica de los vehículos mediante pruebas. 12. Verificar el correcto funcionamiento de la aplicación en diferentes sistemas operativos, Windows y Linux. 4.2 Listado de materiales Listado de los materiales para montar el modem interface: J1 Conector USB tipo B J2 Conector DB-9 Macho Q1,Q3 Transistor 2N7000 Q2 Transistor BS250/VP2106 IC1 PIC18F2455 IC2 MC33290 IC3 MC33390/MC33990 IC4 MCP2551/PCA82C250 IC5 MCP2515 X1 Cristal, 16.000Mhz X2 Cristal, 20.000Mhz D1 LED verde 5 mm D2 LED Amarillo 5mm 68 D3 LED rojo 5mm D4,D5 Diodo 1N4148 R1,R4,R5,R8 10K Ohm R2,R3 330 Ohm R6,R7 22K Ohm R9,R10 510 Ohm R11,R12 100 Ohm C1,C2,C4,C5 15pF C3,C8,C9 0.1uF C6 0.47uF C10,C11 560pF C7 10uF 16V IC Socket Socket para PIC18F2550 28 pin Listado de materiales para montar el programador: J1 Conector DB9 Hembra D1, D2, D6, D7 Diodo 1N4149 D4 Diodo Zener 6.2 V D5 Diodo Zener 5.1 V D3 LED Rojo 5 mm Q1, Q2 Transistor 2N3904 C1, C4 33pF C2 100µF 16V C3 22µF 6.3V R3 100Ω R1 1.5KΩ R2 10KΩ 69 Listado se software y hardware utilizado durante el proyecto: Bloodshed Dev-C++: Programa utilizado para desarrollo de software en C++. Eclipse 3.2: Programa utilizado principalmente para desarrollo de software en JAVA. ScanTool: Programa de diagnostico OBD-II basado en microcontrolador ELM327. Hex Workshop: Programa para la edición de archivos en formato hexadecimal. PICPgm Programer: Utilizado para el gravado del firmware en el PIC18F2550. GerbMagic: Programa utilizado para la edición y diseño del circuito electrónico del modem interface. JDK 6 Update 13: Paquete instalador de la máquina virtual de JAVA. PC de sobremesa con WindowsXP Home Edition y Linux Ubuntu 8.04 instalados para realizar la programación. Ordenador portátil con WindowsXP Home Edition Y Linux Ubuntu 8.04 instalados para realizar las pruebas en los vehículos. 4.3 Presupuesto La tabla siguiente especifica el presupuesto detallado en euros: Referencia Cantidad Precio unitario Precio total Material montaje interface 1 20 20 Material montaje programador 1 5 5 Cable OBD-II a DB9 hembra 1 5 5 Cable USB tipo A-B 1 2 2 Hora trabajo 35 30 1050 Total 1082 70 4.4 Objetivos logrados Durante todo el proyecto se han ido consiguiendo diferentes objetivos que en conjunto han hecho que el resultado final haya sido satisfactorio. A continuación se detallan por puntos: Conseguir que el montaje de la interface funcione correctamente. Lograr que el cable OBD-II utilizado previamente para hacer pruebas sea fiable. Poder acceder a las centralitas electrónicas (ECU), según el estándar OBD-II. Consolidar la comunicación con el modem a través del puerto serie mediante aplicaciones de software de propio desarrollo en C++ y JAVA. Conseguir descifrar las tramas digitales para obtener una información fácilmente comprensible en pantalla de los datos enviados por la ECU. Finalizar el desarrollo de la aplicación visual en JAVA con todas las opciones previstas. Estabilizar la aplicación visual en JAVA sin que se produzca ningún error ya sea de comunicación con la interface o de manejo respecto al usuario. Conseguir que la aplicación visual en JAVA funcione correctamente tanto en Windows como en Linux. 4.5 Conclusiones El lenguaje de programación JAVA es una herramienta muy potente, ya que permite que una misma aplicación pueda funcionar de igual forma en diferentes sistemas operativos y plataformas. Es posible acceder a la centralita electrónica de un vehículo utilizando montajes sencillos y ordenadores personales. En realidad está al alcance de cualquier usuario particular. 71 La ingeniería inversa sobre un “firmware” (desensamblado), tiene limitaciones y para realizar cambios significativos es necesario disponer del código fuente, sino estamos limitados a pequeñas modificaciones. Los fabricantes de automóviles han implementado el estándar OBD-II obligados por EE.UU. i U.E de una forma bastante compatible como lo demuestra el que un pequeño dispositivo genérico como el que se ha realizado, funcione en un amplio rango de vehículos. El hecho de disponer de un microcontrolador programable disminuye la dependencia en la plataforma, ya que solo es necesario que disponga de conexión USB, y a partir de aquí el papel de las plataformas es de gestionar una conexión serie. El procesado de los protocolos los realiza el micro. 4.6. Mejoras futuras Internacionalizar el software de control con la intención de que pueda mostrar la información en varios idiomas ya que en esta primera versión solo se muestran en ingles. Implementar todos los modos de trabajo del estándar OBD-II en el software de control. Dotar a la interface de una botonera y un pequeño “display” para poder realizar las funciones más simples de forma autónoma, como por ejemplo la lectura y borrado de los códigos de error DTC. Implementar en el software de control una opción de autoayuda para poder entender y manejar el sistema de forma más rápida. Esta mejora sería muy útil porque los datos que se manejan son bastante abstractos. Crear un paquete instalador que automáticamente sitúe los ficheros necesarios del software para acelerar su puesta en marcha. 72 Bibliografía [1] OBD2 ELM327 compatible AllPro adapter with USB, www.obddiag.net [2] OBD-II PID’s, Wikipedia-The Free Encyclopedia. [3] ASCII, Wikipedia-The Free Encyclopedia. [4] OBD-II Trouble Codes Home, OBD-Codes.com [5] Scanner OBD2, www.gncusers.com.ar [6] ELM327DS.pdf, www.elmelectronics.com [7] ELM320DS.pdf, www.elmelectronics.com [8] 18F2455_2550.pdf, www.microchip.com [9]Librería nativa “RXTXcomm”, www.rxtx.org 73 Anexo Código ejemplo para el manejo de la librería “RXTXcomm” en lenguaje Java, disponible en www.rxtx.org: import import import import import import import gnu.io.CommPort; gnu.io.CommPortIdentifier; gnu.io.SerialPort; java.io.FileDescriptor; java.io.IOException; java.io.InputStream; java.io.OutputStream; public class TwoWaySerialComm { public TwoWaySerialComm() { super(); } void connect ( String portName ) throws Exception { CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName); if ( portIdentifier.isCurrentlyOwned() ) { System.out.println("Error: Port is currently in use"); } else { CommPort commPort = portIdentifier.open(this.getClass().getName(),2000); if ( commPort instanceof SerialPort ) { SerialPort serialPort = (SerialPort) commPort; serialPort.setSerialPortParams(57600,SerialPort.DATABITS_8, SerialPort.STOPBITS_1,SerialPort.PARITY_NONE); InputStream in = serialPort.getInputStream(); OutputStream out = serialPort.getOutputStream(); (new Thread(new SerialReader(in))).start(); (new Thread(new SerialWriter(out))).start(); } else { System.out.println("Error: Only serial ports are handled by this example."); } } } 74 public static class SerialReader implements Runnable { InputStream in; public SerialReader ( InputStream in ) { this.in = in; } public void run () { byte[] buffer = new byte[1024]; int len = -1; try { while ( ( len = this.in.read(buffer)) > -1 ) { System.out.print(new String(buffer,0,len)); } } catch ( IOException e ) { e.printStackTrace(); } } } public static class SerialWriter implements Runnable { OutputStream out; public SerialWriter ( OutputStream out ) { this.out = out; } public void run () { try { int c = 0; while ( ( c = System.in.read()) > -1 ) { this.out.write(c); } } catch ( IOException e ) { e.printStackTrace(); } } } public static void main ( String[] args ) { try { (new TwoWaySerialComm()).connect("COM3"); } catch ( Exception e ) { e.printStackTrace(); } } } 75 Código fuente del software de control desarrollado en el proyecto: Capa de Datos: Clase Conexión: package Datos; public class Conexion { int velocidad; int dataBits; int stopBits; int paridad; String nombrePuerto; String protocolo; public Conexion(int velocidad, int dataBits, int stopBits, int paridad, String nombrePuerto, String protocolo) { super(); this.velocidad = velocidad; this.dataBits = dataBits; this.stopBits = stopBits; this.paridad = paridad; this.nombrePuerto = nombrePuerto; this.protocolo = protocolo; } public int getDataBits() { return dataBits; } public int getStopBits() { return stopBits; } public String getNombrePuerto() { return nombrePuerto; } public int getParidad() { return paridad; } public int getVelocidad() { return velocidad; } public String getProtocolo(){ return protocolo; } } 76 Clase ControladorConexión: package Datos; import import import import import import import import import import import import java.io.IOException; java.io.InputStream; java.io.OutputStream; java.util.Date; java.util.Enumeration; java.util.Vector; javax.swing.JTextArea; gnu.io.CommPortIdentifier; gnu.io.NoSuchPortException; gnu.io.PortInUseException; gnu.io.SerialPort; gnu.io.UnsupportedCommOperationException; public class ControladorConexion implements Runnable{ SerialPort port; CommPortIdentifier idpuerto; OutputStream datosEnviados; InputStream datosRecibidos; String estado; StringBuffer tramaEnviada; StringBuffer tramaRecibidaInicial; StringBuffer tramaDatos; StringBuffer tramaDatosCan; StringBuffer tramaMediciones; StringBuffer pids_disponibles; JTextArea respuestaTexto; String strDatos; lecturaTXTErrores lecErr; boolean conexionCOM=false; boolean listo=false; boolean procesaDatos=false; boolean permisoEnvioManual=false; boolean DestruirHilo=false; private volatile Thread hilo; Date temps,temps2; String numeroProtocolo; Vector<String> ids; String ID; MuestraIDs MIDs; Conexion con; public ControladorConexion(JTextArea respuestaTexto) { this.respuestaTexto=respuestaTexto; lecErr = new lecturaTXTErrores(); MIDs = new MuestraIDs(); } public void establecerConexion(Conexion con){ this.con=con; this.tramaEnviada=new StringBuffer(); this.tramaRecibidaInicial=new StringBuffer(); this.tramaDatos=new StringBuffer(); this.tramaDatosCan=new StringBuffer(); this.tramaMediciones=new StringBuffer(); this.pids_disponibles=new StringBuffer(); this.ID=""; this.numeroProtocolo="0"; 77 if(conexionCOM==false){ try { idpuerto = CommPortIdentifier.getPortIdentifier(con.getNombrePuerto()); } catch (NoSuchPortException e) { estado("Port "+con.getNombrePuerto()+" not available."); } try { port = ( SerialPort )idpuerto.open("VisualOBD",2000); } catch (PortInUseException e) { estado("Port "+con.getNombrePuerto()+" in use."); } try { port.setSerialPortParams(con.getVelocidad(), con.getDataBits(), con.getStopBits(), con.getParidad()); } catch (UnsupportedCommOperationException e) { estado("Operation not supported."); } hilo=new Thread(this); hilo.start(); hilo.setPriority(Thread.MIN_PRIORITY); conexionCOM=true; } estado("Connected "+con.getNombrePuerto()+"."); enviar("atz"); enviar(con.getProtocolo()); enviar("0100"); enviar("atdp"); enviar("atdpn"); enviar("ath1"); enviar("0100"); timer(); } public void desconectar(){ if(conexionCOM==true){ enviar("atws");//En linux el hilo del run, se para en el datosRecibidos.read(), por tanto necessiatmos mandar algo DestruirHilo=false;//para que se mueva de ahi, atws esta bien porque resetea //la interface al desconectar. while(DestruirHilo==false){//Espera a que se reciba la ultima trama en run() //para poder despues destruir el hilo y cerrar los //puertos. try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } hilo = null;//Obliga a desacer el bucle del hilo para asi pararlo de forma //segura. conexionCOM=false;//Cuando el hilo ya ha recibido la informacion (en linux), //sigue el camino muriendo, ya que hilo=null try { datosEnviados.close(); } catch (IOException e) { estado("Failed to close communication"); } try { 78 datosRecibidos.close(); } catch (IOException e) { estado("Failed to close communication."); } try{ port.disableReceiveFraming();//Meramente formal port.close(); estado("Offline."); } catch (Exception e){ estado("Failed to close port"); } }else{ estado("You are not connected."); } } public void enviar(String trama){ int longitudTramaEnv=0; int data; listo=false; if(conexionCOM==true){ this.tramaEnviada.append(trama+"\r");//Solamente necessita el retorno de //carro, sin el salto de linea. try { datosEnviados = port.getOutputStream(); for(int i=0;i<tramaEnviada.length();i++){ data= tramaEnviada.codePointAt(i); datosEnviados.write(data); } longitudTramaEnv=tramaEnviada.length(); tramaEnviada.delete(0, longitudTramaEnv); } catch (IOException e) { estado("Unable to send "+tramaEnviada+"."); } }else{ estado("You are not connected to any port."); } } public void run(){ boolean datos=false; String tramaRecibida; Thread thisThread = Thread.currentThread(); while(hilo == thisThread){ char z; int longitudTrama=0; int reb=0; try { datosRecibidos = port.getInputStream(); while((reb=datosRecibidos.read())>-1){ z=(char) reb; if(reb==62){ //Cuando se recibe 62 = >, se sale del bucle //para separar los mensajes. //Se hace break en run break; } if(reb!=-1){ tramaRecibidaInicial.append(z); } } DestruirHilo=true;//Esto da permiso al metodo desconectar() para //poner el hilo=null. 79 } catch (IOException e1) { estado("No response."); } if(reb==62){ try { tramaRecibidaInicial.deleteCharAt(tramaRecibidaInicial.length()-1); //Se borra el último //salto de linea } catch (RuntimeException e2) {estado("No response.");} estado("Sent "+tramaRecibidaInicial.toString()); tramaRecibida=tramaRecibidaInicial.toString(); longitudTrama=tramaRecibidaInicial.length(); tramaRecibidaInicial.delete(0, longitudTrama); if(permisoEnvioManual==false){ for(int x=0;x<tramaRecibida.length();x++){ if(tramaRecibida.codePointAt(x)==10){ datos=true; } if(datos==true){ tramaDatos.append(tramaRecibida.charAt(x)); } } datos=false; try { if(tramaRecibida.codePointAt(0)==97 || tramaRecibida.codePointAt(0)==65){ procesaDatos=false; }else{ procesaDatos=true; } } catch (RuntimeException e2) {estado("No response.");} try { if(tramaRecibida.substring(0, 5).toString().compareTo("atdpn")==0){ if(tramaDatos.codePointAt(1)==65){ numeroProtocolo=tramaDatos.substring(2,3); }else{ numeroProtocolo=tramaDatos.substring(1,2); } estado("Protocol number: "+numeroProtocolo); } } catch (RuntimeException e1) {estado("No response.");} if(procesaDatos==true){ if(Integer.parseInt(numeroProtocolo)>=6){ try{ if(tramaDatos.codePointAt(8)==52){ 80 //El siguiente metodo diferencia las cabeceras CAN. if(ID.compareTo("")==0){ ids=new Vector<String>(); for(int f=0;f<tramaDatos.length();f++){ if(tramaDatos.codePointAt(f)==10){ ids.add(tramaDatos.substring(f+1, f+4));//Delemito los IDs, //hay que almacenarlos. } } mostrarIDS(ids); } for(int f=0;f<tramaDatos.length();f++){ if(tramaDatos.codePointAt(f)==10){ if(ID.compareTo(tramaDatos.substring(f+1, f+4))==0){ int longitud=0; try{ for(int g=f+8;tramaDatos.codePointAt(g)!=10;g++){ longitud=g; } }catch(Exception e){ longitud=longitud+1; System.out.println(e); } tramaDatosCan.append("\n"+tramaDatos.substring(f+8,longitud)); //No hacemos break para que asi coja todas las lineas con la misma cabecera. } } } strDatos=tramaDatosCan.toString(); longitudTrama=tramaDatosCan.length(); tramaDatosCan.delete(0, longitudTrama); if(ID==""){ strDatos="N";//Para que los demas metodos sepan que no se han //asignado los ids CAN. } }else if(tramaDatos.codePointAt(10)==55){ strDatos="Neg";//Para que se sepa que hay respuesta negativa. }else{ strDatos="N";//Para que los demas metodos sepan que no a llegado //informacion } }catch(Exception e){ //System.out.println(e); strDatos="N"; } }else{ try{ if(tramaDatos.codePointAt(10)==52){ for(int f=0;f<tramaDatos.length();f++){ if(tramaDatos.codePointAt(f)==10){ tramaDatos.delete(f+1, f+10); } } strDatos=tramaDatos.toString(); }else if(tramaDatos.codePointAt(10)==55){ strDatos="Neg";//Para que se sepa que hay respuesta negativa. }else{ strDatos="N";//Para que los demas metodos sepan que no a llegado informacion } 81 }catch(Exception e){ //System.out.println(e); strDatos="N"; } } } listo=true; longitudTrama=tramaDatos.length(); tramaDatos.delete(0, longitudTrama); } permisoEnvioManual=false; } } } public Vector puertosdisponibles(){ int j=1; Vector <String> listapuertos = new Vector<String>(); for (Enumeration i = CommPortIdentifier.getPortIdentifiers() ; i.hasMoreElements() ;) { CommPortIdentifier idpuerto = (CommPortIdentifier) i.nextElement(); listapuertos.add(j++ +". " } return listapuertos; + idpuerto.getName()+"\n"); } public void estado(String estado){ respuestaTexto.append(">"+estado+"\n\n"); respuestaTexto.setCaretPosition( respuestaTexto.getText().length() ); } public String devuelve_cantidad_errores(){ if(conexionCOM==true){ //esperando cantidad de errores timer(); //strDatos="\n41 01 84 4B A5 F1 0A\r"; //asignando cantidad de errores if(strDatos.compareTo("N")==0){ return "ECU does not respond."; }else if(strDatos.compareTo("Neg")==0){ return "ECU responded negatively."; }else if(strDatos.compareTo("NElm")==0){ return "ELM does not respond."; }else{ return lecErr.descifraTramaHex(strDatos); } }else{ return "Without connection port."; } } public String devuelve_descripcion_errores(){//Este metodo coje 2 o mas lineas de errores if(conexionCOM==true){ //Al devolver 2 lineas, entre lineas no hay el //simbolo ">", esto puede ser bueno. //esperando descripcion de errores timer(); //strDatos="\n43 01 33 02 45 61 21 0A\r\n43 01 33 02 45 61 21 0A\r"; //asignando cantidad de errores if(strDatos.compareTo("N")==0){ return "Not received information about errors."; }else if(strDatos.compareTo("Neg")==0){ 82 return "ECU responded negatively."; }else if(strDatos.compareTo("NElm")==0){ return "ELM does not respond."; }else{ return lecErr.descifraTramaHexDescripcionErrores(strDatos+"\n"); } }else{ return "First you must connect to the COM port."; } } public String borrado_de_errores(){ if(conexionCOM==true){ timer(); //strDatos="\n44 0A\r"; if(strDatos.compareTo("N")==0){ return "ECU does not respond."; }else if(strDatos.compareTo("Neg")==0){ return "ECU responded negatively."; }else if(strDatos.compareTo("NElm")==0){ return "ELM does not respond."; }else{ return "Removed errors stored in the ECU.."; } }else{ return "Without connection port."; } } public String devuelve_pid(){ timer(); //strDatos="\n41 0C 04 88 8F B0\r"; if(strDatos.compareTo("N")==0){ strDatos="\n41 0C 00 00 00 00\r";//Para que no pete el hilo de mediciones si llega //un NO DATA o algo inadecuado. estado("ECU does not respond"); return strDatos; }else if(strDatos.compareTo("Neg")==0){ strDatos="\n41 0C 00 00 00 00\r"; estado("ECU responded negatively"); return strDatos; }else if(strDatos.compareTo("NElm")==0){ strDatos="\n41 0C 00 00 00 00\r"; estado("ELM does not respond"); return strDatos; }else{ return strDatos; } } public boolean estado_conexion(){ return conexionCOM; } public void borrar_pids_establecidos(){ int longitudTrama; longitudTrama=pids_disponibles.length(); pids_disponibles.delete(0, longitudTrama); } public void establece_pids(){ if(conexionCOM==true){ //esperando pids 83 timer(); //asignando pids String pids_binario; //strDatos="\n41 00 FF FF FF FF 0A\r"; int pids_decimal; int longitud_trama; int t=7; if(strDatos.compareTo("N")==0){ pids_disponibles.append("N00000000000000000000000000000000"); estado("ECU does not respond"); }else if(strDatos.compareTo("Neg")==0){ pids_disponibles.append("N00000000000000000000000000000000"); estado("ECU responded negatively"); }else if(strDatos.compareTo("NElm")==0){ pids_disponibles.append("N00000000000000000000000000000000"); estado("ELM does not respond"); }else{ for(int q=0;q<4;q++){ //Da 4 pasadas para lo 4 bytes de datos for(int r=t;r<(t+2);r++){ //coje los bytes, en grupos de 2 chars tramaMediciones.append(strDatos.charAt(r)); } t=t+3; pids_decimal=Integer.parseInt(tramaMediciones.toString(), 16); //pasa de hex a int pids_binario=Integer.toString(pids_decimal, 2);//pasa de int a bin longitud_trama=tramaMediciones.length(); tramaMediciones.delete(0, longitud_trama); for(int f=0;f<(8-pids_binario.length());f++){//introduce un 0 al //principio de las tramas de menos de 8 bits pids_disponibles.append("0"); } pids_disponibles.append(pids_binario); } } } } public String cojer_pids(){ if(conexionCOM==true){ if(pids_disponibles.codePointAt(0)!=78){//Si los datos que llegan empiezan por N return pids_disponibles.toString(); }else{ estado("No data available pids"); return "N"; } }else{ estado("Without connection port."); return "N"; } } public void mostrarIDS(Vector vect){ MIDs.getJListIDs().setListData(vect); MIDs.getJListIDs().setSelectedIndex(0); MIDs.setVisible(true); MIDs.getJButtonIDsAceptar().addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { asignaIDCanBus(); MIDs.setVisible(false); } }); } 84 public void asignaIDCanBus(){ ID=MIDs.getJListIDs().getSelectedValue().toString(); } public void timer(){ temps=new Date(); while(agafatemps()-temps.getTime()<5000){//Espera 5 segundos la respuesta del puerto procedente de la interface ELM. try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } if(listo==true){ break; } } if(listo==false){ estado("Without connection to the interface ELM."); strDatos="NElm"; listo=true; } } public void permiteEnvioManual(boolean permiso){ permisoEnvioManual=permiso;//Avilita el envio manual de ordenes a la interface ELM. } public long agafatemps(){//Metodo que utiliza el timer(). temps2 = new Date(); return temps2.getTime(); } } Clase lecturaTXTErrores: package Datos; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; public class lecturaTXTErrores { FileReader fr; BufferedReader bf; int longitudTrama; int numeroErrores; StringBuffer valorHex; public lecturaTXTErrores(){} 85 public String descifraTramaHex(String error){ String estadoErrores; int valorDec; valorDec=Integer.parseInt(error.substring(7, 9), 16); if(valorDec<128){ estadoErrores= "The check engine light (MIL) is OFF, and the ECU doesn't have any error code stored"; }else{ numeroErrores=valorDec-128; estadoErrores= "The check engine light (MIL) is ON, and the ECU has "+numeroErrores+" error code/s stored"; } return estadoErrores; } public String descifraTramaHexDescripcionErrores(String error){ valorHex = new StringBuffer(); StringBuffer codigoError=new StringBuffer(); int incremento=4; for(int s=0;s<numeroErrores;s++){ boolean codigo_encontrado=false; if(error.codePointAt(incremento)==48){ valorHex.append("P0"); }else if(error.codePointAt(incremento)==49){ valorHex.append("P1"); }else if(error.codePointAt(incremento)==50){ valorHex.append("P2"); }else if(error.codePointAt(incremento)==51){ valorHex.append("P3"); }else if(error.codePointAt(incremento)==52){ valorHex.append("C0"); }else if(error.codePointAt(incremento)==53){ valorHex.append("C1"); }else if(error.codePointAt(incremento)==54){ valorHex.append("C2"); }else if(error.codePointAt(incremento)==55){ valorHex.append("C3"); }else if(error.codePointAt(incremento)==56){ valorHex.append("B0"); }else if(error.codePointAt(incremento)==57){ valorHex.append("B1"); }else if(error.codePointAt(incremento)==65){ valorHex.append("B2"); }else if(error.codePointAt(incremento)==66){ valorHex.append("B3"); }else if(error.codePointAt(incremento)==67){ valorHex.append("U0"); }else if(error.codePointAt(incremento)==68){ valorHex.append("U1"); }else if(error.codePointAt(incremento)==69){ valorHex.append("U2"); }else if(error.codePointAt(incremento)==70){ valorHex.append("U3"); } for(int p=incremento+1;p<(incremento+5);p++){//Introduce el resto de //numeros del error if(error.codePointAt(p)!=32){ valorHex.append(error.charAt(p)); } 86 } incremento=incremento+6;//Coloca la posicion en la trama para el siguiente //error if(error.codePointAt(incremento+3)==10){//Si detecta salto de linea se //prepara la posicion para el siguiente error en la siguiente linea incremento=incremento+7; } String codError=valorHex.toString(); String sCadena; try { fr = new FileReader("CodigosErrores.txt"); bf = new BufferedReader(fr); while ((sCadena = bf.readLine())!=null) { if(codError.compareTo(sCadena.substring(0, 5))==0){//se compara //el error leido con cada linea del fichero, si lo encuentra se sale del bucle codigoError.append(sCadena+"\n\n"); codigo_encontrado=true; break; } } if(codigo_encontrado==false){ codigoError.append("Unknown "+codError+" error\n\n"); } } catch (IOException e) { codigoError.append("Database error codes inaccessible"); } longitudTrama=valorHex.length();//Se deja vacio el buffer que contiene el //código procedente de la ECU valorHex.delete(0, longitudTrama); } return codigoError.toString(); } } 87 Clase MuestraIDs: package Datos; import import import import import import javax.swing.JPanel; javax.swing.JFrame; javax.swing.JList; java.awt.Rectangle; javax.swing.JButton; javax.swing.JScrollPane; public class MuestraIDs extends JFrame { private static final long serialVersionUID = 1L; private JPanel jContentPane = null; private JList jListIDs = null; private JButton jButtonIDsAceptar = null; private JScrollPane jScrollPaneListaIDs = null; public MuestraIDs() { super(); initialize(); } private void initialize() { this.setSize(300, 200); this.setLocation(500, 200); this.setContentPane(getJContentPane()); this.setTitle("CAN Bus IDs"); } private JPanel getJContentPane() { if (jContentPane == null) { jContentPane = new JPanel(); jContentPane.setLayout(null); jContentPane.add(getJButtonIDsAceptar(), null); jContentPane.add(getJScrollPaneListaIDs(), null); } return jContentPane; } public JList getJListIDs() { if (jListIDs == null) { jListIDs = new JList(); } return jListIDs; } public JButton getJButtonIDsAceptar() { if (jButtonIDsAceptar == null) { jButtonIDsAceptar = new JButton(); jButtonIDsAceptar.setBounds(new Rectangle(200, 133, 82, 22)); jButtonIDsAceptar.setText("OK"); } return jButtonIDsAceptar; } 88 private JScrollPane getJScrollPaneListaIDs() { if (jScrollPaneListaIDs == null) { jScrollPaneListaIDs = new JScrollPane(); jScrollPaneListaIDs.setBounds(new Rectangle(10, 10, 273, 115)); jScrollPaneListaIDs.setViewportView(getJListIDs()); } return jScrollPaneListaIDs; } } Capa de Dominio: Clase ControladorDominioConexión: package Dominio; import import import import java.util.Vector; javax.swing.JTextArea; Datos.Conexion; Datos.ControladorConexion; public class ControladorDominioConexion{ Conexion con; ControladorConexion contCon; public ControladorDominioConexion(JTextArea respuestaTexto) { contCon = new ControladorConexion(respuestaTexto); } public void establecerConexion(int velocidad,int dataBits,int stopBits,int paridad,String nombrePuerto,String protocolo){ con = new Conexion(velocidad,dataBits,stopBits,paridad,nombrePuerto,protocolo); contCon.establecerConexion(con); } public void enviar(String tramaEnviada){ contCon.enviar(tramaEnviada); } public void desconectar(){ contCon.desconectar(); } public Vector puertosdisponibles(){ return contCon.puertosdisponibles(); } public String devuelve_cantidad_errores(){ return contCon.devuelve_cantidad_errores(); } public String devuelve_descripcion_errores(){ return contCon.devuelve_descripcion_errores(); } public boolean estado_conexion(){ return contCon.estado_conexion(); } 89 public String cojer_pids(){ return contCon.cojer_pids(); } public String devuelvePid(){ return contCon.devuelve_pid(); } public void establece_pids(){ contCon.establece_pids(); } public String borrado_de_errores(){ return contCon.borrado_de_errores(); } public void borrar_pids_establecidos(){ contCon.borrar_pids_establecidos(); } public void permiteEnvioManual(boolean permiso){ contCon.permiteEnvioManual(permiso); } } Capa de Presentación: Clase ConfirmaciónBorradoErrores: package Presentacion; import import import import import javax.swing.JPanel; javax.swing.JFrame; javax.swing.JLabel; java.awt.Rectangle; javax.swing.JButton; public class ConfirmacionBorradoErrores extends JFrame { private static final long serialVersionUID = 1L; private JPanel jContentPane = null; private JLabel jLabelConfirmaErrores = null; private JButton jButtonOK = null; private JLabel jLabelConfirmarBorradoErrores = null; private JButton jButtonCancel = null; public ConfirmacionBorradoErrores() { super(); initialize(); } private void initialize() { this.setSize(330, 200); this.setLocation(500,200); this.setContentPane(getJContentPane()); 90 this.setTitle("Confirm erasing error codes"); } private JPanel getJContentPane() { if (jContentPane == null) { jLabelConfirmarBorradoErrores = new JLabel(); jLabelConfirmarBorradoErrores.setBounds(new Rectangle(10, 41, 206, 20)); jLabelConfirmarBorradoErrores.setText("Do you really want to continue?"); jLabelConfirmaErrores = new JLabel(); jLabelConfirmaErrores.setBounds(new Rectangle(10, 20, 308, 20)); jLabelConfirmaErrores.setText("You will erase all error codes stored in the ECU."); jContentPane = new JPanel(); jContentPane.setLayout(null); jContentPane.add(jLabelConfirmaErrores, null); jContentPane.add(getJButtonOK(), null); jContentPane.add(jLabelConfirmarBorradoErrores, null); jContentPane.add(getJButtonCancel(), null); } return jContentPane; } public JButton getJButtonOK() { if (jButtonOK == null) { jButtonOK = new JButton(); jButtonOK.setBounds(new Rectangle(161, 135, 75, 20)); jButtonOK.setText("OK"); } return jButtonOK; } public JButton getJButtonCancel() { if (jButtonCancel == null) { jButtonCancel = new JButton(); jButtonCancel.setBounds(new Rectangle(235, 135, 75, 20)); jButtonCancel.setText("Cancel"); } return jButtonCancel; } } 91 Clase ControladorErrores: package Presentacion; import javax.swing.JPanel; import Dominio.ControladorDominioConexion; public class ControladorErrores { VistaCodigosError VCE; ControladorDominioConexion contDom; ControladorMediciones contMed; ConfirmacionBorradoErrores confErr; boolean ventanaConfirmaErrores; public ControladorErrores(ControladorDominioConexion contDom,ControladorMediciones contMed){ this.contMed=contMed; VCE = new VistaCodigosError(); this.contDom = contDom; ventanaConfirmaErrores=false; eventos(); } public void eventos(){ VCE.getJButtonErrores().addMouseListener(new java.awt.event.MouseAdapter() { public void mouseClicked(java.awt.event.MouseEvent e) { if(contMed.lectura==true){ contMed.pararHilo=true; contMed.inicializacion=true; contMed.lectura=false; while(contMed.indica_hilo_destruido==false){ try { Thread.sleep(10); } catch (InterruptedException error) { error.printStackTrace(); } } } consulta_errores(); } }); VCE.getJButtonBorrarErrores().addMouseListener(new java.awt.event.MouseAdapter() { public void mouseClicked(java.awt.event.MouseEvent e) { if(ventanaConfirmaErrores==false){ confirmaErrores(); ventanaConfirmaErrores=true;//Esta variable evita que podamos //abrir varias ventanas. } } }); } public void consulta_errores(){ contDom.enviar("0101"); VCE.getJTextAreaErrores().append(contDom.devuelve_cantidad_errores()+"\n\n"); contDom.enviar("03"); VCE.getJTextAreaErrores().append(contDom.devuelve_descripcion_errores()+"\n\n"); } public JPanel devuelve_panel(){ return this.VCE; } 92 public void confirmaErrores(){ confErr=new ConfirmacionBorradoErrores(); confErr.setVisible(true); confErr.getJButtonOK().addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { contDom.enviar("04"); VCE.getJTextAreaErrores().append(contDom.borrado_de_errores()+"\n\n"); confErr.setVisible(false); ventanaConfirmaErrores=false; } }); confErr.getJButtonCancel().addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { confErr.setVisible(false); ventanaConfirmaErrores=false; } }); confErr.addWindowListener(new java.awt.event.WindowAdapter() { public void windowClosing(java.awt.event.WindowEvent e) { confErr.setVisible(false); ventanaConfirmaErrores=false; } }); } } Clase ControladorMediciones: package Presentacion; import java.text.DecimalFormat; import javax.swing.JPanel; import Dominio.ControladorDominioConexion; public class ControladorMediciones implements Runnable{ VistaMediciones VMed; ControladorDominioConexion contDom; String pids_disponibles; DecimalFormat df; boolean lectura=false; boolean pararHilo=false; boolean inicializacion=false; boolean indica_hilo_destruido; boolean conectado=false; Thread hilo; public ControladorMediciones(ControladorDominioConexion contDom){ VMed = new VistaMediciones(); this.contDom = contDom; df = new DecimalFormat("0.0");//Especifica los decimales mostrados en las TextField. eventos(); } 93 public void eventos(){ VMed.getJButtonLeer().addMouseListener(new java.awt.event.MouseAdapter() { public void mouseClicked(java.awt.event.MouseEvent e) { if(lectura==false){ if(conectado==true){ if(inicializacion==true){ hilo = new Thread(ControladorMediciones.this); inicializacion=false; indica_hilo_destruido=false; } contDom.borrar_pids_establecidos(); contDom.enviar("0100"); contDom.establece_pids(); contDom.enviar("0120"); contDom.establece_pids(); contDom.enviar("0140"); contDom.establece_pids(); pids_disponibles=contDom.cojer_pids(); if(pids_disponibles.codePointAt(0)==78){ lectura=false; }else{ pararHilo=false; lectura=true; hilo.start(); } }else{ contDom.enviar("0100"); } } } }); VMed.getJButtonDetener().addMouseListener(new java.awt.event.MouseAdapter() { public void mouseClicked(java.awt.event.MouseEvent e) { if(conectado==true){ pararHilo=true; lectura=false; inicializacion=true; }else{ contDom.enviar("0100"); } } }); } public JPanel devuelve_panel(){ return this.VMed; } public void run(){ while(true){ if(pids_disponibles.codePointAt(3)==49){ contDom.enviar("0104"); int valorDec=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); VMed.getJTextField04().setText(df.format((valorDec*100)/255)+"%"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(4)==49){ contDom.enviar("0105"); 94 int valorDec=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); VMed.getJTextField05().setText(Integer.toString(valorDec-40)+"ºC"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(5)==49){ contDom.enviar("0106"); int valorDec=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); VMed.getJTextField06().setText(df.format(((valorDec128)*100)/128)+"%"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(6)==49){ contDom.enviar("0107"); int valorDec=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); VMed.getJTextField07().setText(df.format(((valorDec128)*100)/128)+"%"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(7)==49){ contDom.enviar("0108"); int valorDec=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); VMed.getJTextField08().setText(df.format(((valorDec128)*100)/128)+"%"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(8)==49){ contDom.enviar("0109"); int valorDec=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); VMed.getJTextField09().setText(df.format(((valorDec128)*100)/128)+"%"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(9)==49){ contDom.enviar("010A"); int valorDec=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); VMed.getJTextField0A().setText(Integer.toString(valorDec*3)+"kPa"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(10)==49){ contDom.enviar("010B"); int valorDec=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); VMed.getJTextField0B().setText(Integer.toString(valorDec)+"kPa"); if(pararHilo==true){ indica_hilo_destruido=true; break; 95 } } if(pids_disponibles.codePointAt(11)==49){ contDom.enviar("010C"); int a=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); int b=Integer.parseInt(contDom.devuelvePid().substring(10,12), 16); VMed.getJTextField0C().setText(Integer.toString(((a*256)+b)/4)+"rpm"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(12)==49){ contDom.enviar("010D"); int valorDec=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); VMed.getJTextField0D().setText(Integer.toString(valorDec)+"km/h"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(13)==49){ contDom.enviar("010E"); int valorDec=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); VMed.getJTextField0E().setText(df.format((valorDec/2)-64)+"º"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(14)==49){ contDom.enviar("010F"); int valorDec=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); VMed.getJTextField0F().setText(Integer.toString(valorDec-40)+"ºC"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(15)==49){ contDom.enviar("0110"); int a=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); int b=Integer.parseInt(contDom.devuelvePid().substring(10,12), 16); VMed.getJTextField10().setText(df.format(((a*256)+b)/100)+"g/s"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(16)==49){ contDom.enviar("0111"); int valorDec=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); VMed.getJTextField11().setText(df.format((valorDec*100)/255)+"%"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(17)==49){ contDom.enviar("0112"); StringBuffer trama_binaria=new StringBuffer(); int valorDec=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); String pids_binario=Integer.toString(valorDec, 2); 96 for(int f=0;f<(8-pids_binario.length());f++){//introduce un 0 al principio //de las tramas de menos de 8 bits trama_binaria.append("0"); } trama_binaria.append(pids_binario); if(trama_binaria.codePointAt(7)==49){ VMed.getJTextField12().setText("Upstream of catalytic converter"); }else if(trama_binaria.codePointAt(6)==49){ VMed.getJTextField12().setText("Downstream of catalytic converter"); }else if(trama_binaria.codePointAt(5)==49){ VMed.getJTextField12().setText("From the outside atmosphere or off"); }else{ VMed.getJTextField12().setText("OK"); } if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(19)==49){ contDom.enviar("0114"); int voltios=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); int porcentaje=Integer.parseInt(contDom.devuelvePid().substring(10,12), 16); VMed.getJTextField14().setText(df.format(voltios*(0.005))+"V "+df.format((porcentaje-128)*(100/128))+"%"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(20)==49){ contDom.enviar("0115"); int voltios=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); int porcentaje=Integer.parseInt(contDom.devuelvePid().substring(10,12), 16); VMed.getJTextField15().setText(df.format(voltios*(0.005))+"V "+df.format((porcentaje-128)*(100/128))+"%"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(21)==49){ contDom.enviar("0116"); int voltios=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); int porcentaje=Integer.parseInt(contDom.devuelvePid().substring(10,12), 16); VMed.getJTextField16().setText(df.format(voltios*(0.005))+"V "+df.format((porcentaje-128)*(100/128))+"%"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(22)==49){ contDom.enviar("0117"); int voltios=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); int porcentaje=Integer.parseInt(contDom.devuelvePid().substring(10,12), 16); VMed.getJTextField17().setText(df.format(voltios*(0.005))+"V "+df.format((porcentaje-128)*(100/128))+"%"); if(pararHilo==true){ indica_hilo_destruido=true; break; 97 } } if(pids_disponibles.codePointAt(23)==49){ contDom.enviar("0118"); int voltios=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); int porcentaje=Integer.parseInt(contDom.devuelvePid().substring(10,12), 16); VMed.getJTextField18().setText(df.format(voltios*(0.005))+"V "+df.format((porcentaje-128)*(100/128))+"%"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(24)==49){ contDom.enviar("0119"); int voltios=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); int porcentaje=Integer.parseInt(contDom.devuelvePid().substring(10,12), 16); VMed.getJTextField19().setText(df.format(voltios*(0.005))+"V "+df.format((porcentaje-128)*(100/128))+"%"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(25)==49){ contDom.enviar("011A"); int voltios=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); int porcentaje=Integer.parseInt(contDom.devuelvePid().substring(10,12), 16); VMed.getJTextField1A().setText(df.format(voltios*(0.005))+"V "+df.format((porcentaje-128)*(100/128))+"%"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(26)==49){ contDom.enviar("011B"); int voltios=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); int porcentaje=Integer.parseInt(contDom.devuelvePid().substring(10,12), 16); VMed.getJTextField1B().setText(df.format(voltios*(0.005))+"V "+df.format((porcentaje-128)*(100/128))+"%"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(27)==49){ contDom.enviar("011C"); String valorHex=contDom.devuelvePid().substring(7,9); if(valorHex.compareTo("01")==0){ VMed.getJTextField1C().setText("OBD-II as defined by the CARB"); }else if(valorHex.compareTo("02")==0){ VMed.getJTextField1C().setText("OBD as defined by the EPA"); }else if(valorHex.compareTo("03")==0){ VMed.getJTextField1C().setText("OBD ''and'' OBD-II"); }else if(valorHex.compareTo("04")==0){ VMed.getJTextField1C().setText("OBD-I"); }else if(valorHex.compareTo("05")==0){ VMed.getJTextField1C().setText("Not meant to comply with any OBD standard"); }else if(valorHex.compareTo("06")==0){ VMed.getJTextField1C().setText("EOBD"); 98 }else{ VMed.getJTextField1C().setText("Unknown"); } if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(29)==49){ contDom.enviar("011E"); StringBuffer trama_binaria=new StringBuffer(); int valorDec=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); String pids_binario=Integer.toString(valorDec, 2); for(int f=0;f<(8-pids_binario.length());f++){//introduce un 0 al principio //de las tramas de menos de 8 bits trama_binaria.append("0"); } trama_binaria.append(pids_binario); if(trama_binaria.codePointAt(7)==49){ VMed.getJTextField1E().setText("Active"); }else{ VMed.getJTextField1E().setText("No active"); } if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(30)==49){ contDom.enviar("011F"); int a=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); int b=Integer.parseInt(contDom.devuelvePid().substring(10,12), 16); VMed.getJTextField1F().setText(df.format((a*256)+b)+"segs"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(31)==49){ if(pids_disponibles.codePointAt(32)==49){ contDom.enviar("0121"); int a=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); int b=Integer.parseInt(contDom.devuelvePid().substring(10,12), 16); VMed.getJTextField21().setText(Integer.toString((a*256)+b)+"km"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(33)==49){ contDom.enviar("0122"); int a=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); int b=Integer.parseInt(contDom.devuelvePid().substring(10,12), 16); VMed.getJTextField22().setText(df.format(((a*256)+b)*(0.079))+"kPa"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(34)==49){ contDom.enviar("0123"); int a=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); 99 int b=Integer.parseInt(contDom.devuelvePid().substring(10,12), 16); VMed.getJTextField23().setText(Integer.toString(((a*256)+b)*10)+"kPa"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(35)==49){ contDom.enviar("0124"); int c=Integer.parseInt(contDom.devuelvePid().substring(13,15), 16); int d=Integer.parseInt(contDom.devuelvePid().substring(16,18), 16); VMed.getJTextField24().setText(df.format(((c*256)+d)*(0.000122))+"V"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(36)==49){ contDom.enviar("0125"); int c=Integer.parseInt(contDom.devuelvePid().substring(13,15), 16); int d=Integer.parseInt(contDom.devuelvePid().substring(16,18), 16); VMed.getJTextField25().setText(df.format(((c*256)+d)*(0.000122))+"V"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(37)==49){ contDom.enviar("0126"); int c=Integer.parseInt(contDom.devuelvePid().substring(13,15), 16); int d=Integer.parseInt(contDom.devuelvePid().substring(16,18), 16); VMed.getJTextField26().setText(df.format(((c*256)+d)*(0.000122))+"V"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(38)==49){ contDom.enviar("0127"); int c=Integer.parseInt(contDom.devuelvePid().substring(13,15), 16); int d=Integer.parseInt(contDom.devuelvePid().substring(16,18), 16); VMed.getJTextField27().setText(df.format(((c*256)+d)*(0.000122))+"V"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(29)==49){ contDom.enviar("0128"); int c=Integer.parseInt(contDom.devuelvePid().substring(13,15), 16); int d=Integer.parseInt(contDom.devuelvePid().substring(16,18), 16); VMed.getJTextField28().setText(df.format(((c*256)+d)*(0.000122))+"V"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(40)==49){ contDom.enviar("0129"); int c=Integer.parseInt(contDom.devuelvePid().substring(13,15), 16); int d=Integer.parseInt(contDom.devuelvePid().substring(16,18), 16); VMed.getJTextField29().setText(df.format(((c*256)+d)*(0.000122))+"V"); if(pararHilo==true){ 100 indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(41)==49){ contDom.enviar("012A"); int c=Integer.parseInt(contDom.devuelvePid().substring(13,15), 16); int d=Integer.parseInt(contDom.devuelvePid().substring(16,18), 16); VMed.getJTextField2A().setText(df.format(((c*256)+d)*(0.000122))+"V"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(42)==49){ contDom.enviar("012B"); int c=Integer.parseInt(contDom.devuelvePid().substring(13,15), 16); int d=Integer.parseInt(contDom.devuelvePid().substring(16,18), 16); VMed.getJTextField2B().setText(df.format(((c*256)+d)*(0.000122))+"V"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(43)==49){ contDom.enviar("012C"); int valorDec=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); VMed.getJTextField2C().setText(df.format((valorDec*100)/255)+"%"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(44)==49){ contDom.enviar("012D"); int valorDec=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); VMed.getJTextField2D().setText(df.format((valorDec*(0.78125))-100)+"%"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(45)==49){ contDom.enviar("012E"); int valorDec=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); VMed.getJTextField2E().setText(df.format((valorDec*100)/255)+"%"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(46)==49){ contDom.enviar("012F"); int valorDec=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); VMed.getJTextField2F().setText(df.format((valorDec*100)/255)+"%"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } 101 if(pids_disponibles.codePointAt(48)==49){ contDom.enviar("0131"); int a=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); int b=Integer.parseInt(contDom.devuelvePid().substring(10,12), 16); VMed.getJTextField31().setText(Integer.toString((a*256)+b)+"km"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(49)==49){ contDom.enviar("0132"); int a=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); int b=Integer.parseInt(contDom.devuelvePid().substring(10,12), 16); VMed.getJTextField32().setText(df.format((((a*256)+b)/4)-(8.192))+"Pa"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(50)==49){ contDom.enviar("0133"); int valorDec=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); VMed.getJTextField33().setText(Integer.toString(valorDec)+"kPa"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(51)==49){ contDom.enviar("0134"); int c=Integer.parseInt(contDom.devuelvePid().substring(13,15), 16); int d=Integer.parseInt(contDom.devuelvePid().substring(16,18), 16); VMed.getJTextField34().setText(df.format(((c*256)+d)*(0.00390625)-128)+"mA"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(52)==49){ contDom.enviar("0135"); int c=Integer.parseInt(contDom.devuelvePid().substring(13,15), 16); int d=Integer.parseInt(contDom.devuelvePid().substring(16,18), 16); VMed.getJTextField35().setText(df.format(((c*256)+d)*(0.00390625)-128)+"mA"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(53)==49){ contDom.enviar("0136"); int c=Integer.parseInt(contDom.devuelvePid().substring(13,15), 16); int d=Integer.parseInt(contDom.devuelvePid().substring(16,18), 16); VMed.getJTextField36().setText(df.format(((c*256)+d)*(0.00390625)-128)+"mA"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(54)==49){ contDom.enviar("0137"); int c=Integer.parseInt(contDom.devuelvePid().substring(13,15), 16); 102 int d=Integer.parseInt(contDom.devuelvePid().substring(16,18), 16); VMed.getJTextField37().setText(df.format(((c*256)+d)*(0.00390625)-128)+"mA"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(55)==49){ contDom.enviar("0138"); int c=Integer.parseInt(contDom.devuelvePid().substring(13,15), 16); int d=Integer.parseInt(contDom.devuelvePid().substring(16,18), 16); VMed.getJTextField38().setText(df.format(((c*256)+d)*(0.00390625)-128)+"mA"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(56)==49){ contDom.enviar("0139"); int c=Integer.parseInt(contDom.devuelvePid().substring(13,15), 16); int d=Integer.parseInt(contDom.devuelvePid().substring(16,18), 16); VMed.getJTextField39().setText(df.format(((c*256)+d)*(0.00390625)-128)+"mA"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(57)==49){ contDom.enviar("013A"); int c=Integer.parseInt(contDom.devuelvePid().substring(13,15), 16); int d=Integer.parseInt(contDom.devuelvePid().substring(16,18), 16); VMed.getJTextField3A().setText(df.format(((c*256)+d)*(0.00390625)-128)+"mA"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(58)==49){ contDom.enviar("013B"); int c=Integer.parseInt(contDom.devuelvePid().substring(13,15), 16); int d=Integer.parseInt(contDom.devuelvePid().substring(16,18), 16); VMed.getJTextField3B().setText(df.format(((c*256)+d)*(0.00390625)-128)+"mA"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(59)==49){ contDom.enviar("013C"); int a=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); int b=Integer.parseInt(contDom.devuelvePid().substring(10,12), 16); VMed.getJTextField3C().setText(df.format((((a*256)+b)/10)-40)+"ºC"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(60)==49){ contDom.enviar("013D"); int a=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); int b=Integer.parseInt(contDom.devuelvePid().substring(10,12), 16); VMed.getJTextField3D().setText(df.format((((a*256)+b)/10)-40)+"ºC"); if(pararHilo==true){ 103 indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(61)==49){ contDom.enviar("013E"); int a=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); int b=Integer.parseInt(contDom.devuelvePid().substring(10,12), 16); VMed.getJTextField3E().setText(df.format((((a*256)+b)/10)-40)+"ºC"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(62)==49){ contDom.enviar("013F"); int a=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); int b=Integer.parseInt(contDom.devuelvePid().substring(10,12), 16); VMed.getJTextField3F().setText(df.format((((a*256)+b)/10)-40)+"ºC"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(63)==49){ if(pids_disponibles.codePointAt(65)==49){ contDom.enviar("0142"); int a=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); int b=Integer.parseInt(contDom.devuelvePid().substring(10,12), 16); VMed.getJTextField42().setText(df.format(((a*256)+b)/1000)+"V"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(66)==49){ contDom.enviar("0143"); int a=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); int b=Integer.parseInt(contDom.devuelvePid().substring(10,12), 16); VMed.getJTextField43().setText(df.format(((a*256)+b)*(100/255))+"%"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(67)==49){ contDom.enviar("0144"); int a=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); int b=Integer.parseInt(contDom.devuelvePid().substring(10,12), 16); VMed.getJTextField44().setText(df.format(((a*256)+b)*(0.0000305))); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(68)==49){ contDom.enviar("0145"); int valorDec=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); VMed.getJTextField45().setText(df.format((valorDec*100)/255)+"%"); 104 if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(69)==49){ contDom.enviar("0146"); int valorDec=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); VMed.getJTextField46().setText(Integer.toString(valorDec-40)+"ºC"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(70)==49){ contDom.enviar("0147"); int valorDec=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); VMed.getJTextField47().setText(df.format((valorDec*100)/255)+"%"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(71)==49){ contDom.enviar("0148"); int valorDec=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); VMed.getJTextField48().setText(df.format((valorDec*100)/255)+"%"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(72)==49){ contDom.enviar("0149"); int valorDec=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); VMed.getJTextField49().setText(df.format((valorDec*100)/255)+"%"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(73)==49){ contDom.enviar("014A"); int valorDec=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); VMed.getJTextField4A().setText(df.format((valorDec*100)/255)+"%"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(74)==49){ 105 contDom.enviar("014B"); int valorDec=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); VMed.getJTextField4B().setText(df.format((valorDec*100)/255)+"%"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(75)==49){ contDom.enviar("014C"); int valorDec=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); VMed.getJTextField4C().setText(df.format((valorDec*100)/255)+"%"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(76)==49){ contDom.enviar("014D"); int a=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); int b=Integer.parseInt(contDom.devuelvePid().substring(10,12), 16); VMed.getJTextField4D().setText(Integer.toString((a*256)+b)+"min"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(77)==49){ contDom.enviar("014E"); int a=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); int b=Integer.parseInt(contDom.devuelvePid().substring(10,12), 16); VMed.getJTextField4E().setText(Integer.toString((a*256)+b)+"min"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(80)==49){ contDom.enviar("0151"); if(contDom.devuelvePid().substring(7,9).compareTo("01")==0){ VMed.getJTextField51().setText("Gasoline"); }else if(contDom.devuelvePid().substring(7,9).compareTo("02")==0){ VMed.getJTextField51().setText("Methanol"); }else if(contDom.devuelvePid().substring(7,9).compareTo("03")==0){ VMed.getJTextField51().setText("Ethanol"); }else if(contDom.devuelvePid().substring(7,9).compareTo("04")==0){ VMed.getJTextField51().setText("Diesel"); }else if(contDom.devuelvePid().substring(7,9).compareTo("05")==0){ VMed.getJTextField51().setText("LPG"); }else if(contDom.devuelvePid().substring(7,9).compareTo("06")==0){ VMed.getJTextField51().setText("CNG"); }else if(contDom.devuelvePid().substring(7,9).compareTo("07")==0){ VMed.getJTextField51().setText("Propane"); }else if(contDom.devuelvePid().substring(7,9).compareTo("08")==0){ VMed.getJTextField51().setText("Electric"); }else if(contDom.devuelvePid().substring(7,9).compareTo("09")==0){ VMed.getJTextField51().setText("Bifuel running Gasoline"); }else if(contDom.devuelvePid().substring(7,9).compareTo("0A")==0){ VMed.getJTextField51().setText("Bifuel running Methanol"); 106 }else if(contDom.devuelvePid().substring(7,9).compareTo("0B")==0){ VMed.getJTextField51().setText("Bifuel running Ethanol"); }else if(contDom.devuelvePid().substring(7,9).compareTo("0C")==0){ VMed.getJTextField51().setText("Bifuel running LPG"); }else if(contDom.devuelvePid().substring(7,9).compareTo("0D")==0){ VMed.getJTextField51().setText("Bifuel running CNG"); }else if(contDom.devuelvePid().substring(7,9).compareTo("0E")==0){ VMed.getJTextField51().setText("Bifuel running Propane"); }else if(contDom.devuelvePid().substring(7,9).compareTo("0F")==0){ VMed.getJTextField51().setText("Bifuel running Electricity"); }else if(contDom.devuelvePid().substring(7,9).compareTo("10")==0){ VMed.getJTextField51().setText("Bifuel mixed gas/electric"); }else if(contDom.devuelvePid().substring(7,9).compareTo("11")==0){ VMed.getJTextField51().setText("Hybrid gasoline"); }else if(contDom.devuelvePid().substring(7,9).compareTo("12")==0){ VMed.getJTextField51().setText("Hybrid Ethanol"); }else if(contDom.devuelvePid().substring(7,9).compareTo("13")==0){ VMed.getJTextField51().setText("Hybrid Diesel"); }else if(contDom.devuelvePid().substring(7,9).compareTo("14")==0){ VMed.getJTextField51().setText("Hybrid Electric"); }else if(contDom.devuelvePid().substring(7,9).compareTo("15")==0){ VMed.getJTextField51().setText("Hybrid Mixed fuel"); }else if(contDom.devuelvePid().substring(7,9).compareTo("16")==0){ VMed.getJTextField51().setText("Hybrid Regenerative"); } if(pararHilo==true){ indica_hilo_destruido=true; break; } } if(pids_disponibles.codePointAt(81)==49){ contDom.enviar("0152"); int valorDec=Integer.parseInt(contDom.devuelvePid().substring(7,9), 16); VMed.getJTextField52().setText(df.format((valorDec*100)/255)+"%"); if(pararHilo==true){ indica_hilo_destruido=true; break; } } } } } } } Clase ControladorPrincipal: package Presentacion; import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.JPanel; import Dominio.ControladorDominioConexion; public class ControladorPrincipal{ VistaPrincipal VP; ControladorDominioConexion contDomCon; ControladorPSerie cP; ControladorProtocolo cProt; 107 ControladorMediciones cMed; ControladorErrores cErr; JPanel panel; JLabel labelImagen; boolean existe_panel=false; boolean existe_label=true; public ControladorPrincipal(){ VP = new VistaPrincipal(); contDomCon = new ControladorDominioConexion(VP.getJTextArea()); cP = new ControladorPSerie(contDomCon); cProt = new ControladorProtocolo(contDomCon); cMed = new ControladorMediciones(contDomCon); cErr = new ControladorErrores(contDomCon,cMed); labelImagen = new JLabel(); labelImagen.setSize(791, 677); labelImagen.setIcon (new ImageIcon("VisualOBD4_1.jpg")); VP.getJContentPane().add(labelImagen, null); VP.initialize(); } public void inicializar(){ VP.getJButtonConectar().addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { contDomCon.establecerConexion(cP.cojerDatosConexion().getVelocidad(), cP.cojerDatosConexion().getDataBits(), cP.cojerDatosConexion().getStopBits(), cP.cojerDatosConexion().getParidad(), cP.cojerDatosConexion().getNombrePuerto(), cProt.fijar_protocolo()); cMed.pararHilo=false; cMed.inicializacion=true; cMed.conectado=true; } }); VP.getJButtonDesconectar().addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { cMed.pararHilo=true; cMed.conectado=false; if(cMed.lectura==true){ while(cMed.indica_hilo_destruido==false){ try { Thread.sleep(10); } catch (InterruptedException des) { des.printStackTrace(); } } contDomCon.desconectar(); }else{ contDomCon.desconectar(); } cMed.lectura=false; } }); VP.getJMenuItemPSerie().addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { if(existe_panel==true){ VP.getJContentPane().remove(panel); } if(existe_label==true){ VP.getJContentPane().remove(labelImagen); } 108 panel = cP.retornaPanel(); VP.getJContentPane().add(panel, null); existe_panel=true; VP.initialize(); } }); VP.getJMenuItemProtocolo().addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { if(existe_panel==true){ VP.getJContentPane().remove(panel); }if(existe_label==true){ VP.getJContentPane().remove(labelImagen); } panel = cProt.devuelve_panel(); VP.getJContentPane().add(panel, null); existe_panel=true; VP.initialize(); } }); VP.getJMenuItemErrores().addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { if(existe_panel==true){ VP.getJContentPane().remove(panel); }if(existe_label==true){ VP.getJContentPane().remove(labelImagen); } panel = cErr.devuelve_panel(); VP.getJContentPane().add(panel, null); existe_panel=true; VP.initialize(); } }); VP.getJMenuItemLectura().addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { if(existe_panel==true){ VP.getJContentPane().remove(panel); }if(existe_label==true){ VP.getJContentPane().remove(labelImagen); } panel = cMed.devuelve_panel(); VP.getJContentPane().add(panel, null); existe_panel=true; VP.initialize(); } }); VP.getJMenuItemPresentacion().addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { if(existe_panel==true){ VP.getJContentPane().remove(panel); }if(existe_label==true){ VP.getJContentPane().remove(labelImagen); } labelImagen.setSize(791, 677); labelImagen.setIcon (new ImageIcon("VisualOBD4_1.jpg")); VP.getJContentPane().add(labelImagen, null); existe_label=true; VP.initialize(); } }); 109 VP.getJMenuItemExit().addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { System.exit(0); } }); VP.getJButtonEnvioManual().addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { contDomCon.permiteEnvioManual(true); contDomCon.enviar(VP.getJTextFieldEnvioManual().getText()); VP.getJTextFieldEnvioManual().setText(""); } }); VP.getJTextFieldEnvioManual().addKeyListener(new java.awt.event.KeyAdapter() { public void keyPressed(java.awt.event.KeyEvent e) { if(e.getKeyCode()==10){ VP.getJButtonEnvioManual().doClick(); } } }); VP.addWindowListener(new java.awt.event.WindowAdapter() { public void windowClosing(java.awt.event.WindowEvent e) { System.exit(0); } }); VP.getJMenuItemAbout().addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { if(existe_panel==true){ VP.getJContentPane().remove(panel); }if(existe_label==true){ VP.getJContentPane().remove(labelImagen); } labelImagen.setSize(791, 677); labelImagen.setIcon (new ImageIcon("AboutVisualOBD.jpg")); VP.getJContentPane().add(labelImagen, null); existe_label=true; VP.initialize(); } }); } public static void main (String args[]){ ControladorPrincipal conPrin = new ControladorPrincipal(); conPrin.inicializar(); } } Clase ControladorProtocolo: package Presentacion; import javax.swing.JPanel; import Dominio.ControladorDominioConexion; 110 public class ControladorProtocolo { VistaProtocolo VProt; String protocolo; ControladorDominioConexion contDom; public ControladorProtocolo(ControladorDominioConexion contDom){ VProt = new VistaProtocolo(); this.contDom = contDom; eventos(); } public String fijar_protocolo(){ if(VProt.getJRadioButtonAutomatico().isSelected()==true){ protocolo="atsp0"; } if(VProt.getJRadioButtonPWM().isSelected()==true){ protocolo="atsp1"; } if(VProt.getJRadioButtonVPW().isSelected()==true){ protocolo="atsp2"; } if(VProt.getJRadioButtonISO().isSelected()==true){ protocolo="atsp3"; } if(VProt.getJRadioButtonKWP1().isSelected()==true){ protocolo="atsp4"; } if(VProt.getJRadioButtonKWP2().isSelected()==true){ protocolo="atsp5"; } if(VProt.getJRadioButtonCAN1().isSelected()==true){ protocolo="atsp6"; } if(VProt.getJRadioButtonCAN2().isSelected()==true){ protocolo="atsp7"; } if(VProt.getJRadioButtonCAN3().isSelected()==true){ protocolo="atsp8"; } if(VProt.getJRadioButtonCAN4().isSelected()==true){ protocolo="atsp9"; } return protocolo; } public JPanel devuelve_panel(){ return this.VProt; } public void eventos(){ VProt.getJComboBoxPrio1().setEnabled(false); VProt.getJComboBoxPrio2().setEnabled(false); VProt.getJComboBoxRec1().setEnabled(false); VProt.getJComboBoxRec2().setEnabled(false); VProt.getJComboBoxTran1().setEnabled(false); VProt.getJComboBoxTran2().setEnabled(false); VProt.getJButtonAplByHead().setVisible(false); VProt.getJButtonAplByHead().addMouseListener(new java.awt.event.MouseAdapter() { public void mousePressed(java.awt.event.MouseEvent e) { 111 contDom.enviar("atsh "+VProt.getJComboBoxPrio1().getSelectedItem()+VProt.getJComboBoxPrio2().getSelectedItem()+" "+VProt.getJComboBoxRec1().getSelectedItem()+VProt.getJComboBoxRec2().getSelectedItem()+" "+VProt.getJComboBoxTran1().getSelectedItem()+VProt.getJComboBoxTran2().getSelectedItem()); } }); VProt.getJCheckBoxIntroHead().addMouseListener(new java.awt.event.MouseAdapter() { public void mouseClicked(java.awt.event.MouseEvent e) { if(VProt.getJCheckBoxIntroHead().isSelected()==true){ VProt.getJComboBoxPrio1().setEnabled(true); VProt.getJComboBoxPrio2().setEnabled(true); VProt.getJComboBoxRec1().setEnabled(true); VProt.getJComboBoxRec2().setEnabled(true); VProt.getJComboBoxTran1().setEnabled(true); VProt.getJComboBoxTran2().setEnabled(true); VProt.getJButtonAplByHead().setVisible(true); }else{ VProt.getJComboBoxPrio1().setEnabled(false); VProt.getJComboBoxPrio2().setEnabled(false); VProt.getJComboBoxRec1().setEnabled(false); VProt.getJComboBoxRec2().setEnabled(false); VProt.getJComboBoxTran1().setEnabled(false); VProt.getJComboBoxTran2().setEnabled(false); VProt.getJButtonAplByHead().setVisible(false); } } }); } } 112 Clase ControladorPSerie: package Presentacion; import javax.swing.JPanel; import Datos.Conexion; import Dominio.ControladorDominioConexion; public class ControladorPSerie { VistaConfiguracio VC; Conexion con; ControladorDominioConexion contDom; public ControladorPSerie(ControladorDominioConexion contDom){ VC = new VistaConfiguracio(); this.contDom = contDom; eventos(); datosconexion(); } public void eventos(){ VC.getJButtonIdentificarPuertos().addMouseListener(new java.awt.event.MouseAdapter() { public void mouseClicked(java.awt.event.MouseEvent e) { puertosDisponibles(); } }); VC.getJButtonAplicar().addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { try{ if(contDom.estado_conexion()==true){ contDom.desconectar(); } datosconexion(); }catch(Exception err){ } } }); } public JPanel retornaPanel(){ return this.VC; } public void puertosDisponibles(){ VC.getJListListaPuertos().setListData(contDom.puertosdisponibles()); } public Conexion cojerDatosConexion(){ return con; } public void datosconexion(){ con = new Conexion(Integer.parseInt((String)VC.getJComboBoxVelocidad().getSelectedItem()),Integer.pars eInt((String)VC.getJComboBoxDataBits().getSelectedItem()),(VC.getJComboBoxStopBits().getSele ctedIndex())+1,VC.getJComboBoxParidad().getSelectedIndex(),VC.getJComboBoxNombrePort().getSe lectedItem().toString(),"0100"); } } 113 Clase VistaCodigosError: package Presentacion; import import import import import import import java.awt.Dimension; java.awt.Font; javax.swing.JPanel; javax.swing.JTextArea; java.awt.Rectangle; javax.swing.JButton; javax.swing.JScrollPane; public class VistaCodigosError extends JPanel { private private private private private static final long serialVersionUID = 1L; JTextArea jTextAreaErrores = null; JButton jButtonErrores = null; JScrollPane jScrollPaneErrores = null; JButton jButtonBorrarErrores = null; public VistaCodigosError() { super(); initialize(); } private void initialize() { this.setSize(new Dimension(800, 677)); this.setLayout(null); this.add(getJTextAreaErrores(), null); this.add(getJButtonErrores(), null); this.add(getJScrollPaneErrores(), null); this.add(getJButtonBorrarErrores(), null); } public JTextArea getJTextAreaErrores() { if (jTextAreaErrores == null) { jTextAreaErrores = new JTextArea(); jTextAreaErrores.setBounds(new Rectangle(77, 88, 182, 155)); jTextAreaErrores.setFont(new Font("Dialog", Font.BOLD, 19)); jTextAreaErrores.setEditable(false); } return jTextAreaErrores; } public JButton getJButtonErrores() { if (jButtonErrores == null) { jButtonErrores = new JButton(); jButtonErrores.setBounds(new Rectangle(7, 650, 177, 20)); jButtonErrores.setText("Read error codes"); } return jButtonErrores; } private JScrollPane getJScrollPaneErrores() { if (jScrollPaneErrores == null) { jScrollPaneErrores = new JScrollPane(getJTextAreaErrores(),JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,JScrollPane.HORIZONT AL_SCROLLBAR_ALWAYS); jScrollPaneErrores.setBounds(new Rectangle(7, 7, 784, 637)); } return jScrollPaneErrores; } 114 public JButton getJButtonBorrarErrores() { if (jButtonBorrarErrores == null) { jButtonBorrarErrores = new JButton(); jButtonBorrarErrores.setBounds(new Rectangle(183, 650, 183, 20)); jButtonBorrarErrores.setText("Clear error codes"); } return jButtonBorrarErrores; } } Clase VistaConfiguracion: package Presentacion; import import import import import import import import import import import javax.swing.JPanel; java.awt.Dimension; javax.swing.JComboBox; java.awt.Rectangle; java.awt.Color; java.awt.Point; javax.swing.JLabel; java.awt.Font; javax.swing.JButton; javax.swing.JList; javax.swing.JScrollPane; public class VistaConfiguracion extends JPanel { private static final long serialVersionUID = 1L; private JComboBox jComboBoxNombrePort = null; private JComboBox jComboBoxDataBits = null; private JComboBox jComboBoxStopBits = null; private JComboBox jComboBoxParidad = null; private JComboBox jComboBoxVelocidad = null; private JLabel jLabelTituloPserie = null; private JLabel jLabelVelocidad = null; private JLabel jLabelNombrePuerto = null; private JLabel jLabelBitsDatos = null; private JLabel jLabelBitsStop = null; private JLabel jLabelParidad = null; private JButton jButtonAplicar = null; private JButton jButtonIdentificarPuertos = null; String [] puertos ={"COM1","COM2","COM3","COM4","COM5","COM6","COM7","COM8","COM9","COM10","COM11","COM12","/d ev/ttyS0","/dev/ttyS1","/dev/ttyACM0","/dev/ttyACM1","/dev/ttyUSB0","/dev/ttyUSB1"}; String [] velocidad ={"75","110","134","150","300","600","1200","1800","2400","4800","7200","9600","14400","1920 0","38400","57600","115200","128000"}; String [] bitsDatos ={"4","5","6","7","8"}; String [] paridad ={"Ninguno","Impar","Par","Marca","Espacio"}; String [] bitsParada ={"1","2","1,5"}; private JList jListListaPuertos = null; private JScrollPane jScrollPaneListaPuertos = null; public VistaConfiguracion() { super(); initialize(); } 115 private void initialize() { jLabelParidad = new JLabel(); jLabelParidad.setBounds(new Rectangle(30, 385, 68, 17)); jLabelParidad.setText("Parity:"); jLabelParidad.setFont(new Font("Dialog", Font.BOLD, 14)); jLabelBitsStop = new JLabel(); jLabelBitsStop.setBounds(new Rectangle(30, 310, 90, 17)); jLabelBitsStop.setText("Stop bits:"); jLabelBitsStop.setFont(new Font("Dialog", Font.BOLD, 14)); jLabelBitsDatos = new JLabel(); jLabelBitsDatos.setBounds(new Rectangle(30, 235, 88, 17)); jLabelBitsDatos.setText("Data bits:"); jLabelBitsDatos.setFont(new Font("Dialog", Font.BOLD, 14)); jLabelNombrePuerto = new JLabel(); jLabelNombrePuerto.setBounds(new Rectangle(30, 85, 122, 17)); jLabelNombrePuerto.setText("Port Identifier:"); jLabelNombrePuerto.setFont(new Font("Dialog", Font.BOLD, 14)); jLabelVelocidad = new JLabel(); jLabelVelocidad.setBounds(new Rectangle(30, 160, 79, 17)); jLabelVelocidad.setText("Bit rate:"); jLabelVelocidad.setFont(new Font("Dialog", Font.BOLD, 14)); jLabelTituloPserie = new JLabel(); jLabelTituloPserie.setBounds(new Rectangle(30, 25, 257, 26)); jLabelTituloPserie.setFont(new Font("Dialog", Font.BOLD, 18)); jLabelTituloPserie.setText("Serial port configuration"); this.setLayout(null); this.setBackground(new Color(238, 238, 238)); this.setLocation(new Point(0, 0)); this.setSize(new Dimension(800, 675)); this.add(getJComboBoxNombrePort(), null); this.add(getJComboBoxDataBits(), null); this.add(getJComboBoxStopBits(), null); this.add(getJComboBoxParidad(), null); this.add(getJComboBoxVelocidad(), null); this.add(jLabelTituloPserie, null); this.add(jLabelVelocidad, null); this.add(jLabelNombrePuerto, null); this.add(jLabelBitsDatos, null); this.add(jLabelBitsStop, null); this.add(jLabelParidad, null); this.add(getJButtonAplicar(), null); this.add(getJButtonIdentificarPuertos(), null); this.add(getJScrollPaneListaPuertos(), null); } public JComboBox getJComboBoxNombrePort() { if (jComboBoxNombrePort == null) { jComboBoxNombrePort = new JComboBox(puertos); jComboBoxNombrePort.setBounds(new Rectangle(30, 105, 135, 25)); jComboBoxNombrePort.setSelectedIndex(0); } return jComboBoxNombrePort; } public JComboBox getJComboBoxDataBits() { if (jComboBoxDataBits == null) { jComboBoxDataBits = new JComboBox(bitsDatos); jComboBoxDataBits.setBounds(new Rectangle(30, 255, 135, 25)); jComboBoxDataBits.setSelectedIndex(4); } return jComboBoxDataBits; } 116 public JComboBox getJComboBoxStopBits() { if (jComboBoxStopBits == null) { jComboBoxStopBits = new JComboBox(bitsParada); jComboBoxStopBits.setBounds(new Rectangle(30, 330, 135, 25)); jComboBoxStopBits.setSelectedIndex(0); } return jComboBoxStopBits; } public JComboBox getJComboBoxParidad() { if (jComboBoxParidad == null) { jComboBoxParidad = new JComboBox(paridad); jComboBoxParidad.setBounds(new Rectangle(30, 405, 135, 25)); jComboBoxParidad.setSelectedIndex(0); } return jComboBoxParidad; } public JComboBox getJComboBoxVelocidad() { if (jComboBoxVelocidad == null) { jComboBoxVelocidad = new JComboBox(velocidad); jComboBoxVelocidad.setBounds(new Rectangle(30, 180, 135, 25)); jComboBoxVelocidad.setSelectedIndex(14); } return jComboBoxVelocidad; } public JButton getJButtonAplicar() { if (jButtonAplicar == null) { jButtonAplicar = new JButton(); jButtonAplicar.setBounds(new Rectangle(30, 648, 115, 20)); jButtonAplicar.setText("Apply"); } return jButtonAplicar; } public JButton getJButtonIdentificarPuertos() { if (jButtonIdentificarPuertos == null) { jButtonIdentificarPuertos = new JButton(); jButtonIdentificarPuertos.setBounds(new Rectangle(30, 520, 209, 19)); jButtonIdentificarPuertos.setText("Search for available ports"); } return jButtonIdentificarPuertos; } public JList getJListListaPuertos() { if (jListListaPuertos == null) { jListListaPuertos = new JList(); jListListaPuertos.setEnabled(false); jListListaPuertos.setFont(new Font("Dialog", Font.BOLD, 12)); } return jListListaPuertos; } private JScrollPane getJScrollPaneListaPuertos() { if (jScrollPaneListaPuertos == null) { jScrollPaneListaPuertos = new JScrollPane(); jScrollPaneListaPuertos.setBounds(new Rectangle(30, 540, 209, 58)); jScrollPaneListaPuertos.setViewportView(getJListListaPuertos()); } return jScrollPaneListaPuertos; } } 117 Clase VistaMediciones: package Presentacion; import import import import import import import import java.awt.Color; java.awt.Font; javax.swing.JPanel; javax.swing.JTabbedPane; java.awt.Rectangle; javax.swing.JTextField; javax.swing.JLabel; javax.swing.JButton; public class VistaMediciones extends JPanel { private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private static final long serialVersionUID = 1L; JTabbedPane jTabbedPane = null; JPanel jPanel4_19 = null; JPanel jPanel21_40 = null; JPanel jPanel41_60 = null; JTextField jTextField04 = null; JTextField jTextField05 = null; JTextField jTextField06 = null; JTextField jTextField07 = null; JTextField jTextField08 = null; JTextField jTextField09 = null; JTextField jTextField0A = null; JTextField jTextField0B = null; JTextField jTextField0C = null; JTextField jTextField0D = null; JTextField jTextField0E = null; JTextField jTextField0F = null; JTextField jTextField10 = null; JTextField jTextField11 = null; JTextField jTextField12 = null; JTextField jTextField14 = null; JTextField jTextField15 = null; JTextField jTextField16 = null; JTextField jTextField17 = null; JTextField jTextField18 = null; JTextField jTextField19 = null; JTextField jTextField1A = null; JTextField jTextField1B = null; JTextField jTextField1E = null; JTextField jTextField1F = null; JTextField jTextField24 = null; JTextField jTextField25 = null; JTextField jTextField26 = null; JTextField jTextField27 = null; JTextField jTextField28 = null; JTextField jTextField29 = null; JTextField jTextField2A = null; JTextField jTextField2B = null; JTextField jTextField2C = null; JTextField jTextField2D = null; JTextField jTextField2E = null; JTextField jTextField2F = null; JTextField jTextField33 = null; JTextField jTextField31 = null; JTextField jTextField32 = null; JTextField jTextField34 = null; JTextField jTextField35 = null; JTextField jTextField36 = null; 118 private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private JTextField jTextField37 = null; JTextField jTextField38 = null; JTextField jTextField39 = null; JTextField jTextField3A = null; JTextField jTextField3B = null; JTextField jTextField3E = null; JTextField jTextField3F = null; JLabel jLabel04 = null; JLabel jLabel05 = null; JLabel jLabel06 = null; JLabel jLabel07 = null; JLabel jLabel08 = null; JLabel jLabel09 = null; JLabel jLabel0A = null; JLabel jLabel0B = null; JLabel jLabel0C = null; JLabel jLabel0D = null; JLabel jLabel0E = null; JLabel jLabel0F = null; JLabel jLabel10 = null; JLabel jLabel11 = null; JLabel jLabel12 = null; JLabel jLabel14 = null; JLabel jLabel15 = null; JLabel jLabel16 = null; JLabel jLabel18 = null; JLabel jLabel19 = null; JLabel jLabel17 = null; JLabel jLabel1A = null; JLabel jLabel1E = null; JLabel jLabel1B = null; JLabel jLabel1F = null; JLabel jLabel24 = null; JLabel jLabel25 = null; JLabel jLabel26 = null; JLabel jLabel27 = null; JLabel jLabel28 = null; JLabel jLabel29 = null; JLabel jLabel2A = null; JLabel jLabel2B = null; JLabel jLabel2C = null; JLabel jLabel2D = null; JLabel jLabel2E = null; JLabel jLabel2F = null; JLabel jLabel33 = null; JLabel jLabel31 = null; JLabel jLabel32 = null; JLabel jLabel34 = null; JLabel jLabel35 = null; JLabel jLabel36 = null; JLabel jLabel38 = null; JLabel jLabel39 = null; JLabel jLabel37 = null; JLabel jLabel3A = null; JLabel jLabel3E = null; JLabel jLabel3B = null; JLabel jLabel3F = null; JLabel jLabel12_1 = null; JLabel jLabel12_2 = null; JLabel jLabelSensores = null; JTextField jTextField21 = null; JTextField jTextField22 = null; JTextField jTextField23 = null; 119 private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private private JLabel jLabel21 = null; JLabel jLabel22 = null; JLabel jLabel23 = null; JLabel jLabel21_1 = null; JTextField jTextField3C = null; JTextField jTextField3D = null; JLabel jLabel3C = null; JLabel jLabel3D = null; JButton jButtonLeer = null; JButton jButtonDetener = null; JTextField jTextField42 = null; JTextField jTextField43 = null; JTextField jTextField44 = null; JTextField jTextField45 = null; JTextField jTextField46 = null; JTextField jTextField47 = null; JTextField jTextField48 = null; JTextField jTextField49 = null; JTextField jTextField4A = null; JTextField jTextField4B = null; JTextField jTextField4C = null; JTextField jTextField4D = null; JTextField jTextField4E = null; JLabel jLabel42 = null; JLabel jLabel43 = null; JLabel jLabel44 = null; JLabel jLabel45 = null; JLabel jLabel46 = null; JLabel jLabel47 = null; JLabel jLabel48 = null; JLabel jLabel49 = null; JLabel jLabel4A = null; JLabel jLabel4B = null; JLabel jLabel4C = null; JLabel jLabel4D = null; JLabel jLabel4E = null; JTextField jTextField51 = null; JLabel jLabel51 = null; JLabel jLabel52 = null; JTextField jTextField52 = null; JTextField jTextField1C = null; JLabel jLabel1C = null; public VistaMediciones() { super(); initialize(); } private void initialize() { this.setSize(803, 676); this.setLayout(null); this.add(getJTabbedPane(), null); this.add(getJButtonLeer(), null); this.add(getJButtonDetener(), null); } private JTabbedPane getJTabbedPane() { if (jTabbedPane == null) { jTabbedPane = new JTabbedPane(); jTabbedPane.setBounds(new Rectangle(6, 6, 788, 638)); jTabbedPane.addTab(" PID's 4-19 getJPanel4_19(), null); ", null, 120 jTabbedPane.addTab(" getJPanel21_40(), null); jTabbedPane.addTab(" getJPanel41_60(), null); } return jTabbedPane; } PID's 21-40 ", null, PID's 41-60 ", null, private JPanel getJPanel4_19() { if (jPanel4_19 == null) { jLabel1C = new JLabel(); jLabel1C.setBounds(new Rectangle(5, 505, 287, 16)); jLabel1C.setFont(new Font("Dialog", Font.BOLD, 14)); jLabel1C.setText("This vehicle conforms the standards:"); jLabelSensores = new JLabel(); jLabelSensores.setBounds(new Rectangle(380, 145, 335, 17)); jLabelSensores.setText("Oxygen sensor voltage, Short term fuel trim"); jLabelSensores.setFont(new Font("Dialog", Font.BOLD, 14)); jLabel12_2 = new JLabel(); jLabel12_2.setBounds(new Rectangle(675, 121, 78, 17)); jLabel12_2.setText("air status"); jLabel12_2.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel12_1 = new JLabel(); jLabel12_1.setBounds(new Rectangle(675, 103, 85, 17)); jLabel12_1.setText("secondary"); jLabel12_1.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel1F = new JLabel(); jLabel1F.setBounds(new Rectangle(525, 525, 198, 17)); jLabel1F.setText("Run time since engine start"); jLabel1F.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel1B = new JLabel(); jLabel1B.setBounds(new Rectangle(525, 445, 138, 17)); jLabel1B.setText("Bank 2, Sensor 4"); jLabel1B.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel1E = new JLabel(); jLabel1E.setBounds(new Rectangle(525, 485, 152, 17)); jLabel1E.setText("Auxiliary input status"); jLabel1E.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel1A = new JLabel(); jLabel1A.setBounds(new Rectangle(525, 405, 138, 17)); jLabel1A.setText("Bank 2, Sensor 3"); jLabel1A.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel17 = new JLabel(); jLabel17.setBounds(new Rectangle(525, 285, 136, 17)); jLabel17.setText("Bank 1, Sensor 4"); jLabel17.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel19 = new JLabel(); jLabel19.setBounds(new Rectangle(525, 365, 138, 17)); jLabel19.setText("Bank 2, Sensor 2"); jLabel19.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel18 = new JLabel(); jLabel18.setBounds(new Rectangle(525, 325, 136, 17)); jLabel18.setText("Bank 2, Sensor 1"); jLabel18.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel16 = new JLabel(); jLabel16.setBounds(new Rectangle(525, 245, 136, 17)); jLabel16.setText("Bank 1, Sensor 3"); jLabel16.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel15 = new JLabel(); jLabel15.setBounds(new Rectangle(525, 205, 134, 17)); jLabel15.setText("Bank 1, Sensor 2"); jLabel15.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel14 = new JLabel(); 121 jLabel14.setBounds(new Rectangle(525, 165, 133, 17)); jLabel14.setText("Bank 1, Sensor 1"); jLabel14.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel12 = new JLabel(); jLabel12.setBounds(new Rectangle(675, 85, 99, 17)); jLabel12.setText("Commanded "); jLabel12.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel11 = new JLabel(); jLabel11.setBounds(new Rectangle(525, 45, 132, 17)); jLabel11.setText("Throttle position"); jLabel11.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel10 = new JLabel(); jLabel10.setBounds(new Rectangle(525, 5, 132, 17)); jLabel10.setText("MAF air flow rate"); jLabel10.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel0F = new JLabel(); jLabel0F.setBounds(new Rectangle(150, 445, 167, 17)); jLabel0F.setText("Intake air temperature"); jLabel0F.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel0E = new JLabel(); jLabel0E.setBounds(new Rectangle(150, 405, 133, 17)); jLabel0E.setText("Timing advance"); jLabel0E.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel0D = new JLabel(); jLabel0D.setBounds(new Rectangle(150, 365, 120, 17)); jLabel0D.setText("Vehicle speed"); jLabel0D.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel0C = new JLabel(); jLabel0C.setBounds(new Rectangle(150, 325, 104, 17)); jLabel0C.setText("Engine RPM"); jLabel0C.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel0B = new JLabel(); jLabel0B.setBounds(new Rectangle(150, 285, 186, 17)); jLabel0B.setText("Intake manifold pressure"); jLabel0B.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel0A = new JLabel(); jLabel0A.setBounds(new Rectangle(150, 245, 118, 17)); jLabel0A.setText("Fuel pressure"); jLabel0A.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel09 = new JLabel(); jLabel09.setBounds(new Rectangle(150, 205, 225, 17)); jLabel09.setText("Long term fuel % trim_Bank 2"); jLabel09.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel08 = new JLabel(); jLabel08.setBounds(new Rectangle(150, 165, 226, 17)); jLabel08.setText("Short term fuel % trim_Bank 2"); jLabel08.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel07 = new JLabel(); jLabel07.setBounds(new Rectangle(150, 125, 225, 17)); jLabel07.setText("Long term fuel % trim_Bank 1"); jLabel07.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel06 = new JLabel(); jLabel06.setBounds(new Rectangle(150, 85, 224, 17)); jLabel06.setText("Short term fuel % trim_Bank 1"); jLabel06.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel05 = new JLabel(); jLabel05.setBounds(new Rectangle(150, 45, 207, 17)); jLabel05.setText("Engine coolant temperature"); jLabel05.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel04 = new JLabel(); jLabel04.setBounds(new Rectangle(150, 5, 206, 17)); jLabel04.setText("Calculated engine load value"); jLabel04.setFont(new Font("Dialog", Font.PLAIN, 14)); 122 jPanel4_19 = new JPanel(); jPanel4_19.setLayout(null); jPanel4_19.add(getJTextField04(), null); jPanel4_19.add(getJTextField05(), null); jPanel4_19.add(getJTextField06(), null); jPanel4_19.add(getJTextField07(), null); jPanel4_19.add(getJTextField08(), null); jPanel4_19.add(getJTextField09(), null); jPanel4_19.add(getJTextField0A(), null); jPanel4_19.add(getJTextField0B(), null); jPanel4_19.add(getJTextField0C(), null); jPanel4_19.add(getJTextField0D(), null); jPanel4_19.add(getJTextField0E(), null); jPanel4_19.add(getJTextField0F(), null); jPanel4_19.add(getJTextField10(), null); jPanel4_19.add(getJTextField11(), null); jPanel4_19.add(getJTextField12(), null); jPanel4_19.add(getJTextField14(), null); jPanel4_19.add(getJTextField15(), null); jPanel4_19.add(getJTextField16(), null); jPanel4_19.add(getJTextField17(), null); jPanel4_19.add(getJTextField18(), null); jPanel4_19.add(getJTextField19(), null); jPanel4_19.add(getJTextField1A(), null); jPanel4_19.add(getJTextField1B(), null); jPanel4_19.add(getJTextField1E(), null); jPanel4_19.add(getJTextField1F(), null); jPanel4_19.add(jLabel04, null); jPanel4_19.add(jLabel05, null); jPanel4_19.add(jLabel06, null); jPanel4_19.add(jLabel07, null); jPanel4_19.add(jLabel08, null); jPanel4_19.add(jLabel09, null); jPanel4_19.add(jLabel0A, null); jPanel4_19.add(jLabel0B, null); jPanel4_19.add(jLabel0C, null); jPanel4_19.add(jLabel0D, null); jPanel4_19.add(jLabel0E, null); jPanel4_19.add(jLabel0F, null); jPanel4_19.add(jLabel10, null); jPanel4_19.add(jLabel11, null); jPanel4_19.add(jLabel12, null); jPanel4_19.add(jLabel14, null); jPanel4_19.add(jLabel15, null); jPanel4_19.add(jLabel16, null); jPanel4_19.add(jLabel18, null); jPanel4_19.add(jLabel19, null); jPanel4_19.add(jLabel17, null); jPanel4_19.add(jLabel1A, null); jPanel4_19.add(jLabel1E, null); jPanel4_19.add(jLabel1B, null); jPanel4_19.add(jLabel1F, null); jPanel4_19.add(jLabel12_1, null); jPanel4_19.add(jLabel12_2, null); jPanel4_19.add(jLabelSensores, null); jPanel4_19.add(getJTextField1C(), null); jPanel4_19.add(jLabel1C, null); } return jPanel4_19; } 123 private JPanel getJPanel21_40() { if (jPanel21_40 == null) { jLabel3D = new JLabel(); jLabel3D.setBounds(new Rectangle(525, 485, 258, 16)); jLabel3D.setText("Catalyst Temperature Bank2, Sensor1"); jLabel3D.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel3C = new JLabel(); jLabel3C.setBounds(new Rectangle(525, 445, 258, 16)); jLabel3C.setText("Catalyst Temperature Bank1, Sensor1"); jLabel3C.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel21_1 = new JLabel(); jLabel21_1.setBounds(new Rectangle(145, 23, 166, 17)); jLabel21_1.setText("indicator lamp (MIL) on"); jLabel21_1.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel23 = new JLabel(); jLabel23.setBounds(new Rectangle(150, 85, 192, 16)); jLabel23.setText("Fuel Rail Pressure (diesel)"); jLabel23.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel22 = new JLabel(); jLabel22.setBounds(new Rectangle(150, 45, 170, 17)); jLabel22.setText("Fuel Rail Pressure"); jLabel22.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel21 = new JLabel(); jLabel21.setBounds(new Rectangle(145, 5, 243, 17)); jLabel21.setText("Distance traveled with malfunction"); jLabel21.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel3F = new JLabel(); jLabel3F.setBounds(new Rectangle(525, 565, 258, 17)); jLabel3F.setText("Catalyst Temperature Bank2, Sensor2"); jLabel3F.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel3B = new JLabel(); jLabel3B.setBounds(new Rectangle(525, 405, 221, 17)); jLabel3B.setText("O2S8_WR_lambda(1): Current"); jLabel3B.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel3E = new JLabel(); jLabel3E.setBounds(new Rectangle(525, 525, 258, 17)); jLabel3E.setText("Catalyst Temperature Bank1, Sensor2"); jLabel3E.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel3A = new JLabel(); jLabel3A.setBounds(new Rectangle(525, 365, 223, 17)); jLabel3A.setText("O2S7_WR_lambda(1): Current"); jLabel3A.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel37 = new JLabel(); jLabel37.setBounds(new Rectangle(525, 245, 220, 17)); jLabel37.setText("O2S4_WR_lambda(1): Current"); jLabel37.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel39 = new JLabel(); jLabel39.setBounds(new Rectangle(525, 325, 222, 17)); jLabel39.setText("O2S6_WR_lambda(1): Current"); jLabel39.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel38 = new JLabel(); jLabel38.setBounds(new Rectangle(525, 285, 220, 17)); jLabel38.setText("O2S5_WR_lambda(1): Current"); jLabel38.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel36 = new JLabel(); jLabel36.setBounds(new Rectangle(525, 205, 221, 17)); jLabel36.setText("O2S3_WR_lambda(1): Current"); jLabel36.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel35 = new JLabel(); jLabel35.setBounds(new Rectangle(525, 165, 222, 17)); jLabel35.setText("O2S2_WR_lambda(1): Current"); jLabel35.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel34 = new JLabel(); 124 jLabel34.setBounds(new Rectangle(525, 125, 223, 17)); jLabel34.setText("O2S1_WR_lambda(1): Current"); jLabel34.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel32 = new JLabel(); jLabel32.setBounds(new Rectangle(525, 45, 216, 17)); jLabel32.setText("Evap. System Vapor Pressure"); jLabel32.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel31 = new JLabel(); jLabel31.setBounds(new Rectangle(525, 5, 257, 17)); jLabel31.setText("Distance traveled since codes cleared"); jLabel31.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel33 = new JLabel(); jLabel33.setBounds(new Rectangle(525, 85, 159, 17)); jLabel33.setText("Barometric pressure"); jLabel33.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel2F = new JLabel(); jLabel2F.setBounds(new Rectangle(150, 565, 127, 17)); jLabel2F.setText("Fuel Level Input"); jLabel2F.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel2E = new JLabel(); jLabel2E.setBounds(new Rectangle(150, 525, 224, 17)); jLabel2E.setText("Commanded evaporative purge"); jLabel2E.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel2D = new JLabel(); jLabel2D.setBounds(new Rectangle(150, 485, 89, 17)); jLabel2D.setText("EGR Error"); jLabel2D.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel2C = new JLabel(); jLabel2C.setBounds(new Rectangle(150, 445, 153, 17)); jLabel2C.setText("Commanded EGR"); jLabel2C.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel2B = new JLabel(); jLabel2B.setBounds(new Rectangle(150, 405, 224, 17)); jLabel2B.setText("O2S8_WR_lambda(1): Voltage"); jLabel2B.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel2A = new JLabel(); jLabel2A.setBounds(new Rectangle(150, 365, 225, 17)); jLabel2A.setText("O2S7_WR_lambda(1): Voltage"); jLabel2A.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel29 = new JLabel(); jLabel29.setBounds(new Rectangle(150, 325, 226, 17)); jLabel29.setText("O2S6_WR_lambda(1): Voltage"); jLabel29.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel28 = new JLabel(); jLabel28.setBounds(new Rectangle(150, 285, 225, 17)); jLabel28.setText("O2S5_WR_lambda(1): Voltage"); jLabel28.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel27 = new JLabel(); jLabel27.setBounds(new Rectangle(150, 245, 225, 17)); jLabel27.setText("O2S4_WR_lambda(1): Voltage"); jLabel27.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel26 = new JLabel(); jLabel26.setBounds(new Rectangle(150, 205, 227, 17)); jLabel26.setText("O2S3_WR_lambda(1): Voltage"); jLabel26.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel25 = new JLabel(); jLabel25.setBounds(new Rectangle(150, 165, 225, 17)); jLabel25.setText("O2S2_WR_lambda(1): Voltage"); jLabel25.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel24 = new JLabel(); jLabel24.setBounds(new Rectangle(150, 125, 227, 17)); jLabel24.setText("O2S1_WR_lambda(1): Voltage"); jLabel24.setFont(new Font("Dialog", Font.PLAIN, 14)); 125 jPanel21_40 = new JPanel(); jPanel21_40.setLayout(null); jPanel21_40.add(getJTextField24(), jPanel21_40.add(getJTextField25(), jPanel21_40.add(getJTextField26(), jPanel21_40.add(getJTextField27(), jPanel21_40.add(getJTextField28(), jPanel21_40.add(getJTextField29(), jPanel21_40.add(getJTextField2A(), jPanel21_40.add(getJTextField2B(), jPanel21_40.add(getJTextField2C(), jPanel21_40.add(getJTextField2D(), jPanel21_40.add(getJTextField2E(), jPanel21_40.add(getJTextField2F(), jPanel21_40.add(getJTextField33(), jPanel21_40.add(getJTextField31(), jPanel21_40.add(getJTextField32(), jPanel21_40.add(getJTextField34(), jPanel21_40.add(getJTextField35(), jPanel21_40.add(getJTextField36(), jPanel21_40.add(getJTextField37(), jPanel21_40.add(getJTextField38(), jPanel21_40.add(getJTextField39(), jPanel21_40.add(getJTextField3A(), jPanel21_40.add(getJTextField3B(), jPanel21_40.add(getJTextField3E(), jPanel21_40.add(getJTextField3F(), jPanel21_40.add(jLabel24, null); jPanel21_40.add(jLabel25, null); jPanel21_40.add(jLabel26, null); jPanel21_40.add(jLabel27, null); jPanel21_40.add(jLabel28, null); jPanel21_40.add(jLabel29, null); jPanel21_40.add(jLabel2A, null); jPanel21_40.add(jLabel2B, null); jPanel21_40.add(jLabel2C, null); jPanel21_40.add(jLabel2D, null); jPanel21_40.add(jLabel2E, null); jPanel21_40.add(jLabel2F, null); jPanel21_40.add(jLabel33, null); jPanel21_40.add(jLabel31, null); jPanel21_40.add(jLabel32, null); jPanel21_40.add(jLabel34, null); jPanel21_40.add(jLabel35, null); jPanel21_40.add(jLabel36, null); jPanel21_40.add(jLabel38, null); jPanel21_40.add(jLabel39, null); jPanel21_40.add(jLabel37, null); jPanel21_40.add(jLabel3A, null); jPanel21_40.add(jLabel3E, null); jPanel21_40.add(jLabel3B, null); jPanel21_40.add(jLabel3F, null); jPanel21_40.add(getJTextField21(), jPanel21_40.add(getJTextField22(), jPanel21_40.add(getJTextField23(), jPanel21_40.add(jLabel21, null); jPanel21_40.add(jLabel22, null); jPanel21_40.add(jLabel23, null); jPanel21_40.add(jLabel21_1, null); jPanel21_40.add(getJTextField3C(), jPanel21_40.add(getJTextField3D(), jPanel21_40.add(jLabel3C, null); jPanel21_40.add(jLabel3D, null); null); null); null); null); null); null); null); null); null); null); null); null); null); null); null); null); null); null); null); null); null); null); null); null); null); null); null); null); null); null); 126 } return jPanel21_40; } private JPanel getJPanel41_60() { if (jPanel41_60 == null) { jLabel52 = new JLabel(); jLabel52.setBounds(new Rectangle(525, 85, 123, 19)); jLabel52.setText("\tEthanol fuel %"); jLabel52.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel51 = new JLabel(); jLabel51.setBounds(new Rectangle(380, 5, 99, 19)); jLabel51.setText("Fuel Type:"); jLabel51.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel4E = new JLabel(); jLabel4E.setBounds(new Rectangle(150, 485, 239, 19)); jLabel4E.setText("Time since trouble codes cleared"); jLabel4E.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel4D = new JLabel(); jLabel4D.setBounds(new Rectangle(150, 445, 163, 19)); jLabel4D.setText("Time run with MIL on"); jLabel4D.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel4C = new JLabel(); jLabel4C.setBounds(new Rectangle(150, 405, 216, 19)); jLabel4C.setText("Commanded throttle actuator"); jLabel4C.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel4B = new JLabel(); jLabel4B.setBounds(new Rectangle(150, 365, 209, 19)); jLabel4B.setText("Accelerator pedal position F"); jLabel4B.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel4A = new JLabel(); jLabel4A.setBounds(new Rectangle(150, 325, 209, 19)); jLabel4A.setText("Accelerator pedal position E"); jLabel4A.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel49 = new JLabel(); jLabel49.setBounds(new Rectangle(150, 285, 211, 19)); jLabel49.setText("Accelerator pedal position D"); jLabel49.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel48 = new JLabel(); jLabel48.setBounds(new Rectangle(150, 245, 194, 19)); jLabel48.setText("Absolute throttle position C"); jLabel48.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel47 = new JLabel(); jLabel47.setBounds(new Rectangle(150, 205, 194, 19)); jLabel47.setText("Absolute throttle position B"); jLabel47.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel46 = new JLabel(); jLabel46.setBounds(new Rectangle(150, 165, 182, 19)); jLabel46.setText("Ambient air temperature"); jLabel46.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel45 = new JLabel(); jLabel45.setBounds(new Rectangle(150, 125, 179, 19)); jLabel45.setText("Relative throttle position"); jLabel45.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel44 = new JLabel(); jLabel44.setBounds(new Rectangle(150, 85, 201, 19)); jLabel44.setText("Command equivalence ratio"); jLabel44.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel43 = new JLabel(); jLabel43.setBounds(new Rectangle(150, 45, 147, 19)); jLabel43.setText("Absolute load value"); jLabel43.setFont(new Font("Dialog", Font.PLAIN, 14)); jLabel42 = new JLabel(); 127 jLabel42.setBounds(new Rectangle(150, 5, 176, 19)); jLabel42.setText("Control module voltage"); jLabel42.setFont(new Font("Dialog", Font.PLAIN, 14)); jPanel41_60 = new JPanel(); jPanel41_60.setLayout(null); jPanel41_60.add(getJTextField42(), null); jPanel41_60.add(getJTextField43(), null); jPanel41_60.add(getJTextField44(), null); jPanel41_60.add(getJTextField45(), null); jPanel41_60.add(getJTextField46(), null); jPanel41_60.add(getJTextField47(), null); jPanel41_60.add(getJTextField48(), null); jPanel41_60.add(getJTextField49(), null); jPanel41_60.add(getJTextField4A(), null); jPanel41_60.add(getJTextField4B(), null); jPanel41_60.add(getJTextField4C(), null); jPanel41_60.add(getJTextField4D(), null); jPanel41_60.add(getJTextField4E(), null); jPanel41_60.add(jLabel42, null); jPanel41_60.add(jLabel43, null); jPanel41_60.add(jLabel44, null); jPanel41_60.add(jLabel45, null); jPanel41_60.add(jLabel46, null); jPanel41_60.add(jLabel47, null); jPanel41_60.add(jLabel48, null); jPanel41_60.add(jLabel49, null); jPanel41_60.add(jLabel4A, null); jPanel41_60.add(jLabel4B, null); jPanel41_60.add(jLabel4C, null); jPanel41_60.add(jLabel4D, null); jPanel41_60.add(jLabel4E, null); jPanel41_60.add(getJTextField51(), null); jPanel41_60.add(jLabel51, null); jPanel41_60.add(jLabel52, null); jPanel41_60.add(getJTextField52(), null); } return jPanel41_60; } public JTextField getJTextField04() { if (jTextField04 == null) { jTextField04 = new JTextField(); jTextField04.setBounds(new Rectangle(5, 5, 140, 40)); jTextField04.setHorizontalAlignment(JTextField.CENTER); jTextField04.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField04.setEditable(false); jTextField04.setBackground(Color.white); } return jTextField04; } public JTextField getJTextField05() { if (jTextField05 == null) { jTextField05 = new JTextField(); jTextField05.setBounds(new Rectangle(5, 45, 140, 40)); jTextField05.setHorizontalAlignment(JTextField.CENTER); jTextField05.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField05.setEditable(false); jTextField05.setBackground(Color.white); } return jTextField05; } 128 public JTextField getJTextField06() { if (jTextField06 == null) { jTextField06 = new JTextField(); jTextField06.setBounds(new Rectangle(5, 85, 140, 40)); jTextField06.setHorizontalAlignment(JTextField.CENTER); jTextField06.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField06.setEditable(false); jTextField06.setBackground(Color.white); } return jTextField06; } public JTextField getJTextField07() { if (jTextField07 == null) { jTextField07 = new JTextField(); jTextField07.setBounds(new Rectangle(5, 125, 140, 40)); jTextField07.setHorizontalAlignment(JTextField.CENTER); jTextField07.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField07.setEditable(false); jTextField07.setBackground(Color.white); } return jTextField07; } public JTextField getJTextField08() { if (jTextField08 == null) { jTextField08 = new JTextField(); jTextField08.setBounds(new Rectangle(5, 165, 140, 40)); jTextField08.setHorizontalAlignment(JTextField.CENTER); jTextField08.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField08.setEditable(false); jTextField08.setBackground(Color.white); } return jTextField08; } public JTextField getJTextField09() { if (jTextField09 == null) { jTextField09 = new JTextField(); jTextField09.setBounds(new Rectangle(5, 205, 140, 40)); jTextField09.setHorizontalAlignment(JTextField.CENTER); jTextField09.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField09.setEditable(false); jTextField09.setBackground(Color.white); } return jTextField09; } public JTextField getJTextField0A() { if (jTextField0A == null) { jTextField0A = new JTextField(); jTextField0A.setBounds(new Rectangle(5, 245, 140, 40)); jTextField0A.setHorizontalAlignment(JTextField.CENTER); jTextField0A.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField0A.setEditable(false); jTextField0A.setBackground(Color.white); } return jTextField0A; } public JTextField getJTextField0B() { if (jTextField0B == null) { jTextField0B = new JTextField(); 129 jTextField0B.setBounds(new Rectangle(5, 285, 140, 40)); jTextField0B.setHorizontalAlignment(JTextField.CENTER); jTextField0B.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField0B.setEditable(false); jTextField0B.setBackground(Color.white); } return jTextField0B; } public JTextField getJTextField0C() { if (jTextField0C == null) { jTextField0C = new JTextField(); jTextField0C.setBounds(new Rectangle(5, 325, 140, 40)); jTextField0C.setHorizontalAlignment(JTextField.CENTER); jTextField0C.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField0C.setEditable(false); jTextField0C.setBackground(Color.white); } return jTextField0C; } public JTextField getJTextField0D() { if (jTextField0D == null) { jTextField0D = new JTextField(); jTextField0D.setBounds(new Rectangle(5, 365, 140, 40)); jTextField0D.setHorizontalAlignment(JTextField.CENTER); jTextField0D.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField0D.setEditable(false); jTextField0D.setBackground(Color.white); } return jTextField0D; } public JTextField getJTextField0E() { if (jTextField0E == null) { jTextField0E = new JTextField(); jTextField0E.setBounds(new Rectangle(5, 405, 140, 40)); jTextField0E.setHorizontalAlignment(JTextField.CENTER); jTextField0E.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField0E.setEditable(false); jTextField0E.setBackground(Color.white); } return jTextField0E; } public JTextField getJTextField0F() { if (jTextField0F == null) { jTextField0F = new JTextField(); jTextField0F.setBounds(new Rectangle(5, 445, 140, 40)); jTextField0F.setHorizontalAlignment(JTextField.CENTER); jTextField0F.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField0F.setEditable(false); jTextField0F.setBackground(Color.white); } return jTextField0F; } public JTextField getJTextField10() { if (jTextField10 == null) { jTextField10 = new JTextField(); jTextField10.setBounds(new Rectangle(380, 5, 140, 40)); jTextField10.setHorizontalAlignment(JTextField.CENTER); jTextField10.setFont(new Font("Dialog", Font.BOLD, 22)); 130 jTextField10.setEditable(false); jTextField10.setBackground(Color.white); } return jTextField10; } public JTextField getJTextField11() { if (jTextField11 == null) { jTextField11 = new JTextField(); jTextField11.setBounds(new Rectangle(380, 45, 140, 40)); jTextField11.setHorizontalAlignment(JTextField.CENTER); jTextField11.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField11.setEditable(false); jTextField11.setBackground(Color.white); } return jTextField11; } public JTextField getJTextField12() { if (jTextField12 == null) { jTextField12 = new JTextField(); jTextField12.setBounds(new Rectangle(380, 85, 291, 53)); jTextField12.setHorizontalAlignment(JTextField.CENTER); jTextField12.setFont(new Font("Dialog", Font.PLAIN, 17)); jTextField12.setEditable(false); jTextField12.setBackground(Color.white); } return jTextField12; } public JTextField getJTextField14() { if (jTextField14 == null) { jTextField14 = new JTextField(); jTextField14.setBounds(new Rectangle(380, 165, 140, 40)); jTextField14.setHorizontalAlignment(JTextField.CENTER); jTextField14.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField14.setEditable(false); jTextField14.setBackground(Color.white); } return jTextField14; } public JTextField getJTextField15() { if (jTextField15 == null) { jTextField15 = new JTextField(); jTextField15.setBounds(new Rectangle(380, 205, 140, 40)); jTextField15.setHorizontalAlignment(JTextField.CENTER); jTextField15.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField15.setEditable(false); jTextField15.setBackground(Color.white); } return jTextField15; } public JTextField getJTextField16() { if (jTextField16 == null) { jTextField16 = new JTextField(); jTextField16.setBounds(new Rectangle(380, 245, 140, 40)); jTextField16.setHorizontalAlignment(JTextField.CENTER); jTextField16.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField16.setEditable(false); jTextField16.setBackground(Color.white); } 131 return jTextField16; } public JTextField getJTextField17() { if (jTextField17 == null) { jTextField17 = new JTextField(); jTextField17.setBounds(new Rectangle(380, 285, 140, 40)); jTextField17.setHorizontalAlignment(JTextField.CENTER); jTextField17.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField17.setEditable(false); jTextField17.setBackground(Color.white); } return jTextField17; } public JTextField getJTextField18() { if (jTextField18 == null) { jTextField18 = new JTextField(); jTextField18.setBounds(new Rectangle(380, 325, 140, 40)); jTextField18.setHorizontalAlignment(JTextField.CENTER); jTextField18.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField18.setEditable(false); jTextField18.setBackground(Color.white); } return jTextField18; } public JTextField getJTextField19() { if (jTextField19 == null) { jTextField19 = new JTextField(); jTextField19.setBounds(new Rectangle(380, 365, 140, 40)); jTextField19.setHorizontalAlignment(JTextField.CENTER); jTextField19.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField19.setEditable(false); jTextField19.setBackground(Color.white); } return jTextField19; } public JTextField getJTextField1A() { if (jTextField1A == null) { jTextField1A = new JTextField(); jTextField1A.setBounds(new Rectangle(380, 405, 140, 40)); jTextField1A.setHorizontalAlignment(JTextField.CENTER); jTextField1A.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField1A.setEditable(false); jTextField1A.setBackground(Color.white); } return jTextField1A; } public JTextField getJTextField1B() { if (jTextField1B == null) { jTextField1B = new JTextField(); jTextField1B.setBounds(new Rectangle(380, 445, 140, 40)); jTextField1B.setHorizontalAlignment(JTextField.CENTER); jTextField1B.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField1B.setEditable(false); jTextField1B.setBackground(Color.white); } return jTextField1B; } public JTextField getJTextField1E() { 132 if (jTextField1E == null) { jTextField1E = new JTextField(); jTextField1E.setBounds(new Rectangle(380, 485, 140, 40)); jTextField1E.setHorizontalAlignment(JTextField.CENTER); jTextField1E.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField1E.setEditable(false); jTextField1E.setBackground(Color.white); } return jTextField1E; } public JTextField getJTextField1F() { if (jTextField1F == null) { jTextField1F = new JTextField(); jTextField1F.setBounds(new Rectangle(380, 525, 140, 40)); jTextField1F.setHorizontalAlignment(JTextField.CENTER); jTextField1F.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField1F.setEditable(false); jTextField1F.setBackground(Color.white); } return jTextField1F; } public JTextField getJTextField24() { if (jTextField24 == null) { jTextField24 = new JTextField(); jTextField24.setBounds(new Rectangle(5, 125, 140, 40)); jTextField24.setHorizontalAlignment(JTextField.CENTER); jTextField24.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField24.setEditable(false); jTextField24.setBackground(Color.white); } return jTextField24; } public JTextField getJTextField25() { if (jTextField25 == null) { jTextField25 = new JTextField(); jTextField25.setBounds(new Rectangle(5, 165, 140, 40)); jTextField25.setHorizontalAlignment(JTextField.CENTER); jTextField25.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField25.setEditable(false); jTextField25.setBackground(Color.white); } return jTextField25; } public JTextField getJTextField26() { if (jTextField26 == null) { jTextField26 = new JTextField(); jTextField26.setBounds(new Rectangle(5, 205, 140, 40)); jTextField26.setHorizontalAlignment(JTextField.CENTER); jTextField26.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField26.setEditable(false); jTextField26.setBackground(Color.white); } return jTextField26; } public JTextField getJTextField27() { if (jTextField27 == null) { jTextField27 = new JTextField(); jTextField27.setBounds(new Rectangle(5, 245, 140, 40)); 133 jTextField27.setHorizontalAlignment(JTextField.CENTER); jTextField27.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField27.setEditable(false); jTextField27.setBackground(Color.white); } return jTextField27; } public JTextField getJTextField28() { if (jTextField28 == null) { jTextField28 = new JTextField(); jTextField28.setBounds(new Rectangle(5, 285, 140, 40)); jTextField28.setHorizontalAlignment(JTextField.CENTER); jTextField28.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField28.setEditable(false); jTextField28.setBackground(Color.white); } return jTextField28; } public JTextField getJTextField29() { if (jTextField29 == null) { jTextField29 = new JTextField(); jTextField29.setBounds(new Rectangle(5, 325, 140, 40)); jTextField29.setHorizontalAlignment(JTextField.CENTER); jTextField29.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField29.setEditable(false); jTextField29.setBackground(Color.white); } return jTextField29; } public JTextField getJTextField2A() { if (jTextField2A == null) { jTextField2A = new JTextField(); jTextField2A.setBounds(new Rectangle(5, 365, 140, 40)); jTextField2A.setHorizontalAlignment(JTextField.CENTER); jTextField2A.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField2A.setEditable(false); jTextField2A.setBackground(Color.white); } return jTextField2A; } public JTextField getJTextField2B() { if (jTextField2B == null) { jTextField2B = new JTextField(); jTextField2B.setBounds(new Rectangle(5, 405, 140, 40)); jTextField2B.setHorizontalAlignment(JTextField.CENTER); jTextField2B.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField2B.setEditable(false); jTextField2B.setBackground(Color.white); } return jTextField2B; } public JTextField getJTextField2C() { if (jTextField2C == null) { jTextField2C = new JTextField(); jTextField2C.setBounds(new Rectangle(5, 445, 140, 40)); jTextField2C.setHorizontalAlignment(JTextField.CENTER); jTextField2C.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField2C.setEditable(false); 134 jTextField2C.setBackground(Color.white); } return jTextField2C; } public JTextField getJTextField2D() { if (jTextField2D == null) { jTextField2D = new JTextField(); jTextField2D.setBounds(new Rectangle(5, 485, 140, 40)); jTextField2D.setHorizontalAlignment(JTextField.CENTER); jTextField2D.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField2D.setEditable(false); jTextField2D.setBackground(Color.white); } return jTextField2D; } public JTextField getJTextField2E() { if (jTextField2E == null) { jTextField2E = new JTextField(); jTextField2E.setBounds(new Rectangle(5, 525, 140, 40)); jTextField2E.setHorizontalAlignment(JTextField.CENTER); jTextField2E.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField2E.setEditable(false); jTextField2E.setBackground(Color.white); } return jTextField2E; } public JTextField getJTextField2F() { if (jTextField2F == null) { jTextField2F = new JTextField(); jTextField2F.setBounds(new Rectangle(5, 565, 140, 40)); jTextField2F.setHorizontalAlignment(JTextField.CENTER); jTextField2F.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField2F.setEditable(false); jTextField2F.setBackground(Color.white); } return jTextField2F; } public JTextField getJTextField33() { if (jTextField33 == null) { jTextField33 = new JTextField(); jTextField33.setBounds(new Rectangle(380, 85, 140, 40)); jTextField33.setHorizontalAlignment(JTextField.CENTER); jTextField33.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField33.setEditable(false); jTextField33.setBackground(Color.white); } return jTextField33; } public JTextField getJTextField31() { if (jTextField31 == null) { jTextField31 = new JTextField(); jTextField31.setBounds(new Rectangle(380, 5, 140, 40)); jTextField31.setHorizontalAlignment(JTextField.CENTER); jTextField31.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField31.setEditable(false); jTextField31.setBackground(Color.white); } return jTextField31; 135 } public JTextField getJTextField32() { if (jTextField32 == null) { jTextField32 = new JTextField(); jTextField32.setBounds(new Rectangle(380, 45, 140, 40)); jTextField32.setHorizontalAlignment(JTextField.CENTER); jTextField32.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField32.setEditable(false); jTextField32.setBackground(Color.white); } return jTextField32; } public JTextField getJTextField34() { if (jTextField34 == null) { jTextField34 = new JTextField(); jTextField34.setBounds(new Rectangle(380, 125, 140, 40)); jTextField34.setHorizontalAlignment(JTextField.CENTER); jTextField34.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField34.setEditable(false); jTextField34.setBackground(Color.white); } return jTextField34; } public JTextField getJTextField35() { if (jTextField35 == null) { jTextField35 = new JTextField(); jTextField35.setBounds(new Rectangle(380, 165, 140, 40)); jTextField35.setHorizontalAlignment(JTextField.CENTER); jTextField35.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField35.setEditable(false); jTextField35.setBackground(Color.white); } return jTextField35; } public JTextField getJTextField36() { if (jTextField36 == null) { jTextField36 = new JTextField(); jTextField36.setBounds(new Rectangle(380, 205, 140, 40)); jTextField36.setHorizontalAlignment(JTextField.CENTER); jTextField36.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField36.setEditable(false); jTextField36.setBackground(Color.white); } return jTextField36; } public JTextField getJTextField37() { if (jTextField37 == null) { jTextField37 = new JTextField(); jTextField37.setBounds(new Rectangle(380, 245, 140, 40)); jTextField37.setHorizontalAlignment(JTextField.CENTER); jTextField37.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField37.setEditable(false); jTextField37.setBackground(Color.white); } return jTextField37; } public JTextField getJTextField38() { 136 if (jTextField38 == null) { jTextField38 = new JTextField(); jTextField38.setBounds(new Rectangle(380, 285, 140, 40)); jTextField38.setHorizontalAlignment(JTextField.CENTER); jTextField38.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField38.setEditable(false); jTextField38.setBackground(Color.white); } return jTextField38; } public JTextField getJTextField39() { if (jTextField39 == null) { jTextField39 = new JTextField(); jTextField39.setBounds(new Rectangle(380, 325, 140, 40)); jTextField39.setHorizontalAlignment(JTextField.CENTER); jTextField39.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField39.setEditable(false); jTextField39.setBackground(Color.white); } return jTextField39; } public JTextField getJTextField3A() { if (jTextField3A == null) { jTextField3A = new JTextField(); jTextField3A.setBounds(new Rectangle(380, 365, 140, 40)); jTextField3A.setHorizontalAlignment(JTextField.CENTER); jTextField3A.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField3A.setEditable(false); jTextField3A.setBackground(Color.white); } return jTextField3A; } public JTextField getJTextField3B() { if (jTextField3B == null) { jTextField3B = new JTextField(); jTextField3B.setBounds(new Rectangle(380, 405, 140, 40)); jTextField3B.setHorizontalAlignment(JTextField.CENTER); jTextField3B.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField3B.setEditable(false); jTextField3B.setBackground(Color.white); } return jTextField3B; } public JTextField getJTextField3E() { if (jTextField3E == null) { jTextField3E = new JTextField(); jTextField3E.setBounds(new Rectangle(380, 525, 140, 40)); jTextField3E.setHorizontalAlignment(JTextField.CENTER); jTextField3E.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField3E.setEditable(false); jTextField3E.setBackground(Color.white); } return jTextField3E; } public JTextField getJTextField3F() { if (jTextField3F == null) { jTextField3F = new JTextField(); jTextField3F.setBounds(new Rectangle(380, 565, 140, 40)); 137 jTextField3F.setHorizontalAlignment(JTextField.CENTER); jTextField3F.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField3F.setEditable(false); jTextField3F.setBackground(Color.white); } return jTextField3F; } public JTextField getJTextField21() { if (jTextField21 == null) { jTextField21 = new JTextField(); jTextField21.setBounds(new Rectangle(5, 5, 140, 40)); jTextField21.setHorizontalAlignment(JTextField.CENTER); jTextField21.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField21.setEditable(false); jTextField21.setBackground(Color.white); } return jTextField21; } public JTextField getJTextField22() { if (jTextField22 == null) { jTextField22 = new JTextField(); jTextField22.setBounds(new Rectangle(5, 45, 140, 40)); jTextField22.setHorizontalAlignment(JTextField.CENTER); jTextField22.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField22.setEditable(false); jTextField22.setBackground(Color.white); } return jTextField22; } public JTextField getJTextField23() { if (jTextField23 == null) { jTextField23 = new JTextField(); jTextField23.setBounds(new Rectangle(5, 85, 140, 40)); jTextField23.setHorizontalAlignment(JTextField.CENTER); jTextField23.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField23.setEditable(false); jTextField23.setBackground(Color.white); } return jTextField23; } public JTextField getJTextField3C() { if (jTextField3C == null) { jTextField3C = new JTextField(); jTextField3C.setBounds(new Rectangle(380, 445, 140, 40)); jTextField3C.setHorizontalAlignment(JTextField.CENTER); jTextField3C.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField3C.setEditable(false); jTextField3C.setBackground(Color.white); } return jTextField3C; } public JTextField getJTextField3D() { if (jTextField3D == null) { jTextField3D = new JTextField(); jTextField3D.setBounds(new Rectangle(380, 485, 140, 40)); jTextField3D.setHorizontalAlignment(JTextField.CENTER); jTextField3D.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField3D.setEditable(false); 138 jTextField3D.setBackground(Color.white); } return jTextField3D; } public JButton getJButtonLeer() { if (jButtonLeer == null) { jButtonLeer = new JButton(); jButtonLeer.setBounds(new Rectangle(6, 650, 130, 20)); jButtonLeer.setText("Start reading"); } return jButtonLeer; } public JButton getJButtonDetener() { if (jButtonDetener == null) { jButtonDetener = new JButton(); jButtonDetener.setBounds(new Rectangle(135, 650, 130, 20)); jButtonDetener.setText("Stop"); } return jButtonDetener; } public JTextField getJTextField42() { if (jTextField42 == null) { jTextField42 = new JTextField(); jTextField42.setBounds(new Rectangle(5, 5, 140, 40)); jTextField42.setHorizontalAlignment(JTextField.CENTER); jTextField42.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField42.setEditable(false); jTextField42.setBackground(Color.white); } return jTextField42; } public JTextField getJTextField43() { if (jTextField43 == null) { jTextField43 = new JTextField(); jTextField43.setBounds(new Rectangle(5, 45, 140, 40)); jTextField43.setHorizontalAlignment(JTextField.CENTER); jTextField43.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField43.setEditable(false); jTextField43.setBackground(Color.white); } return jTextField43; } public JTextField getJTextField44() { if (jTextField44 == null) { jTextField44 = new JTextField(); jTextField44.setBounds(new Rectangle(5, 85, 140, 40)); jTextField44.setHorizontalAlignment(JTextField.CENTER); jTextField44.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField44.setEditable(false); jTextField44.setBackground(Color.white); } return jTextField44; } public JTextField getJTextField45() { if (jTextField45 == null) { 139 jTextField45 = new JTextField(); jTextField45.setBounds(new Rectangle(5, 125, 140, 40)); jTextField45.setHorizontalAlignment(JTextField.CENTER); jTextField45.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField45.setEditable(false); jTextField45.setBackground(Color.white); } return jTextField45; } public JTextField getJTextField46() { if (jTextField46 == null) { jTextField46 = new JTextField(); jTextField46.setBounds(new Rectangle(5, 165, 140, 40)); jTextField46.setHorizontalAlignment(JTextField.CENTER); jTextField46.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField46.setEditable(false); jTextField46.setBackground(Color.white); } return jTextField46; } public JTextField getJTextField47() { if (jTextField47 == null) { jTextField47 = new JTextField(); jTextField47.setBounds(new Rectangle(5, 205, 140, 40)); jTextField47.setHorizontalAlignment(JTextField.CENTER); jTextField47.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField47.setEditable(false); jTextField47.setBackground(Color.white); } return jTextField47; } public JTextField getJTextField48() { if (jTextField48 == null) { jTextField48 = new JTextField(); jTextField48.setBounds(new Rectangle(5, 245, 140, 40)); jTextField48.setHorizontalAlignment(JTextField.CENTER); jTextField48.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField48.setEditable(false); jTextField48.setBackground(Color.white); } return jTextField48; } public JTextField getJTextField49() { if (jTextField49 == null) { jTextField49 = new JTextField(); jTextField49.setBounds(new Rectangle(5, 285, 140, 40)); jTextField49.setHorizontalAlignment(JTextField.CENTER); jTextField49.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField49.setEditable(false); jTextField49.setBackground(Color.white); } return jTextField49; } public JTextField getJTextField4A() { if (jTextField4A == null) { jTextField4A = new JTextField(); jTextField4A.setBounds(new Rectangle(5, 325, 140, 40)); jTextField4A.setHorizontalAlignment(JTextField.CENTER); 140 jTextField4A.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField4A.setEditable(false); jTextField4A.setBackground(Color.white); } return jTextField4A; } public JTextField getJTextField4B() { if (jTextField4B == null) { jTextField4B = new JTextField(); jTextField4B.setBounds(new Rectangle(5, 365, 140, 40)); jTextField4B.setHorizontalAlignment(JTextField.CENTER); jTextField4B.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField4B.setEditable(false); jTextField4B.setBackground(Color.white); } return jTextField4B; } public JTextField getJTextField4C() { if (jTextField4C == null) { jTextField4C = new JTextField(); jTextField4C.setBounds(new Rectangle(5, 405, 140, 40)); jTextField4C.setHorizontalAlignment(JTextField.CENTER); jTextField4C.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField4C.setEditable(false); jTextField4C.setBackground(Color.white); } return jTextField4C; } public JTextField getJTextField4D() { if (jTextField4D == null) { jTextField4D = new JTextField(); jTextField4D.setBounds(new Rectangle(5, 445, 140, 40)); jTextField4D.setHorizontalAlignment(JTextField.CENTER); jTextField4D.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField4D.setEditable(false); jTextField4D.setBackground(Color.white); } return jTextField4D; } public JTextField getJTextField4E() { if (jTextField4E == null) { jTextField4E = new JTextField(); jTextField4E.setBounds(new Rectangle(5, 485, 140, 40)); jTextField4E.setHorizontalAlignment(JTextField.CENTER); jTextField4E.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField4E.setEditable(false); jTextField4E.setBackground(Color.white); } return jTextField4E; } public JTextField getJTextField51() { if (jTextField51 == null) { jTextField51 = new JTextField(); jTextField51.setBounds(new Rectangle(380, 25, 336, 59)); jTextField51.setHorizontalAlignment(JTextField.CENTER); jTextField51.setFont(new Font("Dialog", Font.PLAIN, 17)); jTextField51.setEditable(false); jTextField51.setBackground(Color.white); 141 } return jTextField51; } public JTextField getJTextField52() { if (jTextField52 == null) { jTextField52 = new JTextField(); jTextField52.setBounds(new Rectangle(380, 85, 140, 40)); jTextField52.setHorizontalAlignment(JTextField.CENTER); jTextField52.setFont(new Font("Dialog", Font.BOLD, 22)); jTextField52.setEditable(false); jTextField52.setBackground(Color.white); } return jTextField52; } public JTextField getJTextField1C() { if (jTextField1C == null) { jTextField1C = new JTextField(); jTextField1C.setBounds(new Rectangle(5, 525, 300, 40)); jTextField1C.setFont(new Font("Dialog", Font.PLAIN, 17)); jTextField1C.setEditable(false); jTextField1C.setBackground(Color.white); } return jTextField1C; } } Clase VistaPrincipal: package Presentacion; import import import import import import import import import import import javax.swing.JPanel; javax.swing.JFrame; javax.swing.JMenuBar; javax.swing.JMenu; javax.swing.JMenuItem; java.awt.Rectangle; javax.swing.JButton; javax.swing.JTextArea; java.awt.Point; javax.swing.JScrollPane; javax.swing.JTextField; public class VistaPrincipal extends JFrame { private static final long serialVersionUID = 1L; private JPanel jContentPane = null; private JMenuBar jJMenuBar = null; private JMenu jMenuInicio = null; private JMenuItem jMenuItemErrores = null; private JMenuItem jMenuItemLectura = null; private JPanel jPanel = null; private JButton jButtonConectar = null; 142 private JButton jButtonDesconectar = null; private JTextArea jTextArea = null; private JMenu jMenuOpciones = null; private JMenu jMenuAyuda = null; private JMenuItem jMenuItemPSerie = null; private JMenuItem jMenuItemProtocolo = null; private JScrollPane jScrollPane = null; private JButton jButtonEnvioManual = null; private JTextField jTextFieldEnvioManual = null; private JMenuItem jMenuItemPresentacion = null; private JMenuItem jMenuItemAbout = null; private JMenuItem jMenuItemExit = null; public VistaPrincipal() { super(); this.setLocation(new Point(100, 25)); initialize(); } public void initialize() { this.setSize(1050, 734); this.setContentPane(getJContentPane()); this.setJMenuBar(getJJMenuBar()); this.setTitle("VisualOBD"); this.setVisible(true); } public JPanel getJContentPane() { if (jContentPane == null) { jContentPane = new JPanel(); jContentPane.setLayout(null); jContentPane.add(getJPanel(), null); } return jContentPane; } private JMenuBar getJJMenuBar() { if (jJMenuBar == null) { jJMenuBar = new JMenuBar(); jJMenuBar.add(getJMenuInicio()); jJMenuBar.add(getJMenuOpciones()); jJMenuBar.add(getJMenuAyuda()); } return jJMenuBar; } private JMenu getJMenuInicio() { if (jMenuInicio == null) { jMenuInicio = new JMenu(); jMenuInicio.setText(" Start "); jMenuInicio.add(getJMenuItemPresentacion()); jMenuInicio.add(getJMenuItemErrores()); 143 jMenuInicio.add(getJMenuItemLectura()); jMenuInicio.add(getJMenuItemExit()); } return jMenuInicio; } public JMenuItem getJMenuItemErrores() { if (jMenuItemErrores == null) { jMenuItemErrores = new JMenuItem(); jMenuItemErrores.setText("Reading errors"); } return jMenuItemErrores; } public JMenuItem getJMenuItemLectura() { if (jMenuItemLectura == null) { jMenuItemLectura = new JMenuItem(); jMenuItemLectura.setText("Real-time measurements"); } return jMenuItemLectura; } private JPanel getJPanel() { if (jPanel == null) { jPanel = new JPanel(); jPanel.setLayout(null); jPanel.setBounds(new Rectangle(795, 2, 250, 675)); jPanel.add(getJButtonConectar(), null); jPanel.add(getJButtonDesconectar(), null); jPanel.add(getJScrollPane(), null); jPanel.add(getJButtonEnvioManual(), null); jPanel.add(getJTextFieldEnvioManual(), null); } return jPanel; } public JButton getJButtonConectar() { if (jButtonConectar == null) { jButtonConectar = new JButton(); jButtonConectar.setBounds(new Rectangle(5, 647, 115, 20)); jButtonConectar.setText("Connect"); } return jButtonConectar; } public JButton getJButtonDesconectar() { if (jButtonDesconectar == null) { jButtonDesconectar = new JButton(); jButtonDesconectar.setBounds(new Rectangle(120, 647, 119, 20)); jButtonDesconectar.setText("Disconnect"); } return jButtonDesconectar; } public JTextArea getJTextArea() { if (jTextArea == null) { jTextArea = new JTextArea(); jTextArea.setEditable(false); } return jTextArea; } 144 private JMenu getJMenuOpciones() { if (jMenuOpciones == null) { jMenuOpciones = new JMenu(); jMenuOpciones.setText(" Options "); jMenuOpciones.add(getJMenuItemPSerie()); jMenuOpciones.add(getJMenuItemProtocolo()); } return jMenuOpciones; } private JMenu getJMenuAyuda() { if (jMenuAyuda == null) { jMenuAyuda = new JMenu(); jMenuAyuda.setText(" Help "); jMenuAyuda.add(getJMenuItemAbout()); } return jMenuAyuda; } public JMenuItem getJMenuItemPSerie() { if (jMenuItemPSerie == null) { jMenuItemPSerie = new JMenuItem(); jMenuItemPSerie.setText("Serial Port configuration"); } return jMenuItemPSerie; } public JMenuItem getJMenuItemProtocolo() { if (jMenuItemProtocolo == null) { jMenuItemProtocolo = new JMenuItem(); jMenuItemProtocolo.setText("Communication protocol configuration"); } return jMenuItemProtocolo; } private JScrollPane getJScrollPane() { if (jScrollPane == null) { jScrollPane = new JScrollPane(getJTextArea(),JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,JScrollPane.HORIZONTAL_SCRO LLBAR_ALWAYS); jScrollPane.setBounds(new Rectangle(5, 26, 235, 616)); jScrollPane.setViewportView(getJTextArea()); jScrollPane.setWheelScrollingEnabled(true); } return jScrollPane; } public JButton getJButtonEnvioManual() { if (jButtonEnvioManual == null) { jButtonEnvioManual = new JButton(); jButtonEnvioManual.setBounds(new Rectangle(163, 5, 77, 19)); jButtonEnvioManual.setText("Send"); } return jButtonEnvioManual; } public JTextField getJTextFieldEnvioManual() { if (jTextFieldEnvioManual == null) { jTextFieldEnvioManual = new JTextField(); jTextFieldEnvioManual.setBounds(new Rectangle(5, 5, 159, 20)); 145 } return jTextFieldEnvioManual; } public JMenuItem getJMenuItemPresentacion() { if (jMenuItemPresentacion == null) { jMenuItemPresentacion = new JMenuItem(); jMenuItemPresentacion.setText("Initial presentation"); } return jMenuItemPresentacion; } public JMenuItem getJMenuItemAbout() { if (jMenuItemAbout == null) { jMenuItemAbout = new JMenuItem(); jMenuItemAbout.setText("About VisualOBD"); } return jMenuItemAbout; } public JMenuItem getJMenuItemExit() { if (jMenuItemExit == null) { jMenuItemExit = new JMenuItem(); jMenuItemExit.setText("Exit"); } return jMenuItemExit; } } Clase VistaProtocolo: package Presentacion; import import import import import import import import import import java.awt.Dimension; javax.swing.ButtonGroup; javax.swing.JPanel; javax.swing.JRadioButton; java.awt.Rectangle; javax.swing.JLabel; java.awt.Font; javax.swing.JCheckBox; javax.swing.JComboBox; javax.swing.JButton; public class VistaProtocolo extends JPanel { private private private private private private private private private private private private private private static final long serialVersionUID = 1L; JRadioButton jRadioButtonAutomatico = null; JRadioButton jRadioButtonPWM = null; JRadioButton jRadioButtonVPW = null; JRadioButton jRadioButtonISO = null; JRadioButton jRadioButtonKWP1 = null; JRadioButton jRadioButtonKWP2 = null; JRadioButton jRadioButtonCAN1 = null; JRadioButton jRadioButtonCAN2 = null; JRadioButton jRadioButtonCAN3 = null; JRadioButton jRadioButtonCAN4 = null; ButtonGroup grupoBotones; JLabel jLabelProtocolo = null; JCheckBox jCheckBoxIntroHead = null; 146 private private private private private private private private private private private JComboBox jComboBoxPrio1 = null; JComboBox jComboBoxPrio2 = null; JComboBox jComboBoxRec1 = null; JComboBox jComboBoxRec2 = null; JComboBox jComboBoxTran1 = null; JComboBox jComboBoxTran2 = null; JLabel jLabelPrio = null; JLabel jLabelRec = null; JLabel jLabelTran = null; JButton jButtonAplByHead = null; String [] hexa={"0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"}; public VistaProtocolo() { super(); initialize(); } private void initialize() { jLabelTran = new JLabel(); jLabelTran.setBounds(new Rectangle(690, 120, 86, 16)); jLabelTran.setFont(new Font("Dialog", Font.PLAIN, 12)); jLabelTran.setText("Tool address"); jLabelRec = new JLabel(); jLabelRec.setBounds(new Rectangle(575, 120, 91, 16)); jLabelRec.setFont(new Font("Dialog", Font.PLAIN, 12)); jLabelRec.setText("ECU address"); jLabelPrio = new JLabel(); jLabelPrio.setBounds(new Rectangle(445, 120, 53, 16)); jLabelPrio.setFont(new Font("Dialog", Font.PLAIN, 12)); jLabelPrio.setText("Priority"); jLabelProtocolo = new JLabel(); jLabelProtocolo.setBounds(new Rectangle(10, 10, 375, 28)); jLabelProtocolo.setFont(new Font("Dialog", Font.BOLD, 18)); jLabelProtocolo.setText("Selecting the communication protocol"); this.setSize(new Dimension(775, 712)); this.setLayout(null); this.add(getJRadioButtonAutomatico(), null); this.add(getJRadioButtonPWM(), null); this.add(getJRadioButtonVPW(), null); this.add(getJRadioButtonISO(), null); this.add(getJRadioButtonKWP1(), null); this.add(getJRadioButtonKWP2(), null); this.add(getJRadioButtonCAN1(), null); this.add(getJRadioButtonCAN2(), null); this.add(getJRadioButtonCAN3(), null); this.add(getJRadioButtonCAN4(), null); this.add(jLabelProtocolo, null); this.add(getJCheckBoxIntroHead(), null); this.add(getJComboBoxPrio1(), null); this.add(getJComboBoxPrio2(), null); this.add(getJComboBoxRec1(), null); this.add(getJComboBoxRec2(), null); this.add(getJComboBoxTran1(), null); this.add(getJComboBoxTran2(), null); this.add(jLabelPrio, null); this.add(jLabelRec, null); this.add(jLabelTran, null); this.add(getJButtonAplByHead(), null); grupoBotones = new ButtonGroup(); grupoBotones.add(getJRadioButtonAutomatico()); grupoBotones.add(getJRadioButtonPWM()); grupoBotones.add(getJRadioButtonVPW()); grupoBotones.add(getJRadioButtonISO()); 147 grupoBotones.add(getJRadioButtonKWP1()); grupoBotones.add(getJRadioButtonKWP2()); grupoBotones.add(getJRadioButtonCAN1()); grupoBotones.add(getJRadioButtonCAN2()); grupoBotones.add(getJRadioButtonCAN3()); grupoBotones.add(getJRadioButtonCAN4()); getJRadioButtonAutomatico().setSelected(true); } public JRadioButton getJRadioButtonAutomatico() { if (jRadioButtonAutomatico == null) { jRadioButtonAutomatico = new JRadioButton(); jRadioButtonAutomatico.setBounds(new Rectangle(10, 70, 328, 21)); jRadioButtonAutomatico.setText("Automatic detection of communication protocol"); } return jRadioButtonAutomatico; } public JRadioButton getJRadioButtonPWM() { if (jRadioButtonPWM == null) { jRadioButtonPWM = new JRadioButton(); jRadioButtonPWM.setBounds(new Rectangle(10, 120, 219, 21)); jRadioButtonPWM.setText("SAE J1850 PWM (41.6 kBit/s)"); } return jRadioButtonPWM; } public JRadioButton getJRadioButtonVPW() { if (jRadioButtonVPW == null) { jRadioButtonVPW = new JRadioButton(); jRadioButtonVPW.setBounds(new Rectangle(10, 170, 219, 21)); jRadioButtonVPW.setText("SAE J1850 VPW (10.4 kBit/s)"); } return jRadioButtonVPW; } public JRadioButton getJRadioButtonISO() { if (jRadioButtonISO == null) { jRadioButtonISO = new JRadioButton(); jRadioButtonISO.setBounds(new Rectangle(10, 220, 114, 21)); jRadioButtonISO.setText("ISO 9141-2"); } return jRadioButtonISO; } public JRadioButton getJRadioButtonKWP1() { if (jRadioButtonKWP1 == null) { jRadioButtonKWP1 = new JRadioButton(); jRadioButtonKWP1.setBounds(new Rectangle(10, 270, 256, 21)); jRadioButtonKWP1.setText("ISO 14230-4 KWP2000 (5-baud init)"); } return jRadioButtonKWP1; } public JRadioButton getJRadioButtonKWP2() { if (jRadioButtonKWP2 == null) { jRadioButtonKWP2 = new JRadioButton(); jRadioButtonKWP2.setBounds(new Rectangle(10, 320, 243, 21)); jRadioButtonKWP2.setText("ISO 14230-4 KWP2000 (fast init)"); } return jRadioButtonKWP2; } 148 public JRadioButton getJRadioButtonCAN1() { if (jRadioButtonCAN1 == null) { jRadioButtonCAN1 = new JRadioButton(); jRadioButtonCAN1.setBounds(new Rectangle(10, 370, 300, 21)); jRadioButtonCAN1.setText("ISO 15765-4 CAN (11-bit ID, 500 kBit/s)"); } return jRadioButtonCAN1; } public JRadioButton getJRadioButtonCAN2() { if (jRadioButtonCAN2 == null) { jRadioButtonCAN2 = new JRadioButton(); jRadioButtonCAN2.setBounds(new Rectangle(10, 420, 300, 21)); jRadioButtonCAN2.setText("ISO 15765-4 CAN (29-bit ID, 500 kBit/s)"); } return jRadioButtonCAN2; } public JRadioButton getJRadioButtonCAN3() { if (jRadioButtonCAN3 == null) { jRadioButtonCAN3 = new JRadioButton(); jRadioButtonCAN3.setBounds(new Rectangle(10, 470, 300, 21)); jRadioButtonCAN3.setText("ISO 15765-4 CAN (11-bit ID, 250 kBit/s)"); } return jRadioButtonCAN3; } public JRadioButton getJRadioButtonCAN4() { if (jRadioButtonCAN4 == null) { jRadioButtonCAN4 = new JRadioButton(); jRadioButtonCAN4.setBounds(new Rectangle(10, 520, 300, 21)); jRadioButtonCAN4.setText("ISO 15765-4 CAN (29-bit ID, 250 kBit/s)"); } return jRadioButtonCAN4; } public JCheckBox getJCheckBoxIntroHead() { if (jCheckBoxIntroHead == null) { jCheckBoxIntroHead = new JCheckBox(); jCheckBoxIntroHead.setBounds(new Rectangle(425, 70, 254, 21)); jCheckBoxIntroHead.setFont(new Font("Dialog", Font.BOLD, 14)); jCheckBoxIntroHead.setText("Enter specific header bytes"); } return jCheckBoxIntroHead; } public JComboBox getJComboBoxPrio1() { if (jComboBoxPrio1 == null) { jComboBoxPrio1 = new JComboBox(hexa); jComboBoxPrio1.setBounds(new Rectangle(445, 135, 40, 20)); } return jComboBoxPrio1; } public JComboBox getJComboBoxPrio2() { if (jComboBoxPrio2 == null) { jComboBoxPrio2 = new JComboBox(hexa); jComboBoxPrio2.setBounds(new Rectangle(484, 135, 40, 20)); } return jComboBoxPrio2; } public JComboBox getJComboBoxRec1() { 149 if (jComboBoxRec1 == null) { jComboBoxRec1 = new JComboBox(hexa); jComboBoxRec1.setBounds(new Rectangle(575, 135, 40, 20)); } return jComboBoxRec1; } public JComboBox getJComboBoxRec2() { if (jComboBoxRec2 == null) { jComboBoxRec2 = new JComboBox(hexa); jComboBoxRec2.setBounds(new Rectangle(614, 135, 40, 20)); } return jComboBoxRec2; } public JComboBox getJComboBoxTran1() { if (jComboBoxTran1 == null) { jComboBoxTran1 = new JComboBox(hexa); jComboBoxTran1.setBounds(new Rectangle(690, 135, 40, 20)); } return jComboBoxTran1; } public JComboBox getJComboBoxTran2() { if (jComboBoxTran2 == null) { jComboBoxTran2 = new JComboBox(hexa); jComboBoxTran2.setBounds(new Rectangle(729, 135, 40, 20)); } return jComboBoxTran2; } public JButton getJButtonAplByHead() { if (jButtonAplByHead == null) { jButtonAplByHead = new JButton(); jButtonAplByHead.setBounds(new Rectangle(445, 180, 81, 18)); jButtonAplByHead.setText("Apply"); } return jButtonAplByHead; } } 150