communication between Arduino and Java

I want to send data (G-code) from a Java program on my PC to an Arduino. The communication between the Arduino and my PC works fine because I can send data in in both directions.
If I test the parsing code of my Arduino with the serial monitor of the Arduino I works fine.
If I do the same thing with my Java program, it's not working. In my Java program I receive the data I send to the Arduino but I'm not receiving any parsed data. The problem is, that this is hard to debug because I can't open the serial monitor of the Arduino when I'm communicating with my Java program.

Below you can find my programs:

Arduino:

#include <Arduino.h>

char ch;
const int NUMBER_OF_FIELDS = 6;
int fieldIndex = 0;
double values[NUMBER_OF_FIELDS];
int decimalPoint[NUMBER_OF_FIELDS];

void setup()
{
  Serial.begin(9600);
  Serial.println("setup");
  delay(250);
}

void loop()
{
  // G/M position 0 (code)
  // X position 1
  // Y position 2
  // Z position 3
  // F feedrate
  // E length of filament to consume
  // a typical array looks like this:
  // [G/M, X, Y, Z, F, E]

  if (Serial.available() > 0)
  {
      ch = Serial.read();
      delay(250);
      Serial.println(ch);
      delay(250);
      
      if (ch == 'G' || ch == 'M') {
        fieldIndex = 0;
      } else if (ch == 'X') {
        fieldIndex = 1;
      } else if (ch == 'Y') {
        fieldIndex = 2;
      } else if (ch == 'Z') {
        fieldIndex = 3;
      } else if (ch == 'F') {
        fieldIndex = 4;
      } else if (ch == 'E') {
        fieldIndex = 5;
      } else if (ch >= '0' && ch <='9') {
        values[fieldIndex] = values[fieldIndex] * 10 + (ch - '0');
        if (decimalPoint[fieldIndex] > 0) decimalPoint[fieldIndex] *= 10;
      } else if (ch == '.') {
        decimalPoint[fieldIndex]++;
      } else if (ch == ' ') {
        if(fieldIndex < NUMBER_OF_FIELDS -1);
        fieldIndex++;
      } else {
        delay(250);
        Serial.print(fieldIndex + 1);
        delay(250);
        Serial.println(" field received");
        delay(250);

        for (int i = 0; i <= fieldIndex; i++) {
          if (decimalPoint[i] > 0) {
            Serial.println(values[i] / decimalPoint[i]);
            delay(250);
          } else {
            Serial.println(values[i]);
            delay(250);
          }
          values[i] = 0;
          decimalPoint[i] = 0;
        }
        fieldIndex = 0;
      }
      

   
  }

  
}

Java

package communicationArduino;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.PrintWriter;
import java.util.Scanner;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import com.fazecast.jSerialComm.SerialPort;

public class Main {
	
	static SerialPort chosenPort;
	static int x = 0;

	public static void main(String[] args) {
		
		// create and configure the window
		JFrame window = new JFrame();
		window.setTitle("Sensor Graph GUI");
		window.setSize(600, 400);
		window.setLayout(new BorderLayout());
		window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		// create a drop-down box and connect button, then place them at the top of the window
		JComboBox<String> portList = new JComboBox<String>();
		JButton connectButton = new JButton("Connect");
		JPanel topPanel = new JPanel();
		topPanel.add(portList);
		topPanel.add(connectButton);
		window.add(topPanel, BorderLayout.NORTH);
		
		// populate the drop-down box
		SerialPort[] portNames = SerialPort.getCommPorts();
		for(int i = 0; i < portNames.length; i++)
			portList.addItem(portNames[i].getSystemPortName());
		
		
		// configure the connect button and use another thread to listen for data
		connectButton.addActionListener(new ActionListener(){
			@Override public void actionPerformed(ActionEvent arg0) {
				if(connectButton.getText().equals("Connect")) {
					// attempt to connect to the serial port
					chosenPort = SerialPort.getCommPort(portList.getSelectedItem().toString());
					chosenPort.setComPortTimeouts(SerialPort.TIMEOUT_SCANNER, 0, 0);
					if(chosenPort.openPort()) {
						connectButton.setText("Disconnect");
						portList.setEnabled(false);
					}
					
					// create a new thread that listens for incoming text and populates the graph
					Thread thread = new Thread(){
						@Override public void run() {
							System.out.println("connected read");
							Scanner scanner = new Scanner(chosenPort.getInputStream());
							
							while(scanner.hasNextLine()) {
								try {
									String line = scanner.nextLine();
									System.out.println(line);
									window.repaint();									
								} catch(Exception e) {}
							}							
							scanner.close();
						}
					};
					thread.start();
					
					
					// create a new thread that listens for incoming text and populates the graph
					Thread thread2 = new Thread(){
						@Override public void run() {
							System.out.println("connected write");
							Scanner scan = new Scanner(System.in);
							String input = "";
							PrintWriter output = new PrintWriter(chosenPort.getOutputStream());
							while (true) {
								input = scan.nextLine();
								output.print(input);
								output.flush();
							}
							// output.close();
						}
					};
					thread2.start();
					
					
				} else {
					// disconnect from the serial port
					chosenPort.closePort();
					portList.setEnabled(true);
					connectButton.setText("Connect");
					x = 0;
				}
			}
		});
		
		// show the window
		window.setVisible(true);
	}

}
const int NUMBER_OF_FIELDS = 6;
int fieldIndex = 0;

