Sub_loops and delay() problem?

Hi there,
Could anyone please help me for an Arduino project that emulates Dualshock2 which will pass the PS2 Fortuna Project’s 2-X (cross), 2-O (circle) startup routine so that i could go directly to OpenPS2Launcher. No physical buttons needed, send commands digital. After OPL launched i can use Bluetooth PS3 controllers.
Thanks

Hi friends;
I managed to interface Playstation 2’s controller port with
MCranford’s DS2emulator code: GitHub - mcranford13/Ps2ControllerEmulator: Ps2 Controller Emulator for Arduino
by adding hex codes of cross and circle buttons.
I add sub_loops to code
However i couldnt add delays between loops.
Any help would be greatful.

data.response[3] = ~0x40; hex code for cross button X
data.response[3] = ~0x20; hex code for circle button O

The code looks like this:

#include <SPI.h>

#define ackPin 9
#define triPin 7
#define sqPin 6
#define oPin 5
#define exPin 4


/*
  General Process

  1. Set up MCU as slave - check
  2. Set up MCU for interrupts, letting the ps2 handle SS and clock rate - check
  3. Collect data regarding the controller state
  4. When an interrupt occurs, transfer this data to the Ps2, byte by byte
  
  
  Transfer Data Process:
  
  1. Have 1 array (data.response) that can hold all the needed data to transfer.
  2. For each command we recieve from the ps2, we set up the array for the needed information and the needed response length
  3. Transfer it one byte at time. (NOTE: One byte per interrupt)
  4. Except for a few special cases, we don't have to worry about another command from the ps2 until the transfer is complete.
  5. Reset our index for the next transfer.

*/

struct DATA { //Main data structure

  byte response[20];

  volatile size_t count;
  volatile size_t sendAck;
  size_t responseLength;


  bool configState;
  bool aboutToConfig;
  bool aboutToSwitchBetweenAnalogDigital;
  bool secondPass;
  bool modeLocked;
  bool isDigital;
  bool isAnalog;
  bool ssState;
  bool oldSsState;
  bool FourcSecondPass;
  bool aboutToSetMotorStates;
  bool smallMotorOn;

  long lastChange;

} data = {{0x41, 0x5A}, 0, 0, 5, false, false, false, false, false, true, false, false, false, false, false, false, 0};



void SlaveInit(void) {

  /*
     This function sets up the arduino in the correct configureation to communicate with the PS2.
  */

  pinMode(MOSI, INPUT);  //pin 11
  pinMode(MISO, OUTPUT); //pin 12
  pinMode(SCK, INPUT);   //pin 13
  pinMode(SS, INPUT);    //pin 10

  SPCR |= bit (SPE); //Init as slave
  SPCR |= 0x2C;      //Configure for LSB & correct SPI_Mode

  pinMode(ackPin, OUTPUT);
  digitalWrite(ackPin, LOW); //Because of external circuitry (open drain) need to flip this so it works appropriately

  pinMode(triPin, INPUT_PULLUP);
  pinMode(sqPin, INPUT_PULLUP);
  pinMode(oPin, INPUT_PULLUP);
  pinMode(exPin, INPUT_PULLUP);

  SPCR |= _BV(SPIE); //Attach Interrupts

}

void setup() {

  SlaveInit();



}


/*
   This function reads the states of the pins and returns the correct byte describing the state of the controller
*/
byte getControllerStateFirstByte() {
  byte data = 0xFF; //Buttons are ative low

  byte pinState = PIND; //digitalRead() is too slow, we need to read the pins directly from the register

  
  //The following are examples of reading the pins and correctly setting up the data to be transferred.
  
/*
  if (!(pinState & 0b00001000)) {

    data &= ~0x10; // up
  }

  
    if (!(pinState & 00000010)) {


    data &= ~0x40; //down
    }
  */
  
  return data;
}

byte getControllerStateSecondByte() {
  /*
     This function reads the states of the pins and
     sets up the byte describing the state of the controller appropriately
  */
  byte pinState = PIND;

  byte data = 0xFF;
  
  //The following are examples of reading the pins and correctly setting up the data to be transferred.

  /*
  if (!(pinState & 0b10000000)) {

    data &= ~0x10; //triangle
  }

  if (!(pinState & 0b01000000)) {

    data &= ~0x40; // X
  }


  if (!(pinState & 0b00100000)) {

    data &= ~0x20; // O
  }

  if (!(pinState & 0b00010000)) {

    data &= ~0x80; //Square
    
  }


  */

  return data; //Buttons are active low in the bus, so we invert all the bits
}



