mirror of
https://github.com/mnzlmstr/N64toiQue
synced 2024-11-24 10:12:22 -05:00
deleted source files from root
This commit is contained in:
parent
75729b083b
commit
260829afa4
@ -1,206 +0,0 @@
|
||||
#include "ControllerBuffer.h"
|
||||
#include "PinMappings.h"
|
||||
#include "Debug.h"
|
||||
|
||||
// buffer to hold data being read from controller
|
||||
bool buffer[DATA_SIZE + DATA_OFFSET];
|
||||
|
||||
// bit resolution and offsets
|
||||
int bitOffsets[32];
|
||||
int bitResolution;
|
||||
|
||||
/** Function to send a Command to the attached N64-Controller.
|
||||
* Must be run from RAM to defy timing differences introduced from
|
||||
* reading Code from ESP32's SPI Flash Chip.
|
||||
*/
|
||||
void IRAM_ATTR sendCommand(byte command)
|
||||
{
|
||||
// the current bit to write
|
||||
bool bit;
|
||||
|
||||
// clear output buffer
|
||||
memset(buffer,0,DATA_SIZE + DATA_OFFSET);
|
||||
|
||||
// for each bit
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
// get value
|
||||
bit = (1 << (7 - i)) & command;
|
||||
|
||||
// write data
|
||||
LINE_WRITE_LOW;
|
||||
delayMicroseconds((3 - 2 * bit));
|
||||
LINE_WRITE_HIGH;
|
||||
delayMicroseconds((1 + 2 * bit));
|
||||
}
|
||||
|
||||
// console stop bit
|
||||
LINE_WRITE_LOW;
|
||||
delayMicroseconds(1);
|
||||
LINE_WRITE_HIGH;
|
||||
delayMicroseconds(2);
|
||||
|
||||
// read returned data as fast as possible
|
||||
for(int i = 0;i < DATA_SIZE + DATA_OFFSET;i++)
|
||||
{
|
||||
buffer[i] = digitalRead(DATA_PIN);
|
||||
}
|
||||
|
||||
// plot polling process from controller if unstructed to
|
||||
#ifdef PLOT_CONSOLE_POLLING
|
||||
for(int i = 0; i < DATA_SIZE + DATA_OFFSET;i++)
|
||||
{
|
||||
Serial.println(buffer[i]*2500);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Function to extract a controller bit from the buffer of returned data */
|
||||
void getBit(bool *bit,int offset,bool *data)
|
||||
{
|
||||
// sanity check offset
|
||||
if(offset < 0) offset = 0;
|
||||
|
||||
// count
|
||||
short count = 0;
|
||||
|
||||
// get count from offset to offset + length
|
||||
for(int i = offset + DATA_OFFSET;i < offset + bitResolution;i++)
|
||||
{
|
||||
count += *(data + i);
|
||||
}
|
||||
|
||||
// if offset surpasses threshold set bit
|
||||
*bit = false;
|
||||
if(count > BIT_THRESHOLD) *bit = true;
|
||||
}
|
||||
|
||||
/** Function to populate the controller struct if command 0x01 was sent.
|
||||
* Buttons are set according to data in buffer, raw axis data is written,
|
||||
* Axis Data is correctly decoded from raw axis data by taking two's complement
|
||||
* and checking if value if below 'MAX_INCLINE_AXIS_X' or 'MAX_INCLINE_AXIS_Y'.
|
||||
* If values surpass the maximum incline they are set to match those values.
|
||||
*/
|
||||
void populateControllerStruct(ControllerData *data)
|
||||
{
|
||||
// first byte
|
||||
getBit(&(data->buttonA) , bitOffsets[0] ,&buffer[0]);
|
||||
getBit(&(data->buttonB), bitOffsets[1] ,&buffer[0]);
|
||||
getBit(&(data->buttonZ), bitOffsets[2] ,&buffer[0]);
|
||||
getBit(&(data->buttonStart), bitOffsets[3] ,&buffer[0]);
|
||||
getBit(&(data->DPadUp), bitOffsets[4] ,&buffer[0]);
|
||||
getBit(&(data->DPadDown), bitOffsets[5] ,&buffer[0]);
|
||||
getBit(&(data->DPadLeft), bitOffsets[6] ,&buffer[0]);
|
||||
getBit(&(data->DPadRight), bitOffsets[7] ,&buffer[0]);
|
||||
|
||||
// second byte, first two bits are unused
|
||||
getBit(&(data->buttonL), bitOffsets[10] ,&buffer[0]);
|
||||
getBit(&(data->buttonR), bitOffsets[11] ,&buffer[0]);
|
||||
getBit(&(data->CUp), bitOffsets[12] ,&buffer[0]);
|
||||
getBit(&(data->CDown), bitOffsets[13] ,&buffer[0]);
|
||||
getBit(&(data->CLeft), bitOffsets[14] ,&buffer[0]);
|
||||
getBit(&(data->CRight), bitOffsets[15] ,&buffer[0]);
|
||||
|
||||
// third byte
|
||||
getBit(&(data->xAxisRaw[0]), bitOffsets[16], &buffer[0]);
|
||||
getBit(&(data->xAxisRaw[1]), bitOffsets[17], &buffer[0]);
|
||||
getBit(&(data->xAxisRaw[2]), bitOffsets[18], &buffer[0]);
|
||||
getBit(&(data->xAxisRaw[3]), bitOffsets[19], &buffer[0]);
|
||||
getBit(&(data->xAxisRaw[4]), bitOffsets[20], &buffer[0]);
|
||||
getBit(&(data->xAxisRaw[5]), bitOffsets[21], &buffer[0]);
|
||||
getBit(&(data->xAxisRaw[6]), bitOffsets[22], &buffer[0]);
|
||||
getBit(&(data->xAxisRaw[7]), bitOffsets[23], &buffer[0]);
|
||||
|
||||
// fourth byte
|
||||
getBit(&(data->yAxisRaw[0]), bitOffsets[24], &buffer[0]);
|
||||
getBit(&(data->yAxisRaw[1]), bitOffsets[25], &buffer[0]);
|
||||
getBit(&(data->yAxisRaw[2]), bitOffsets[26], &buffer[0]);
|
||||
getBit(&(data->yAxisRaw[3]), bitOffsets[27], &buffer[0]);
|
||||
getBit(&(data->yAxisRaw[4]), bitOffsets[28], &buffer[0]);
|
||||
getBit(&(data->yAxisRaw[5]), bitOffsets[29], &buffer[0]);
|
||||
getBit(&(data->yAxisRaw[6]), bitOffsets[30], &buffer[0]);
|
||||
getBit(&(data->yAxisRaw[7]), bitOffsets[31], &buffer[0]);
|
||||
|
||||
// sum up bits to get axis bytes
|
||||
data->xAxis = 0;
|
||||
data->yAxis = 0;
|
||||
for(int i = 0;i < 8;i++)
|
||||
{
|
||||
data->xAxis += (data->xAxisRaw[i] * (0x80 >> (i)));
|
||||
data->yAxis += (data->yAxisRaw[i] * (0x80 >> (i)));
|
||||
|
||||
// print y axis values
|
||||
#ifdef PRINT_Y_AXIS_VALUES
|
||||
Serial.printf("%i %i %i %i %i %i %i %i\n",data->yAxisRaw[0],data->yAxisRaw[1],data->yAxisRaw[2],data->yAxisRaw[3],data->yAxisRaw[4],data->yAxisRaw[5],data->yAxisRaw[6],data->yAxisRaw[7]);
|
||||
Serial.printf("yAxis: %i \n",data->yAxis);
|
||||
#endif
|
||||
|
||||
// print x axis values
|
||||
#ifdef PRINT_X_AXIS_VALUES
|
||||
Serial.printf("%i %i %i %i %i %i %i %i\n",data->xAxisRaw[0],data->xAxisRaw[1],data->xAxisRaw[2],data->xAxisRaw[3],data->xAxisRaw[4],data->xAxisRaw[5],data->xAxisRaw[6],data->xAxisRaw[7]);
|
||||
Serial.printf("xAxis: %i \n",data->xAxis);
|
||||
#endif
|
||||
}
|
||||
|
||||
// decode xAxis two's complement
|
||||
if(data->xAxis & 0x80)
|
||||
{
|
||||
data->xAxis = -1 * (0xff - data->xAxis);
|
||||
}
|
||||
|
||||
// decode yAxis two's complement
|
||||
if(data->yAxis & 0x80)
|
||||
{
|
||||
data->yAxis = -1 * (0xff - data->yAxis);
|
||||
}
|
||||
|
||||
// keep x axis below maxIncline
|
||||
if(data->xAxis > MAX_INCLINE_AXIS_X) data->xAxis = MAX_INCLINE_AXIS_X;
|
||||
if(data->xAxis < -MAX_INCLINE_AXIS_X) data->xAxis = -MAX_INCLINE_AXIS_X;
|
||||
|
||||
// keep y axis below maxIncline
|
||||
if(data->yAxis > MAX_INCLINE_AXIS_Y) data->yAxis = MAX_INCLINE_AXIS_Y;
|
||||
if(data->yAxis < -MAX_INCLINE_AXIS_Y) data->yAxis = -MAX_INCLINE_AXIS_Y;
|
||||
|
||||
//Serial.printf("xaxis: %-3i yaxis: %-3i \n",data->xAxis,data->yAxis);
|
||||
}
|
||||
|
||||
void updateOffsetsAndResolution()
|
||||
{
|
||||
// the current bit counter
|
||||
int bitCounter = 0;
|
||||
|
||||
// to hold the offset of A Button's falling edge
|
||||
int bitAfallingOffset = 0;
|
||||
|
||||
// iterate over buffer
|
||||
for(int i = 0;i < DATA_SIZE + DATA_OFFSET - 1;i++)
|
||||
{
|
||||
// if a falling edge is detected
|
||||
if(buffer[i] == true && buffer[1+i] == false)
|
||||
{
|
||||
// store bit's end offset
|
||||
bitOffsets[bitCounter] = i+1;
|
||||
|
||||
// if it's the A button store offset of the falling edge
|
||||
if(bitCounter == 0) bitAfallingOffset = i+1;
|
||||
|
||||
// if it's the B button calculate the bit Resolution
|
||||
if(bitCounter == 1) bitResolution = (i+1) - bitAfallingOffset;
|
||||
|
||||
// increment bit counter
|
||||
bitCounter++;
|
||||
}
|
||||
}
|
||||
|
||||
Serial.printf("Bit resolution is %i \n",bitResolution);
|
||||
|
||||
// calculate bit's beginning offsets by subtracting resolution
|
||||
for(int i = 0;i < 32;i++)
|
||||
{
|
||||
bitOffsets[i] -= bitResolution;
|
||||
Serial.printf("beginning of bit %i detected @ begin+%i \n",i+1,bitOffsets[i]);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
#ifndef CONTROLLER_BUFFER_H
|
||||
#define CONTROLLER_BUFFER_H
|
||||
|
||||
#include "ControllerData.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
#define DATA_SIZE 450 // number of sample points to poll
|
||||
#define DATA_OFFSET 0 // number of samples to ignore after staring to poll
|
||||
|
||||
#define MAX_INCLINE_AXIS_X 60
|
||||
#define MAX_INCLINE_AXIS_Y 60
|
||||
|
||||
#define BIT_THRESHOLD 6
|
||||
|
||||
extern void IRAM_ATTR sendCommand(byte command);
|
||||
extern void populateControllerStruct(ControllerData *data);
|
||||
|
||||
/** Function to read the offsets of the individual bits so that they can be updated for reading.
|
||||
* Resolution is detected by taking the distance of two falling edges of Button A and B.
|
||||
* Buttons must not be pressed by the time this command is invoked !
|
||||
* sendCommand(0x01) must be invoked before !
|
||||
*/
|
||||
extern void updateOffsetsAndResolution();
|
||||
|
||||
|
||||
#endif
|
@ -1,31 +0,0 @@
|
||||
#ifndef CONTROLLER_DATA_H
|
||||
#define CONTROLLER_DATA_H
|
||||
|
||||
struct ControllerData
|
||||
{
|
||||
bool buttonA;
|
||||
bool buttonB;
|
||||
bool buttonZ;
|
||||
bool buttonL;
|
||||
bool buttonR;
|
||||
bool buttonStart;
|
||||
|
||||
bool DPadUp;
|
||||
bool DPadDown;
|
||||
bool DPadLeft;
|
||||
bool DPadRight;
|
||||
|
||||
bool CUp;
|
||||
bool CDown;
|
||||
bool CLeft;
|
||||
bool CRight;
|
||||
|
||||
short xAxis;
|
||||
short yAxis;
|
||||
|
||||
bool xAxisRaw[8];
|
||||
bool yAxisRaw[8];
|
||||
|
||||
};
|
||||
|
||||
#endif
|
8
Debug.h
8
Debug.h
@ -1,8 +0,0 @@
|
||||
#ifndef DEBUG_H
|
||||
#define DEBUG_H
|
||||
|
||||
//#define PLOT_CONSOLE_POLLING
|
||||
//#define PRINT_X_AXIS_VALUES
|
||||
//#define PRINT_Y_AXIS_VALUES
|
||||
|
||||
#endif
|
135
Output.cpp
135
Output.cpp
@ -1,135 +0,0 @@
|
||||
#include "Output.h"
|
||||
#include "PinMappings.h"
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
int encoderXpos = 0;
|
||||
int encoderYpos = 0;
|
||||
|
||||
void setupIO()
|
||||
{
|
||||
// the controller data line
|
||||
LINE_WRITE_HIGH;
|
||||
|
||||
pinMode(PIN_BUTTON_A,OUTPUT);
|
||||
pinMode(PIN_BUTTON_B,OUTPUT);
|
||||
pinMode(PIN_BUTTON_Z,OUTPUT);
|
||||
pinMode(PIN_BUTTON_S,OUTPUT);
|
||||
pinMode(PIN_BUTTON_L,OUTPUT);
|
||||
pinMode(PIN_BUTTON_R,OUTPUT);
|
||||
|
||||
pinMode(PIN_DPAD_UP, OUTPUT);
|
||||
pinMode(PIN_DPAD_DOWN, OUTPUT);
|
||||
pinMode(PIN_DPAD_LEFT, OUTPUT);
|
||||
pinMode(PIN_DPAD_RIGHT,OUTPUT);
|
||||
|
||||
pinMode(PIN_C_UP, OUTPUT);
|
||||
pinMode(PIN_C_DOWN, OUTPUT);
|
||||
pinMode(PIN_C_LEFT, OUTPUT);
|
||||
pinMode(PIN_C_RIGHT,OUTPUT);
|
||||
|
||||
pinMode(PIN_A_AXIS_X, OUTPUT);
|
||||
pinMode(PIN_B_AXIS_X, OUTPUT);
|
||||
|
||||
pinMode(PIN_A_AXIS_Y, OUTPUT);
|
||||
pinMode(PIN_B_AXIS_Y, OUTPUT);
|
||||
}
|
||||
|
||||
/** Function to simulate the 90° phaseshifted quadrature encoding used by
|
||||
* the N64-Controller's joystick's linear encoders. As only change in position
|
||||
* (not absolute position) is reported the change in the value between writes
|
||||
* is needed for calculation. Must be run from RAM to mitigate timing differences in
|
||||
* ESP32's SPI-Flash Chip Access Times.
|
||||
* @param relativeMovement should be processed by calling 'mapJoystickToEncoderPos'
|
||||
* with the read joystick position.
|
||||
*/
|
||||
void IRAM_ATTR moveAxis(int axisPinA,int axisPinB,int requestedEncoderPos,int *realEncoderPos)
|
||||
{
|
||||
// get difference from requested ender position to real encoder position
|
||||
int difference = requestedEncoderPos - *realEncoderPos;
|
||||
|
||||
// store new real encoder position
|
||||
*realEncoderPos = requestedEncoderPos;
|
||||
|
||||
// set pins used for outputting
|
||||
int pinA = axisPinA;
|
||||
int pinB = axisPinB;
|
||||
|
||||
// invert pins if moving in the other direction
|
||||
if(difference > 0)
|
||||
{
|
||||
pinA = axisPinB;
|
||||
pinB = axisPinA;
|
||||
}
|
||||
|
||||
// get absolute movement value
|
||||
difference = abs(difference);
|
||||
|
||||
// for each change in movement
|
||||
for(int i = 0;i < difference;i++)
|
||||
{
|
||||
// replicate 90° phaseshifted quadrate output
|
||||
digitalWrite(pinA,LOW);
|
||||
delayMicroseconds(2);
|
||||
digitalWrite(pinB,LOW);
|
||||
delayMicroseconds(6);
|
||||
digitalWrite(pinA,HIGH);
|
||||
delayMicroseconds(2);
|
||||
digitalWrite(pinB,HIGH);
|
||||
|
||||
// debounce as N64 will not detect change correctly otherwise
|
||||
delayMicroseconds(40);
|
||||
}
|
||||
}
|
||||
|
||||
/** Function to map Joystick position to relative Encoder Position.
|
||||
* According to Nintendo the maximum value for any axis to be assumed should
|
||||
* be +- 60. The encoder starts acting strange after ~ 30 turns in a given
|
||||
* direction. Also passing on ControllerData struct so that user specified
|
||||
* modifiers can be used to specify alternate mapping, eg. for
|
||||
* easier ESS-Position in Ocarina of Time (see my example)
|
||||
*/
|
||||
int mapJoystickToEncoderPos(int joyval,ControllerData *data)
|
||||
{
|
||||
// ESS-Modifier for Ocarina of Time, hold A+B to stay in ESS-Position
|
||||
if(data->buttonA && data->buttonB) return -2;
|
||||
|
||||
// deadzone handling
|
||||
if(abs(joyval) < 3) return 0;
|
||||
|
||||
// normally return half ???
|
||||
return (int)(joyval * .5f);
|
||||
}
|
||||
|
||||
void outputToiQue(ControllerData *data)
|
||||
{
|
||||
// ===== Write Button Data =====
|
||||
digitalWrite(PIN_BUTTON_A,data->buttonA);
|
||||
digitalWrite(PIN_BUTTON_B,data->buttonB);
|
||||
digitalWrite(PIN_BUTTON_L,data->buttonL);
|
||||
digitalWrite(PIN_BUTTON_R,data->buttonR);
|
||||
digitalWrite(PIN_BUTTON_Z,data->buttonZ);
|
||||
digitalWrite(PIN_BUTTON_S,data->buttonStart);
|
||||
|
||||
// ===== Write D-Pad Data =====
|
||||
digitalWrite(PIN_DPAD_UP, data->DPadUp);
|
||||
digitalWrite(PIN_DPAD_DOWN, data->DPadDown);
|
||||
digitalWrite(PIN_DPAD_LEFT, data->DPadLeft);
|
||||
digitalWrite(PIN_DPAD_RIGHT,data->DPadRight);
|
||||
|
||||
// ===== Write C-Button Data =====
|
||||
digitalWrite(PIN_C_UP, data->CUp);
|
||||
digitalWrite(PIN_C_DOWN, data->CDown);
|
||||
digitalWrite(PIN_C_LEFT, data->CLeft);
|
||||
digitalWrite(PIN_C_RIGHT, data->CRight);
|
||||
|
||||
// ===== Write Joystick Data =====
|
||||
|
||||
// calculate change in axis between writes
|
||||
//int xAxisChange = data->xAxis - lastxAxis;
|
||||
//int yAxisChange = data->yAxis - lastyAxis;
|
||||
|
||||
// move axis accordingly
|
||||
moveAxis(PIN_A_AXIS_X,PIN_B_AXIS_X,mapJoystickToEncoderPos(data->xAxis,data),&encoderXpos);
|
||||
moveAxis(PIN_A_AXIS_Y,PIN_B_AXIS_Y,mapJoystickToEncoderPos(data->yAxis,data),&encoderYpos);
|
||||
}
|
19
Output.h
19
Output.h
@ -1,19 +0,0 @@
|
||||
#ifndef OUTPUT_H
|
||||
#define OUTPUT_H
|
||||
|
||||
#include "ControllerData.h"
|
||||
|
||||
/** Function to output Data stored in ControllerData struct to the iQue console.
|
||||
* Buttons states are directly set usig digitalWrite(), Axis Data is written by
|
||||
* Simulating the 90° shifted quadrate encoding used by the N64 joysticks.
|
||||
* As these operate on a relative basis the difference between the current
|
||||
* and the last joystick positions are calculated and simulated.
|
||||
*/
|
||||
extern void outputToiQue(ControllerData *data);
|
||||
|
||||
/** Function to setup the IO used for interfacing with the N64-Controller
|
||||
* and the iQue-Console
|
||||
*/
|
||||
extern void setupIO();
|
||||
|
||||
#endif
|
@ -1,33 +0,0 @@
|
||||
#ifndef PIN_MAPPINGS_H
|
||||
#define PIN_MAPPINGS_H
|
||||
|
||||
#define DATA_PIN 13
|
||||
|
||||
#define PIN_BUTTON_A 15
|
||||
#define PIN_BUTTON_B 5
|
||||
#define PIN_BUTTON_Z 23
|
||||
#define PIN_BUTTON_S 1
|
||||
#define PIN_BUTTON_L 1
|
||||
#define PIN_BUTTON_R 1
|
||||
|
||||
#define PIN_DPAD_UP 1
|
||||
#define PIN_DPAD_DOWN 1
|
||||
#define PIN_DPAD_LEFT 1
|
||||
#define PIN_DPAD_RIGHT 1
|
||||
|
||||
#define PIN_C_UP 1
|
||||
#define PIN_C_DOWN 1
|
||||
#define PIN_C_LEFT 1
|
||||
#define PIN_C_RIGHT 1
|
||||
|
||||
#define PIN_A_AXIS_X 14
|
||||
#define PIN_B_AXIS_X 27
|
||||
|
||||
#define PIN_A_AXIS_Y 2
|
||||
#define PIN_B_AXIS_Y 4
|
||||
|
||||
#define LINE_WRITE_HIGH pinMode(DATA_PIN,INPUT_PULLUP)
|
||||
#define LINE_WRITE_LOW pinMode(DATA_PIN,OUTPUT)
|
||||
|
||||
|
||||
#endif
|
39
iQue.ino
39
iQue.ino
@ -1,39 +0,0 @@
|
||||
#include "Output.h"
|
||||
#include "ControllerData.h"
|
||||
#include "ControllerBuffer.h"
|
||||
#include "Debug.h"
|
||||
|
||||
ControllerData controller;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
|
||||
// setup io pins
|
||||
setupIO();
|
||||
|
||||
#ifdef PLOT_CONSOLE_POLLING
|
||||
delay(5000);
|
||||
sendCommand(0x01);
|
||||
while(true);
|
||||
#endif
|
||||
|
||||
sendCommand(0x01);
|
||||
updateOffsetsAndResolution();
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
// send command 0x01 to n64 controller
|
||||
sendCommand(0x01);
|
||||
|
||||
// store received data in controller struct
|
||||
populateControllerStruct(&controller);
|
||||
|
||||
// output received data to ique
|
||||
outputToiQue(&controller);
|
||||
|
||||
// polling must not occur faster than every 20 ms
|
||||
delay(14);
|
||||
}
|
Loading…
Reference in New Issue
Block a user