You need an int to count to 6?

int decimalPoint[NUMBER_OF_FIELDS];

The strings representing the values will be more than 255 characters long?

        if (decimalPoint[fieldIndex] > 0) decimalPoint[fieldIndex] *= 10;

Oh, wait, the values in the variables are not the location of the decimal point at all. What a dumb name...

            Serial.println(values[i] / decimalPoint[i]);

Anonymous printing sucks.

The problem is, that this is hard to debug because I can't open the serial monitor of the Arduino when I'm communicating with my Java program.

So? Clearly, your poorly indented Java program CAN read from the serial port, and can print what it read. That is ALL that the Serial Monitor application does with respect to incoming serial data.

	Scanner scan = new Scanner(System.in);
		String input = "";
		PrintWriter output = new PrintWriter(chosenPort.getOutputStream());
			while (true) {
			input = scan.nextLine();
			output.print(input);
			output.flush();
		}

What DID you read from System.in? Maybe it was not what you expected.

Those are a lot of questions:

const int NUMBER_OF_FIELDS = 6;
int fieldIndex = 0;

NUMBER_OF_FIELDS is just the size of my array, I have an array with 6 fields, 1 for every variable (Xpos, Ypos,...). fieldIndex is the index I would like to write to.

This is wath my typical G-code looks like:

G01 X25.01 Y32.01
G00 E1000 Z5.0
G01 F200 X25.01 Y50.06
etc.

I'm reading char after char, I I see a . (decimal point) I keep track of how many digits are there after the decimal point and I devide the result by the decimal point value

In my Java program I can read the serial port, that is correct, but I'm seeing the correct values there and I was guessing that maybe the Arduino reads the Ascii code instead of the value or something like that.

	Scanner scan = new Scanner(System.in);
		String input = "";
		PrintWriter output = new PrintWriter(chosenPort.getOutputStream());
		while (true) {
			input = scan.nextLine();
			output.print(input);
			output.flush();
		}

I'm using the System.in so I can enter a String manually that is send to the arduino.

This is a sample output I get on my Java console (G1 X10 is the string I enter on my System.in):

connected read
connected write
setup
G1 X10
G
1
 
X
1
0

fieldIndex is the index I would like to write to.

So, that variable needs to hold values in the range 0 to 5. Do you really need an int, capable of holding values in the range -32768 to 32767, to do that? Using the appropriate type IS important.

This is a sample output I get on my Java console (G1 X10 is the string I enter on my System.in):

But, you have no clue what caused the Arduino to generate that output. That's what I meant by "Anonymous printing sucks".

Add MORE Serial.print() statements, to show where you got in the program, and add statements to clearly indicate what is being printed.

Serial.print("I got a ");
Serial.println(ch);

conveys a LOT more information than

Serial.println(ch);

At least it does to me.

So, what decisions DID the Arduino make, based on that data?

The Serial Monitor application can append data to what you type, or not, depending on what you selected. What did you select?

Your JAVA application is NOT sending any end-of-packet marker (like the Serial Monitor application probably did). The Arduino program dumps the data it received one character at a time, until the end of packet marker arrives, at which time it dumps a lot more data.

No end of packet marker means no big dump.

bleau83:
The problem is, that this is hard to debug because I can't open the serial monitor of the Arduino when I'm communicating with my Java program.

The first thing is to add some code to your Java program to print the raw message received from the Arduino. That will be as good as seeing it on the Serial Monitor.

I don't understand this

If I do the same thing with my Java program, it's not working. In my Java program I receive the data I send to the Arduino but I'm not receiving any parsed data.

What do you mean by "the same thing"

Where would the parsed data come from?

Have a look at the examples in Serial Input Basics - simple reliable ways to receive data. There is also a parse example to illustrate how to extract numbers from the received text.

The technique in the 3rd example will be the most reliable. It is what I use for Arduino to Arduino and Arduino to PC communication.

You can send data in a compatible format with code like this (or the equivalent in any other programming language)

Serial.print('<'); // start marker
Serial.print(value1);
Serial.print(','); // comma separator
Serial.print(value2);
Serial.println('>'); // end marker

For now, don't worry about the size of your Arduino variables - as long as they are big enough.

...R

I found the problem. There seems to be a difference between the data the arduino gets from the serial monitor and the data the arduino gets from the serial communication. I used a CR to check the end of the string, this works for data from the serial monitor but not for data from the serial interface (PC). I added another end marker and now it works.
Because the software didn't recieve a CR, the loop never ended and the received data was never send back.

bleau83:
I used a CR to check the end of the string, this works for data from the serial monitor but not for data from the serial interface (PC). I added another end marker and now it works.

You can select the line-ending character in the Serial Monitor - I guess you have been relying on the default setting.

If you are writing your own code then, of course, it must add whatever line-ending character the Arduino is expecting.

...R