// SPI interrupt routine
ISR (SPI_STC_vect) {


  //By the time we reach this routine, we have already transferred the first byte i.e CMD: 0x01, Data: 0xFF, aka the first byte of the header has already been sent
  byte cmd = SPDR; //Read incomming command from ps2

  switch (cmd) { //Main logic handling of the cmds of the ps2

    //See http://store.curiousinventor.com/guides/PS2/ for more information about these commands.

    case 0x41:

      data.responseLength = 9;

      if (data.configState && data.isAnalog) {

        data.response[0] = 0x79;
        data.response[1] = 0x5a;
        data.response[2] = 0x00;
        data.response[3] = 0x00;
        data.response[4] = 0x03;
        data.response[5] = 0x00;
        data.response[6] = 0x00;
        data.response[7] = 0x5A; //last byte is always 0x5A

      } else if (data.configState && data.isDigital) {

        data.response[0] = 0x41;
        data.response[1] = 0x5A;
        data.response[2] = 0xFF;
        data.response[3] = 0xFF;
        data.response[4] = 0x00;
        data.response[5] = 0x00;
        data.response[6] = 0x00;
        data.response[7] = 0x5A; //last byte is always 0x5A

      }
      break;


    case 0x42:


      if (data.isDigital) {

        data.responseLength = 5;

        data.response[0] = 0x41;

      }

      else if (data.isAnalog) {

        data.responseLength = 9;

        data.response[0] = 0x79;
        data.response[4] = 0x7F;
        data.response[5] = 0x7F;
        data.response[6] = 0x7F;
        data.response[7] = 0x7F;
        data.response[8] = 0x7F;

      }

      /*
         TODO: handle rumble here
      */
      data.response[1] = 0x5A;
      data.response[2] = getControllerStateFirstByte();
      data.response[3] = getControllerStateSecondByte(); //This is the 5th byte

      break;

    case 0x43: // enter/exit config mode

      data.aboutToConfig = true;
      data.responseLength = 9;

      if (data.isDigital) {
        data.responseLength = 5;
        data.response[0] = 0x41;

      }

      else if (data.isAnalog) {


        data.response[0] = 0x79; //analog mode

        if (!(data.configState)) {
          data.response[4] = 0x7F; //analog sticks
          data.response[5] = 0x7F;
          data.response[6] = 0x7F;
          data.response[7] = 0x7F;
        }
      }

      if (!(data.configState)) {
        data.response[2] = getControllerStateFirstByte();
        data.response[3] = getControllerStateSecondByte();

        //No vibration motor control necessary
      }

      break;


    case 0x44:

      data.responseLength = 9;

      if (data.configState) { //Only works if we are in config mode

        data.aboutToSwitchBetweenAnalogDigital = true;
        data.response[0] = 0xF3; //Stating that we are indeed in config mode
        data.response[1] = 0x5A;


      }

      break;


    case 0x45:

      data.responseLength = 9;

      // if (data.configState) { //For some reason this causes glitches though all documentation says we should be in config mode

      data.response[0] = 0xF3;
      data.response[1] = 0x5A;
      data.response[2] = 0x03;
      data.response[3] = 0x02;
      data.response[4] = 0x00; //0x01 if LED is on, possibly a way to switch between analog & digtial?
      data.response[5] = 0x02;
      data.response[6] = 0x01;
      data.response[7] = 0x00;
      // }

      break;

    case 0x46:

      data.responseLength = 9;

      if (data.configState && data.secondPass == false) { //Only works if we are in config mode

        data.response[0] = 0xF3;
        data.response[1] = 0x5A;
        data.response[3] = 0x00;
        data.response[4] = 0x00;
        data.response[5] = 0x02;
        data.response[6] = 0x00;
        data.response[7] = 0x0A;

        data.secondPass = true;

      }

      break;

    case 0x47:

      data.responseLength = 9;

      if (data.configState) {

        data.response[0] = 0xF3;
        data.response[1] = 0x5A;
        data.response[3] = 0x00;
        data.response[4] = 0x02;
        data.response[5] = 0x00;
        data.response[6] = 0x00;
        data.response[7] = 0x0A;
      }

      break;


    case 0x4C:

      data.responseLength = 9;

      if (data.configState && data.FourcSecondPass == false) {

        data.response[0] = 0xF3;
        data.response[1] = 0x5A;
        data.response[2] = 0x00;
        data.response[3] = 0x00;
        data.response[4] = 0x00;
        data.response[5] = 0x04;
        data.response[6] = 0x00;
        data.response[7] = 0x00;

        data.FourcSecondPass = true;

      }

      break;

    case 0x4D:

      //Not implemented

      break;

    case 0x4F:

      //Not implemented

      break;


    case 0x00: //Special commands after recieving a specific command

      if (data.count == 2) { //This jumps over the end of the header where the cmd would be 0x00
        
        if (data.aboutToConfig) {
          
          data.configState = false;
          data.response[0] = 0x41;
          data.aboutToConfig = false;
          
        }


        else if (data.aboutToSwitchBetweenAnalogDigital && data.modeLocked == false) {

          data.isDigital = true;
          data.isAnalog = false;
          data.response[0] = 0x41;

          data.aboutToSwitchBetweenAnalogDigital = false;
        }

        else if (data.aboutToSetMotorStates) {

          data.smallMotorOn = true;

        }

      }

      break;

    case 0x01: //Special commands after recieving a specific command

      if (data.count == 2) { //this jumps over the header where cmd would be 0x01, may not need this

        if (data.aboutToConfig) {

          data.configState = true;
          data.response[0] = 0xF3;
          data.aboutToConfig = false;

        }


        else if (data.aboutToSwitchBetweenAnalogDigital && data.modeLocked == false) {

          data.isDigital = false;
          data.isAnalog = true;

          data.response[0] = 0xF3;

          data.aboutToSwitchBetweenAnalogDigital = false;

        }

        else if (data.configState && data.secondPass) { //Only works if we are in config mode

          data.response[0] = 0xF3;
          data.response[1] = 0x5A;
          data.response[3] = 0x00;
          data.response[4] = 0x00;
          data.response[5] = 0x00;
          data.response[6] = 0x00;
          data.response[7] = 0x14;

        }
        else if (data.configState && data.FourcSecondPass) { //Only works if we are in config mode

          data.response[0] = 0xF3;
          data.response[1] = 0x5A;
          data.response[3] = 0x00;
          data.response[4] = 0x00;
          data.response[5] = 0x06;
          data.response[6] = 0x00;
          data.response[7] = 0x00;

        }
      }

      break;

    case 0x03: //Lock Analog/Digital

      data.modeLocked = true;
      data.response[4] = 0x00;
      data.response[5] = 0x00;
      data.response[6] = 0x00;
      data.response[7] = 0x00;

      data.aboutToSwitchBetweenAnalogDigital = false;

      break;


  }// end switch


  SPDR = data.response[data.count]; //Put the data into the registers to be transferred during this interuupt


  if (data.count < (data.responseLength - 1)) { //only increase our counter until we are at the end of the needed response

    data.count++;
  }

  data.sendAck = 1;

}

