N64 to USB HID interface

Dependencies:   mbed

main.cpp

Committer:
igor_m
Date:
2011-09-30
Revision:
4:fee2d61ad6bc
Parent:
3:b9cecf3e2496
Child:
5:eb93a4f91396

File content as of revision 4:fee2d61ad6bc:


/*
N64 Controller Interface for the mbed.

by Igor Martinovski
March, 2011.

Function Mapping (from www.mixdown.ca/n64dev/)

Bit     Function
0        A
1        B
2        Z
3        Start
4        Directional Up
5        Directional Down
6        Directional Left
7        Directional Right

8        unknown (always 0)
9        unknown (always 0)
10        L
11        R
12        C Up
13        C Down
14        C Left
15        C Right

16-23   X value (signed)

23-32   Y value (signed)

Pinout:
Looking at the controller plug, flat side down.
Pin 1 (Left)    Ground
Pin 2 (Center)  Data**
Pin 3 (Right)   +3.3V*

(*)Note: The controller is supplied by 3.6V on the N64, but it seems to work fine on
the 3.3V provided by the mbed.

(**)Warning: The N64 controller must be connected to an open drain pin with a
pull-up resistor. The line must never be driven high by the mbed! If you are not
sure how to connect the controller safely, you may damage the mbed and/or
controller. You have been warned.
*/

#include "mbed.h"
#include "stdint.h"
#include "usbhid.h"


USBJoystick joystick;


/*
N64 Controller Interface for the mbed.

by Igor Martinovski
March, 2011.

Function Mapping (from www.mixdown.ca/n64dev/)

Bit     Function
0        A
1        B
2        Z
3        Start
4        Directional Up
5        Directional Down
6        Directional Left
7        Directional Right

8        unknown (always 0)
9        unknown (always 0)
10        L
11        R
12        C Up
13        C Down
14        C Left
15        C Right

16-23   X value (signed)

23-32   Y value (signed)

Pinout:
Looking at the controller plug, flat side down.
Pin 1 (Left)    Ground
Pin 2 (Center)  Data**
Pin 3 (Right)   +3.3V*

(*)Note: The controller is supplied by 3.6V on the N64, but it seems to work fine on
the 3.3V provided by the mbed.

(**)Warning: The N64 controller must be connected to an open drain pin with a
pull-up resistor. The line must never be driven high by the mbed! If you are not
sure how to connect the controller safely, you may damage the mbed and/or
controller. You have been warned.
*/

#include "mbed.h"
#include "stdint.h"

// Controller Commands

#define GET_STATUS          0x00
#define REQUEST_CONTROLS    0x01
#define READ_MEMPACK        0x02
#define WRITE_MEMPACK       0x03
#define READ_EEPROM         0x04
#define WRITE_EEPROM        0x05
#define RESET_CONTROLLER    0xff

#define T1                  22      // Corresponds to 1 us        
#define T2                  68      // Corresponds to 3 us

DigitalInOut inout(p14);            // Connect controller here
// using 220 ohm pull-up
Serial pc(USBTX, USBRX);

uint8_t x, y;
union controls { /* A definition and a declaration */
    uint8_t array[8];
    uint32_t result[2];
} controls;

// Temp array for controller data

/* void delay(unsigned int n) is used as a short delay to
   time the bit patterns. 1 n is roughly 0.042us on 96MHz CCLK
 */
void delay(unsigned int n) {
    unsigned int i;
    for (i=0; i<n; i++)
        ;
}

/* int receive(char *data_array, unsigned char n) is used to
   receive a bit stream of bits into an array of n bytes coming
   from the controller. This must be called immediately after
   sending any kind of request to the controller
 */

