Multiple Serial in multiple windows can it be Done?

Hello Processing community. I am working with multiple Windows and with multiple Serials. I been trying to separate my 2 serial data into 2 different Windows (not 1 windows with multiple panes) in processing. Hopefully I don’t sound to confusing. but I been breaking my head over this. I have gotten so many response with different ideas, but because I am not that good in java I am just not getting it.
here is my code, I have broken everything down with for simplicity.

/* 
==========> Arduino Code Simple Analog Code For Now <=============
*/

// the setup routine runs once when you press reset:
void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
}

// the loop routine runs over and over again forever:
void loop() {
  // read the input on analog pin 0:
  int sensorValue = analogRead(A0);
  // print out the value you read:
  Serial.println(sensorValue);
  delay(1);        // delay in between reads for stability
}
/* 
==========> Processing Code <=============
*/

/* Device will be used for configuration and Diagnostics
Configurtion will display the device Status and Test of each Fuctions of sensors and Data Ports
Diagnostics will display the actual data being processed in real time
*/


// import Libraries
import java.awt.event.KeyEvent;
import javax.swing.JOptionPane;
import processing.serial.*;

ChildApplet0 child;
ChildApplet1 child1;
//ChildApplet2 child2;

//serial port select
Serial myPort = null; // serial is at null until
Serial myPort2 = null; // serial is at null until
String portname = null; 
String portname2 = null;

// multiple srial listing
StringList list = new StringList(1); // stored lines
StringList list2 = new StringList(1); // stored lines

//Serial port data
String data; // latest arduino line
int[] datai; // as array of integers
String data2; // latest arduino line
int[] datai2; // as array of integers

//FONTS
PFont myFont; // specify a Font
PFont myFont2; // specify a Font
 
//INITIALZTION
int w= 800, h =400; // canvas settings, workable sized window desired.
int listlong = 2; // list of lines to append. append function will be called out later void serialEvent
int listlong2 = 2; // list of lines to append. append function will be called out later void serialEvent

  
  //-----------------------------------------------serial1

 void openserialport()
  {
  if (portname == null) return;
  if (myPort != null) myPort.stop(); 
  myPort = new Serial(this, portname, 115200); 
  myPort.bufferUntil('\n');    
}

 void selectSerialPort()
{
  String result = (String) JOptionPane.showInputDialog(null,
    "Select the Serial Port that Corresponds to your Arduino board.", "Select Serial Port",
    JOptionPane.QUESTION_MESSAGE,  null, Serial.list(), 0);    

  if (result != null) {
    portname = result;
    openserialport();
  }
}

 void serialEvent(Serial p1)
{
data = trim(p1.readStringUntil('\n')); // initialize the data as what is read in serial p
  
  if (data != null) { // check if data is not null
    //println(data); // print every GOOD line
    datai = int( split(data, ", ") ); // create int array (unused example ) //initialize DATA1 and split data incase there is a coma
    list.append( data ); // OR store line as String list // append the data that is gathered from the serial port
    if ( list.size() >= listlong ) list.remove(0); // erase the oldest? // for ( int i = 0; i }// 
  }
}

//-------------------------------------------------end serial1

  
//-------------------------------------------------serial2  

 void openserialport2()
  {
  if (portname2 == null) return;
  if (myPort2 != null) myPort2.stop(); 
  myPort2 = new Serial(this, portname2, 115200); 
  myPort2.bufferUntil('\n');    
}

 void selectSerialPort2()
{
  String result2 = (String) JOptionPane.showInputDialog(null,
    "Select the Serial Port that Corresponds to your Arduino board.", "Select Serial Port",
    JOptionPane.QUESTION_MESSAGE,  null, Serial.list(), 0);    

  if (result2 != null) {
    portname2 = result2;
    openserialport2();
  }
}

 void serialEvent2(Serial p2)
{
data2 = trim(p2.readStringUntil('\n')); // initialize the data as what is read in serial p
  
  if (data2 != null) { // check if data is not null
    //println(data); // print every GOOD line
    datai2 = int( split(data2, ", ") ); // create int array (unused example ) //initialize DATA1 and split data incase there is a coma
    list.append( data2 ); // OR store line as String list // append the data that is gathered from the serial port
    if ( list.size() >= listlong ) list.remove(0); // erase the oldest? // for ( int i = 0; i }// 
    
  }
}
//-------------------------------------end serial2


 void settings() {
  size(w, h, JAVA2D);
  
}

 void setup() {
  surface.setTitle("Main sketch");
  
  child = new ChildApplet0();
  child1 = new ChildApplet1();
  delay(1000);
  
}

 void draw() {
 
  background(50, 100, 180); // background color for size of canvas (R, G, B) 

  myFont = createFont("Arial", 30);    // fonts call out for type and size for title
  fill(234);
  textFont(myFont);
  text("Instructions ... ", 325, 30);//lets give title to our window
  

  myFont = createFont("Arial",20);
  fill(234);
  textFont(myFont);
  
  text("To Enable and Disable Console Press ....'C'.", 35, 75);
  text("To Active Serial Port for any API Press ..'P'.", 35, 100);
  text("Disable Console before Entering Production Mode.", 35, 135);
  text("Diagnostics Port is always availabe at anytime.", 35, 165);  
 
}
  


