<commit_before>#define axisLx 2
#define axisLy 3
#define axisRy 4
#define axisRx 5
#define buttonDDown 6
#define buttonDLeft 7

#define buttonL1 8
#define buttonL2 9
#define buttonSelect 10
#define buttonAnalog 11
#define buttonStart 12
#define buttonR1 13

#define buttonDUp 22
#define buttonDRight 23
#define buttonSquare 24
#define buttonR2 25
#define buttonTriangle 26
#define buttonCircle 27

#define buttonCross 28
#define buttonR3 29
#define buttonL3 30

#define leftMotor A0
#define rightMotor A1
#define analogLed A2

#define attentionPin A3

boolean isInputting = false;
boolean isInputtingDelayed = false;
boolean sentPing = false;
boolean sentPong = false;
boolean isConnected = false;

unsigned long inputDelay = 0;
unsigned long previousInputDelay = 0;
unsigned long currentMillis = 0;

unsigned long pingTimeOut = 0;
unsigned long pongTimeOut = 0;
unsigned long pingTimeIn = 0;
unsigned long pongTimeIn = 0;
unsigned long pingDelay = 1000;
unsigned long pongDelay = 1000;
unsigned long previousCalc = 0;
unsigned long calcDelay = 1000;
unsigned long previousPingDelay = 0;
unsigned long previousPongDelay = 0;
unsigned long lastPingIn = 0;
unsigned long lastPongIn = 0;
unsigned long lastPingOut = 0;
unsigned long lastPongOut = 0;
unsigned long calcPingTimestampIn = 0;
unsigned long calcPongTimestampIn = 0;
unsigned long calcPingTimestampOut = 0;
unsigned long calcPongTimestampOut = 0;

unsigned int leftMotorVal = 0;
unsigned int rightMotorVal = 0;
unsigned int analogLedVal = 0;

unsigned int attentionLevel = 0;
unsigned int previousAttentionLevel = 0;
unsigned long attentionLevelLow = 0;
unsigned long attentionLevelHigh = 0;
unsigned long previousAttentionLevelHigh = 0;
unsigned long previousAttentionLevelLow = 0;

unsigned int leftMotorLevel = 0;
unsigned int previousLeftMotorLevel = 0;
unsigned long leftMotorLevelLow = 0;
unsigned long leftMotorLevelHigh = 0;
unsigned long previousLeftMotorLevelHigh = 0;
unsigned long previousLeftMotorLevelLow = 0;

unsigned int rightMotorLevel = 0;
unsigned int previousRightMotorLevel = 0;
unsigned long rightMotorLevelLow = 0;
unsigned long rightMotorLevelHigh = 0;
unsigned long previousRightMotorLevelHigh = 0;
unsigned long previousRightMotorLevelLow = 0;

unsigned int analogLedLevel = 0;
unsigned int previousAnalogLedLevel = 0;
unsigned long analogLedLevelLow = 0;
unsigned long analogLedLevelHigh = 0;
unsigned long previousAnalogLedLevelHigh = 0;
unsigned long previousAnalogLedLevelLow = 0;

unsigned long resetCalled = 0;
unsigned long resetDone = 0;

unsigned long disconnectCalled = 0;
unsigned long disconnectDone = 0;

unsigned long baudRate = 115200;

byte serial_rx_buffer[12];
byte serial_rx_buffer_inverted[12];
byte serial_rx_buffer_controller[12];
byte serial_rx_buffer_ping_in[12];
byte serial_rx_buffer_ping_out[12];
byte serial_rx_buffer_pong_in[12];
byte serial_rx_buffer_pong_out[12];
byte serial_rx_buffer_motor[12];
byte serial_rx_buffer_reset[12];
byte serial_rx_buffer_disconnect[12];
byte serial_rx_buffer_inverted_controller[12];
unsigned long serial_rx_buffer_counter = 0;
unsigned long controller = 0;

//  The array below is an array of all buttons in the order the bytes have to be sent
unsigned int commandArray[] = {buttonSelect, buttonL3, buttonR3, buttonStart, buttonDUp, buttonDRight, buttonDDown, buttonDLeft, buttonL2, buttonR2, buttonL1, buttonR1, buttonTriangle, buttonCircle, buttonCross, buttonSquare, axisRx, axisRy, axisLx, axisLy, buttonAnalog};
unsigned int motorArray[] = {leftMotor, rightMotor, analogLed};

