Error: ArrayIndexOutOfBoundsException: Index -1 out of bounds for length 32768

hello! i am making this game in Processing and using a Teensy hooked up to some buttons to play the game. you know the drill haha. well… i am getting this amazingly frustrating error almost everytime i run the program, and this error wasnt happening a few months ago either…
It must have to do with this serial port maybe overflowing?? idk. ive tried stepping through the code, but it sometimes doesnt happen until the code has cycled like hundreds of times.

here is the error on Processing 3.5.4

ArrayIndexOutOfBoundsException: -1
java.lang.ArrayIndexOutOfBoundsException: -1
at processing.serial.Serial.serialEvent(Unknown Source)
at jssc.SerialPort$EventThread.run(SerialPort.java:1112)

and here is it on Processing 4.0

ArrayIndexOutOfBoundsException: Index -1 out of bounds for length 32768
java.lang.ArrayIndexOutOfBoundsException: Index -1 out of bounds for length 32768
at processing.serial.Serial.serialEvent(Unknown Source)
at jssc.SerialPort$EventThread.run(SerialPort.java:1194)
ArrayIndexOutOfBoundsException: Index -1 out of bounds for length 32768

and here is my code

import processing.video.*; //<>// //<>// //<>// //<>// //<>//
import processing.serial.*;
import processing.sound.*;
///check to make sure the serial port is the right one

//fetching input data from microcontroller
Serial myPort;  // Create object from Serial class
boolean serialInited;
String val;     // Data received from the serial port
String[] list;
int inputs[] = {0, 0, 0, 0, 0, 0, 0}; //button inputs from arduino
int prevInputs[] = {0, 0, 0, 0, 0, 0, 0}; // left, right, up, down, punch, kick, reset
int comboSigTime = 0;
int comboSigTimeout = 6000;
boolean comboSent = false;
String serialString;
boolean serialReceived = false;

//font for timer
PFont fightingFont;

//assets
Fighter fighter;    //our fighter
//Movie background;   //background image
Movie callToActionScreen; //intro screen
Movie winScreen;
Movie resetScreen;
//Movie comboVideo1;  //combo video
//Movie comboVideo2;  //combo video
//Movie comboVideo3;  //combo video
//Movie comboVideo4;  //combo video
PImage staticBackground;
PImage playerOverlay;  //player healthbar
PImage[] comboBar = new PImage[11];

//image arrays for all animations
PImage[] idleLeft = new PImage[9];
PImage[] idleRight = new PImage[9];
PImage[] walkLeft = new PImage[7];
PImage[] walkRight = new PImage[7];
PImage[] punchLeft = new PImage[7];
PImage[] punchRight = new PImage[7];
PImage[] kickLeft = new PImage[7];
PImage[] kickRight = new PImage[7];
PImage[] jumpLeft = new PImage[7];
PImage[] jumpRight = new PImage[7];
PImage[] winningMove1 = new PImage[12];
PImage[] winningMove2 = new PImage[12];
PImage[] winningMove3 = new PImage[12];
PImage[] winningMove4 = new PImage[13];

//sound files
SoundFile bgMusic;
SoundFile punchSound;
SoundFile kickSound;
SoundFile introSound;
SoundFile beginSound;
SoundFile[] winSound = new SoundFile[4];
SoundFile resetSound;

//array of all animations arrays for our fighter
PImage[][] animations = new PImage[14][];

//keeping track of what part of the game we're in
int gameState = 0; //0 = call to action; 1 = gameplay; 2 = win; 3 = try again;
boolean playWinSound = false;
int masterTimer = 0;

float bgDimmer = 0;

int timeLimit = 40; //seconds allowed



void serialEvent(Serial p) {
  try {
    serialString = p.readString();
    serialReceived = true;
    //print(serialString);
    myPort.clear();
  }
  catch (ArrayIndexOutOfBoundsException e) {
    System.out.println("Exception: " + e.toString());
  }
}


void loadAssets() {
  //load the MP4s
  //background = new Movie(this, "0_BACKGROUND/BACKGROUND.mp4");
  callToActionScreen = new Movie(this, "0_CALL_TO_ACTION_SCREEN/CALL_TO_ACTION_SCREEN.mov");
  resetScreen = new Movie(this, "0_TRY_AGAIN_SCREEN/TRY_AGAIN_SCREEN.mov");
  winScreen = new Movie(this, "0_WIN_SCREEN/WIN_SCREEN.mov");
  callToActionScreen.frameRate(20);
  resetScreen.frameRate(20);
  winScreen.frameRate(20);
  //comboVideo1 = new Movie(this, "6_WINNING_MOVE_1/WINNING_MOVE_1_VID.mp4");
  //comboVideo2 = new Movie(this, "6_WINNING_MOVE_2/WINNING_MOVE_2_VID.mp4");
  //comboVideo3 = new Movie(this, "6_WINNING_MOVE_3/WINNING_MOVE_3_VID.mp4");
  //comboVideo4 = new Movie(this, "6_WINNING_MOVE_4/WINNING_MOVE_4_VID.mp4");
  staticBackground = loadImage("0_BACKGROUND/BACKGROUND.png");

  //load the PNGs
  for (int i = 0; i < 7; i++) {
    walkLeft[i] = loadImage("1_LEFT_WALK_V2/LEFT_WALK_FRAME_" + (i+1) + "_V2.png");
    walkRight[i] = loadImage("1_RIGHT_WALK_V2/RIGHT_WALK_FRAME_" + (i+1) + "_V2.png");
    kickLeft[i] = loadImage("2_LEFT_KICK/LEFT_KICK_FRAME_" + (i+1) + ".png");
    kickRight[i] = loadImage("2_RIGHT_KICK/RIGHT_KICK_FRAME_" + (i+1) + ".png");
    punchLeft[i] = loadImage("3_LEFT_PUNCH/LEFT_PUNCH_FRAME_" + (i+1) + ".png");
    punchRight[i] = loadImage("3_RIGHT_PUNCH/RIGHT_PUNCH_FRAME_" + (i+1) + ".png");
    jumpLeft[i] = loadImage("4_LEFT_JUMP/LEFT_JUMP_FRAME_" + (i+1) + ".png");
    jumpRight[i] = loadImage("4_RIGHT_JUMP/RIGHT_JUMP_FRAME_" + (i+1) + ".png");
  }
  for (int i = 0; i < 9; i++) {
    idleLeft[i] = loadImage("5_LEFT_IDLE_V2/LEFT_IDLE_FRAME_" + (i+1) + "_V2.png");
    idleRight[i] = loadImage("5_RIGHT_IDLE_V2/RIGHT_IDLE_FRAME_" + (i+1) + "_V2.png");
  }
  for (int i = 0; i < 12; i++) {
    winningMove1[i] = loadImage("6_WINNING_MOVE_1/PNG_FOLDER/WINNING_MOVE_1_FRAME_" + (i+1) + ".png");
    winningMove2[i] = loadImage("6_WINNING_MOVE_2/PNG_FOLDER/WINNING_MOVE_2_FRAME_" + (i+1) + ".png");
    winningMove3[i] = loadImage("6_WINNING_MOVE_3/PNG_FOLDER/WINNING_MOVE_3_FRAME_" + (i+1) + ".png");
  }
  for (int i = 0; i <13; i++) {
    winningMove4[i] = loadImage("6_WINNING_MOVE_4/PNG_FOLDER/WINNING_MOVE_4_FRAME_" + (i+1) + ".png");
  }

  playerOverlay = loadImage("0_GRAPHICS/PLAYER_1_FANG/PLAYER_1_FANG.png");

  for (int i = 0; i <11; i++) {
    comboBar[i] = loadImage("0_GRAPHICS/COMBO_BAR/COMBO_BAR_FRAME_" + (i+1) + ".png");
  }

  //load the sounds
  bgMusic = new SoundFile(this, "SOUNDS/bg.mp3");
  bgMusic.amp(0.3);
  punchSound = new SoundFile(this, "SOUNDS/punch.wav");
  kickSound = new SoundFile(this, "SOUNDS/kick.wav");
  introSound = new SoundFile(this, "SOUNDS/announcer/intro.wav");
  beginSound = new SoundFile(this, "SOUNDS/announcer/beginning.wav");
  resetSound = new SoundFile(this, "SOUNDS/announcer/reset.wav");

  for (int i = 0; i < 4; i++) {
    winSound[i] = new SoundFile(this, "SOUNDS/announcer/WIN/WIN_" + (i+1) + ".wav");
  }

  //set up animations array for fighter
  animations[0] = idleLeft;
  animations[1] = idleRight;
  animations[2] = walkLeft;
  animations[3] = walkRight;
  animations[4] = punchLeft;
  animations[5] = punchRight;
  animations[6] = kickLeft;
  animations[7] = kickRight;
  animations[8] = jumpLeft;
  animations[9] = jumpRight;
  animations[10] = winningMove1;
  animations[11] = winningMove2;
  animations[12] = winningMove3;
  animations[13] = winningMove4;

  // Make Fighter object
  fighter = new Fighter(animations, 100, 0);
}