class ChildApplet0 extends PApplet {
  //JFrame frame;

  public ChildApplet0() {
    super();
    PApplet.runSketch(new String[]{this.getClass().getName()}, this);
  }
  

public void settings() {
    size(w, h, JAVA2D);
    smooth();
  }
  
  public void setup() { 
    surface.setTitle("Device Diagnostics");
    //arcball2 = new Arcball(this, 300);
    delay(1000);
  } 
  

public void draw() {
 background(50, 100, 180); // background color for size of canvas (R, G, B) 

  myFont = createFont("Arial", 30);    // fonts call out for type and size for title
  fill(234);
  textFont(myFont);
  text("Diagnostics ... ", 15, 25);//lets give title to our window
  for ( int i = 0; i < list.size(); i++ ) text( list.get(i), 50, 110+i*20 ); // running list of arduino lines

  myFont = createFont("Arial",16);
  fill(234);
  textFont(myFont);
  int y = 24, dy = 12; 
  text("Press ' P ' to Select Serial Port", 575, 385); y += dy;  
  y = height - dy; 
  text("Current Serial Port: " + portname, 12, y); y -= dy;
}

public void keyPressed()
{    
    if (key == 'p' || key == 'P') selectSerialPort();
    clear();
  }
}

/////-----------------------------------------diagnostics data
 class ChildApplet1 extends PApplet {
  //JFrame frame;

  public ChildApplet1() {
    super();
    PApplet.runSketch(new String[]{this.getClass().getName()}, this);
  }
  


public void settings() {
    size(w, h, JAVA2D);
    smooth();
  }
  
  public void setup() { 
    surface.setTitle("Console"); //////Console////////
    delay(1000);
   
  }  

 public void draw() {
   background(50, 100, 180); // background color for size of canvas (R, G, B) 

  myFont2 = createFont("Arial", 30);    // fonts call out for type and size for title
  fill(230);
  textFont(myFont2);
  text("Console ... ",  15, 25);//lets give title to our window
  for ( int i = 0; i < list.size(); i++ ) text( list.get(i), 50, 110+i*20 ); // running list of arduino lines

  myFont2 = createFont("Arial",16);
  fill(234);
  textFont(myFont2);
  int y = 24, dy = 12; 
  text("Press ' P ' to Select Serial Port", 575, 385); y += dy;  
  y = height - dy; 
  text("Current Serial Port: " + portname2, 12, y); y -= dy;
}
 

public void keyPressed()
{    
    if (key == 'p' || key == 'P') selectSerialPort2();
    clear();
  } 
}
1 Like

I’ve got data coming into two windows from a single Serial connection. Is that what you are trying to achieve? Your source code has the baud rate set at 115200 but the Arduino code is for 9600. As soon as I changed the 115200 to 9600 it started to display data in two windows (see below). I did use a different Arduino program that I use for testing my own apps.

Actually that is what i am getting as well .but i don’t want that… I want to separate both (myPort1 and myPort2) to their Applet0 (myport1) and Applet1 (myport2). I don’t know if I am clear on that…

as you choose the first windows and press “P” and from the pulldown select the first Com Port for that first window, let that first com port to stay with that first windows,

when you choose the second window, and press “P” and from the pulldown select the second Com Port for that second Window, let that second Com port to stay with the second Window.

its been a challenge for me, hopefully i could get an idea from the community how to make this work.

you think it can be dowe or should i scrap it and do it all in 1 window and with multiple panes within that window.?

by the way this is windows Computer… i don’t know how different it is on the MACs. Also how did you get the images. I tried putting the windows and it didn’t allow me at the moment.