void loop() {
   sub_loop1();
   sub_loop2();
   sub_loop3();
   sub_loop4();
}
void sub_loop1() {
    data.response[3] = ~0x40; 
  //Send ack after each bit transfer
        if (data.sendAck) {

    digitalWrite(ackPin, HIGH); //Again in opposite configuration due to external open drain circuitry
    delayMicroseconds(4);
    digitalWrite(ackPin, LOW);
    data.sendAck = 0;
  }

  //Debouce the SS line

  /*
     We debounce this line so that our count is reset appropriately when we aren't communicating
  */
  data.ssState = digitalRead(SS);

  if (data.ssState == HIGH) { //Reset where we are when we aren't communicating

    if (millis() - data.lastChange > 10) { //State is valid
      data.count = 0;
      data.responseLength = 0;


    }
  }
  if (data.ssState != data.oldSsState) {

    data.lastChange = millis();
  }

  data.oldSsState = data.ssState;

} //end loop()

void sub_loop2() {
  data.response[3] = ~0x40; 
  //Send ack after each bit transfer
  if (data.sendAck) {

    digitalWrite(ackPin, HIGH); //Again in opposite configuration due to external open drain circuitry
    delayMicroseconds(4);
    digitalWrite(ackPin, LOW);
    data.sendAck = 0;
  }

  //Debouce the SS line

  /*
     We debounce this line so that our count is reset appropriately when we aren't communicating
  */
  data.ssState = digitalRead(SS);

  if (data.ssState == HIGH) { //Reset where we are when we aren't communicating

    if (millis() - data.lastChange > 10) { //State is valid
      data.count = 0;
      data.responseLength = 0;


    }
  }
  if (data.ssState != data.oldSsState) {

    data.lastChange = millis();
  }

  data.oldSsState = data.ssState;
 //end loop()

}
void sub_loop3() {
    data.response[3] = ~0x20; 
  //Send ack after each bit transfer
        if (data.sendAck) {

    digitalWrite(ackPin, HIGH); //Again in opposite configuration due to external open drain circuitry
    delayMicroseconds(4);
    digitalWrite(ackPin, LOW);
    data.sendAck = 0;
  }

  //Debouce the SS line

  /*
     We debounce this line so that our count is reset appropriately when we aren't communicating
  */
  data.ssState = digitalRead(SS);

  if (data.ssState == HIGH) { //Reset where we are when we aren't communicating

    if (millis() - data.lastChange > 10) { //State is valid
      data.count = 0;
      data.responseLength = 0;


    }
  }
  if (data.ssState != data.oldSsState) {

    data.lastChange = millis();
  }

  data.oldSsState = data.ssState;

} //end loop()

void sub_loop4() {
  data.response[3] = ~0x20; 
  //Send ack after each bit transfer
  if (data.sendAck) {

    digitalWrite(ackPin, HIGH); //Again in opposite configuration due to external open drain circuitry
    delayMicroseconds(4);
    digitalWrite(ackPin, LOW);
    data.sendAck = 0;
  }

  //Debouce the SS line

  /*
     We debounce this line so that our count is reset appropriately when we aren't communicating
  */
  data.ssState = digitalRead(SS);

  if (data.ssState == HIGH) { //Reset where we are when we aren't communicating

    if (millis() - data.lastChange > 10) { //State is valid
      data.count = 0;
      data.responseLength = 0;


    }
  }
  if (data.ssState != data.oldSsState) {

    data.lastChange = millis();
  }

  data.oldSsState = data.ssState;
 //end loop()

}

Sorry for my English, not native speaker.

Blok-alıntı

Up please