void setup() {
  currentMillis = millis();
  Serial.begin(baudRate);
  isConnected = true;
  //Serial.println("START OF SETUP");

  //  Define buttons and axis to neutral state on startup
  pinMode(axisLx, OUTPUT);
  pinMode(axisLy, OUTPUT);
  pinMode(axisRy, OUTPUT);
  pinMode(axisRx, OUTPUT);
  pinMode(buttonDDown, OUTPUT);
  pinMode(buttonDLeft, OUTPUT);

  pinMode(buttonL1, OUTPUT);
  pinMode(buttonL2, OUTPUT);
  pinMode(buttonSelect, OUTPUT);
  pinMode(buttonAnalog, OUTPUT);
  pinMode(buttonStart, OUTPUT);
  pinMode(buttonR1, OUTPUT);

  pinMode(buttonDUp, OUTPUT);
  pinMode(buttonDRight, OUTPUT);
  pinMode(buttonSquare, OUTPUT);
  pinMode(buttonR2, OUTPUT);
  pinMode(buttonTriangle, OUTPUT);
  pinMode(buttonCircle, OUTPUT);

  pinMode(buttonCross, OUTPUT);
  pinMode(buttonR3, OUTPUT);
  pinMode(buttonL3, OUTPUT);

  pinMode(leftMotor, INPUT);
  pinMode(rightMotor, INPUT);
  pinMode(analogLed, INPUT);

  digitalWrite(buttonSelect, HIGH);
  digitalWrite(buttonL3, HIGH);
  digitalWrite(buttonR3, HIGH);
  digitalWrite(buttonStart, HIGH);
  digitalWrite(buttonDUp, HIGH);
  digitalWrite(buttonDRight, HIGH);
  digitalWrite(buttonDDown, HIGH);
  digitalWrite(buttonDLeft, HIGH);

  digitalWrite(buttonL2, HIGH);
  digitalWrite(buttonR2, HIGH);
  digitalWrite(buttonL1, HIGH);
  digitalWrite(buttonR1, HIGH);
  digitalWrite(buttonTriangle, HIGH);
  digitalWrite(buttonCircle, HIGH);
  digitalWrite(buttonCross, HIGH);
  digitalWrite(buttonSquare, HIGH);

  analogWrite(axisRx, 128);
  analogWrite(axisRy, 128);
  analogWrite(axisLx, 128);
  analogWrite(axisLy, 128);

  digitalWrite(buttonAnalog, HIGH);

  //  Define Input pins for motors and analog LED
  pinMode(leftMotor, INPUT);
  pinMode(rightMotor, INPUT);
  pinMode(analogLed, INPUT);

  pinMode(attentionPin, INPUT);

  //  Prepare data to sent on startup as a way to tell the controller is in Neutral position
  //  That means, when all buttons and analog sticks are reset to their Neutral positions
  serial_rx_buffer_controller[0] = 0x01; //  Preamble
  serial_rx_buffer_controller[1] = 0x00; //  SELECT, L3, R3, START, DUP, DRIGHT, DDOWN, DLEFT
  serial_rx_buffer_controller[2] = 0x00; //  L2, R2, L1, R1, Triangle/Delta, Circle/O, Cross/X, Square
  serial_rx_buffer_controller[3] = 0x7F; //  RX
  serial_rx_buffer_controller[4] = 0x7F; //  RY
  serial_rx_buffer_controller[5] = 0x7F; //  LX
  serial_rx_buffer_controller[6] = 0x7F; //  LY
  serial_rx_buffer_controller[7] = 0x00; //  Analog button (Used to change between Digital and Analog modes in older games), Buffer Array Element 7  //  All other bits in this Buffer Array Element are unused
  serial_rx_buffer_controller[8] = 0x00; //  Unused
  serial_rx_buffer_controller[9] = 0x00; //  Delay Byte 2
  serial_rx_buffer_controller[10] = 0x00; // Delay Byte 1
  serial_rx_buffer_controller[11] = 0x01; // Postamble
  delay(5000); // Wait for the serial program on the computer to startup before sending any data
  //  Count bytes and parse ASCII values to their respective commands, such as buttons and axis
  for (serial_rx_buffer_counter = 0; serial_rx_buffer_counter < sizeof(serial_rx_buffer); serial_rx_buffer_counter++) {
    Serial.write(serial_rx_buffer_controller[serial_rx_buffer_counter]); //  This line writes the serial data back to the computer as a way to check if the Arduino isn't interpreting wrong values
    serial_rx_buffer_inverted_controller[serial_rx_buffer_counter] = (255 - serial_rx_buffer_controller[serial_rx_buffer_counter]); //  Invert 0 to 255 and vice versa to make it easier to determine which commands to enable or not, and their values
  }
  Serial.flush();
  //  Now we send PING to the computer as a way to tell we are connected and ready to receive and send data through the serial port
  //  This will be executed whenever the computer starts serial through the Processing Serial Library, which forces the Arduino to reset, due to DTR line (Data Terminal Ready)
  pingTimeOut = currentMillis;
  serial_rx_buffer_ping_out[8] = (byte)((pingTimeOut & 0xFF));
  serial_rx_buffer_ping_out[7] = (byte)((pingTimeOut >> 8) & 0xFF);
  serial_rx_buffer_ping_out[6] = (byte)((pingTimeOut >> 16) & 0xFF);
  serial_rx_buffer_ping_out[5] = (byte)((pingTimeOut >> 24) & 0xFF);
  sentPing = false;
  for (serial_rx_buffer_counter = 0; serial_rx_buffer_counter < sizeof(serial_rx_buffer_ping_out); serial_rx_buffer_counter++) {
    if (serial_rx_buffer_counter == 0) {
      Serial.write(0x03);
    }
    if ((serial_rx_buffer_counter == 1) || (serial_rx_buffer_counter == 2) || (serial_rx_buffer_counter == 3) || (serial_rx_buffer_counter == 4)) {
      Serial.write(0x00);
    }
    if ((serial_rx_buffer_counter == 5) || (serial_rx_buffer_counter == 6) || (serial_rx_buffer_counter == 7) || (serial_rx_buffer_counter == 8)) {
      Serial.write(serial_rx_buffer_ping_out[serial_rx_buffer_counter]);
    }
    if ((serial_rx_buffer_counter == 9) || (serial_rx_buffer_counter == 10)) {
      Serial.write(0x00);
    }
    if (serial_rx_buffer_counter == 11) {
      Serial.write(0x03);
    }
    sentPing = true;
  }
  sentPing = false;
  Serial.flush();
  sendPing();
  calculatePing();
  calculatePong();
  getAttention();
  readMotors();
  //Serial.println("END OF SETUP");
  //  And we are ready to go
}

