En este proyecto se muestra el uso del JNI (Java Native Interface) como nexo entre Java y un lenguaje nativo de la maquina en este caso C.
Se explica la implementación del Java Native Interface para así entender y aprender un poco sobre esta utilidad.
Java es una herramienta muy útil no solo para este proyecto sino también para muchas aplicaciones, ya que tiene la capacidad de crear ambientes gráficos muy amigables y poder ejecutarse en cualquier maquina.
La aplicación que se dio al uso de JNI en este proyecto fue la unión entre Electrónica y Software, para el envío y recepción de datos por el puerto paralelo.
Aunque la potencia de las API de Java es más que suficiente para casi todo tipo de aplicaciones, algunas de ellas necesitan utilizar la potencia específica de una plataforma en concreto.
Java desde un principio incluyo una forma de hacer llamadas nativas desde la maquina virtual y viceversa, pero tenia 2 problemas:
1. Las llamada a código nativo desde Java accedían a estructuras C, pero no estaba definida la posición exacta que debían ocupar estos campos en memoria con lo que una llamada nativa en una maquina virtual no coincidían con las llamadas en otra maquina virtual.
2. Las llamada nativas en versiones anteriores a JSDK 1.1 se basaban en el uso de un recolector de basura conservativo, este recolector recogía el puntero nativo que apuntaba a un objeto Java, por lo tanto cuando se apuntaba a un objeto Java desde el método nativo éste no se liberaba nunca más.
Esta forma de
llamadas nativas es la que se usó en las primeras versiones de Java para
implementar clases que accedían a la maquina host como java.io*, java.net*.
Debido a los problemas que se presentaron al invocar métodos nativos se implemento una nueva forma de acceder a estos métodos nativos a la que se llamo JNI.
JNI es un entorno el cual nos permite ejecutar código nativo de la maquina en la cual se esta corriendo desde Java y viceversa.
Código Nativo son funciones escritas en algún leguaje de programación como C o C++, donde se ejecuta la maquina virtual.
Aquí se muestra un esquema de como un programa escrito en C interactúa con uno escrito en Java.
El siguiente esquema muestra el caso de un programa Java interactúa con uno escrito en lenguaje nativo en este caso C.
El siguiente esquema muestra el lugar donde actúa JNI.
Para implementar JNI se debe seguir los siguientes pasos:
§ Escribir el código en java
§ Compilar el Código Java
§ Crear el fichero .h
§ Escribir la implementación del Método Nativo.
§ Crear una librería Compartida.
§ Ejecutar el programa.
En el código que se generara se deben definir dentro de una clase Java
todos los métodos Java, como los métodos nativos. Para la implementación de un
método en un lenguaje de programación distinto de Java, se debe incluir la
palabra clave native como parte de la definición del método dentro de la
clase java. La clave native indica al compilador Java que la función es una
función en lenguaje nativo. En
este caso la clase java creada es Parallel.java, donde readOneByte
(int address) y writeOneByte (int
address, int oneByte) son los
métodos que están implementados en C.
package parport;
public class ParallelPort {
public ParallelPort (int portBase)
{
this.portBase = portBase;
}
public int read ()
{
return ParallelPort.readOneByte
(this.portBase+1);
}
public void write (int oneByte)
{
ParallelPort.writeOneByte(this.portBase,
oneByte);
}
public static native int
readOneByte (int address);
public static native
void writeOneByte(int address, int oneByte);
static
{
System.loadLibrary("parport");
}
}
El método System.loadLibrary es invocado para cargar la librería compartida que se creara cuando compile la implementación del código. Este método se coloca con un inicializador static. El argumento de System.loadLibrary es el nombre de la librería. El sistema utiliza un estándard, pero específico de la plataforma, para convertir el nombre de la librería a un nombre de librería nativo.
Luego se debe crear una aplicación Java a parte que ejemplarice la clase que contiene la definición de método nativo. Esta aplicación Java también llamará al método nativo. Como es una aplicación, debe tener un método main. En un fichero fuente separado, que para el proyecto se llama Proyecto.java, se crea una aplicación Java que ejemplariza ParallelPort y llama a los métodos nativos read() y write().
Como se puede ver la llamada a métodos nativos es de la misma forma que la llamada a un método normal. En el programa para el proyecto:
ParallelPort lpt1 = new
ParallelPort(0x378);
lpt1.write(bit);
lpt1.read();
Donde lpt1 es una referencia a
la clase ParallelPort.java
, 0x378 es la dirección del puerto paralelo y bit es la señal a enviar
al puerto paralelo.
Ahora se procede a compilar la clase Java
anterior creada ParallelPort.java
de la forma convencional.
La creación del fichero .h es
para proporcionar un prototipo de función para la implementación de los métodos
nativos write() y read() definidos en la clase ParalellPort().
Para crear este fichero se
ejecuta el comando:
javah ParalellPort
El resultado de esta acción crea
un archivo parport_ParallelPort.h.
Si miramos dentro del fichero
creado parport_ParallelPort.h
nos encontramos con lo siguiente:
JNIEXPORT jint JNICALL
Java_parport_ParallelPort_readOneByte (JNIEnv *, jclass , jint);
JNIEXPORT void
JNICALL Java_parport_ParallelPort_writeOneByte (JNIEnv *, jclass , jint, jint);
Donde:
·
Java_parport_ParallelPort_readOneByte y Java_parport_ParallelPort_writeOneByte son
las funciones que nos ayudaran en la implementación en el método nativo de la
clase ParallelPort , esto quiere decir que son los métodos que serán
implementadas en C.
·
parport
es el nombre del paquete.
·
ParallelPort es el nombre de la clase.
·
readOneByte
y writeOneByte son los nombres de los métodos en el lenguaje nativo
·
JNIEnv * y
jclass son requeridos para cualquier método nativo. Estos parámetros permiten
al método nativo comunicarse con su entorno.
·
Jinit son la dirección del puerto paralelo y bit a
mandar en el caso de write.
Escribir la implementación del
Método Nativo.
Ahora se procede a escribir la implementación del método nativo en C.
En el proyecto el archivo parport_ParallelPort.c se incluyen los siguientes ficheros de cabecera:
#include <jni.h>
#include
<conio.h>
#include
"parport_ParalellPort.h"
·
jni.h proporciona información que el
código nativo necesita para interactuar con el sistema de ejecución Java, este
fichero siempre se incluye cuando se escriben métodos nativos.
·
conio.h
este fichero es incluido por que ocupa las funciones inp y outp nativas de C.
·
parport_ParalellPort.h necesario para la implementación de los métodos nativos.
Ahora se procede a escribir las funciones con las mismas firmas de las funciones que se generaron en parport_ParallelPort.h.
Esta función lee en el puerto
paralelo y retorna el valor leído (status) a la acción que lo invoco en Java.
JNIEXPORT jint JNICALL
Java_parport_ParallelPort_readOneByte
(JNIEnv * algo, jclass otro, jint portStatus)
{
unsigned short status;
status = (unsigned short)portStatus;
return _inp(status);
}
Por otro lado esta función
envía un Byte al puerto paralelo que fue enviado por una acción en el programa
Java que lo invoca.
JNIEXPORT void
JNICALL Java_parport_ParallelPort_writeOneByte
(JNIEnv * algo, jclass otro, jint portData,
jint oneByte)
{
unsigned short data;
int aByte;
data = (unsigned short)portData;
aByte = (int)oneByte;
_outp(data,aByte);
}
}
Las librerías son ficheros que almacenan las funciones, clases y variables globales y sirve para enlazar los lenguajes. Se pueden crear librerías de enlace estático o enlace dinámico.
Las librerías de enlace estático se incluyen dentro del ejecutable durante el enlace y una vez generado el ejecutable ya no se necesita de ésta librería. En sistemas UNIX tienen extensión .o y en Windows .lib.
Las librerías de enlace dinámico no
se añaden al ejecutable sino que al momento de solicitarlas se cargan y enlazan
sus contenidos. Su extensión en sistemas UNIX es .so y en Windows .dll.
En este caso se utilizara de enlace dinámico ya que la ventaja que tiene sobre la otra es que varios programas pueden compartir las mismas librerías lo que ahorra uso de CPU.
Para el proyecto esta librería será parport.dll donde es ligada en la clase ParallelPort.
System.loadLibrary("parport")
Hay varias formas de crear una librería, cada compilador y sistema operativo tienen formas distintas de llevar a cabo esta acción.
Ahora queda solo ejecutar el programa Proyecto.java,
pero antes hay que guardar en la carpeta classes del compilador java la carpeta
con nombre parport con los archivos: parport.dll y la clase ParallelPort .java.
Al ejecutar el programa se desplegara una pantalla
tipo Windows donde se encuentran 4 botones los cuales sétean el estado de los
leds conectados a la salida del puerto
paralelo.
En el programa se ocupo las capacidades graficas del
lenguaje Java lo cual hace amigable una interacción de este tipo.
Además se hizo uso de ActionListener para poder transmitir la acción de seleccionar un botón y generar el evento que envía el bit al puerto paralelo.
Al momento de ejecutar el programa de envío muestra inmediatamente un panel con cuatro botones los cuales controlan independientemente cada led.
Al ejecutar el programa de recepción de datos se mostrara una ventana que cambiara el fondo de esta al accionar el botón que se encuentra conectado al Puerto Paralelo.
El fondo será azul cuando no hay pulsación del botón y rojo cuando se pulsa.
El proyecto lleva a la conclusión de que el uso de java y sus capacidades (en éste caso JNI y capacidades graficas) es una herramienta muy potente para el desarrollo de proyectos y Softwares para resolver problemas o ayudar en algo.
El envío y adquisición de datos con el PC puede tener variados usos como controlar una simple lámpara, un horno, sensores, seguridad, control remoto etc., además con un interfaz amigable que pueda ser entendido y conocido, puede llevar a desarrollar proyectos mas grandes.
http://profesores.elo.utfsm.cl/~agv/elo330/2s04/
http://www.programacion.com/java/tutorial/jni/
http://www.itapizaco.edu.mx/paginas/JavaTut/
http://java.sun.com/j2se/1.4.2/docs/guide/jni/
http://java.sun.com/docs/books/tutorial/native1.1/TOC.html