Cleaner technique for two-way Serial?

Folks,

I am working on two-way Serial communications between Arduino and Processing. Simply using serialEvent wasn’t working, I believe that the orders-of-magnitudes-faster computer was just wiping out the Arduino’s ability to keep up (I think serialEvent kept getting called so fast that the Arduino never got a chance to send).

I worked out the technique below to force Processing and Arduino to “take turns.” I know that there’s not a lot of sophistication as far as error traps and other polish, but it does work. I was hoping someone could take a look and let me know if there’s any cleaner or better way to do this two-way comms before I get back to polishing code that I could be doing a better way.

A lower priority would be a better way to deal with CSVs in Arduino. I like the trim() / split() combo in Processing, it just seems really clean. Is there a better way to handle the CSV than what I implemented?

Thanks.

PROCESSING CODE

import processing.serial.*;

int[] controlInput = new int[4];  //Create the array for input
Serial arduinoADK;

boolean goodComms = false;  //Turns true once comms established with Arduino
boolean myTurn = false;  //Flops each time data is sent/received

void setup()
{
  size(640, 480);

  //Create the Arduino object
  arduinoADK = new Serial(this, Serial.list()[0], 9600);
  arduinoADK.clear();
  arduinoADK.bufferUntil('\n');
}

void draw()
{ 
  //Basic text display commands
  background(255);
  textSize(32);
  fill(0, 0, 0);
  text("Input String", 10, 50);
  for(int x = 0 ; x < 4 ; x++) text(controlInput[x], (10 + 100*x), 150);
  
  if(goodComms)
  {
    text("GOOD COMMS", 10, 250);
  }
  
  //If it is Processing's turn, send data
  if(myTurn)
  {
    arduinoADK.write("2,3,5,7");
    arduinoADK.write('\n');
    myTurn = false;  //Once data is sent, it's Arduino's turn
  }
}

//Called when data is received
void serialEvent(Serial arduinoADK)
{      
  myTurn = true;  //Once data is received, it is Processing's turn
  
  if(!goodComms)  //Very first handshake between Processing and Arduino
  {
    if(arduinoADK.read() == '\n')
    {
      arduinoADK.clear();
      goodComms = true;
      arduinoADK.write('\n');
      myTurn = true;
    }
  }
  else
  {
    //Receive data from the Arduino
    String inputString = arduinoADK.readStringUntil('\n');
  
    if(inputString != null)
    {
      //Translate the inputString CSVs into the array
      inputString = trim(inputString);
      int tempInput[] = int(split(inputString, ','));

      for(int x = 0 ; x < tempInput.length ; x++) controlInput[x] = tempInput[x];
    }
    else
      println("NULL!");
  }
}

ARDUINO CODE

boolean myTurn = true;  //Turns true once comms established with Processing
boolean goodComms = false;  //Flops each time data is sent/received

int inputArray[] = {1,1,1,1};  //Array for incoming values
int outputArray[] = {1,1,2,3};  //Array for outgoing values

void setup()
{
  //Begin Serial
  Serial.begin(9600);  //PC/Arduino
  Serial1.begin(4800);  //Arduino/ATS-1 Terminal Shield
  Serial1.write(1);
  
  establishComms();  //Don't do anything until Serial comms are established
}

void loop()
{
  //If it is Arduino's turn, send Serial data
  if(myTurn)
  {
    for(int x = 0 ; x < 4 ; x++)
    {
      Serial.print(outputArray[x]);
      
      if(x < 3)
        Serial.print(',');
    }
    Serial.print('\n');
    myTurn = false;  //Once data is sent, it is Processing's turn
  }
}

void serialEvent()
{
  myTurn = true;  //Once data is received, it is Arduino's turn
  
  if(goodComms)
  {
    //Receive the input, terminated with a newline
    String inputString = Serial.readStringUntil('\n');
    
    int CSV;
    int arrayPos = 0;
    String tempInput[4];
    CSV = inputString.indexOf(',');
    
    //Split the CSV into the array
    while(CSV != -1)
    {
      tempInput[arrayPos] = inputString.substring(0, CSV);
      inputString = inputString.substring(CSV+1, inputString.length());
      arrayPos++;
      CSV = inputString.indexOf(',');
    }
    
    for(int x = 0 ; x < 4 ; x++)
    {
      inputArray[x] = tempInput[x].toInt();
    }
  }
}

//This is the wait-until-comms function
void establishComms()
{
  while(Serial.available() <= 0)
  {
    Serial.print('\n');
    delay(300);
  }
  goodComms = true;
}

//Commands related to the ATS Shield
//Basically just a way to test that comms are working
void serialEvent1()
{
  char key = Serial1.read();
  
  if(key == '1') outputArray[0]++;  
  if(key == '2') outputArray[1]++;  
  if(key == '3') outputArray[2]++;  
  if(key == '4') outputArray[3]++;
  
  Serial1.write(1);
  Serial1.print(key);
}

All of this code is testing for eventual integration into an on-going robot project. I know that there are a lot of assumptions being made about “perfect” data in this code, it will be fixed once I know the technique is a solid foundation.

I appreciate your input. Thanks!

I haven't studied your code but I would be inclined to have start and end markers on each transmission so that it is clear when all the data has been received. Then the receiver would process the received data and listen for the next start marker or would use the end marker as "permission" to take its turn at sending.

You could also include a check byte to enable checking the validity of each transmission.

...R