[JAVA] [Javax Comm API] Read COM Port

Closed
goddet Posted messages 6 Status Membre -  
 amoun -
Hello everyone!
I'm using the javax.comm API in a Java program to read information from a USB GPS receiver (detected on a virtual serial port).
Since the COM port number assigned to the GPS receiver can change and the user of the program should not have to worry about it, I scan all the serial ports and check if NMEA formatted data (frames from the GPS receiver) is coming from the relevant COM port. (I couldn't find a better way!)
So I'm trying to read from the serial port based on events as shown in this tutorial:
https://christophej.developpez.com/tutoriel/java/javacomm/#L2.3.3

I just have a small issue now: I can find my GPS receiver, but my program crashes once the frames are read! I believe the program gets stuck in the switch structure that handles the serial port events!
 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; //port identifier private SerialPort serialPort; //the serial port private BufferedReader fluxLecture; //reading stream from the port /* * Method that initializes the serial port in event mode */ public void ModeEvenement(String portCOM) { //retrieving the port identifier try { portID = CommPortIdentifier.getPortIdentifier(portCOM); } catch (NoSuchPortException e) { } //opening the port try { serialPort = (SerialPort) portID.open("ModeEvenement", 2000); } catch (PortInUseException e) { } //retrieving the stream try { fluxLecture = new BufferedReader( new InputStreamReader(serialPort.getInputStream())); } catch (IOException e) {} //adding the listener try { serialPort.addEventListener(this); } catch (TooManyListenersException e) { } //configuring the serial port serialPort.notifyOnDataAvailable(true); try { serialPort.setSerialPortParams( 4800, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); } catch (UnsupportedCommOperationException e) {} System.out.println("port opened, waiting for read"); } /* * Method that reads 7 frames from the serial port * Once the read is done we close the reading stream and the COM port */ public void ReadSerialPort(){ int i=7; String reponse = new String(); try { System.out.println("i="+i); while(i!=0){ System.out.println("Reading from COM port\n"); reponse = (String) fluxLecture.readLine(); System.out.println(reponse); i--; System.out.println("i="+i); } } catch (IOException e) {} //closing the reading stream try { fluxLecture.close(); } catch (IOException e) {} //closing the COM port serialPort.close(); } public void serialEvent(SerialPortEvent event) { //handling events on the port : //we do nothing except when data is available switch (event.getEventType()) { case SerialPortEvent.DATA_AVAILABLE : this.ReadSerialPort();//if data is available we start the read break; default: break;//we do nothing for other events } } /* * Method that scans all COM ports and tests if any data comes from the scanned COM port */ public void listPort(){ Enumeration listePorts = CommPortIdentifier.getPortIdentifiers(); int typePort; String GPSPortCOM; while (listePorts.hasMoreElements()){ portID = (CommPortIdentifier) (CommPortIdentifier) listePorts.nextElement(); if(portID.getPortType()==CommPortIdentifier.PORT_SERIAL){ System.out.println("PORT Name :"+portID.getName()); System.out.println("User :"+portID.getCurrentOwner()); System.out.println("In use ? :"+portID.isCurrentlyOwned()); System.out.println("Type of PORT :"+portID.getPortType()); // Start managing events on portID this.ModeEvenement(portID.getName()); } } } public static void main(String[] args) { //initializing the Win32Driver driver Win32Driver w32Driver = new Win32Driver(); w32Driver.initialize(); testCOM test = new testCOM(); test.listPort(); } }

I don't know if I was clear enough! But if anyone has an idea, I'm all ears!!!
Thanks in advance.
Configuration: Windows XP Firefox 2.0.0.3

2 réponses

oyopi
 
Hi!

It seems to me that your approach is not quite right; in fact, I'm already surprised that you manage to retrieve frames like that.

If I understood correctly, it goes like this:
- you create your object testCOM
- you call the ModeEvenement() method of that object which initializes the port and adds a listener to it, this method finishes successfully and then you rely on the object itself to handle the rest via its serialEvent method.
- if you receive data on the port, serialEvent calls the ReadSerialPort() method which reads 7 frames and then closes the port.

From that point, I see several issues:

You have no control over what’s happening; your testCOM object continues to receive relevant events or not, and that as long as it’s not destroyed, but in addition, you’ve closed the port in the meantime...
Then, reading seven frames in a row like that isn’t ideal; why don’t you continue to use serialEvent to handle frame by frame?

In short, what I say is:
- you should really, really start by making a thread of this class (as suggested at the end of the tutorial you mentioned, for the barcode reader management)!
In fact, just take the tutorial code as is and only change the stopping condition.
Add as global variables to your class:
private int nbreTramesLues = 0; private final int NBRE_TRAMES_A_LIRE = 7;

and instead of putting in the run(), while(running) like in the tutorial, you put
while(this.nbreTramesLues < this.NBRE_TRAMES_A_LIRE)


- and then for the frames, read frame by frame and not all seven at once:

public void serialEvent(SerialPortEvent event) { //handling events on the port : //do nothing unless data is available switch (event.getEventType()) { case SerialPortEvent.DATA_AVAILABLE : try{ System.out.println("Reading from the COM port\n"); reponse = (String) fluxLecture.readLine(); System.out.println(reponse); this.nbreTramesLues++; }catch(IOException e){ } break; default: break;//do nothing for other events } } 


In the main method, just start your thread by calling the start() method (be careful, don’t call run() directly!), if all goes well, the thread stops by itself once the seven frames are received and the port
is closed, no more problems!
Finally, that’s if all goes well; even like that if you don’t get your seven frames, your thread will remain blocked indefinitely in the while, you’ll need to fix that, but it’s already a start.

There you go, also I didn’t quite understand, do you do this for each serial port? What do you do if you receive nothing on a port? Do you wait indefinitely for data to arrive?

One more thing, methods start with a lowercase letter in Java and classes with an uppercase letter; here you’ve done exactly the opposite! It’s easier to keep track of if you follow these naming conventions.

That’s just my opinion on the matter; I hope it helps you a bit!

bye!
2
sabron
 
I almost have the same problem. I want to send AT commands to my Samsung phone connected via USB. The program shows two COM ports, 4 and 5, in addition to 3, which is (COM3 is my PC's modem).
When I send these commands, nothing happens (no response).
But when I close or open the character keyboard, strange characters and squares appear, as well as "locked" or "unlocked" messages. I think my phone is not receiving these commands.
If you have encountered this problem, contact me on MSN [removed by moderation]. I really need your help; I'm currently working on this for my graduate project, and I have other problems...

Here is this code, and I await your ideas on my Hotmail:


/*Most projects that deal with hardware and devices need to communicate with them using the COM port of the PC or Server. For example, if there is a modem that is connected to a server via its COM port and the Java program has to read the output of the modem, then the Java program has to read the COM port for any incoming data.

This sample Java program can be used to read from a COM port for incoming data and process it. Note that you will need to change the Port number to COM1 or COM2 or any other ports as required.

Also, if you are using UNIX-based machines, then you will have to uncomment the /dev/term/a instead of 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("erreur dans l'écriture sur le port série\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("erreur dans la lecture du 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("saisir la commande :") ; BufferedReader stdin =new BufferedReader(new InputStreamReader(System.in)); String data=stdin.readLine(); EcritureSurRS232(data); lecturePortRS232(); } } } } }
0
amoun
 
I am actually addressing Goddet, I am developing an application that allows GPS navigation on a Pocket PC. As a first step, I need to capture the NMEA frames coming from the GPS on a serial port. I tried to do this with HyperTerminal, and I see that your code works well with my application?
Have you found a solution to your problem?
Can you help me?
1