void loop() {
  currentMillis = millis();
  //  Get data from Serial Port
  //  Preamble/Postamble = 0x01 for Controller Input // Does the Arduino have to respond with a different Preamble/Postamble value when it receives a valid Controller Input Data?
  //  Preamble/Postamble = Send 0x02 to Arduino for Motors and Analog Status
  //  Preamble/Postamble = Arduino responds with 0x06 for Motors and Analog Status, when Preamble/Postamble = 0x02
  //  Preamble/Postamble = 0x07 for Motors and Analog Status, when Attention Pin is LOW
  //  Preamble/Postamble = 0x08 for Motors and Analog Status, when Attention Pin is HIGH

  //  Preamble/Postamble = 0x03 for PING for BOTH ways
  //  PING/PONG System where PING is sent from the Arduino and PONG is sent from the Computer:
  //  Where ">>" is incoming data and "<<" is outgoing data
  //  << PING 3000  // This is data sent from the Arduino
  //  >> PONG 3000  // This is data the Arduino received

  //  Preamble/Postamble = 0x04 for PONG for BOTH ways
  //  PING/PONG System where PING is sent from the Computer and PONG is sent from the Arduino:
  //  Where ">>" is incoming data and "<<" is outgoing data
  //  >> PING 1487568769420  // This is data the Arduino received
  //  << PONG 1487568769420  // This is data sent from the Arduino

  //  NOTE: This is in no way supposed to represent actual communication, it's only a way to making visualizing data traffic more easily

  //  Preamble/Postamble = 0xA0 for Soft Reset the Arduino without resetting Variables
  //  Preamble/Postamble = 0xA1 for Command that tells the computer the Reset command 0xA0 was understood by the Arduino

  //  Preamble/Postamble = 0x09 for Disconnect
  //  Preamble/Postamble = 0x0A for Disconnect Understood
  //  Preamble/Postamble = 0x0B for Reconnect Successful
  //  Example:
  //  Arduino sends Disconnect to the computer in case of PING timeout (The Computer didn't respond with PONG in time)
  //  The computer then sends Disconnect Understood back to the Arduino, both close connections on their ends, then start connection again
  //  The Arduino then sends Reconnect Successful to tell the computer Connection is working as intended
  //  Or:
  //  Computer sends Disconnect to the Arduino in case of PING timeout (The Arduino didn't respond with PONG in time)
  //  The Arduino then sends Disconnect Understood back to the Computer, both close connections on their ends, then start connection again
  //  The Computer then sends Reconnect Successful to tell the Arduino Connection is working as intended
  if (Serial.available() > 0) {

    controller = Serial.readBytes(serial_rx_buffer, sizeof(serial_rx_buffer)) && 0xFF;

    //  Set Start Byte (Preamble Byte) and End Byte (Postamble Byte)
    //  1 == 0x01
    if ((serial_rx_buffer[0] == 0x01) && (serial_rx_buffer[11] == 0x01)) {

      //  Count bytes and parse ASCII values to their respective commands, such as buttons and axis
      for (serial_rx_buffer_counter = 0; serial_rx_buffer_counter < sizeof(serial_rx_buffer); serial_rx_buffer_counter++) {
        Serial.write(serial_rx_buffer[serial_rx_buffer_counter]); //  This line writes the serial data back to the computer as a way to check if the Arduino isn't interpreting wrong values
        //  Invert 0 to 255 and vice versa to make it easier to determine which commands to enable or not, and their values
        serial_rx_buffer_inverted[serial_rx_buffer_counter] = (255 - serial_rx_buffer[serial_rx_buffer_counter]);
        serial_rx_buffer_controller[serial_rx_buffer_counter] = serial_rx_buffer[serial_rx_buffer_counter];
        serial_rx_buffer_inverted_controller[serial_rx_buffer_counter] = (255 - serial_rx_buffer_controller[serial_rx_buffer_counter]);
      }
      //Serial.print('\n');
      Serial.flush();
      // Make the button presses actually work
      isInputting = true;
      previousInputDelay = currentMillis;
    }
    //  Get Motors and Analog status
    else if ((serial_rx_buffer[0] == 0x02) && (serial_rx_buffer[11] == 0x02)) {
      for (serial_rx_buffer_counter = 0; serial_rx_buffer_counter < sizeof(serial_rx_buffer); serial_rx_buffer_counter++) {
        Serial.write(serial_rx_buffer[serial_rx_buffer_counter]); //  This line writes the serial data back to the computer as a way to check if the Arduino isn't interpreting wrong values
        serial_rx_buffer_motor[serial_rx_buffer_counter] = serial_rx_buffer[serial_rx_buffer_counter];
      }
      readMotors();
    }
    //  Get PING/PONG status
    else if ((serial_rx_buffer[0] == 0x03) && (serial_rx_buffer[11] == 0x03)) {
      //  Get PING status
      for (serial_rx_buffer_counter = 0; serial_rx_buffer_counter < sizeof(serial_rx_buffer_ping_in); serial_rx_buffer_counter++) {
        //  Pass Serial Buffer to Ping Input Buffer
        serial_rx_buffer_ping_in[serial_rx_buffer_counter] = serial_rx_buffer[serial_rx_buffer_counter];
      }
      getPing();
    }
    else if ((serial_rx_buffer[0] == 0x04) && (serial_rx_buffer[11] == 0x04)) {
      //  Get PONG status
      for (serial_rx_buffer_counter = 0; serial_rx_buffer_counter < sizeof(serial_rx_buffer_pong_in); serial_rx_buffer_counter++) {
        //  Pass Serial Buffer to Pong Input Buffer
        serial_rx_buffer_pong_in[serial_rx_buffer_counter] = serial_rx_buffer[serial_rx_buffer_counter];
      }
      getPong();
    }
    else if ((serial_rx_buffer[0] == 0xA0) && (serial_rx_buffer[11] == 0xA0)) {
      // Reset Arduino without reseting Variables
      for (serial_rx_buffer_counter = 0; serial_rx_buffer_counter < sizeof(serial_rx_buffer_reset); serial_rx_buffer_counter++) {
        //  Pass Serial Buffer to Reset Buffer
        serial_rx_buffer_reset[serial_rx_buffer_counter] = serial_rx_buffer[serial_rx_buffer_counter];
      }
      arduinoReset();
    }
    else if ((serial_rx_buffer[0] == 0x09) && (serial_rx_buffer[11] == 0x09)) {
      // Reset Arduino without reseting Variables
      for (serial_rx_buffer_counter = 0; serial_rx_buffer_counter < sizeof(serial_rx_buffer_disconnect); serial_rx_buffer_counter++) {
        //  Pass Serial Buffer to Reset Buffer
        serial_rx_buffer_disconnect[serial_rx_buffer_counter] = serial_rx_buffer[serial_rx_buffer_counter];
      }
      arduinoDisconnect();
    }
  }
  pressButtons();
  sendPing();
  calculatePing();
  calculatePong();
  getAttention();
} // Close Loop Function