int receive(uint8_t *data_array, unsigned char n) {
    unsigned char sample, previous_sample;
    unsigned char bit, byte;
    int i;


    //inout.input();                // Not sure about this..

    sample = inout.read();
    for (i=0; i < n ; i++) {
        byte = 0;
        bit  = 0;
        while (bit<8) {
            previous_sample = sample;
            sample = inout.read();
            if ((previous_sample ^ sample) & previous_sample) {

                delay(60);
                sample=inout.read();
                if (sample)
                    byte = byte  | (1<<bit);
                bit++;
            }

            data_array[i]= byte;
        }

    }
    /* The for loop here is used to reverse the bits for the x and y values retured
          by the controller. I am not entirely sure of the format. I'm missing a bit
          somewhere.. Values don't range from -127..128. */
   /*
    x=y=0;
    for (i=0; i<=7; i++) {
        if (controls.array[2] & (1 << i))
            x=x | (1 << (7-i));
        if (controls.array[3] & (1 << i))
            y=y | (1 << (7-i));
    }
    data_array[2]=x;
    data_array[3]=y;
    */
    //data_array[2]= 5;
    return n;
}
/* void send_byte(unsigned char byte) is used to send a single
   byte to the controller.
 */
void send_byte(unsigned char byte) {
    char i;
    //inout.output();           // Not sure about this.
    inout.write(1);             // Makes sure line is left high

    wait_us(500);
    for (i=0; i<8; i++) {
        if (byte & 128>>i) {
            inout.write(0);
            delay(T1);
            inout.write(1);
            delay(T2);
        } else {
            inout.write(0);
            delay(T2);
            inout.write(1);
            delay(T1);
        }
    }
    /* Send Stop Bit */
    inout.write(0);
    delay(T1);
    inout.write(1);
    delay(T1);
}

/* void send_byte(unsigned char byte) is used to send a single
   byte to the controller.
 */
void send(uint8_t * cmd, uint8_t n) {
    uint8_t i,j,byte;

    inout.write(1);             // Makes sure line is left high
    wait_us(500);
    for (j=0; j<n; j++) {
        byte=cmd[j];
        for (i=0; i<8; i++) {
            if (byte & 128>>i) {
                inout.write(0);
                delay(T1);
                inout.write(1);
                delay(T2);
            } else {
                inout.write(0);
                delay(T2);
                inout.write(1);
                delay(T1);
            }
        }

    }/* Send Stop Bit */
    inout.write(0);
    delay(T1);
    inout.write(1);
    delay(T1);

}


uint8_t cmd[8];


int main() {
    inout.mode(OpenDrain);           // Must use open-drain for N64 Controller!
    uint8_t cmd[8];
    int8_t n;
    int temp;
    uint32_t i, previous_result=0;                           // Used for the bit-shifting for x and y values
    while (1) {
        wait_ms(10);
        n=3;
        cmd[0]=2; // Request Controls
        cmd[1]=3;
        cmd[0]=64;
        send(cmd,3);
        receive(controls.array, 8);           // Start receiving bit stream
        //pc.printf("%3d %3d %d %d\n ", controls.array[0], controls.array[1], (int8_t)controls.array[2], (int8_t)controls.array[3]);

        for (n=7; n>=0; n--){
            if (controls.array[2] & (1 << n))
            pc.printf("1");
            else 
            pc.printf("0");
            }
          //pc.printf("%d %d", (int8_t)(controls.array[2]^= (1 << 7)),controls.array[3]);
        pc.printf("\n");
/*
        for (n=0; n<16; n++)
            pc.printf("%d", (1 & ((uint16_t)controls.result[0] >> n)));
        pc.printf(" ");

        for (n=17; n<32; n++)
            pc.printf("%d", (1 & ((uint32_t)controls.result[0] >> n)));
        pc.printf(" ");
        
        for (n=0; n<16; n++)
            pc.printf("%d", (1 & ((uint16_t)controls.result[1] >> n)));
        pc.printf(" ");
        
        for (n=17; n<32; n++)
        pc.printf("%d", (1 & ((uint32_t)controls.result[1] >> n)));
        pc.printf("\n");
*/
    }

    while (1) {
        wait_ms(10);
        //previous_result=controls.result_32;
        send_byte(1);                // Send the request byte
        receive(controls.array, 8);           // Start receiving bit stream

        // if (controls.result_32==previous_result) continue;


        //pc.printf("%3d %3d %d %d\n ", controls.array[0], controls.array[1], (int8_t)controls.array[2], (int8_t)controls.array[3]);
        //pc.printf("%d\n",controls.result_32);
        joystick.joystick(controls.array[0],controls.array[1], controls.array[2], controls.array[3]);
    }

}