Adding programmability to PS360+ controller

This was my first project, and I've been at it for about 4 years now. It started from humble beginnings, and now has pretty much all the features that I wanted it to have.

I have no computing/electronics background, so all of this has been learnt from the ground up. Hence, the code is pretty simplistic.

In the playstation days, though rare, it was possible to buy joystick and gamepads that could be programmed. Obviously these could be used for cheating, but for the interested, they allowed us to take games apart and investigate the core of how things work.

While these can still be used (via converters) they're getting old, rare and increasingly hard to find.

I took up the challenge of replicating what they allowed, as well as adding a lot of new features.

The setup is an arduino mega, a 4x20 lcd screen, and a control pad of sorts (up, down, left, right and two buttons). It also has a swtich to determine how many controllers you're using (first, second or both). It has an SD card for backing up sequence (very rudimentary, just added).

I have it set up so that it sends wires from pins on the side of the arduino 21-49 to a PS360+ board, bought at aki-shop customs. I have successfully piggybacked it onto a number of different joysticks.

On the software side, you are able to input commands to be played back at 60fps. You can also record commands by using a joystick normally.

You can do all the editing onboard, via the LCD screen and control pad. There is also functionality to loop commands.

Anyway, posting this here more as a reference for anyone else wanting to try something similar. I've got a few ideas left, but for now it seems to work very well.

#include <LiquidCrystal.h>
#include <SD.h>   
LiquidCrystal lcd(60,59,58,57,56,55,54);

int controller_used=1;
int pins[] = {69,68, 64,67,65,66, 61,62,63};//AB LUDR
 
 char* myTXTs[]={"log0.txt", "log1.txt", "log2.txt", "log3.txt"};
 
 int p1[] = {38,39,40,41,45,46,20,21}; 
 int p3[] = {47,19,48,18,44,42,43,44};
 int p2[] = {22,23,24,25,29,30,34,35};
 int p4[] = {31,36,32,37,28,26,27,28};
  
 int invert_controls=0;
 int P1=0;
 int P2=0;
int tempread;
 int cs_pin=53;
 int button=0; int last_button;
 byte record[4][1200]; 
 int loop_frame=148; int loop_number=3; int repetition=0;
 unsigned long time1; unsigned long time2; unsigned long time3; unsigned long time4;
 unsigned long time5;
 int lag=0;
 int mode = -1;
 int current_slot = 0; int cursor_position = 0;
 int pressed=0; int unpressed=1; int all_unpressed=255;int all_pressed=0;
 int F=16656; int frame_count=0;
 int n;int i;





void setup() {
lcd.begin(20,4);
 Serial.begin(115200);
 pinMode(cs_pin,OUTPUT);
 if(!SD.begin(cs_pin))
 {lcd.setCursor(10,3);lcd.print("error");}
  for(n=0;n<9;n++)
  {pinMode(pins[n],INPUT); digitalWrite(pins[n],HIGH);}
    
 for(n=0;n<8;n++)
  {pinMode(p1[n],OUTPUT);pinMode(p2[n],OUTPUT);
   pinMode(p3[n],OUTPUT);pinMode(p4[n],OUTPUT);
   digitalWrite(p1[n],unpressed); digitalWrite(p2[n],unpressed);
   digitalWrite(p3[n],unpressed);digitalWrite(p4[n],unpressed);} 
   
 
 for(n=0;n<1200;n++){record[0][n]=all_unpressed; record[1][n]=all_unpressed;
                    record[2][n]=all_unpressed; record[3][n]=all_unpressed;}
}

void dispP1(){
   for(n=0;n<8;n++){lcd.setCursor(n,1);lcd.print(bitRead(record[0][current_slot],n));
                    lcd.setCursor(n+8,1);lcd.print(bitRead(record[2][current_slot],n));}}
void dispP2(){
   for(n=0;n<8;n++){lcd.setCursor(n,2);lcd.print(bitRead(record[1][current_slot],n));
                    lcd.setCursor(n+8,2);lcd.print(bitRead(record[3][current_slot],n));}}

void saveSD (int x,  int y) {
  SD.remove(myTXTs[x]);
    File datafile = SD.open(myTXTs[x],FILE_WRITE);
     if(datafile){
      for(i=0;i<1200;i++){for(n=0;n<8;n++){
       datafile.print(bitRead(record[y][i],n));}}
       datafile.close();}}

void loadSD (int x, int y)    
 {File readfile = SD.open(myTXTs[x]);
 if (readfile){while(readfile.available())
  {for(i=0;i<1200;i++){
  for (n=0;n<8;n++){
   tempread=readfile.read();
  if(tempread=='0'){bitWrite(record[y][i],n,0);}
  if(tempread=='1'){bitWrite(record[y][i],n,1);}
}}}}
 readfile.close();}