As far as I know, and I’m fairly certain about this but others can correct me if I’m wrong, you can only have one serial port open at a time on a single operating system. Therefore, my opinion is that you will be unable to have a separate serial port open for each of two windows.

The image was obtained by overlapping the three windows (which look nice by the way) and then taking a screenshot of a certain area of the desktop. There is a certain combination of three keys held down simultaneously that will allow selecting a rectangular area of the Desktop on a Mac.

Okay, yeah that’s what i thought as well. Cause I tried everything. But I am able to open 2 ports in one window and divide that windows in multiple Panes. IN which I have already done that successfully.

The other thought I had if there is some kind of library like in Arduino "SerialSoft " where you can call out multiple serials. I will keep on testing and searching for alternativs.

Thank you so much for the reply SVAN

To test whether I could have two serial ports open at one time I connected two Arduino Uno boards to my Mac through different USB ports. Somewhat to my surprise it allowed me to connect to both. I connected one Uno with one of your windows and the other Uno with the other window as shown below. At first everything seemed to be going ok, but then the app crashed with the error message below. The problem seemed to be an array overrun on line 230. I am unable to tell if this is just a problem with the code or was it due to having two serial ports connected at once.

line 230 of code:

You may want to wait for opinions from others. I could be wrong. If you can open two ports in one window and have done it before, then it could just be a code problem. If the data is coming in to one default window and you store it in a global then you should be able to access that global from any of the other windows.

Forget about serial ports for a moment and consider this demo with one default Processing window containing two sliders and two PApplet windows which display output from their respective slider: slider1 outputs to WindowOne and slider2 outputs to WindowTwo. The globals radius1 and radius2 are kept with the default window but are available for each of the Applet windows. Therefore, if you can connect two serial ports to a default processing window you should be able to feed data to the two windows. However, you may have been trying to connect the serial ports to different windows (I need to study your code some more). Demo follows:

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import javax.swing.event.*;
import java.awt.event.MouseListener;
import java.awt.event.MouseEvent;

javax.swing.JFrame frame;
java.awt.Canvas canvas;

final int _wndW = 300;
final int _wndH = 300;

int radius1 = 50;
int radius2 = 100;

WindowOne wnd1;
WindowTwo wnd2;

void buildWnd() {

  JSlider slider1 = new JSlider(JSlider.HORIZONTAL, 5, 300, 50);
  slider1.setBounds(60, 10, 200, 30);
  slider1.setToolTipText("slider1");
  frame.add(slider1);
  // **** Action **** //
  slider1.addChangeListener(new ChangeListener() {
    void stateChanged(ChangeEvent changeEvent) {
      radius1 = slider1.getValue();
    }
  });
  
  JSlider slider2 = new JSlider(JSlider.HORIZONTAL, 5, 200, 50);
  slider2.setBounds(60, 50, 200, 30);
  slider2.setToolTipText("slider2");
  frame.add(slider2);
  // **** Action **** //
  slider2.addChangeListener(new ChangeListener() {
    void stateChanged(ChangeEvent changeEvent) {
      radius2 = slider2.getValue();
    }
  });
    
}

void setup() { 
  frame = (javax.swing.JFrame) ((processing.awt.PSurfaceAWT.SmoothCanvas) surface.getNative()).getFrame();
  canvas = (processing.awt.PSurfaceAWT.SmoothCanvas) ((processing.awt.PSurfaceAWT)surface).getNative();
  frame.setBounds(900, 300, _wndW, _wndH);
  frame.remove(canvas);
  surface.setTitle("Default Window");
  surface.setResizable(true);
  javax.swing.SwingUtilities.invokeLater(new Runnable() {
    public void run() { 
     wnd1 = new WindowOne();
     wnd2 = new WindowTwo();
      buildWnd(); // Builds components on EventDispatchThread
    }
  }
  );  
}
 
class WindowOne extends PApplet {

 public WindowOne() {
    PApplet.runSketch(new String[] {this.getClass().getSimpleName()}, this);
  }

  void settings() {
    size(400, 400);
  }

  void setup() {
    background(150);
  }

  void draw() {
    background(150);
    fill(0,255,0);
    circle(width/2,height/2,radius1);
  }

  void mousePressed() {
    println("mousePressed in window one");
  }
}

class WindowTwo extends PApplet {

 public WindowTwo() {
    PApplet.runSketch(new String[] {this.getClass().getSimpleName()}, this);
  }

  void settings() {
    size(300, 300);
  }

  void setup() {
    background(150);
  }

