Skip to content

Commit

Permalink
Add files via upload
Browse files Browse the repository at this point in the history
  • Loading branch information
L10N37 authored Oct 30, 2022
1 parent 30b8bc2 commit d6b1523
Show file tree
Hide file tree
Showing 3 changed files with 253 additions and 0 deletions.
113 changes: 113 additions & 0 deletions files/N64_Interface.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/**
* Author: John Crain Welsby (john.welsby@gmail.com) in collaboration with Arduino community, especially Nick Gammon.
* Date: October 2016
* Version: 1.0
*
* Implementation of N64_Interface. Specifically designed to run on 16MHz 5V Arduino Uno, or compatible.
*/




// V2.00
// VajskiDs consoles (October 2022)
// Reworked into an In Game reset!


// ************** IGR Combination L+R+A+B+Z **************


#include "N64_Interface.h"
#include "Arduino.h"

//Do nothing for 1 cycle, 1/16 of a microsecond on Arduino Uno
#define NOP asm volatile ("nop\n\t") //as per original, delayMicroseconds doesn't seem to be as accurate - insta crash. Tried using 1 and 3 microseconds respectively. Moved to macros.
#define OneMicroSecondDelay NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP;
#define ThreeMicroSecondDelay NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP;NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP;NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP;
#define low bitWrite(DDRD, 2, 1); //Make data pin an output (low)
#define high bitWrite(DDRD, 2, 0); //Make data pin an input (high impedence, lets if float, console pulls it up)
#define resetpin 4
#define rst pinMode(resetpin, OUTPUT), bitWrite(PORTD, 4, 0), delay(100), pinMode(resetpin, INPUT);


N64_Interface::N64_Interface(int serialpin) : mask_(1 << serialpin) {

}


void N64_Interface::send(char const* input, uint16_t length) {

for (int i = 0; i < length; i++) {
char currentByte = input[i];

for (int j = 0; j < 8; j++) {
bool currentBit = currentByte & 0x80; //get leftmost bit
currentByte <<= 1; //shift left

if (currentBit) {
//send logical 1
low
OneMicroSecondDelay
high
ThreeMicroSecondDelay
} else {
//send logical 0
low
ThreeMicroSecondDelay
high
OneMicroSecondDelay
}
}
}

//send stop bit
bitWrite(DDRD, 2, 1); //Make data pin an output (low)
OneMicroSecondDelay
bitWrite(DDRD, 2, 0); //Make data pin an input (high impedence, simulates high
}


void N64_Interface::receive(char* output, uint16_t length) {

char mask = mask_; //Create a local copy for speed reasons


for (int i = 0; i < length; i++) {
char currentByte = 0;

for (int j = 0; j < 8; j++) {
while (PIND & mask) {}; //wait for low

//wait 1 microsecond
OneMicroSecondDelay

currentByte <<= 1; //shift left
currentByte |= (PIND & mask) != 0; //add latest bit

while (!(PIND & mask)) {}; //wait for high
}

output[i] = currentByte;
}

//wait for stop bit
while (PIND & mask)
;
while (!(PIND & mask))
;

}


void IGR(const N64_Status& status) {
if (status.buttons1 & BUTTON_A && status.buttons1 & BUTTON_B && status.buttons1 & BUTTON_Z && status.buttons2 & BUTTON_L && status.buttons2 && BUTTON_R) rst; // Wanted to use START instead of Z but this can't catch that combo for some reason.
}


void N64_Interface::sendStatusQuery() {
send(&COMMAND_STATUS, 1); //Pass the status command byte to the send() function.
}

