Connect to a serial port without it crashing if the device isn't connected?

Hello, I am new to processing and am trying to connect processing 3 to an Arduino Nano. I am able to get it connected successfully through the standard means:

import processing.serial.*;

void setup(){
  port = new Serial(this, "COM3", 250000);
  port.bufferUntil('\n');
}

(Processing 3.5.4 Java mode btw)

The problem is, if I try to run the program when the Arduino isn’t connected to the serial port, the program crashes with the error: “RuntimeException: Error opening serial port COM3: Port not found”.

The thing is I would like for it to be possible for the user to open the program first, and then be able to connect the arduino to his/her PC whenever they want. Ideally they would be able to choose from a drop down list which COM port to use. I can figure out how to do all that but I just need to know how to allow processing to handle a failed serial connection attempt without crashing the whole program, then I can go from there.

Thanks in advance!

you could allow user to select port with keyboard?


import processing.serial.*;

Serial myPort; 
String datas;                                         // latest arduino line
int[] datai;                                          // as array of integers
StringList list = new StringList();                   // stored lines
int listlong = 18;                                    // textlines only

int w= 640, h = 360;                                  // canvas settings

// rev plot
int a=120, d = 5;                                     // scope background area rectangle
int[] datainew, dataiold;                             // as array of integers to make lines
float range = 0.3, basex = 130, basey = h-30;         // scope area
float step = ( w-basex-d )/ ( listlong-1 );           // line step calc of array length

boolean diag = true;                                  // print diagnostic info

boolean connect=false;                                // start unconnected but list ports
int connectto=0;                                      // start port

void setup_serial() {                                 // USB arduino..
  //printArray(Serial.list());
  String portName = Serial.list()[connectto];         // adjust 0.. x port
  myPort = new Serial(this, portName, 115200);
  myPort.clear();
  myPort.bufferUntil('\n');
  println("try connect to "+portName);
}

void serialEvent(Serial p) {                          // handle serial data
  datas = trim(p.readStringUntil('\n'));
  if (datas != null) {
    if (diag) println(datas);                         // print every ?GOOD? line
    datai = int( split(datas, ",") );                 // create int array from line to check valid vals
    if ( datai.length >= 3 ) {
      list.append( datas );                           // good, min 3 vals,  store line at String list
    } else { 
      println("bad line: "+datas);
    }
    if ( list.size() >= listlong ) list.remove(0);    // erase the oldest
  }
}

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

void setup() {
  printArray(Serial.list());
  //setup_serial();
  println("select port with key [0] ..[9]");
}

void draw() {
  background(0, 0, 80);
  for ( int i = 0; i < list.size(); i++ ) text( list.get(i), 10, 20+i*20 );      // running list of arduino lines
  plot();
}

void plot() {
  push();
  fill(100);
  rect(a, d, width-a-d, height-2*d);
  for ( int i = 0; i < list.size()-1; i++ ) {
    dataiold = int( split(list.get(i), ",") );
    datainew = int( split(list.get(i+1), ",") ); 
    if ( dataiold.length >=2 && datainew.length >=2 ) { // avoid array errors
      stroke(0, 200, 0);
      line(basex+i*step, basey-range*dataiold[0], basex+(1+i)*step, basey-range*datainew[0]);  // line A0
      stroke(200, 200, 0);
      line(basex+i*step, basey-range*dataiold[1], basex+(1+i)*step, basey-range*datainew[1]);  // line A1
      stroke(0, 200, 200);
      line(basex+i*step, basey-range*dataiold[2], basex+(1+i)*step, basey-range*datainew[2]);  // line A2
    }
  }
  pop();
}

void keyPressed() {
  println(key, keyCode);
  if ( key >= 48 && key <= 57 ) { 
    connectto = key-48;
    setup_serial();
  }
  if ( key == 'c' ) setup_serial(); // unused
}


/*
 [0] "COM1"
 [1] "COM7"
 try connect to COM7
 1023,880,778,
 1023,880,779,
 */


// using arduino code ( test on Arduino Leonardo and IDE 1.8.10 hourly )

/*
 int dt = 100; // msec between sending
 
 void setup() {
 Serial.begin(115200);
 }
 
 void loop() {
 Serial.print( analogRead(0) );          // A0
 Serial.print(",");
 Serial.print( analogRead(1) );          // A1
 Serial.print(",");
 Serial.print( analogRead(2) );          // A2
 Serial.println(",");
 delay(dt);                              // sample rate
 }
 
 
 */

/*
//    with A0 jumper to 5V see like
 1023,885,788,
 1023,884,786,
 1023,884,786,
 1023,883,786,
 1023,885,788,
 */

I only spent a minute on this; it may give you some insights.
I do not have a serial port on [10] so I added that for testing.

import processing.serial.*;
String SerialIn;

Serial myPort;

void setup(){
  
  //Setup Window
  size(1200,300);
  background(255,255,255);
  stroke(0,0,0);
  
  //Setup Serial
  printArray(Serial.list());
  //myPort = new Serial(this, Serial.list()[0], 9600);
  //myPort.bufferUntil('\n');
  
  try 
    {
    myPort = new Serial(this, Serial.list()[10], 9600);
    } 
  catch (Exception e)
     {
    println("Woops 1!");
    exit();
    }
  }

void draw() {
  background(255,255,255);
  SerialIn = myPort.readStringUntil('\n');
  if (SerialIn == null)
    println("Woops 2!");
  else
    {
    text(SerialIn, width/2,height/2);
    }
  fill(0,0,0);
 // println(SerialIn);
}

References:

https://www.merriam-webster.com/dictionary/woops

:slight_smile:

The easiest solution would be to simply to not even attempt to initialize a serial connection until the user asks to. If that’s what you want to do, it’s critical to show/tell that to the use and provide some way to manually request one. In such a case you probably want to let them pick one to use.

Theoretically you could poll the list of serial devices regularly and whenever a new one shows up to connect to it until you have a working connection. This should work because the Arduino and most similar boards use USB serial port adapters, so there is no serial port until you connect the board.

Since you are getting a RuntimeException a try-catch approach should work just fine. Just don’t exit the program because you caught an exception. I would also recommend that you never go with this style:

try {
    // ...
}
catch( Exception e ) {
}

You always want to be as specific as possible as to the sort of exception you’re expecting might occur so you don’t trip over any other kind.