Hello,
I am developing a desktop app on Processing that reads data arriving on a Serial port. The app will be distributed to users running either Windows or MacOS. They will have an Arduino Uno set up to stream data to the app.
Because there is no way of knowing in advance the name of the serial port to which the user will connect their Arduino, my program iterates through every available port trying to complete a handshake. For every port, the program opens a connection, waits a few seconds for the Arduino to be ready to receive data, sends a connection message to the Arduino, and waits for the reply.
Here is a simplified version of the code:
import processing.serial.*;
Boolean HANDSHAKE_SUCCESSFUL = false; // Keep track of success of current handshake attempt
Serial Arduino; // Object representing the connection to the Arduino
void setup() {
if (TryConnectToArduino()) {
println("Connection successful");
}
}
// Tries to connect to Arduino
// Tries each available port, sends connection message, and waits for a response
public Boolean TryConnectToArduino() {
// Global variable set to true elsewhere in the program when a
// response is received from the Arduino
HANDSHAKE_SUCCESSFUL = false;
// Connect to each available port until we find the right one
for (String nextPort : Serial.list()) {
try {
// Open connection
Arduino = new Serial(this, nextPort, 9600);
println("Trying port " + nextPort);
// Buffer data until newline and wait for connection to be set up
Arduino.bufferUntil('\n');
delay(3000);
Arduino.clear();
// Send connection message
Arduino.write("SYN\n");
// Wait for reply
delay(3000);
// Check if the program received the response
// When the response is received, serialEvent() sets HANDSHAKE_SUCCESSFUL to true
if (HANDSHAKE_SUCCESSFUL) {
// Success; return
return true;
} else {
// Close the current serial connection
Arduino.clear();
Arduino.stop();
}
} catch (RuntimeException e) {
// The port is busy - it's not the right one
println(nextPort + " was busy");
continue;
}
}
return false;
}
// Called when data is available to be read from the Arduino
void serialEvent(Serial p) {
// Read the data
String response = p.readString();
// Check if the data is the response we want
if (response != null && response.equals("ACK\n")) {
HANDSHAKE_SUCCESSFUL = true;
}
}
The Arduino code is a very simple script that waits for the connection message and replies:
void setup() {
Serial.begin(9600);
completeHandshake();
}
// Loop until we complete the three-way handshake
void completeHandshake() {
while (true) {
// Listen for an incoming SYN
if (Serial.available() == 0) continue;
// Check if we received SYN
String syn = Serial.readString();
if (!syn.equals("SYN\n")) continue;
// Respond so app knows we're connected
Serial.write("ACK\n");
return;
}
}
void loop() {}
In most cases, this code works fine. However, for one of my users running it on Windows, it failed. It turned out after a lot of debugging that their Bluetooth headphones were connected to their computer, and that turning off Bluetooth solved the problem.
Here is the issue: on certain Bluetooth ports, the line Arduino.write("SYN\n")
blocks. The program doesn’t crash or print out an error message; the program just blocks at that function call, and never moves on. I’m not sure why this is happening, and the reference doesn’t mention any case where Serial write() would block.
This post on the Arduino forum states that, on Arduino, Serial write() blocks when the output buffer is or becomes full. I’m guessing something similar happens in Processing, but I thought that calling Arduino.clear()
would prevent this.
I can think of a couple of solutions:
- Check if a port is associated with Bluetooth before attempting to connect. If so, ignore it.
- Implement a timeout to move on if a write() call is taking too long
I haven’t yet implemented these, and I would be interested in understanding a bit more clearly why this is happening first.
I would really appreciate any help, either solutions or extra information about why this is happening. Thank you!