[JAVA] [API Javax Comm] Leer Puerto COM

Cerrado
goddet Mensajes publicados 6 Estado Miembro -  
 amoun -
¡Hola a todos!
Estoy usando en un programa Java la API javax.comm para leer información de un receptor GPS USB (detectado en un puerto serie virtual).
Dado que el número del puerto COM asignado al receptor GPS puede cambiar y que el usuario del programa no debe preocuparse por ello, escaneo todos los puertos serie y pruebo si hay datos en formato NMEA (tramas del receptor GPS) que llegan del puerto COM en cuestión. (¡No encontré nada mejor!)
Así que intento hacer una lectura del puerto serie basada en eventos como en este tutorial:
https://christophej.developpez.com/tutoriel/java/javacomm/#L2.3.3

Tengo un pequeño problema ahora: logro encontrar mi receptor GPS, pero mi programa se bloquea una vez que se leen las tramas. Creo que el programa se queda atascado en la estructura switch que gestiona los eventos del puerto serie.
 import javax.comm.*; import java.util.*; import java.math.*; import java.net.*; import com.sun.comm.Win32Driver; import java.io.*; public class testCOM implements SerialPortEventListener { private String portCOM; private CommPortIdentifier portID = null; //identificador del puerto privado SerialPort serialPort; //el puerto serie privado BufferedReader flujoLectura; //flujo de lectura del puerto /* * Método que inicializa el puerto serie en modo de eventos */ public void ModificarModoEvento(String portCOM) { //recuperación del identificador del puerto try { portID = CommPortIdentifier.getPortIdentifier(portCOM); } catch (NoSuchPortException e) { } //apertura del puerto try { serialPort = (SerialPort) portID.open("ModoEvento", 2000); } catch (PortInUseException e) { } //recuperación del flujo try { flujoLectura = new BufferedReader( new InputStreamReader(serialPort.getInputStream())); } catch (IOException e) {} //agregar el listener try { serialPort.addEventListener(this); } catch (TooManyListenersException e) { } //configuración del puerto serialPort.notifyOnDataAvailable(true); try { serialPort.setSerialPortParams( 4800, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); } catch (UnsupportedCommOperationException e) {} System.out.println("puerto abierto, esperando lectura"); } /* * Método que realiza la lectura de 7 tramas en el puerto serie * Una vez realizada la lectura, se cierra el flujo de lectura y el puerto COM */ public void LeerPuertoSerial(){ int i=7; String respuesta = new String(); try { System.out.println("i="+i); while(i!=0){ System.out.println("Leyendo en el puerto COM\n"); respuesta = (String) flujoLectura.readLine(); System.out.println(respuesta); i--; System.out.println("i="+i); } } catch (IOException e) {} //cierre del flujo de lectura try { flujoLectura.close(); } catch (IOException e) {} //cierre del puerto COM serialPort.close(); } public void serialEvent(SerialPortEvent event) { //gestión de eventos en el puerto: //no hacemos nada excepto cuando los datos están disponibles switch (event.getEventType()) { case SerialPortEvent.DATA_AVAILABLE : this.LeerPuertoSerial();//si hay datos disponibles, lanzamos la lectura break; default: break;//no hacemos nada para otros eventos } } /* * Método que escanea todos los puertos COM y prueba si hay datos del puerto COm escaneado */ public void listarPuerto(){ Enumeration listaPuertos = CommPortIdentifier.getPortIdentifiers(); int tipoPuerto; String GPSPuertoCOM; while (listaPuertos.hasMoreElements()){ portID = (CommPortIdentifier) (CommPortIdentifier) listaPuertos.nextElement(); if(portID.getPortType()==CommPortIdentifier.PORT_SERIAL){ System.out.println("Nombre del PUERTO :"+portID.getName()); System.out.println("Usuario :"+portID.getCurrentOwner()); System.out.println("¿En uso? :"+portID.isCurrentlyOwned()); System.out.println("Tipo del PUERTO :"+portID.getPortType()); // Iniciar el manejo de eventos en portID this.ModificarModoEvento(portID.getName()); } } } public static void main(String[] args) { //inicialización del driver Win32Driver w32Driver = new Win32Driver(); w32Driver.initialize(); testCOM test = new testCOM(); test.listarPuerto(); } }

No sé si he sido lo suficientemente claro. ¡Pero si alguien tiene una idea, estoy dispuesto a escuchar!
¡Gracias de antemano!
Configuración: Windows XP Firefox 2.0.0.3

2 respuestas

oyopi
 
¡Hola!

Me parece que tu enfoque no es el correcto, de hecho me sorprende que logres recuperar tramas así.

Si he seguido bien, esto es lo que tienes:
- creas tu objeto testCOM
- lanzas el método ModeEvenement() de este objeto que inicializa el puerto y le añade un listener, este método termina con éxito y luego cuentas con el propio objeto para manejar el resto a través de su método serialEvent.
- si recibes datos en el puerto, serialEvent llama al método ReadSerialPort() que lee 7 tramas y luego cierra el puerto

A partir de ahí, veo varios problemas:

No tienes ningún control sobre lo que ocurre, tu objeto testCOM sigue recibiendo eventos que te interesan o no, y eso hasta que no sea destruido, pero además has cerrado el puerto en ese tiempo...
Luego, esta manera de leer siete tramas a la vez no es ideal, ¿por qué no sigues usando serialEvent para manejar trama por trama?

En resumen, lo que digo es:
- realmente deberías empezar por hacer un hilo de esta clase (como se recomienda al final del tutorial del que hablas, para la gestión del lector de códigos de barras)!
De hecho, toma el código del tutorial tal como está y solo cambia la condición de parada.
añades como variables globales a tu clase :
private int nbreTramesLues = 0; private final int NBRE_TRAMES_A_LIRE = 7;

y en lugar de poner en el run(), while(running) como en el tutorial, pones
while(this.nbreTramesLues < this.NBRE_TRAMES_A_LIRE)


- y luego para las tramas, lee trama por trama y no las siete de golpe:

public void serialEvent(SerialPortEvent event) { //gestión de eventos en el puerto: //no hacemos nada excepto cuando los datos están disponibles switch (event.getEventType()) { case SerialPortEvent.DATA_AVAILABLE : try{ System.out.println("Estamos leyendo en el puerto COM\n"); reponse = (String) flujoLectura.readLine(); System.out.println(reponse); this.nbreTramesLues++; }catch(IOException e){ } break; default: break;//no hacemos nada para los otros eventos } } 


En el main solo lanzas tu hilo llamando al método start() (¡cuidado, no run() directamente!), si todo va bien, el hilo se detendrá solo una vez que se reciban las siete tramas y el puerto
se cierra, ¡sin más problemas!
Por último, eso es si todo va bien, incluso así, si no recibes tus siete tramas, tu hilo se quedará bloqueado indefinidamente en el while, tendrás que arreglar eso, pero ya es un comienzo.

Eso es, después no entendí bien, ¿haces esto para cada puerto serie? ¿Qué haces si no recibes nada en un puerto? ¿Esperas indefinidamente a que lleguen datos?

Otra cosa más, los métodos empiezan con minúscula en java y las clases con mayúscula, ¡ahí has hecho exactamente lo contrario! es más fácil orientarse si sigues estas convenciones de escritura.

Bueno, esta es solo mi opinión sobre el asunto, ¡espero que te ayude un poco!

¡adiós!
2
sabron
 
casi tengo el mismo problema. Quiero enviar comandos AT a mi teléfono Samsung conectado por USB. El programa muestra dos puertos COM, 4 y 5, además del 3, que es (COM3, el puerto de mi módem de PC).
Cuando envío estos comandos, no pasa nada (sin resultados)
Pero cuando cierro o abro el teclado, aparecen caracteres extraños y cuadros, así como "locked" o "unlocked". Creo que mi teléfono no recibe estos comandos.
Si has encontrado este problema, contáctame en MSN [suprimido por moderación]. Realmente necesito tu ayuda, ahora tengo que realizar esto para mi proyecto final y hay otros problemas...

Aquí está este código y espero tus ideas en mi hotmail:


/*La mayoría de los proyectos que tratan con hardware y dispositivos, necesitan comunicarse con ellos utilizando el puerto COM de la PC o servidor. Por ejemplo, si hay un módem que está conectado a un servidor a través de su puerto COM y el programa Java tiene que leer la salida del módem, entonces el programa Java debe leer el puerto COM para cualquier dato entrante.

Este programa de ejemplo en Java se puede utilizar para leer desde un puerto COM datos entrantes y procesarlos. Tenga en cuenta que necesitará cambiar el número de puerto a COM1, COM2 o cualquier otro puerto según sea necesario.

Además, si está utilizando máquinas basadas en Unix, entonces deberá descomentar /dev/term/a en lugar de COM.*/

import java.io.*; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; import java.util.*; import javax.comm.*; import com.sun.comm.Win32Driver; public class SimpleRead implements Runnable, SerialPortEventListener { static CommPortIdentifier portId; static Enumeration portList; static InputStream inputStream; static SerialPort serialPort; static Thread readThread; static OutputStream outputStream; static SerialPortEvent event; private static BufferedReader in; public SimpleRead() { try { serialPort = (SerialPort) portId.open("Envoi", 20000); } catch (PortInUseException e) {System.out.println(e);} /* try { serialPort.addEventListener(this); } catch (TooManyListenersException e) {System.out.println(e);}*/ serialPort.notifyOnDataAvailable(true); try { serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); } catch (UnsupportedCommOperationException e) {System.out.println(e);} readThread = new Thread(this); readThread.start(); } public static void EcritureSurRS232(String data ) { try { outputStream = serialPort.getOutputStream(); outputStream.write(data.getBytes()); } catch (IOException e) { System.out.println("error writing to serial port\n" + e.getMessage()); } } public static void lecturePortRS232() throws IOException{ //byte[] readBuffer = new byte[2]; char[] charbuffer=new char[100]; //inputStream= serialPort.getInputStream(); try { //while (inputStream.available() > 0) { //int numBytes = inputStream.read(readBuffer); //} //System.out.print(new String(readBuffer)); in=new BufferedReader(new InputStreamReader(serialPort.getInputStream())); String codeBarre = new String(); try { //lecture du buffer et affichage codeBarre = (String) in.readLine(); System.out.println(codeBarre); } catch (IOException e) {} //in.close(); } catch (IOException ex) { System.out.println("error reading port\n"+ex.getMessage()); } } public void run() { try { Thread.sleep(20000); } catch (InterruptedException e) {System.out.println(e);} } public void serialEvent(SerialPortEvent event) { switch(event.getEventType()) { case SerialPortEvent.BI: case SerialPortEvent.OE: case SerialPortEvent.FE: case SerialPortEvent.PE: case SerialPortEvent.CD: case SerialPortEvent.CTS: case SerialPortEvent.DSR: case SerialPortEvent.RI: case SerialPortEvent.OUTPUT_BUFFER_EMPTY: break; case SerialPortEvent.DATA_AVAILABLE: byte[] readBuffer = new byte[20]; try { while (inputStream.available() > 0) { int numBytes = inputStream.read(readBuffer); } System.out.print(new String(readBuffer)); } catch (IOException e) {System.out.println(e);} break; } } public static void main(String[] args) throws IOException { portList = CommPortIdentifier.getPortIdentifiers(); while (portList.hasMoreElements()) { portId = (CommPortIdentifier) portList.nextElement(); if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) { if (portId.getName().equals("COM4")) { SimpleRead reader = new SimpleRead(); System.out.println("enter the command:") ; BufferedReader stdin =new BufferedReader(new InputStreamReader(System.in)); String data=stdin.readLine(); EcritureSurRS232(data); lecturePortRS232(); } } } } }
0
amoun
 
me dirijo en realidad a Goddet, estoy desarrollando una aplicación que permite la navegación GPS en un Pocket PC, como primer paso necesito captar los tramas NMEA provenientes del GPS en un puerto serie, he intentado hacerlo con el Hyperterminal, y veo que su código funciona bien con mi aplicación.
¿Ha encontrado una solución para su problema?
¿Puede ayudarme?
1