void N64_Interface::receiveStatus(N64_Status& status) {
receive((char*)&status, status_size); //Pass the status struct to the receive() function.
}
91 changes: 91 additions & 0 deletions files/N64_Interface.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// ************* ORIGINAL KUDOS ************* https://github.com/LogicalUnit/N64_Interface
/**
* Author: John Crain Welsby (john.welsby@gmail.com) in collaboration with Arduino community, especially Nick Gammon.
* Date: October 2016
* Version: 1.0
*
* Use this header file to communicate with a Nintendo 64 controller. It is specifically designed to run on a 16MHz 5V Arduino Uno, or compatible.
* Looking into the N64 controller connector, arrow on top, wires from left to right are: GND, Data, 3V3.
* You must specify which pin is connected to the Data wire in the constructor of N64_Interface. Valid pins are: 2, 3, 4, 5, 6, or 7.
* If you just want to get the status of the N64 controller's joystick and buttons, use the convenience functions to send and receive status queries.
* Multi-byte queries, such as when communicating with a memory card, have not been tested -- but might work.
* Be sure to disable interrupts when communicating with the controller.
* Search online for more information about the N64 controller communication protocol.
*/


// V2.00
// VajskiDs consoles (October 2022)
// Reworked into an In Game reset!


// ************** IGR Combination L+R+A+B+Z **************


#ifndef N64_INTERFACE_H
#define N64_INTERFACE_H



//Status buttons1:
const char BUTTON_D_RIGHT = 0x01;
const char BUTTON_D_LEFT = 0x02;
const char BUTTON_D_DOWN = 0x04;
const char BUTTON_D_UP = 0x08;
const char BUTTON_START = 0x10;
const char BUTTON_Z = 0x20;
const char BUTTON_B = 0x40;
const char BUTTON_A = 0x80;

//Status buttons2:
const char BUTTON_C_RIGHT = 0x01;
const char BUTTON_C_LEFT = 0x02;
const char BUTTON_C_DOWN = 0x04;
const char BUTTON_C_UP = 0x08;
const char BUTTON_R = 0x10;
const char BUTTON_L = 0x20;

//Controller commands (queries to send).
const char COMMAND_IDENFITY = 0x00;
const char COMMAND_STATUS = 0x01;

//Structure for storing controller status (joystick and buttons).
typedef struct {
char buttons1;
char buttons2;
char stick_x;
char stick_y;
} N64_Status;

//Number of bytes in a N64_Status struct
const int status_size = sizeof(N64_Status);

//Print the contents of a N64_Status struct to serial
void IGR(const N64_Status& status);

//Interface to the Nintendo 64 controller
class N64_Interface {

public:
//Specify which pin is connected to the N64 controller's Data wire. Choose pin 2, 3, 4, 5, 6, or 7.
N64_Interface(int serialpin = 2);

//Convenience function. Send the status query byte to the controller.
void sendStatusQuery();

//Convenience function. Receive the status response from the controller.
void receiveStatus(N64_Status& status);

//Send bytes starting at input to controller, length is number of bytes to send.
void send(char const* input, unsigned int length);

//Receive bytes starting at output from controller, length is number of bytes to receive.
void receive(char* output, unsigned int length);

private:
//Hex representation of the data pin.
char mask_;

};

#endif
49 changes: 49 additions & 0 deletions files/N64_Interface.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// ************* ORIGINAL KUDOS *************
/**
* Author: John Crain Welsby (john.welsby@gmail.com)
* Date: October 2016
* Version: 1.0
*
* Simple demonstration of communication with a Nintendo 64 controller.
* Controller must be connected as described in N64_Interface.h (GND, Data, 3V3).
* Serial output at 115200 baud.
*/



// V2.00
// VajskiDs consoles (October 2022)
// Reworked into an In Game reset!


// ************** IGR Combination L+R+A+B+Z **************


#include "N64_Interface.h"
#define resetpin 4
#define serialpin 2


//Global variables
N64_Interface interface(serialpin); //N64 controller Data wire is connected to pin 2.
N64_Status status, oldStatus; //Status of joystick and buttons.

void setup() {
pinMode (resetpin, INPUT);

//Start by clearing the status variables
memset(&status, 0, status_size);
memset(&oldStatus, 0, status_size);
}


void loop() {

noInterrupts(); //Disable interrupts, they interfere with timings.
interface.sendStatusQuery(); //This is how we send the status query (1 byte).
interface.receiveStatus(status); //This is how we receive the status response (4 bytes).
interrupts(); //Timing critical section complete, re-enable interrupts.
IGR(status);
delay(500);

}

0 comments on commit d6b1523

Please sign in to comment.