void movieEvent(Movie m) {
  m.read();
}

//void keyPressed() {
//  if (gameState == 1) {
//    gameState = 2;
//  }

//  if (key == 'z') {
//    println("punch");
//    inputs[4] = 1;
//  } else if (key == 'x') {
//    inputs[5] = 1;
//    println("kick");
//  } else if (key == 'r') {
//    gameState = 7;
//  }
//  if (key == CODED) {
//    if (keyCode == LEFT) {
//      inputs[0] = 1;
//    }
//    if (keyCode == RIGHT) {
//      inputs[1] = 1;
//    }
//    if (keyCode == UP) {
//      inputs[2] = 1;
//    }
//    if (keyCode == DOWN) {
//      inputs[3] = 1;
//    }
//  }
//}

//void keyReleased() {
//  if (key == 'z') {
//    println("punch");
//    inputs[4] = 0;
//    fighter.punchAllow = true;
//    fighter.punching = false;
//  } else if (key == 'x') {
//    inputs[5] = 0;
//    println("kick");
//    fighter.kickAllow = true;
//    fighter.kicking = false;
//  }

//  if (key == CODED) {
//    if (keyCode == LEFT) {
//      inputs[0] = 0;
//      fighter.inputsAllow[0] = true;
//    }
//    if (keyCode == RIGHT) {
//      inputs[1] = 0;
//      fighter.inputsAllow[1] = true;
//    }
//    if (keyCode == UP) {
//      inputs[2] = 0;
//      fighter.inputsAllow[2] = true;
//      fighter.jumpAllow = true;
//    }
//    if (keyCode == DOWN) {
//      inputs[3] = 0;
//      fighter.inputsAllow[3] = true;
//    }
//  }
//}

void readTeensy() {
  //println("readTeensy");
  //read inputs from arduino
  //if ( myPort.available() > 0)
  //{  // If data is available,

  //  val = myPort.readStringUntil('\n');       // read it and store it in val
  //  //println(val);
  //  if (val != null) {

  //    list = split(val, "a");
  //    for (int i = 0; i < list.length-1; i++) {
  //      prevInputs[i] = inputs[i];
  //      inputs[i] = Integer.parseInt(list[i]);
  //    }
  //    println(inputs);
  //    println("END PACKET");
  //  }
  //}
  if (serialReceived) {
    if (serialString.length() == 15) {
      list = split(serialString, "a");
      for (int i = 0; i < 7; i++) {
        prevInputs[i] = inputs[i];
        inputs[i] = Integer.parseInt(list[i]);
      }
    }
    serialReceived = false;
  }
  //println(inputs);
  //println(serialString);

  for (int i = 0; i < 7; i++) {
    if (inputs[i] == 1 && prevInputs[i] == 0) {
      teensyKeyPressed(i);
    } else if (inputs[i] == 0 && prevInputs[i] == 1) {
      teensyKeyReleased(i);
    }
  }

  //if winning combo has been done, send signal to arduino to release the drink
  if (gameState == 6 && !comboSent) {
    int i =0;
    while (i< 2) {
      myPort.clear();
      myPort.write("c");
      comboSent = true;
      comboSigTime = millis() + comboSigTimeout;
      println("sending c to teensy");
      i++;
    }
  }
  if (millis() > comboSigTime) comboSent = false;
  myPort.clear();
  //print("has the combo been sent?");
  //println(comboSent);
}

//Replicating functionality of builtin keyPressed() function for serial data from teensy
void teensyKeyPressed(int code) {
  if (gameState == 1) {
    gameState = 2;
  }

  //reset button pressed
  if (code == 6) {
    gameState = 0;
  }

  //  if (code == 'z'){
  //    println("punch");
  //    inputs[4] = 1;
  //  } else if (key == 'x'){
  //    inputs[5] = 1;
  //    println("kick");
  //  } else if (key == 'r'){
  //    gameState = 7;
  //  }
  //  if (key == CODED) {
  //    if (keyCode == LEFT){
  //      inputs[0] = 1;
  //    }
  //    if (keyCode == RIGHT){
  //      inputs[1] = 1;
  //    }
  //    if (keyCode == UP){
  //      inputs[2] = 1;
  //    }
  //    if (keyCode == DOWN){
  //      inputs[3] = 1;
  //    }
  //  }
}