void loop() {
  time2=micros();
  if((time2)>(time1+F)) {
    //lcd.setCursor(7,3);lcd.print(time2-time1);
    time1=micros();
       
  if(mode==1) {time4=micros();
    if(P1==1){for(n=0;n<8;n++)
     {digitalWrite(p1[n],(bitRead(record[0][frame_count],n)));
      digitalWrite(p3[n],(bitRead(record[2][frame_count],n)));}}
    if(P2==1){for(n=0;n<8;n++)
     {digitalWrite(p2[n],(bitRead(record[1][frame_count],n)));
      digitalWrite(p4[n],(bitRead(record[3][frame_count],n)));}}
      if((frame_count==loop_frame) && (repetition>0))
     {repetition--;frame_count=-1;}
    
    if(frame_count>1199){for(n=0;n<8;n++)
     {digitalWrite(p1[n],unpressed); digitalWrite(p2[n],unpressed);
      digitalWrite(p3[n],unpressed); digitalWrite(p4[n],unpressed);}
    time3=micros();time5=time3-time4;mode=-1;} 
     } 


   if(mode==2) {
     if(P1==1){for(n=0;n<8;n++){bitWrite(record[0][frame_count],n,digitalRead(p1[n]));
                                  bitWrite(record[2][frame_count],n,digitalRead(p3[n]));}}
     if(P2==1){for(n=0;n<8;n++){bitWrite(record[1][frame_count],n,digitalRead(p2[n]));
                                 bitWrite(record[3][frame_count],n,digitalRead(p4[n]));}}
 if(frame_count==0){
   if((P1==1) && (P2==0) && (record[0][0]==all_unpressed) && (record[2][0]==all_unpressed)){frame_count=-1;} 
   if((P1==0) && (P2==1) && (record[1][0]==all_unpressed) && (record[3][0]==all_unpressed)){frame_count=-1;} 
   if((P1==1) && (P2==1) && (record[0][0]==all_unpressed) && (record[2][0]==all_unpressed) && 
       (record[1][0]==all_unpressed) && (record[3][0]==all_unpressed)){frame_count=-1;} 
   }
  if(frame_count>1199){mode=-1;}
}


  if(mode==0){
     if(P1==1){for(n=0;n<8;n++){bitWrite(record[0][current_slot],n,digitalRead(p1[n]));
                                bitWrite(record[2][current_slot],n,digitalRead(p3[n]));}}
     if(P2==1){for(n=0;n<8;n++){bitWrite(record[1][current_slot],n,digitalRead(p2[n]));
                               bitWrite(record[3][current_slot],n,digitalRead(p4[n]));}}

     dispP2();dispP1();  
                     
     current_slot++;delay(300);
      
     dispP2();
     dispP1(); 
      mode=-1;}


  if (digitalRead(pins[6])==1){P1=0;}
    if (digitalRead(pins[8])==1){P2=0;}
    if (digitalRead(pins[6])==0){P1=1;}
    if (digitalRead(pins[8])==0){P2=1;}
    if(digitalRead(pins[7])==0 && digitalRead(pins[6])==1 && digitalRead(pins[8])==1){P1=1;P2=1;}

   button=0; 
   if(digitalRead(pins[0])==0){button=5;}
   if(digitalRead(pins[1])==0){button=7;}
   if(digitalRead(pins[2])==0){button=4;}
   if(digitalRead(pins[3])==0){button=8;}
   if(digitalRead(pins[4])==0){button=2;}
   if(digitalRead(pins[5])==0){button=6;}
  if (button==4){
    mode=-1;for(n=0;n<8;n++)
     {digitalWrite(p1[n],unpressed); digitalWrite(p2[n],unpressed);
      digitalWrite(p3[n],unpressed); digitalWrite(p4[n],unpressed);}
    if ((cursor_position>0) && (last_button==0)){cursor_position--;}
    
  }
 

  
  if (button==6){
    mode=-1;
    for(n=0;n<8;n++)
     {digitalWrite(p1[n],unpressed); digitalWrite(p2[n],unpressed);
      digitalWrite(p3[n],unpressed); digitalWrite(p4[n],unpressed);}



    
   if((cursor_position <19) && (last_button==0)){cursor_position++;}}


  if(button==8){
    if((cursor_position==0) && (last_button==0) && (current_slot<1199)){
          current_slot++;mode=-1;
      dispP2();dispP1();    
        }
   
   if((cursor_position==1) && (current_slot<1199)){
     delay(25);           current_slot++;mode=-1;
          dispP2();dispP1(); 
        }
   
   if((cursor_position==2) && (current_slot<1199)){
          delay(5);
          current_slot++;mode=-1;
         // dispP2();dispP1(); 
        }
   
   if((cursor_position==3) && (last_button==0) && (current_slot<1199)){
     if(P1==1) {record[0][current_slot+1]=record[0][current_slot]; record[0][current_slot]=all_unpressed;
                record[2][current_slot+1]=record[2][current_slot]; record[2][current_slot]=all_unpressed;}
     if(P2==1) {record[1][current_slot+1]=record[1][current_slot]; record[1][current_slot]=all_unpressed;
                record[3][current_slot+1]=record[3][current_slot]; record[3][current_slot]=all_unpressed;}
                  current_slot++;mode=-1;
     dispP2();dispP1();}
   
   if((cursor_position==4) && (last_button==0) && (current_slot<1199)){             
     if(P1==1) {record[0][current_slot+1]=record[0][current_slot];
                 record[2][current_slot+1]=record[2][current_slot];}     
     if(P2==1)  {record[1][current_slot+1]=record[1][current_slot];
                 record[3][current_slot+1]=record[3][current_slot];}
                 current_slot++;mode=-1;
      dispP2();dispP1(); }
   
   if((cursor_position==5) && (last_button==0) && (current_slot<1199)){
     if(P1==1){for(n=1198;n>(current_slot-1);n--){record[0][n+1]=record[0][n];record[2][n+1]=record[2][n];}
                                          record[0][current_slot]=all_unpressed;record[2][current_slot]=all_unpressed;}
     if(P2==1){for(n=1198;n>(current_slot-1);n--){record[1][n+1]=record[1][n];record[3][n+1]=record[3][n];}
                                          record[1][current_slot]=all_unpressed;record[3][current_slot]=all_unpressed;}
      current_slot++;mode=-1;
      dispP2();dispP1();}
  
  if((cursor_position==6) && (last_button==0)){
  if(P1==1){for(n=1198;n>-1;n--){record[0][n+1]=record[0][n];record[2][n+1]=record[2][n];}
                                          record[0][0]=all_unpressed;record[2][0]=all_unpressed;}
     if(P2==1){for(n=1198;n>-1;n--){record[1][n+1]=record[1][n];record[3][n+1]=record[3][n];}
                                          record[1][0]=all_unpressed;record[3][0]=all_unpressed;}
      current_slot++;mode=-1;
      dispP2();dispP1();}
  
    if(cursor_position==16){F++;}

    if((cursor_position==7) && (loop_frame<1199))
      {delay(50);loop_frame++;}                   
 
    if((cursor_position==8) && (loop_number<40) && (last_button==0))
      {loop_number++;}
     
    if(cursor_position==9){
      unpressed=1;pressed=0;all_unpressed=255;
      for(n=0;n<8;n++){
       digitalWrite(p1[n],unpressed); digitalWrite(p2[n],unpressed);
       digitalWrite(p3[n],unpressed); digitalWrite(p4[n],unpressed);} 

      for(n=0;n<1200;n++){record[0][n]=all_unpressed; record[1][n]=all_unpressed;
                         record[2][n]=all_unpressed;record[3][n]=all_unpressed;}}  
  
  }

                  
  if ((button==2)){
    if ((cursor_position==0) && (last_button==0) && (current_slot>0)){
     current_slot--;mode=-1;
     dispP2();dispP1();}

    if ((cursor_position==1) && (current_slot>0)){
     delay(25); current_slot--;mode=-1;
     dispP2();dispP1();}

    if ((cursor_position==2) && (current_slot>0)){
     delay(5); current_slot--;mode=-1;
     //dispP2();dispP1();
   }    
    
    if ((cursor_position==3) && (current_slot>0) && (last_button==0)){
      if(P1==1) {record[0][current_slot-1]=record[0][current_slot]; record[0][current_slot]=all_unpressed;
                 record[2][current_slot-1]=record[2][current_slot]; record[2][current_slot]=all_unpressed;}
      if(P2==1)  {record[1][current_slot-1]=record[1][current_slot]; record[1][current_slot]=all_unpressed;
                  record[3][current_slot-1]=record[3][current_slot]; record[3][current_slot]=all_unpressed;}
            current_slot--;mode=-1;
     dispP2();
     dispP1();}
    
    if ((cursor_position==4) && (current_slot>0) && (last_button==0)){ 
      if (P1==1) {record[0][current_slot-1]=record[0][current_slot];
                                          record[2][current_slot-1]=record[2][current_slot];}
      if (P2==1) {record[1][current_slot-1]=record[1][current_slot];
                                          record[3][current_slot-1]=record[3][current_slot];}
     current_slot--;mode=-1;
     dispP2();
     dispP1();}
  
  if ((cursor_position==5) && (current_slot>0) && (last_button==0)){
    if (P1==1) {for(n=current_slot;n<1199;n++){record[0][n-1]=record[0][n];record[2][n-1]=record[2][n];}
      record[0][1199]=all_unpressed;record[2][1199]=all_unpressed;}
    if (P2==1) {for(n=current_slot;n<1199;n++){record[1][n-1]=record[1][n];record[3][n-1]=record[3][n];}
      record[1][1199]=all_unpressed;record[3][1199]=all_unpressed;}
     current_slot--;mode=-1;
     dispP2();
     dispP1();  
 }    
                  
                
                
  if((cursor_position==6)&& (current_slot>0) && (last_button==0)){
                if (P1==1) {for(n=1;n<1199;n++){record[0][n-1]=record[0][n];record[2][n-1]=record[2][n];}
      record[0][1199]=all_unpressed;record[2][1199]=all_unpressed;}
    if (P2==1) {for(n=1;n<1199;n++){record[1][n-1]=record[1][n];record[3][n-1]=record[3][n];}
      record[1][1199]=all_unpressed;record[3][1199]=all_unpressed;}
     current_slot--;mode=-1;
     dispP2();
     dispP1(); }
                
                
  if(cursor_position==16){F--;}
  
  if((cursor_position==7) && (loop_frame>0))
     {delay(50);loop_frame--;}
  
  if((cursor_position==8) && (loop_number>0) && (last_button==0))
    {loop_number--;}

  if(cursor_position==9){
      unpressed=0;pressed=1;all_unpressed=0;
      for(n=0;n<8;n++){
       digitalWrite(p1[n],unpressed); digitalWrite(p2[n],unpressed);
       digitalWrite(p3[n],unpressed); digitalWrite(p4[n],unpressed);} 

      for(n=0;n<1200;n++){record[0][n]=all_unpressed; record[1][n]=all_unpressed;
                         record[2][n]=all_unpressed; record[3][n]=all_unpressed;}}

  }

  if(button==5){
    if((cursor_position==0) && (last_button==0))
      {mode=0;}
    
    if((cursor_position==1) && (last_button==0))
      {repetition=0;frame_count=-1;mode=1;}
    
    if((cursor_position==2) && (last_button==0)){
        if(P1==1)
          {for(n=0;n<1200;n++){record[0][n]=all_unpressed;record[2][n]=all_unpressed;}frame_count=-1;mode=2;}
        if(P2==1)
          {for(n=0;n<1200;n++){record[1][n]=all_unpressed;record[3][n]=all_unpressed;}frame_count=-1;mode=2;}}

    if((cursor_position==3) && (last_button==0))
      {frame_count=-1;mode=1;}
    
    if((cursor_position==4) && (last_button==0))
      {frame_count=-1;mode=1;}
    
    if((cursor_position==5) && (last_button==0))
      {frame_count=-1;mode=1;}

    if((cursor_position==6) && (last_button==0))
      {frame_count=-1;mode=1;}

    if((cursor_position==7) && (last_button==0))
      {repetition=loop_number;frame_count=-1;mode=3;}

    if((cursor_position==8) && (last_button==0))
      {repetition=loop_number;frame_count=-1;mode=3;}

    if(cursor_position==9)
      {if(P1==1){for(n=0;n<1200;n++){record[0][n]=all_unpressed;record[2][n]=all_unpressed;}
                 frame_count=-1;cursor_position=0;current_slot=0;}
       if(P2==1){for(n=0;n<1200;n++){record[1][n]=all_unpressed;record[3][n]=all_unpressed;}
                 frame_count=-1;cursor_position=0;current_slot=0;}
       loop_frame=148;loop_number=3;lag=0;lcd.clear();}

if((cursor_position==13) && (last_button==0))
 { saveSD(0,0);
   saveSD(1,1);
   saveSD(2,2);
   saveSD(3,3);
 }
  
if((cursor_position==14) && (last_button==0))
{ loadSD(0,0);
  loadSD(1,1);
  loadSD(2,2);
  loadSD(3,3);
 }

}



  //CUT HERE TO SPEED UP LCD
     lcd.setCursor(0,0);lcd.print(current_slot);
     lcd.setCursor(4,0);lcd.print(cursor_position);
     lcd.setCursor(7,0);lcd.print(loop_number); 
     lcd.setCursor(10,0);lcd.print(loop_frame);
     if(cursor_position==16){lcd.setCursor(9,3);lcd.print(F);}
     lcd.setCursor(0,3);lcd.print(time5);
     time2=micros();
   
     
     
     frame_count++;
     last_button=button;

  }
  }

Good job! My next project is going to be almost like yours(just need to finish my current one and find the time). I plan to piggyback an x360 controller and record the all the keys/stick movement to a SD card and then be able to play it up again with the arduino.The useness of this? Have no idea, just doing it for the learning experience. Going to use an 328 so I can play with I/O expanders and so on.