void arduinoDisconnect() {
  disconnectCalled = currentMillis;
  //Serial.println(disconnectCalled);
  //Serial.println("DISCONNECTING...");
  serial_rx_buffer_disconnect[0] = 0x0A;
  serial_rx_buffer_disconnect[11] = 0x0A;
  for (serial_rx_buffer_counter = 0; serial_rx_buffer_counter < sizeof(serial_rx_buffer_disconnect); serial_rx_buffer_counter++) {
    Serial.write(serial_rx_buffer_disconnect[serial_rx_buffer_counter]); //  This line writes the serial data back to the computer as a way to check if the Arduino isn't interpreting wrong values
  }
  Serial.flush();
  Serial.end();
  isConnected = false;
  disconnectDone = currentMillis;
  delay(5000); // Wait 5 seconds before reconnecting
  Serial.begin(baudRate);
  serial_rx_buffer_disconnect[0] = 0x0B;
  serial_rx_buffer_disconnect[11] = 0x0B;
  isConnected = true;
  for (serial_rx_buffer_counter = 0; serial_rx_buffer_counter < sizeof(serial_rx_buffer_disconnect); serial_rx_buffer_counter++) {
    Serial.write(serial_rx_buffer_disconnect[serial_rx_buffer_counter]); //  This line writes the serial data back to the computer as a way to check if the Arduino isn't interpreting wrong values
  }
  Serial.flush();
  //Serial.println("RECONNECTED!");
  //Serial.println(disconnectDone);
}

void arduinoReset() {
  resetCalled = currentMillis;
  serial_rx_buffer_reset[0] = 0xA1;
  serial_rx_buffer_reset[11] = 0xA1;
  for (serial_rx_buffer_counter = 0; serial_rx_buffer_counter < sizeof(serial_rx_buffer_reset); serial_rx_buffer_counter++) {
    Serial.write(serial_rx_buffer_reset[serial_rx_buffer_counter]); //  This line writes the serial data back to the computer as a way to check if the Arduino isn't interpreting wrong values
  }
  Serial.flush();
  asm volatile ("  jmp 0");
  resetDone = currentMillis;
  for (serial_rx_buffer_counter = 0; serial_rx_buffer_counter < sizeof(serial_rx_buffer_reset); serial_rx_buffer_counter++) {
    Serial.write(serial_rx_buffer_reset[serial_rx_buffer_counter]); //  This line writes the serial data back to the computer as a way to check if the Arduino isn't interpreting wrong values
  }
  Serial.flush();
  //  From here on, the setup() function will be called again, the computer then proceeds to reset its variables just like an usual startup routine
}