//Replicating functionality of builtin keyPressed() function for serial data from teensy
void teensyKeyReleased(int code) {
  if (code == 4) {
    println("punch");
    inputs[4] = 0;
    fighter.punchAllow = true;
    fighter.punching = false;
  } else if (code == 5) {
    inputs[5] = 0;
    println("kick");
    fighter.kickAllow = true;
    fighter.kicking = false;
  }
  if (code == 0) {
    inputs[0] = 0;
    fighter.inputsAllow[0] = true;
  } else if (code == 1) {
    inputs[1] = 0;
    fighter.inputsAllow[1] = true;
  } else if (code == 2) {
    inputs[2] = 0;
    fighter.inputsAllow[2] = true;
    fighter.jumpAllow = true;
  } else if (code == 3) {
    inputs[3] = 0;
    fighter.inputsAllow[3] = true;
  }
}

void initSerial () {
  println("init serial");
  try {
    println("trying serial");
    printArray(Serial.list());

    String portName = Serial.list()[4]; //change the 0 to a 1 or 2 etc. to match your port
    myPort = new Serial(this, portName, 115200);
    myPort.bufferUntil('\n');
    serialInited = true;
  }
  catch (RuntimeException e) {
    if (e.getMessage().contains("<init>")) {
      println("port in use, trying again later...");
      serialInited = false;
    }
  }
}

void setup() {
  size(1280, 720);
  frameRate(20);

  //get font ready
  fightingFont = createFont("FONTS/hollowpoint.ttf", 64);
  textFont(fightingFont);

  textSize(200);
  fill(255);
  textAlign(CENTER);
  background(0, 200, 140);
  text("loading...", width/2, height/2);
  textAlign(LEFT);
  //load images, videos and sounds
  loadAssets();

  //initialize serial comm
  initSerial();
  bgMusic.loop();
  masterTimer = millis();
  delay(2000);
}

void draw() {
  //println("in the draw loop");
  //background(255);
  if (serialInited) {
    println("gamestate = " + gameState);
    //println("in the teensy loop");
    // serial is up and running
    //try {
    //if (myPort.available() > 0) {
    //  serialInited = true;
    //} else {
    //  serialInited = false;
    //  gameState = 9;
    //  callToActionScreen.loop();
    //  image(callToActionScreen, 0, 0);
    //}
    //all serial stuff happens here
    readTeensy();
    switch (gameState) {
    case 0:
      //call to action sound
      introSound.play();
      callToActionScreen.loop();
      image(callToActionScreen, 0, 0);
      gameState = 1;
      break;

    case 1:
      //call to action

      image(callToActionScreen, 0, 0);
      callToActionScreen.loop();
      break;

    case 2:
      //play begin sound
      callToActionScreen.stop();
      masterTimer = millis();
      beginSound.play();
      gameState = 11;
      break;

    case 11:
      //prepare for gameplay
      //background.loop();
      gameState = 3;
      break;

    case 3:
      //gameplay
      image(staticBackground, 0, 0);
      // Display, cycle, and move all the animation objects
      fighter.decideAction(inputs);
      fighter.move();
      fighter.next();
      fighter.display();
      fighter.comboCheck();
      image(playerOverlay, 0, 0);
      image(comboBar[fighter.comboMeterNum], 0, 0);
      //timer
      int currTime = timeLimit - (millis() - masterTimer)/1000;
      fill(255);
      textSize(100);
      text(currTime, 625, 115);
      fill(0);
      text(currTime, 627, 117);
      if (currTime <= 0) {
        gameState = 7;
      }
      break;

    case 4:
      //winning combo
      image(staticBackground, 0, 0);
      noStroke();
      fill(0, bgDimmer);
      bgDimmer += 5;
      rect(0, 0, width, height);
      fighter.move();
      fighter.next();
      fighter.display();
      fighter.comboDone();
      image(playerOverlay, 0, 0);
      break;

    case 5:
      //victory sound
      int tmp = (int)random(0, 4);
      winSound[tmp].play();
      winScreen.play();
      image(winScreen, 0, 0);
      gameState = 6;
      break;

    case 6:
      //victory screen
      image(winScreen, 0, 0);
      if (winScreen.time()+.05 >= winScreen.duration()) {
        gameState = 9;
        winScreen.jump(0);
        winScreen.stop();
      }
      break;

    case 7:
      //failure sound
      resetSound.play();
      resetScreen.play();
      image(resetScreen, 0, 0);
      gameState = 8;
      break;

    case 8:
      //failure screen
      image(resetScreen, 0, 0);
      if (resetScreen.time()+.05 >= resetScreen.duration()) {
        resetScreen.jump(0);
        resetScreen.stop();
        gameState = 10;
      }
      break;

    case 10:
      noStroke();
      fill(0, bgDimmer);
      bgDimmer += 3;
      rect(0, 0, width, height);
      if (bgDimmer >= 255) {
        gameState = 9;
      }
      break;

    case 9:
      //resetting
      playWinSound = false;
      bgDimmer = 0;
      gameState = 0;
      break;
    }
    //}
    //catch (RuntimeException e) {
    //  // serial port closed :(
    //  serialInited = false;
    //  println("stopping serial!");
    //  myPort.stop(); //if port isnt availbile, stop it
    //  //delay(2000);
    //  //String portName = Serial.list()[0]; //restart the serial connection
    //  //myPort = new Serial(this, portName, 9600);
    //}
  } else {
    // serial port is not available. bang on it until it is.
    //for (int i=0; i<200; i++) {
    //  //this is a looop so we dont knock the door down on the serial port
    //  //println("in the waiting loop" + i);
    //}
    //initSerial();
  }
}

THANK you for any help dear coding gurus! i am totally at a loss for how to figure this out…

Hi @zumdar, the error seems to be saying it’s in serialEvent, so suggest adding print statements to show what’s happening when it exceptions.

