I often see Processing code (for communication with e.g. Arduino) where the port is hard-coded. E.g.
myPort = new Serial(this, Serial.list()[0], 9600);
One thing that people don’t seem to realise is that the second parameter for the constructor is a String and one can actually use e.g.
myPort = new Serial(this, "COM3", 9600);
It’s still hardcoded and in both cases, if one needs to change the port for some reason, one has to modify the Processing code to cater for it. Not a big issue if you’re working in the IDE but a little more of a inconvenience if you’re using an exported application.
The below is a way how to prevent to have to change the code (and export again) after a change. The code uses a function to read a specified serial port from a text file; it also provides a function to check if the specified port actually exists. The code is kept simple (always a relative term )
The configuration file is simple and only contains one line specifying the port; the specified port must be on the first line as the function to read the file only checks the first line.
In setup()
, the application attempts to read the configuration file and on success checks if the specified port exists; if so, it attempts to open the specified port. In this example, draw()
is used to display the status of the process.
import processing.serial.*;
// serial object
Serial mySerial = null;
// configuration file
final String configFile = "data/PortConfig.txt";
// baudrate
final int baudrate = 115200;
// serial port selected by user; one can set this to a default (e.g. COM8)
String selectedPort = "";
// message to display
String displayMessage= "";
void setup()
{
size(350, 400);
// possible Processing bug
// when the application starts, it does not always react on key presses
// and one has to manucally click in the application to give it the focus
// workaround that might solve it found at https://discourse.processing.org/t/keypressed-only-works-sometimes/22340/
surface.setVisible(true);
// if read port from file succeeded
if (readPortFromFile() == true)
{
// if the specified port exists
if (chkPortExists() == true)
{
try
{
mySerial = new Serial(this, selectedPort, baudrate);
displayMessage = "Port " + selectedPort + "' is open";
}
catch(RuntimeException rtex)
{
displayMessage = rtex.getMessage();
}
}
}
}
void draw()
{
background(0xFFFFF1C4);
textSize(16);
textAlign(CENTER, CENTER);
if (mySerial == null)
{
fill(0xFF800000);
} //
else
{
fill(0xFF008000);
}
text(displayMessage, width/2, height / 2);
}
/*
Retrieve port-to-use from file
Returns:
true on successfu read, else false
*/
boolean readPortFromFile()
{
boolean success = true;
try
{
BufferedReader reader = createReader(configFile);
// if the file was not opened
if (reader == null)
{
displayMessage = "Could not open file '" + configFile + "'";
success = false;
} //
else
{
selectedPort = reader.readLine();
}
}
catch (Exception ex)
{
displayMessage = ex.getMessage();
success = false;
}
return success;
}
/*
Check if selected port exists
Returns:
true if it exists, else false
*/
boolean chkPortExists()
{
boolean portExists = false;
// loop through the list of ports
for (int pCnt = 0; pCnt < Serial.list().length; pCnt++)
{
// if specified port exists in the list
if (Serial.list()[pCnt].equals(selectedPort) == true)
{
portExists = true;
break;
}
}
// if the specified port does not exists in the list
if (portExists == false)
{
displayMessage = "Serial port '" + selectedPort + "' does not exist";
}
return portExists;
}
Configuration file:
COM9
Tested in a Windows world.