void pressButtons() {
  if (isInputtingDelayed == false) {
    //  Define input delay (If Buffer Array Element 9 and 10 !=0)
    inputDelay = (unsigned long)serial_rx_buffer[9] << 8 | (unsigned long)serial_rx_buffer[10];
  }
  if (isInputting == true)
  {
    for (serial_rx_buffer_counter = 0; serial_rx_buffer_counter < sizeof(serial_rx_buffer_controller); serial_rx_buffer_counter++) {
      Serial.write(serial_rx_buffer_controller[serial_rx_buffer_counter]); //  This line writes the serial data back to the computer as a way to check if the Arduino isn't interpreting wrong values
      //  Invert 0 to 255 and vice versa to make it easier to determine which commands to enable or not, and their values
      serial_rx_buffer_inverted_controller[serial_rx_buffer_counter] = (255 - serial_rx_buffer_controller[serial_rx_buffer_counter]);
    }
    //Serial.print('\n');<commit_msg>Fixed more typos<commit_after>#define axisLx 2
#define axisLy 3
#define axisRy 4
#define axisRx 5
#define buttonDDown 6
#define buttonDLeft 7

#define buttonL1 8
#define buttonL2 9
#define buttonSelect 10
#define buttonAnalog 11
#define buttonStart 12
#define buttonR1 13

#define buttonDUp 22
#define buttonDRight 23
#define buttonSquare 24
#define buttonR2 25
#define buttonTriangle 26
#define buttonCircle 27

#define buttonCross 28
#define buttonR3 29
#define buttonL3 30

#define leftMotor A0
#define rightMotor A1
#define analogLed A2

#define attentionPin A3

boolean isInputting = false;
boolean isInputtingDelayed = false;
boolean sentPing = false;
boolean sentPong = false;
boolean isConnected = false;

unsigned long inputDelay = 0;
unsigned long previousInputDelay = 0;
unsigned long currentMillis = 0;

unsigned long pingTimeOut = 0;
unsigned long pongTimeOut = 0;
unsigned long pingTimeIn = 0;
unsigned long pongTimeIn = 0;
unsigned long pingDelay = 1000;
unsigned long pongDelay = 1000;
unsigned long previousCalc = 0;
unsigned long calcDelay = 1000;
unsigned long previousPingDelay = 0;
unsigned long previousPongDelay = 0;
unsigned long lastPingIn = 0;
unsigned long lastPongIn = 0;
unsigned long lastPingOut = 0;
unsigned long lastPongOut = 0;
unsigned long calcPingTimestampIn = 0;
unsigned long calcPongTimestampIn = 0;
unsigned long calcPingTimestampOut = 0;
unsigned long calcPongTimestampOut = 0;

unsigned int leftMotorVal = 0;
unsigned int rightMotorVal = 0;
unsigned int analogLedVal = 0;

unsigned int attentionLevel = 0;
unsigned int previousAttentionLevel = 0;
unsigned long attentionLevelLow = 0;
unsigned long attentionLevelHigh = 0;
unsigned long previousAttentionLevelHigh = 0;
unsigned long previousAttentionLevelLow = 0;

unsigned int leftMotorLevel = 0;
unsigned int previousLeftMotorLevel = 0;
unsigned long leftMotorLevelLow = 0;
unsigned long leftMotorLevelHigh = 0;
unsigned long previousLeftMotorLevelHigh = 0;
unsigned long previousLeftMotorLevelLow = 0;

unsigned int rightMotorLevel = 0;
unsigned int previousRightMotorLevel = 0;
unsigned long rightMotorLevelLow = 0;
unsigned long rightMotorLevelHigh = 0;
unsigned long previousRightMotorLevelHigh = 0;
unsigned long previousRightMotorLevelLow = 0;

unsigned int analogLedLevel = 0;
unsigned int previousAnalogLedLevel = 0;
unsigned long analogLedLevelLow = 0;
unsigned long analogLedLevelHigh = 0;
unsigned long previousAnalogLedLevelHigh = 0;
unsigned long previousAnalogLedLevelLow = 0;

unsigned long resetCalled = 0;
unsigned long resetDone = 0;

unsigned long disconnectCalled = 0;
unsigned long disconnectDone = 0;

unsigned long baudRate = 115200;

byte serial_rx_buffer[12];
byte serial_rx_buffer_inverted[12];
byte serial_rx_buffer_controller[12];
byte serial_rx_buffer_ping_in[12];
byte serial_rx_buffer_ping_out[12];
byte serial_rx_buffer_pong_in[12];
byte serial_rx_buffer_pong_out[12];
byte serial_rx_buffer_motor[12];
byte serial_rx_buffer_reset[12];
byte serial_rx_buffer_disconnect[12];
byte serial_rx_buffer_inverted_controller[12];
unsigned long serial_rx_buffer_counter = 0;
unsigned long controller = 0;

//  The array below is an array of all buttons in the order the bytes have to be sent
unsigned int commandArray[] = {buttonSelect, buttonL3, buttonR3, buttonStart, buttonDUp, buttonDRight, buttonDDown, buttonDLeft, buttonL2, buttonR2, buttonL1, buttonR1, buttonTriangle, buttonCircle, buttonCross, buttonSquare, axisRx, axisRy, axisLx, axisLy, buttonAnalog};
unsigned int motorArray[] = {leftMotor, rightMotor, analogLed};

void setup() {
  currentMillis = millis();
  Serial.begin(baudRate);
  isConnected = true;
  //Serial.println("START OF SETUP");

  //  Define buttons and axis to neutral state on startup
  pinMode(axisLx, OUTPUT);
  pinMode(axisLy, OUTPUT);
  pinMode(axisRy, OUTPUT);
  pinMode(axisRx, OUTPUT);
  pinMode(buttonDDown, OUTPUT);
  pinMode(buttonDLeft, OUTPUT);

  pinMode(buttonL1, OUTPUT);
  pinMode(buttonL2, OUTPUT);
  pinMode(buttonSelect, OUTPUT);
  pinMode(buttonAnalog, OUTPUT);
  pinMode(buttonStart, OUTPUT);
  pinMode(buttonR1, OUTPUT);

  pinMode(buttonDUp, OUTPUT);
  pinMode(buttonDRight, OUTPUT);
  pinMode(buttonSquare, OUTPUT);
  pinMode(buttonR2, OUTPUT);
  pinMode(buttonTriangle, OUTPUT);
  pinMode(buttonCircle, OUTPUT);

  pinMode(buttonCross, OUTPUT);
  pinMode(buttonR3, OUTPUT);
  pinMode(buttonL3, OUTPUT);

  pinMode(leftMotor, INPUT);
  pinMode(rightMotor, INPUT);
  pinMode(analogLed, INPUT);

  digitalWrite(buttonSelect, HIGH);
  digitalWrite(buttonL3, HIGH);
  digitalWrite(buttonR3, HIGH);
  digitalWrite(buttonStart, HIGH);
  digitalWrite(buttonDUp, HIGH);
  digitalWrite(buttonDRight, HIGH);
  digitalWrite(buttonDDown, HIGH);
  digitalWrite(buttonDLeft, HIGH);

  digitalWrite(buttonL2, HIGH);
  digitalWrite(buttonR2, HIGH);
  digitalWrite(buttonL1, HIGH);
  digitalWrite(buttonR1, HIGH);
  digitalWrite(buttonTriangle, HIGH);
  digitalWrite(buttonCircle, HIGH);
  digitalWrite(buttonCross, HIGH);
  digitalWrite(buttonSquare, HIGH);

  analogWrite(axisRx, 128);
  analogWrite(axisRy, 128);
  analogWrite(axisLx, 128);
  analogWrite(axisLy, 128);

  digitalWrite(buttonAnalog, HIGH);

  //  Define Input pins for motors and analog LED
  pinMode(leftMotor, INPUT);
  pinMode(rightMotor, INPUT);
  pinMode(analogLed, INPUT);

  pinMode(attentionPin, INPUT);

  //  Prepare data to sent on startup as a way to tell the controller is in Neutral position
  //  That means, when all buttons and analog sticks are reset to their Neutral positions
  serial_rx_buffer_controller[0] = 0x01; //  Preamble
  serial_rx_buffer_controller[1] = 0x00; //  SELECT, L3, R3, START, DUP, DRIGHT, DDOWN, DLEFT
  serial_rx_buffer_controller[2] = 0x00; //  L2, R2, L1, R1, Triangle/Delta, Circle/O, Cross/X, Square
  serial_rx_buffer_controller[3] = 0x7F; //  RX
  serial_rx_buffer_controller[4] = 0x7F; //  RY
  serial_rx_buffer_controller[5] = 0x7F; //  LX
  serial_rx_buffer_controller[6] = 0x7F; //  LY
  serial_rx_buffer_controller[7] = 0x00; //  Analog button (Used to change between Digital and Analog modes in older games), Buffer Array Element 7  //  All other bits in this Buffer Array Element are unused
  serial_rx_buffer_controller[8] = 0x00; //  Unused
  serial_rx_buffer_controller[9] = 0x00; //  Delay Byte 2
  serial_rx_buffer_controller[10] = 0x00; // Delay Byte 1
  serial_rx_buffer_controller[11] = 0x01; // Postamble
  delay(5000); // Wait for the serial program on the computer to startup before sending any data
  //  Count bytes and parse ASCII values to their respective commands, such as buttons and axis
  for (serial_rx_buffer_counter = 0; serial_rx_buffer_counter < sizeof(serial_rx_buffer); serial_rx_buffer_counter++) {
    Serial.write(serial_rx_buffer_controller[serial_rx_buffer_counter]); //  This line writes the serial data back to the computer as a way to check if the Arduino isn't interpreting wrong values
    serial_rx_buffer_inverted_controller[serial_rx_buffer_counter] = (255 - serial_rx_buffer_controller[serial_rx_buffer_counter]); //  Invert 0 to 255 and vice versa to make it easier to determine which commands to enable or not, and their values
  }
  Serial.flush();
  //  Now we send PING to the computer as a way to tell we are connected and ready to receive and send data through the serial port
  //  This will be executed whenever the computer starts serial through the Processing Serial Library, which forces the Arduino to reset, due to DTR line (Data Terminal Ready)
  pingTimeOut = currentMillis;
  serial_rx_buffer_ping_out[8] = (byte)((pingTimeOut & 0xFF));
  serial_rx_buffer_ping_out[7] = (byte)((pingTimeOut >> 8) & 0xFF);
  serial_rx_buffer_ping_out[6] = (byte)((pingTimeOut >> 16) & 0xFF);
  serial_rx_buffer_ping_out[5] = (byte)((pingTimeOut >> 24) & 0xFF);
  sentPing = false;
  for (serial_rx_buffer_counter = 0; serial_rx_buffer_counter < sizeof(serial_rx_buffer_ping_out); serial_rx_buffer_counter++) {
    if (serial_rx_buffer_counter == 0) {
      Serial.write(0x03);
    }
    if ((serial_rx_buffer_counter == 1) || (serial_rx_buffer_counter == 2) || (serial_rx_buffer_counter == 3) || (serial_rx_buffer_counter == 4)) {
      Serial.write(0x00);
    }
    if ((serial_rx_buffer_counter == 5) || (serial_rx_buffer_counter == 6) || (serial_rx_buffer_counter == 7) || (serial_rx_buffer_counter == 8)) {
      Serial.write(serial_rx_buffer_ping_out[serial_rx_buffer_counter]);
    }
    if ((serial_rx_buffer_counter == 9) || (serial_rx_buffer_counter == 10)) {
      Serial.write(0x00);
    }
    if (serial_rx_buffer_counter == 11) {
      Serial.write(0x03);
    }
    sentPing = true;
  }
  sentPing = false;
  Serial.flush();
  sendPing();
  calculatePing();
  calculatePong();
  getAttention();
  readMotors();
  //Serial.println("END OF SETUP");
  //  And we are ready to go
}

void loop() {
  currentMillis = millis();
  //  Get data from Serial Port
  //  Preamble/Postamble = 0x01 for Controller Input // Does the Arduino have to respond with a different Preamble/Postamble value when it receives a valid Controller Input Data?
  //  Preamble/Postamble = Send 0x02 to Arduino for Motors and Analog Status
  //  Preamble/Postamble = Arduino responds with 0x06 for Motors and Analog Status, when Preamble/Postamble = 0x02
  //  Preamble/Postamble = 0x07 for Motors and Analog Status, when Attention Pin is LOW
  //  Preamble/Postamble = 0x08 for Motors and Analog Status, when Attention Pin is HIGH

  //  Preamble/Postamble = 0x03 for PING for BOTH ways
  //  PING/PONG System where PING is sent from the Arduino and PONG is sent from the Computer:
  //  Where ">>" is incoming data and "<<" is outgoing data
  //  << PING 3000  // This is data sent from the Arduino
  //  >> PONG 3000  // This is data the Arduino received

  //  Preamble/Postamble = 0x04 for PING for BOTH ways
  //  PING/PONG System where PING is sent from the Arduino and PONG is sent from the Computer:
  //  Where ">>" is incoming data and "<<" is outgoing data
  //  << PING 3000  // This is data sent from the Arduino
  //  >> PONG 3000  // This is data the Arduino received

  //  Preamble/Postamble = 0x05 for PONG for BOTH ways
  //  PING/PONG System where PING is sent from the Computer and PONG is sent from the Arduino:
  //  Where ">>" is incoming data and "<<" is outgoing data
  //  << PONG (0x04) 3000  // This is data sent from the Arduino
  //  >> PONG (0x05) 3000  // This is data the Arduino received

  //  NOTE: This is in no way supposed to represent actual communication, it's only a way to making visualizing data traffic more easily

  //  Preamble/Postamble = 0xA0 for Soft Reset the Arduino without resetting Variables
  //  Preamble/Postamble = 0xA1 for Command that tells the computer the Reset command 0xA0 was understood by the Arduino

  //  Preamble/Postamble = 0x09 for Disconnect
  //  Preamble/Postamble = 0x0A for Disconnect Understood
  //  Preamble/Postamble = 0x0B for Reconnect Successful
  //  Example:
  //  Arduino sends Disconnect to the computer in case of PING timeout (The Computer didn't respond with PONG in time)
  //  The computer then sends Disconnect Understood back to the Arduino, both close connections on their ends, then start connection again
  //  The Arduino then sends Reconnect Successful to tell the computer Connection is working as intended
  //  Or:
  //  Computer sends Disconnect to the Arduino in case of PING timeout (The Arduino didn't respond with PONG in time)
  //  The Arduino then sends Disconnect Understood back to the Computer, both close connections on their ends, then start connection again
  //  The Computer then sends Reconnect Successful to tell the Arduino Connection is working as intended
  if (Serial.available() > 0) {

    controller = Serial.readBytes(serial_rx_buffer, sizeof(serial_rx_buffer)) && 0xFF;

    //  Set Start Byte (Preamble Byte) and End Byte (Postamble Byte)
    //  1 == 0x01
    if ((serial_rx_buffer[0] == 0x01) && (serial_rx_buffer[11] == 0x01)) {

      //  Count bytes and parse ASCII values to their respective commands, such as buttons and axis
      for (serial_rx_buffer_counter = 0; serial_rx_buffer_counter < sizeof(serial_rx_buffer); serial_rx_buffer_counter++) {
        Serial.write(serial_rx_buffer[serial_rx_buffer_counter]); //  This line writes the serial data back to the computer as a way to check if the Arduino isn't interpreting wrong values
        //  Invert 0 to 255 and vice versa to make it easier to determine which commands to enable or not, and their values
        serial_rx_buffer_inverted[serial_rx_buffer_counter] = (255 - serial_rx_buffer[serial_rx_buffer_counter]);
        serial_rx_buffer_controller[serial_rx_buffer_counter] = serial_rx_buffer[serial_rx_buffer_counter];
        serial_rx_buffer_inverted_controller[serial_rx_buffer_counter] = (255 - serial_rx_buffer_controller[serial_rx_buffer_counter]);
      }
      //Serial.print('\n');
      Serial.flush();
      // Make the button presses actually work
      isInputting = true;
      previousInputDelay = currentMillis;
    }
    //  Get Motors and Analog status
    else if ((serial_rx_buffer[0] == 0x02) && (serial_rx_buffer[11] == 0x02)) {
      for (serial_rx_buffer_counter = 0; serial_rx_buffer_counter < sizeof(serial_rx_buffer); serial_rx_buffer_counter++) {
        Serial.write(serial_rx_buffer[serial_rx_buffer_counter]); //  This line writes the serial data back to the computer as a way to check if the Arduino isn't interpreting wrong values
        serial_rx_buffer_motor[serial_rx_buffer_counter] = serial_rx_buffer[serial_rx_buffer_counter];
      }
      readMotors();
    }
    //  Get PING/PONG status
    else if ((serial_rx_buffer[0] == 0x03) && (serial_rx_buffer[11] == 0x03)) {
      //  Get PING status
      for (serial_rx_buffer_counter = 0; serial_rx_buffer_counter < sizeof(serial_rx_buffer_ping_in); serial_rx_buffer_counter++) {
        //  Pass Serial Buffer to Ping Input Buffer
        serial_rx_buffer_ping_in[serial_rx_buffer_counter] = serial_rx_buffer[serial_rx_buffer_counter];
      }
      getPing();
    }
    else if ((serial_rx_buffer[0] == 0x04) && (serial_rx_buffer[11] == 0x04)) {
      //  Get PONG status
      for (serial_rx_buffer_counter = 0; serial_rx_buffer_counter < sizeof(serial_rx_buffer_pong_in); serial_rx_buffer_counter++) {
        //  Pass Serial Buffer to Pong Input Buffer
        serial_rx_buffer_pong_in[serial_rx_buffer_counter] = serial_rx_buffer[serial_rx_buffer_counter];
      }
      getPong();
    }
    else if ((serial_rx_buffer[0] == 0xA0) && (serial_rx_buffer[11] == 0xA0)) {
      // Reset Arduino without reseting Variables
      for (serial_rx_buffer_counter = 0; serial_rx_buffer_counter < sizeof(serial_rx_buffer_reset); serial_rx_buffer_counter++) {
        //  Pass Serial Buffer to Reset Buffer
        serial_rx_buffer_reset[serial_rx_buffer_counter] = serial_rx_buffer[serial_rx_buffer_counter];
      }
      arduinoReset();
    }
    else if ((serial_rx_buffer[0] == 0x09) && (serial_rx_buffer[11] == 0x09)) {
      // Reset Arduino without reseting Variables
      for (serial_rx_buffer_counter = 0; serial_rx_buffer_counter < sizeof(serial_rx_buffer_disconnect); serial_rx_buffer_counter++) {
        //  Pass Serial Buffer to Reset Buffer
        serial_rx_buffer_disconnect[serial_rx_buffer_counter] = serial_rx_buffer[serial_rx_buffer_counter];
      }
      arduinoDisconnect();
    }
  }
  pressButtons();
  sendPing();
  calculatePing();
  calculatePong();
  getAttention();
} // Close Loop Function

void arduinoDisconnect() {
  disconnectCalled = currentMillis;
  //Serial.println(disconnectCalled);
  //Serial.println("DISCONNECTING...");
  serial_rx_buffer_disconnect[0] = 0x0A;
  serial_rx_buffer_disconnect[11] = 0x0A;
  for (serial_rx_buffer_counter = 0; serial_rx_buffer_counter < sizeof(serial_rx_buffer_disconnect); serial_rx_buffer_counter++) {
    Serial.write(serial_rx_buffer_disconnect[serial_rx_buffer_counter]); //  This line writes the serial data back to the computer as a way to check if the Arduino isn't interpreting wrong values
  }
  Serial.flush();
  Serial.end();
  isConnected = false;
  disconnectDone = currentMillis;
  delay(5000); // Wait 5 seconds before reconnecting
  Serial.begin(baudRate);
  serial_rx_buffer_disconnect[0] = 0x0B;
  serial_rx_buffer_disconnect[11] = 0x0B;
  isConnected = true;
  for (serial_rx_buffer_counter = 0; serial_rx_buffer_counter < sizeof(serial_rx_buffer_disconnect); serial_rx_buffer_counter++) {
    Serial.write(serial_rx_buffer_disconnect[serial_rx_buffer_counter]); //  This line writes the serial data back to the computer as a way to check if the Arduino isn't interpreting wrong values
  }
  Serial.flush();
  //Serial.println("RECONNECTED!");
  //Serial.println(disconnectDone);
}

void arduinoReset() {
  resetCalled = currentMillis;
  serial_rx_buffer_reset[0] = 0xA1;
  serial_rx_buffer_reset[11] = 0xA1;
  for (serial_rx_buffer_counter = 0; serial_rx_buffer_counter < sizeof(serial_rx_buffer_reset); serial_rx_buffer_counter++) {
    Serial.write(serial_rx_buffer_reset[serial_rx_buffer_counter]); //  This line writes the serial data back to the computer as a way to check if the Arduino isn't interpreting wrong values
  }
  Serial.flush();
  delay(5000); // Wait 5 seconds before resetting
  asm volatile ("  jmp 0");
  resetDone = currentMillis;
  for (serial_rx_buffer_counter = 0; serial_rx_buffer_counter < sizeof(serial_rx_buffer_reset); serial_rx_buffer_counter++) {
    Serial.write(serial_rx_buffer_reset[serial_rx_buffer_counter]); //  This line writes the serial data back to the computer as a way to check if the Arduino isn't interpreting wrong values
  }
  Serial.flush();
  //  From here on, the setup() function will be called again, the computer then proceeds to reset its variables just like an usual startup routine
}

void pressButtons() {
  if (isInputtingDelayed == false) {
    //  Define input delay (If Buffer Array Element 9 and 10 !=0)
    inputDelay = (unsigned long)serial_rx_buffer[9] << 8 | (unsigned long)serial_rx_buffer[10];
  }
  if (isInputting == true)
  {
    for (serial_rx_buffer_counter = 0; serial_rx_buffer_counter < sizeof(serial_rx_buffer_controller); serial_rx_buffer_counter++) {
      Serial.write(serial_rx_buffer_controller[serial_rx_buffer_counter]); //  This line writes the serial data back to the computer as a way to check if the Arduino isn't interpreting wrong values
      //  Invert 0 to 255 and vice versa to make it easier to determine which commands to enable or not, and their values
      serial_rx_buffer_inverted_controller[serial_rx_buffer_counter] = (255 - serial_rx_buffer_controller[serial_rx_buffer_counter]);
    }
    //Serial.print('\n');
{'fraction_non_alphanumeric': 0.08609843678285051, 'fraction_numerical': 0.02516266637868193, 'mean_word_length': 4.563232201862421, 'pattern_counts': {'":': 0, '<': 53, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '952275', 'n_tokens_mistral': 12488, 'n_tokens_neox': 11559, 'n_words': 3487}