void serialEvent(Serial p) {
  try {
    print("¬");
    serialString = p.readString();
    serialReceived = true;
    print(serialString);
    myPort.clear();
    print("~");
  }

thank you for the suggestion. i went thru and added lots of print statements. but still getting error. here is the new code:

import processing.video.*; //<>// //<>// //<>//
import processing.serial.*;
import processing.sound.*;
///check to make sure the serial port is the right one

//fetching input data from microcontroller
Serial myPort;  // Create object from Serial class
boolean serialInited;
String val;     // Data received from the serial port
String[] list;
int inputs[] = {0, 0, 0, 0, 0, 0, 0}; //button inputs from arduino
int prevInputs[] = {0, 0, 0, 0, 0, 0, 0}; // left, right, up, down, punch, kick, reset
int comboSigTime = 0;
int comboSigTimeout = 6000;
boolean comboSent = false;
String serialString;
boolean serialReceived = false;

//font for timer
PFont fightingFont;

//assets
Fighter fighter;    //our fighter
//Movie background;   //background image
Movie callToActionScreen; //intro screen
Movie winScreen;
Movie resetScreen;
//Movie comboVideo1;  //combo video
//Movie comboVideo2;  //combo video
//Movie comboVideo3;  //combo video
//Movie comboVideo4;  //combo video
PImage staticBackground;
PImage playerOverlay;  //player healthbar
PImage[] comboBar = new PImage[11];

//image arrays for all animations
PImage[] idleLeft = new PImage[9];
PImage[] idleRight = new PImage[9];
PImage[] walkLeft = new PImage[7];
PImage[] walkRight = new PImage[7];
PImage[] punchLeft = new PImage[7];
PImage[] punchRight = new PImage[7];
PImage[] kickLeft = new PImage[7];
PImage[] kickRight = new PImage[7];
PImage[] jumpLeft = new PImage[7];
PImage[] jumpRight = new PImage[7];
PImage[] winningMove1 = new PImage[12];
PImage[] winningMove2 = new PImage[12];
PImage[] winningMove3 = new PImage[12];
PImage[] winningMove4 = new PImage[13];

//sound files
SoundFile bgMusic;
SoundFile punchSound;
SoundFile kickSound;
SoundFile introSound;
SoundFile beginSound;
SoundFile[] winSound = new SoundFile[4];
SoundFile resetSound;

//array of all animations arrays for our fighter
PImage[][] animations = new PImage[14][];

//keeping track of what part of the game we're in
int gameState = 0; //0 = call to action; 1 = gameplay; 2 = win; 3 = try again;
boolean playWinSound = false;
int masterTimer = 0;

float bgDimmer = 0;

int timeLimit = 40; //seconds allowed



void serialEvent(Serial p) {
  print("¬");
  serialString = p.readString();
  serialReceived = true;
  print(serialString);
  myPort.clear();
  println("~");
}

void loadAssets() {
  //load the MP4s
  //background = new Movie(this, "0_BACKGROUND/BACKGROUND.mp4");
  callToActionScreen = new Movie(this, "0_CALL_TO_ACTION_SCREEN/CALL_TO_ACTION_SCREEN.mov");
  resetScreen = new Movie(this, "0_TRY_AGAIN_SCREEN/TRY_AGAIN_SCREEN.mov");
  winScreen = new Movie(this, "0_WIN_SCREEN/WIN_SCREEN.mov");
  callToActionScreen.frameRate(20);
  resetScreen.frameRate(20);
  winScreen.frameRate(20);
  //comboVideo1 = new Movie(this, "6_WINNING_MOVE_1/WINNING_MOVE_1_VID.mp4");
  //comboVideo2 = new Movie(this, "6_WINNING_MOVE_2/WINNING_MOVE_2_VID.mp4");
  //comboVideo3 = new Movie(this, "6_WINNING_MOVE_3/WINNING_MOVE_3_VID.mp4");
  //comboVideo4 = new Movie(this, "6_WINNING_MOVE_4/WINNING_MOVE_4_VID.mp4");
  staticBackground = loadImage("0_BACKGROUND/BACKGROUND.png");

  //load the PNGs
  for (int i = 0; i < 7; i++) {
    walkLeft[i] = loadImage("1_LEFT_WALK_V2/LEFT_WALK_FRAME_" + (i+1) + "_V2.png");
    walkRight[i] = loadImage("1_RIGHT_WALK_V2/RIGHT_WALK_FRAME_" + (i+1) + "_V2.png");
    kickLeft[i] = loadImage("2_LEFT_KICK/LEFT_KICK_FRAME_" + (i+1) + ".png");
    kickRight[i] = loadImage("2_RIGHT_KICK/RIGHT_KICK_FRAME_" + (i+1) + ".png");
    punchLeft[i] = loadImage("3_LEFT_PUNCH/LEFT_PUNCH_FRAME_" + (i+1) + ".png");
    punchRight[i] = loadImage("3_RIGHT_PUNCH/RIGHT_PUNCH_FRAME_" + (i+1) + ".png");
    jumpLeft[i] = loadImage("4_LEFT_JUMP/LEFT_JUMP_FRAME_" + (i+1) + ".png");
    jumpRight[i] = loadImage("4_RIGHT_JUMP/RIGHT_JUMP_FRAME_" + (i+1) + ".png");
  }
  for (int i = 0; i < 9; i++) {
    idleLeft[i] = loadImage("5_LEFT_IDLE_V2/LEFT_IDLE_FRAME_" + (i+1) + "_V2.png");
    idleRight[i] = loadImage("5_RIGHT_IDLE_V2/RIGHT_IDLE_FRAME_" + (i+1) + "_V2.png");
  }
  for (int i = 0; i < 12; i++) {
    winningMove1[i] = loadImage("6_WINNING_MOVE_1/PNG_FOLDER/WINNING_MOVE_1_FRAME_" + (i+1) + ".png");
    winningMove2[i] = loadImage("6_WINNING_MOVE_2/PNG_FOLDER/WINNING_MOVE_2_FRAME_" + (i+1) + ".png");
    winningMove3[i] = loadImage("6_WINNING_MOVE_3/PNG_FOLDER/WINNING_MOVE_3_FRAME_" + (i+1) + ".png");
  }
  for (int i = 0; i <13; i++) {
    winningMove4[i] = loadImage("6_WINNING_MOVE_4/PNG_FOLDER/WINNING_MOVE_4_FRAME_" + (i+1) + ".png");
  }

  playerOverlay = loadImage("0_GRAPHICS/PLAYER_1_FANG/PLAYER_1_FANG.png");

  for (int i = 0; i <11; i++) {
    comboBar[i] = loadImage("0_GRAPHICS/COMBO_BAR/COMBO_BAR_FRAME_" + (i+1) + ".png");
  }

  //load the sounds
  bgMusic = new SoundFile(this, "SOUNDS/bg.mp3");
  bgMusic.amp(0.3);
  punchSound = new SoundFile(this, "SOUNDS/punch.wav");
  kickSound = new SoundFile(this, "SOUNDS/kick.wav");
  introSound = new SoundFile(this, "SOUNDS/announcer/intro.wav");
  beginSound = new SoundFile(this, "SOUNDS/announcer/beginning.wav");
  resetSound = new SoundFile(this, "SOUNDS/announcer/reset.wav");

  for (int i = 0; i < 4; i++) {
    winSound[i] = new SoundFile(this, "SOUNDS/announcer/WIN/WIN_" + (i+1) + ".wav");
  }

  //set up animations array for fighter
  animations[0] = idleLeft;
  animations[1] = idleRight;
  animations[2] = walkLeft;
  animations[3] = walkRight;
  animations[4] = punchLeft;
  animations[5] = punchRight;
  animations[6] = kickLeft;
  animations[7] = kickRight;
  animations[8] = jumpLeft;
  animations[9] = jumpRight;
  animations[10] = winningMove1;
  animations[11] = winningMove2;
  animations[12] = winningMove3;
  animations[13] = winningMove4;

  // Make Fighter object
  fighter = new Fighter(animations, 100, 0);
}

void movieEvent(Movie m) {
  m.read();
}

//void keyPressed() {
//  if (gameState == 1) {
//    gameState = 2;
//  }

//  if (key == 'z') {
//    println("punch");
//    inputs[4] = 1;
//  } else if (key == 'x') {
//    inputs[5] = 1;
//    println("kick");
//  } else if (key == 'r') {
//    gameState = 7;
//  }
//  if (key == CODED) {
//    if (keyCode == LEFT) {
//      inputs[0] = 1;
//    }
//    if (keyCode == RIGHT) {
//      inputs[1] = 1;
//    }
//    if (keyCode == UP) {
//      inputs[2] = 1;
//    }
//    if (keyCode == DOWN) {
//      inputs[3] = 1;
//    }
//  }
//}

//void keyReleased() {
//  if (key == 'z') {
//    println("punch");
//    inputs[4] = 0;
//    fighter.punchAllow = true;
//    fighter.punching = false;
//  } else if (key == 'x') {
//    inputs[5] = 0;
//    println("kick");
//    fighter.kickAllow = true;
//    fighter.kicking = false;
//  }

//  if (key == CODED) {
//    if (keyCode == LEFT) {
//      inputs[0] = 0;
//      fighter.inputsAllow[0] = true;
//    }
//    if (keyCode == RIGHT) {
//      inputs[1] = 0;
//      fighter.inputsAllow[1] = true;
//    }
//    if (keyCode == UP) {
//      inputs[2] = 0;
//      fighter.inputsAllow[2] = true;
//      fighter.jumpAllow = true;
//    }
//    if (keyCode == DOWN) {
//      inputs[3] = 0;
//      fighter.inputsAllow[3] = true;
//    }
//  }
//}

void readTeensy() {
  //println("readTeensy");
  //read inputs from arduino
  //if ( myPort.available() > 0)
  //{  // If data is available,

  //  val = myPort.readStringUntil('\n');       // read it and store it in val
  //  //println(val);
  //  if (val != null) {

  //    list = split(val, "a");
  //    for (int i = 0; i < list.length-1; i++) {
  //      prevInputs[i] = inputs[i];
  //      inputs[i] = Integer.parseInt(list[i]);
  //    }
  //    println(inputs);
  //    println("END PACKET");
  //  }
  //}


  if (serialReceived) {
    serialString = serialString.trim();
    if (serialString.length() == 15) {
      list = split(serialString, "a");
      for (int i = 0; i < 7; i++) {
        prevInputs[i] = inputs[i];
        inputs[i] = Integer.parseInt(list[i]);
      }
    }
    serialReceived = false;
  }
  println(inputs);
  println(serialString);

  for (int i = 0; i < 7; i++) {
    if (inputs[i] == 1 && prevInputs[i] == 0) {
      teensyKeyPressed(i);
    } else if (inputs[i] == 0 && prevInputs[i] == 1) {
      teensyKeyReleased(i);
    }
  }
  //if winning combo has been done, send signal to arduino to release the drink
  if (gameState == 6 && !comboSent) {
    int i =0;
    while (i< 2) {
      myPort.clear();
      myPort.write("c");
      comboSent = true;
      comboSigTime = millis() + comboSigTimeout;
      println("sending c to teensy");
      i++;
    }
  }

  if (millis() > comboSigTime) comboSent = false;
  myPort.clear();
  //print("has the combo been sent?");
  //println(comboSent);
  println("end of readTeensy");
}

//Replicating functionality of builtin keyPressed() function for serial data from teensy
void teensyKeyPressed(int code) {
  if (gameState == 1) {
    gameState = 2;
  }

  //reset button pressed
  if (code == 6) {
    gameState = 0;
  }

  //  if (code == 'z'){
  //    println("punch");
  //    inputs[4] = 1;
  //  } else if (key == 'x'){
  //    inputs[5] = 1;
  //    println("kick");
  //  } else if (key == 'r'){
  //    gameState = 7;
  //  }
  //  if (key == CODED) {
  //    if (keyCode == LEFT){
  //      inputs[0] = 1;
  //    }
  //    if (keyCode == RIGHT){
  //      inputs[1] = 1;
  //    }
  //    if (keyCode == UP){
  //      inputs[2] = 1;
  //    }
  //    if (keyCode == DOWN){
  //      inputs[3] = 1;
  //    }
  //  }
}

//Replicating functionality of builtin keyPressed() function for serial data from teensy
void teensyKeyReleased(int code) {
  if (code == 4) {
    println("punch");
    inputs[4] = 0;
    fighter.punchAllow = true;
    fighter.punching = false;
  } else if (code == 5) {
    inputs[5] = 0;
    println("kick");
    fighter.kickAllow = true;
    fighter.kicking = false;
  }
  if (code == 0) {
    inputs[0] = 0;
    fighter.inputsAllow[0] = true;
  } else if (code == 1) {
    inputs[1] = 0;
    fighter.inputsAllow[1] = true;
  } else if (code == 2) {
    inputs[2] = 0;
    fighter.inputsAllow[2] = true;
    fighter.jumpAllow = true;
  } else if (code == 3) {
    inputs[3] = 0;
    fighter.inputsAllow[3] = true;
  }
}

void initSerial () {
  println("init serial");
  try {
    println("trying serial");
    //printArray(Serial.list());

    String portName = Serial.list()[4]; //change the 0 to a 1 or 2 etc. to match your port
    myPort = new Serial(this, portName, 115200);
    //myPort.bufferUntil('\n');
    myPort.bufferUntil(107); // ASCII for 'k'
    serialInited = true;
  } 
  catch (RuntimeException e) {
    if (e.getMessage().contains("<init>")) {
      println("port in use, trying again later...");
      serialInited = false;
    }
  }
}

void setup() {
  size(1280, 720);
  frameRate(20);

  //get font ready
  fightingFont = createFont("FONTS/hollowpoint.ttf", 64);
  textFont(fightingFont);

  textSize(200);
  fill(255);
  textAlign(CENTER);
  background(0, 200, 140);
  text("loading...", width/2, height/2);
  textAlign(LEFT);
  //load images, videos and sounds
  loadAssets();

  //initialize serial comm
  initSerial();

  bgMusic.loop();
  masterTimer = millis();
  delay(2000);
}

void draw() {
  println("in the draw loop");
  //background(255);
  if (serialInited) {
    println("serial is inited");
    // serial is up and running
    //try { 
    //if (myPort.available() > 0) {
    //  serialInited = true;
    //} else {
    //  serialInited = false;
    //  gameState = 9;
    //  callToActionScreen.loop();
    //  image(callToActionScreen, 0, 0);
    //}
    //all serial stuff happens here
    readTeensy();
    println("after read teensy in draw code");
    switch (gameState) {
    case 0:
      println("case0");

      //call to action sound
      introSound.play();
      callToActionScreen.loop();
      image(callToActionScreen, 0, 0);
      gameState = 1;
      break;

    case 1:
      println("case1");
      //call to action
      //image(callToActionScreen, 0, 0);
      println("case1: after image()"); 
      break;

    case 2:     
      println("case2");
      //play begin sound
      callToActionScreen.stop();
      masterTimer = millis();
      beginSound.play();
      gameState = 11;
      break;

    case 11:
          println("case11");

      //prepare for gameplay
      //background.loop();
      gameState = 3;
      break;

    case 3:
          println("case3");

      //gameplay
      image(staticBackground, 0, 0);
      // Display, cycle, and move all the animation objects
      fighter.decideAction(inputs);
      fighter.move();
      fighter.next();
      fighter.display();
      fighter.comboCheck();
      image(playerOverlay, 0, 0);
      image(comboBar[fighter.comboMeterNum], 0, 0);
      //timer
      int currTime = timeLimit - (millis() - masterTimer)/1000;
      fill(255);
      textSize(100);
      text(currTime, 625, 115);
      fill(0);
      text(currTime, 627, 117);
      if (currTime <= 0) {
        gameState = 7;
      }
      break;

    case 4:
          println("case4");

      //winning combo
      image(staticBackground, 0, 0);
      noStroke();
      fill(0, bgDimmer);
      bgDimmer += 5;
      rect(0, 0, width, height);
      fighter.move();
      fighter.next();
      fighter.display();
      fighter.comboDone();
      image(playerOverlay, 0, 0);
      break;

    case 5:
          println("case5");

      //victory sound
      int tmp = (int)random(0, 4);
      winSound[tmp].play();
      winScreen.play();
      image(winScreen, 0, 0);
      gameState = 6;
      break;

    case 6:
          println("case6");

      //victory screen
      image(winScreen, 0, 0);
      if (winScreen.time()+.05 >= winScreen.duration()) {
        gameState = 9;
        winScreen.jump(0);
        winScreen.stop();
      }
      break;

    case 7:
          println("case7");

      //failure sound
      resetSound.play();
      resetScreen.play();
      image(resetScreen, 0, 0);
      gameState = 8;
      break;

    case 8:
          println("case8");

      //failure screen
      image(resetScreen, 0, 0);
      if (resetScreen.time()+.05 >= resetScreen.duration()) {
        resetScreen.jump(0);
        resetScreen.stop();
        gameState = 10;
      }
      break;

    case 10:
          println("case10");

      noStroke();
      fill(0, bgDimmer);
      bgDimmer += 3;
      rect(0, 0, width, height);
      if (bgDimmer >= 255) {
        gameState = 9;
      }
      break;

    case 9:
          println("case9");

      //resetting
      playWinSound = false;
      bgDimmer = 0;
      gameState = 0;
      break;
    }
    //}  
    //catch (RuntimeException e) {
    //  // serial port closed :(
    //  serialInited = false;
    //  println("stopping serial!");
    //  myPort.stop(); //if port isnt availbile, stop it 
    //  //delay(2000);
    //  //String portName = Serial.list()[0]; //restart the serial connection
    //  //myPort = new Serial(this, portName, 9600);
    //}
  } else {
    // serial port is not available. bang on it until it is.
    //for (int i=0; i<200; i++) {
    //  //this is a looop so we dont knock the door down on the serial port
    //  //println("in the waiting loop" + i);
    //}
    //initSerial();
    println("serial not inited");
  }
  println("end of draw loop");
}

so here is my error and last like 50 lines ofconsole log:

¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
in the draw loop
serial is inited
[0] 0
[1] 0
[2] 0
[3] 0
[4] 0
[5] 0
[6] 0
0a0a0a0a0a0a0ak
¬null~
end of readTeensy
after read teensy in draw code
case1
case1: after image()
end of draw loop
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
in the draw loop
serial is inited
[0] 0
[1] 0
[2] 0
[3] 0
[4] 0
[5] 0
[6] 0
0a0a0a0a0a0a0ak
end of readTeensy
after read teensy in draw code
case1
case1: after image()
end of draw loop


ArrayIndexOutOfBoundsException: -1
java.lang.ArrayIndexOutOfBoundsException: -1
	at processing.serial.Serial.serialEvent(Unknown Source)
	at jssc.SerialPort$EventThread.run(SerialPort.java:1112)
ArrayIndexOutOfBoundsException: -1

also here is the MCU code for posterity :

// this is the arcade machine microcontroller code
// made in spring 2021

#define LEFTPIN 10
#define RIGHTPIN 9
#define UPPIN 12
#define DOWNPIN 11
#define TOP1 8
#define TOP2 7
#define TOP3 6
#define BOTTOM1 5
#define BOTTOM2 4
#define BOTTOM3 3
#define RESETPIN 2
#define RELAYPIN 15
#define LEDPIN 13
int left;
int right;
int up;
int down;
int top1;
int top2;
int top3;
int bottom1;
int bottom2;
int bottom3;
int resetbutton;



int incomingByte = 0;

int interval = 50;
int targetTime = 0;

byte inputPins[] = {LEFTPIN, RIGHTPIN, UPPIN, DOWNPIN, TOP1, TOP2, TOP3, BOTTOM1, BOTTOM2, BOTTOM3, RESETPIN};
//int inputsRead[] = {left, right, up, down, top1, top2, top3, bottom1, bottom2, bottom3, resetbutton};
bool inputsRead[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
int inputsRaw[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
//output to processing: {left(0) right(1) up(2) down(3) kick(4) punch(5) reset(6)}
int inputs[] = {1, 1, 1, 1, 1, 1, 1};
unsigned int timethrottle = 50;
unsigned int time_del = 1;

void setup() {
  //initialize serial communications at a 9600 baud rate
  Serial.begin(115200);
  //initialize input pins
  for (int i = 0; i < 11; i++) {
    pinMode(inputPins[i], INPUT_PULLUP);
  }
  pinMode(RELAYPIN, OUTPUT);
  pinMode(LEDPIN, OUTPUT);
}


void loop() {
  digitalWrite(LEDPIN, LOW);
  if (Serial.available() > 0) {
    incomingByte = Serial.read();
    digitalWrite(LEDPIN, HIGH);
    if (incomingByte == 'c') {
      Serial.println(incomingByte);
      digitalWrite(RELAYPIN, HIGH);
      delay(1000);
      digitalWrite(RELAYPIN, LOW);
    }
  }

  if( millis() > timethrottle){
    //read inputs
    for (int i = 0; i < 11; i++) {
      inputsRead[i] = digitalRead(inputPins[i]);
      //    Serial.print("array  : ");
      //    Serial.print(inputsRead[0]);
      //    Serial.print("left variable: ");
      //    Serial.print(left);
      if (inputsRead[0] == 0) inputs[0] = 1; else inputs[0] = 0; // left
      if (inputsRead[1] == 0) inputs[1] = 1; else inputs[1] = 0; // right
      // i dont want to take the time to figure how to do this with pointers and variable names so i am doing it in a raw undreadable fashion
      //int inputsRead[] = {left(0), right(1), up(2), down(3), top1(4), top2(5), top3(6), bottom1(7), bottom2(8), bottom3(9), resetbutton(10)};
      //    goal: if (up || top1 || bottom1 == 0) inputs[2] = 1; else inputs[2] = 0;
      if ( !(!(inputsRead[2]) || !(inputsRead[4]) || !(inputsRead[7])) == 0) inputs[2] = 1; else inputs[2] = 0; // having to do my own logical XOR cause all inputs default to 1
      if (inputsRead[3] == 0) inputs[3] = 1; else inputs[3] = 0; //down
  
      //    if (top2 || top3 == 0) inputs[2] = 1; else inputs[3] = 0;
      if ( !(!(inputsRead[5]) || !(inputsRead[6]) ) == 0) inputs[4] = 1; else inputs[4] = 0; // kick
      //    if (bottom2 || bottom3 == 0) inputs[2] = 1; else inputs[3] = 0;
      if ( !(!(inputsRead[8]) || !(inputsRead[9]) ) == 0) inputs[5] = 1; else inputs[5] = 0; // punch
      if (inputsRead[10] == 0) inputs[6] = 1; else inputs[6] = 0; //reset
  
      if (inputsRaw[i] == 1) inputsRaw[i] = 0; // flipping the bit
      else if (inputsRaw[i] == 0) inputsRaw[i] = 1; // flipping the bit
    }
    
    //send inputs
    if (millis() > targetTime)
      //    for (int i = 0; i < 11; i++) {
      //      Serial.print(inputsRead[i]);
      //      Serial.print("a");
      //    }
      //  Serial.print("filtered inputs");
      for (int i = 0; i < 7; i++) {
        Serial.print(inputs[i]);
        Serial.print("a");
      }
  
    // end byte
//    Serial.print("\n");
    Serial.print('k');
    timethrottle = millis() + time_del;
  }


  //wait 50 milliseconds so we don't drive ourselves crazy
//  delay(50);
}

i think my next move is to make it so that the teensy doesnt send serial constantly? idk… this is killing me!!!

thank you again for any possible hints!!

i made it so the teensy only sends where there is a state change. the code works, its not constantly sending messages. but, this worked for few button presses and then it errors out again!!!

new mcu code just in case:

// this is the arcade machine microcontroller code
// made in spring 2021

#define LEFTPIN 10
#define RIGHTPIN 9
#define UPPIN 12
#define DOWNPIN 11
#define TOP1 8
#define TOP2 9
#define TOP3 6
#define BOTTOM1 7
#define BOTTOM2 4
#define BOTTOM3 3
#define RESETPIN 2
#define RELAYPIN 15
#define LEDPIN 13
int left;
int right;
int up;
int down;
int top1;
int top2;
int top3;
int bottom1;
int bottom2;
int bottom3;
int resetbutton;
boolean equalFlag;
int incomingByte = 0;

int interval = 50;
int targetTime = 0;

byte inputPins[] = {LEFTPIN, RIGHTPIN, UPPIN, DOWNPIN, TOP1, TOP2, TOP3, BOTTOM1, BOTTOM2, BOTTOM3, RESETPIN};
//int inputsRead[] = {left, right, up, down, top1, top2, top3, bottom1, bottom2, bottom3, resetbutton};
bool inputsRead[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
int inputsRaw[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
//output to processing: {left(0) right(1) up(2) down(3) kick(4) punch(5) reset(6)}
int inputs[] = {1, 1, 1, 1, 1, 1, 1};
int prevInputs[] = {1, 1, 1, 1, 1, 1, 1};
unsigned int timethrottle = 50;
unsigned int time_del = 1;

void setup() {
  //initialize serial communications at a 9600 baud rate
  Serial.begin(115200);
  //initialize input pins
  for (int i = 0; i < 11; i++) {
    pinMode(inputPins[i], INPUT_PULLUP);
  }
  pinMode(RELAYPIN, OUTPUT);
  pinMode(LEDPIN, OUTPUT);
}


void loop() {
  digitalWrite(LEDPIN, LOW);
  if (Serial.available() > 0) {
    incomingByte = Serial.read();
    digitalWrite(LEDPIN, HIGH);
    if (incomingByte == 'c') {
      Serial.println(incomingByte);
      digitalWrite(RELAYPIN, HIGH);
      delay(1000);
      digitalWrite(RELAYPIN, LOW);
    }
  }

  //read inputs
  for (int i = 0; i < 11; i++) {
    inputsRead[i] = digitalRead(inputPins[i]);
    //    Serial.print("array  : ");
    //    Serial.print(inputsRead[0]);
    //    Serial.print("left variable: ");
    //    Serial.print(left);
    if (inputsRead[0] == 0) inputs[0] = 1; else inputs[0] = 0; // left
    if (inputsRead[1] == 0) inputs[1] = 1; else inputs[1] = 0; // right
    // i dont want to take the time to figure how to do this with pointers and variable names so i am doing it in a raw undreadable fashion
    //int inputsRead[] = {left(0), right(1), up(2), down(3), top1(4), top2(5), top3(6), bottom1(7), bottom2(8), bottom3(9), resetbutton(10)};
    //    goal: if (up || top1 || bottom1 == 0) inputs[2] = 1; else inputs[2] = 0;
    if ( !(!(inputsRead[2]) || !(inputsRead[4]) || !(inputsRead[7])) == 0) inputs[2] = 1; else inputs[2] = 0; // having to do my own logical XOR cause all inputs default to 1
    if (inputsRead[3] == 0) inputs[3] = 1; else inputs[3] = 0; //down

    //    if (top2 || top3 == 0) inputs[2] = 1; else inputs[3] = 0;
    if ( !(!(inputsRead[5]) || !(inputsRead[6]) ) == 0) inputs[4] = 1; else inputs[4] = 0; // kick
    //    if (bottom2 || bottom3 == 0) inputs[2] = 1; else inputs[3] = 0;
    if ( !(!(inputsRead[8]) || !(inputsRead[9]) ) == 0) inputs[5] = 1; else inputs[5] = 0; // punch
    if (inputsRead[10] == 0) inputs[6] = 1; else inputs[6] = 0; //reset

    if (inputsRaw[i] == 1) inputsRaw[i] = 0; // flipping the bit
    else if (inputsRaw[i] == 0) inputsRaw[i] = 1; // flipping the bit
  }
  equalFlag = checkArrays(inputs, prevInputs, 7);
  if (!equalFlag) {
    //begin transmission
    for (int i = 0; i < 7; i++) {
      Serial.print(inputs[i]);
      Serial.print("a");
    }
    //    Serial.print("\n");
    Serial.print('k'); // line ending delimiter
    //end of transmission
  }

  for ( int i = 0 ; i < 7 ; ++i ) {
    prevInputs[i] = inputs[i];
  }
}


boolean checkArrays(int arrayA[], int arrayB[], long numItems) {

  boolean same = true;
  long i = 0;
  while (i < numItems && same) {
    same = arrayA[i] == arrayB[i];
    i++;
  }
  return same;
}

error code this time:

serial is inited
[0] 0
[1] 0
[2] 1
[3] 0
[4] 0
[5] 0
[6] 0
0a0a1a0a0a0a0ak
end of readTeensy
after read teensy in draw code
case3
end of draw loop
¬0a0a0a0a0a0a0ak~
¬0a0a1a0a0a0a0ak~
in the draw loop
serial is inited
[0] 0
[1] 0
[2] 1
[3] 0
[4] 0
[5] 0
[6] 0
0a0a1a0a0a0a0ak
end of readTeensy
after read teensy in draw code
case3
end of draw loop
¬0a0a0a0a0a0a0ak~
¬0a0a1a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a1a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a1a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a1a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
in the draw loop
serial is inited
[0] 0
[1] 0
[2] 0
[3] 0
[4] 0
[5] 0
[6] 0
0a0a0a0a0a0a0ak
end of readTeensy
after read teensy in draw code
case3
¬0a0a1a0a0a0a0ak~
end of draw loop
end of draw loop
in the draw loop
serial is inited
[0] 0
[1] 0
[2] 1
[3] 0
[4] 0
[5] 0
[6] 0
0a0a1a0a0a0a0ak
end of readTeensy
after read teensy in draw code
case3
end of draw loop
in the draw loop
serial is inited
[0] 0
[1] 0
[2] 1
[3] 0
[4] 0
[5] 0
[6] 0
0a0a1a0a0a0a0ak
end of readTeensy
after read teensy in draw code
case3
end of draw loop
¬0a0a0a0a0a0a0ak~
¬0a0a1a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a1a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a1a0a0a0a0ak~
¬0a0a0a0a0a0a0ak~
¬0a0a1a0a0a0a0ak~
in the draw loop
serial is inited
[0] 0
[1] 0
[2] 1
[3] 0
[4] 0
[5] 0
[6] 0
0a0a1a0a0a0a0ak
end of readTeensy
after read teensy in draw code
case3
ArrayIndexOutOfBoundsException: -1
java.lang.ArrayIndexOutOfBoundsException: -1
	at processing.serial.Serial.serialEvent(Unknown Source)
	at jssc.SerialPort$EventThread.run(SerialPort.java:1112)
ArrayIndexOutOfBoundsException: -1

ahh this is so infuriating!

I was hoping that the console would show ¬ crash ~ confirming that the problem is in the SerialEvent. I don’t know Teensy, can’t see from your code how often you are sending. Sending rate has to be less than Processing can read. If not then buffer fills, data lags, data is lost or something breaks. I usually send on changes and at a slow rate.

Could you maybe simplify both the Processing and the C++ code to the minimum? to just a few lines, even if there’s no game left at all? Maybe then you find out what causes the problem. Does it happen if you lower the serial port speed?

The file where it crashes seems to be here:

(found the link at processing/jssc.txt at master · processing/processing · GitHub )

It seems like serialEvent runs in a different thread. serialString and serialReceived are then accessed from two different threads. Might that be related? Maybe synchronized helps? Random guess.

thank you! I simplified things and so I have kinda got it to work, i slowed down the speed at which the messages were sending over.

the processing application works now, but when I export it to an exe file, it doesnt work anymore and crashes the same way. of course I cant see why it is crashing now cause no console… ive tried a logger but thats not catching the error either.

This is probably a bad idea, but I want to modify these two codes it is referencing, the serialEvent code (which ive found on my computer) and the SerialPort.java code and add a catch IndexOutOfBoundsException. Problem is, I can find that SerialPort.java code on the github, but I believe on my machine, it is all compiled into a jssc.jar file which I dont know how to edit.

is this a really bad idea…? and if not, how can i modify this jssc.jar file?

thank youuuu

-still crying

strike that, the above idea is a bad one. I have no idea how to successfully compile this .java file .

back to the drawing board

OK! so this is all being caused by the line

myport.bufferUntil(107) % ASCII for k

somehow processing isnt getting that endline character sometimes and then the buffer completely fills up? or something like that! so… i am trying to figure out a way to check the buffer size. I think somehow the buffer gets full and then the serialEvent gets called…

its so weird though because i am sending that ‘k’ character every time data gets sent over so even if it misses a couple it shouldn’t fill up the entire buffer… and i think it would take a second for me to really fill up that whole buffer… especially if I am only sending messages from Teensy when the button is being pressed. im thinking it has something to do with the multithreading going on. I found this little clue in the SerialEvent method in the serial.java file

                // serialEvent() is invoked in the context of the current (serial) thread
                // which means that serialization and atomic variables need to be used to
                // guarantee reliable operation (and better not draw() etc..)
                // serialAvailable() does not provide any real benefits over using
                // available() and read() inside draw - but this function has no
                // thread-safety issues since it's being invoked during pre in the context
                // of the Processing applet

Ive tried adding ‘synchronized’ to my serialEvent void , but that didnt help. ahh im so closee

1 Like

I wonder if the issue comes from reading and writing serialString from two different threads because serialString.length() == 15 can be true but then it’s potentially no longer true on the next line because it has received new data in serialEvent precisely in that moment.

I was wondering if something like this might work:

String serialString;
String serialStringCopy;
Object lock = new Object();


...

void serialEvent(Serial p) {
    synchronized(lock) {
        serialString = p.readString();
    }
    myPort.clear();
}

....

void readTeensy() {
    synchronized(lock) {
        serialStringCopy = serialString;
        serialString = "";
    }

    if (serialStringCopy.length() == 15) {
      list = split(serialStringCopy, "a");
      for (int i = 0; i < 7; i++) {
        prevInputs[i] = inputs[i];
        inputs[i] = Integer.parseInt(list[i]);
      }
    }
    ....
}

....

In that code serialStringCopy will stay unchanged while processing it. Also the reading and writing of serialString is synchronized to avoid two threads trying to access it simultaneously. Note that I haven’t tried this, maybe something doesn’t make sense :slight_smile:

ps. not sure if you added synchronized to one method or two, but adding it to only one doesn’t make much sense as the goal is that no two methods can run simultaneously called from different threads. In my example above I made it more granular: instead of locking whole methods I just applied it to as few lines as possible, to reduce the locking time.

Thank you so much @hamoid for the tips! the whole synchronized thing is new to me. I tried what you suggested and it did not work unfortunately.

I have decided to go with a workaround. If i delay the serial messages on the Teensy side 50ms every loop, I dont get this error. Ive tried to break it and get the indexoutofbounds error but so far so good, fingers crossed.

One day, I’d love to figure out exactly what was causing this error, but after getting so deep into the serial code and cpp file I have just given up. It works and I’ve gotta install this thing asap.

Thank yall again for the help! I hope one day someone figures out this mystery

1 Like