  void draw() {
    background(150);
    fill(255,255,0);
    circle(width/2,height/2,radius2);
  }

  void mousePressed() {
    println("mousePressed in window two");
  }
}

Hello @Graci2017,

The Processing code below worked with 2 Arduinos on a W10 PC.
I started with your code and simplified it down to a working example.

Main sketch tab:

/*
 ==========> Processing Code <=============
 */

// Source of original code from:
// https://discourse.processing.org/t/multiple-serial-in-multiple-windows-can-it-be-done/39325

/* Device will be used for configuration and Diagnostics
 Configuration will display the device Status and Test of each Functions of sensors and Data Ports
 Diagnostics will display the actual data being processed in real time
 */

// import Libraries
import processing.serial.*;

ChildApplet0 child;
ChildApplet1 child1;

//serial port select
Serial myPort = null; // serial is at null until
Serial myPort2 = null; // serial is at null until
String portname = null;
String portname2 = null;

//FONTS
PFont myFont; // specify a Font
PFont myFont2; // specify a Font

//INITIALZTION
int w=300, h=200; // canvas settings, workable sized window desired.

void settings() {
  size(w, h, JAVA2D);
}

void setup() {
  surface.setTitle("Main sketch");

  child = new ChildApplet0();
  child1 = new ChildApplet1();
  delay(1000);
}

void draw()
{
}

Diagnostics tab:

class ChildApplet0 extends PApplet {

  public ChildApplet0() {
    super();
    PApplet.runSketch(new String[]{this.getClass().getName()}, this);
  }

  public void settings() {
    size(w, h, JAVA2D);
  }

  public void setup() {
    surface.setTitle("Device Diagnostics");
    myPort = new Serial(this, "COM5", 9600);
    myPort.bufferUntil('\n');
    delay(1000);
  }

  public void draw() {
    background(50, 100, 180); // background color for size of canvas (R, G, B)

    myFont = createFont("Arial", 30);    // fonts call out for type and size for title
    fill(234);
    textFont(myFont);
    text("Diagnostics ... ", 15, 30);//lets give title to our window

    while (myPort.available() > 0) {
      String myString = myPort.readStringUntil('\n');
      if (myString != null) {
        text(myString, 50, 100);
      }
    }
  }
}

Console tab:


class ChildApplet1 extends PApplet {

  public ChildApplet1() {
    super();
    PApplet.runSketch(new String[]{this.getClass().getName()}, this);
  }

  public void settings() {
    size(w, h, JAVA2D);
  }

  public void setup() {
    surface.setTitle("Console"); //////Console////////
    myPort2 = new Serial(this, "COM6", 9600);
    myPort2.bufferUntil('\n');
    delay(1000);
  }

  public void draw() {
    background(50, 100, 180); // background color for size of canvas (R, G, B)

    myFont2 = createFont("Arial", 30);    // fonts call out for type and size for title
    fill(230);
    textFont(myFont2);
    text("Console ... ", 15, 30);//lets give title to our window

    while (myPort2.available() > 0) {
      String myString = myPort2.readStringUntil('\n');
      if (myString != null) {
        text(myString, 50, 100);
      }
    }
  }
}

One Arduino was counting up and the other down:

:)

Same code runs ok on Mac also. Data is flying by so fast my screenshot can’t capture it! This should answer your question; I was wrong, it is possible.

GLV, SVN, thank you guys so much. I had the basic single Serial port working fine without java.awt.event.KeyEvent and javax.swing.JOptionPane; and i guess i just complicated things by putting more fancy steps to makes things more user friendly.

It was fancy with the Java Option panes…But i guess the simpler it is the better.

Thank you guys so much.

Svan, you did fine. I played with this after your replies and i even went barebone multipleserail code and into the basics. and yes everything worked but as soon i added the bells and whistle it wouldnt work again.

Thank you so much.

Hi,

Don’t know if this helps. Not sure links are allowed but this was written with the explicit intention of having 4 serial ports logging at the same time.

There is a Processing one, and a Javaesque Processing variant for those that prefer IntelliJ. The two projects have diverted somewhat but a couple of bodies suggested it works out the box for them.

Have fun.

thank you I will try, at moment i am still working with the previous code, made some modification , but still not working as i wanted

Hello @Graci2017,

I was able to add a JOptionPane to each of the PApplets and select the COM port for that PApplet.

I also was able to select the COM port and PApplet (two variables) from the main sketch window and pass these to each PApplet to set the COM ports.

It can be done!

Busy these days but can provide a minimal example if requested.

:)