Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //Code written by Zas & Slask, Modified from both Andrew Brown & Moltov codes
- /*
- Copyright (c) 2009 Andrew Brown
- Permission is hereby granted, free of charge, to any person
- obtaining a copy of this software and associated documentation
- files (the "Software"), to deal in the Software without
- restriction, including without limitation the rights to use,
- copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the
- Software is furnished to do so, subject to the following
- conditions:
- The above copyright notice and this permission notice shall be
- included in all copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- OTHER DEALINGS IN THE SOFTWARE.
- */
- /*
- Copyright (c) 2018 Pontus Johansson & Zas_
- Permission is hereby granted, free of charge, to any person
- obtaining a copy of this software and associated documentation
- files (the "Software"), to deal in the Software without
- restriction, including without limitation the rights to use,
- copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the
- Software is furnished to do so, subject to the following
- conditions:
- The above copyright notice and this permission notice shall be
- included in all copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- OTHER DEALINGS IN THE SOFTWARE.
- */
- /* user controls */
- //comment to disable
- #define ENABLE_SERIAL //ZAS USES THIS, Used for Boards without HID capability for Input Display(N64C3)
- #define ENABLE_JOYSTICK //SLASK USES THIS, Used for ATmega32u4 Boards or similar for Gamepad Support
- //console input pin
- #define GC_PIN 3
- #define GC_HIGH DDRD &= ~0x01
- #define GC_LOW DDRD |= 0x01
- #define GC_QUERY (PIND & 0x01)
- //controller input pin
- #define N64_PIN 5
- #define N64_HIGH DDRC &= ~0x40
- #define N64_LOW DDRC |= 0x40
- #define N64_QUERY (PINC & 0x40)
- /******************/
- #ifdef ENABLE_JOYSTICK
- #include <HID-Project.h>
- #include <HID-Settings.h>
- #endif
- #include "crc_table.h" //can be found at https://github.com/brownan/Gamecube-N64-Controller/blob/master/crc_table.h
- #define SERIAL_SYNC (4)
- int serialTiming = 0;
- unsigned char gc_Buffer[33];
- bool needCommand = false;
- char gc_Raw_Dump[281];
- unsigned char gc_Command;
- void get_GC_Command();
- void gc_Send(unsigned char *buffer, char length, bool wide_stop);
- #define ABS(A)((A)<0?(-A):(A))
- #define SIGN(A)((A)==0?(0):((A)<0?(-1):(1)))
- #define OOTess (23)
- #define OOTwalk (39)
- #define OOTrun (57)
- #define INPUTrange (64)
- #define ESSstart (8)
- #define ESSend (27)
- #define OUTPUTrange (75)
- struct state {
- char stick_x;
- char stick_y;
- // bits: 0, 0, 0, start, y, x, b, a
- unsigned char data1;
- // bits: 1, L, R, Z, Dup, Ddown, Dright, Dleft
- unsigned char data2;
- } N64_status;
- char N64_raw_dump[33]; // 1 received bit per byte
- void setup() {
- #ifdef ENABLE_SERIAL
- Serial.begin(9600);
- #endif
- #ifdef ENABLE_JOYSTICK
- //pinMode(17, OUTPUT); //Used to check usb status
- Gamepad.begin();
- #endif
- //init gc buffer
- memset(gc_Buffer, 0, sizeof(gc_Buffer));
- digitalWrite(GC_PIN, LOW);
- pinMode(GC_PIN, INPUT);
- digitalWrite(N64_PIN, LOW);
- pinMode(N64_PIN, INPUT);
- }
- void loop() {//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- if (needCommand == false) {
- getN64();
- translate_raw_data();
- #ifdef ENABLE_SERIAL
- #ifndef ENABLE_JOYSTICK
- if (serialTiming >= SERIAL_SYNC) {
- print_N64_status();
- serialTiming = 0;
- } else {
- serialTiming++;
- }
- #endif
- #endif
- #ifdef ENABLE_JOYSTICK
- if (USBSTA >> VBUS & 1)//Checks if power is coming through USB
- {
- //digitalWrite(17, LOW);
- if (serialTiming >= SERIAL_SYNC)
- {
- #ifdef ENABLE_SERIAL
- print_N64_status();
- #endif
- update_joystick();
- Gamepad.write();
- serialTiming = 0;
- }
- else
- {
- serialTiming++;
- }
- }
- #endif
- N64_status.stick_x = essMod(N64_status.stick_x);
- N64_status.stick_y = essMod(N64_status.stick_y);
- N64toGC();
- noInterrupts();
- get_GC_Command(0);
- }
- if (needCommand == true) {
- needCommand = false;
- }
- switch (gc_Command) {
- case 0x00:
- case 0xff:
- //ID what controller you are using, return 0x090000
- gc_Buffer[0] = 0x29;
- gc_Buffer[1] = 0x00;
- gc_Buffer[2] = 0x20;
- gc_Buffer[3] = 0x00;
- gc_Send(gc_Buffer, 3, 0);
- needCommand = true;
- get_GC_Command(0);
- //Serial.println("ID command:");
- //Serial.println(gc_Command, HEX);
- break;
- case 0x40:
- //Return the data input from the classic controller
- gc_Send(gc_Buffer, 8, 0);
- get_GC_Command(1);
- //Serial.println("Input Request command:");
- //Serial.println(gc_Command, HEX);
- break;
- case 0x41:
- case 0x42:
- //
- gc_Buffer[0] = 0x00;
- gc_Buffer[1] = 0x80;
- gc_Buffer[2] = 0x80;
- gc_Buffer[3] = 0x80;
- gc_Buffer[4] = 0x80;
- gc_Buffer[5] = 0x80;
- gc_Buffer[6] = 0x00;
- gc_Buffer[7] = 0x00;
- gc_Buffer[8] = 0x02;
- gc_Buffer[9] = 0x02;
- gc_Send(gc_Buffer, 10, 0);
- //Serial.println("Origin command:");
- //Serial.println(gc_Command, HEX);
- break;
- default:
- //
- //Serial.println("Error, unknown command from console.");
- //Serial.println(gc_Command, HEX);
- break;
- }
- interrupts();
- }
- int essMod(float v)
- {
- if (v > 128)
- {
- v -= 256;
- }
- float amount = ABS(v);
- float sign = SIGN(v);
- if (amount >= ESSstart) {
- if (amount < ESSend) {
- //ess
- amount = (OOTess + (amount - ESSstart) * (OOTwalk - OOTess) / (ESSend - ESSstart)) * sign;
- } else {
- amount = (OOTwalk + (amount - ESSend) * (INPUTrange - OOTwalk) / (OUTPUTrange - ESSend)) * sign;
- }
- } else {
- //less
- amount = (amount * OOTess / ESSstart) * sign;
- }
- return amount < 0 ? amount + 256 : amount;
- }
- void N64_send(unsigned char *buffer, char length)
- {
- // Send these bytes
- char bits;
- bool bit;
- // This routine is very carefully timed by examining the assembly output.
- // Do not change any statements, it could throw the timings off
- //
- // We get 16 cycles per microsecond, which should be plenty, but we need to
- // be conservative. Most assembly ops take 1 cycle, but a few take 2
- //
- // I use manually constructed for-loops out of gotos so I have more control
- // over the outputted assembly. I can insert nops where it was impossible
- // with a for loop
- asm volatile (";Starting outer for loop");
- outer_loop:
- {
- asm volatile (";Starting inner for loop");
- bits = 8;
- inner_loop:
- {
- // Starting a bit, set the line low
- asm volatile (";Setting line to low");
- N64_LOW; // 1 op, 2 cycles
- asm volatile (";branching");
- if (*buffer >> 7) {
- asm volatile (";Bit is a 1");
- // 1 bit
- // remain low for 1us, then go high for 3us
- // nop block 1
- asm volatile ("nop\nnop\nnop\nnop\nnop\n");
- asm volatile (";Setting line to high");
- N64_HIGH;
- // nop block 2
- // we'll wait only 2us to sync up with both conditions
- // at the bottom of the if statement
- asm volatile ("nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- );
- } else {
- asm volatile (";Bit is a 0");
- // 0 bit
- // remain low for 3us, then go high for 1us
- // nop block 3
- asm volatile ("nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\n");
- asm volatile (";Setting line to high");
- N64_HIGH;
- // wait for 1us
- asm volatile ("; end of conditional branch, need to wait 1us more before next bit");
- }
- // end of the if, the line is high and needs to remain
- // high for exactly 16 more cycles, regardless of the previous
- // branch path
- asm volatile (";finishing inner loop body");
- --bits;
- if (bits != 0) {
- // nop block 4
- // this block is why a for loop was impossible
- asm volatile ("nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\n");
- // rotate bits
- asm volatile (";rotating out bits");
- *buffer <<= 1;
- goto inner_loop;
- } // fall out of inner loop
- }
- asm volatile (";continuing outer loop");
- // In this case: the inner loop exits and the outer loop iterates,
- // there are /exactly/ 16 cycles taken up by the necessary operations.
- // So no nops are needed here (that was lucky!)
- --length;
- if (length != 0) {
- ++buffer;
- goto outer_loop;
- } // fall out of outer loop
- }
- // send a single stop (1) bit
- // nop block 5
- asm volatile ("nop\nnop\nnop\nnop\n");
- N64_LOW;
- // wait 1 us, 16 cycles, then raise the line
- // 16-2=14
- // nop block 6
- asm volatile ("nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\n");
- N64_HIGH;
- }
- void N64_get()
- {
- // listen for the expected 8 bytes of data back from the controller and
- // blast it out to the N64_raw_dump array, one bit per byte for extra speed.
- // Afterwards, call translate_raw_data() to interpret the raw data and pack
- // it into the N64_status struct.
- asm volatile (";Starting to listen");
- unsigned char timeout;
- char bitcount = 32;
- char *bitbin = N64_raw_dump;
- // Again, using gotos here to make the assembly more predictable and
- // optimization easier (please don't kill me)
- read_loop:
- timeout = 0x3f;
- // wait for line to go low
- while (N64_QUERY) {
- if (!--timeout)
- return;
- }
- // wait approx 2us and poll the line
- asm volatile (
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- );
- *bitbin = N64_QUERY;
- ++bitbin;
- --bitcount;
- if (bitcount == 0)
- return;
- // wait for line to go high again
- // it may already be high, so this should just drop through
- timeout = 0x3f;
- while (!N64_QUERY) {
- if (!--timeout)
- return;
- }
- goto read_loop;
- }
- #ifdef ENABLE_SERIAL
- void print_N64_status()
- {
- char out[30];
- sprintf(out, "%i%i%i%i%i%i%i%i%i%i%i%i%i%i %i %i",
- N64_status.data1&16?1:0,
- N64_status.data1&32?1:0,
- N64_status.data1&64?1:0,
- N64_status.data1&128?1:0,
- N64_status.data2&32?1:0,
- N64_status.data2&16?1:0,
- N64_status.data2&0x08?1:0,
- N64_status.data2&0x04?1:0,
- N64_status.data2&0x01?1:0,
- N64_status.data2&0x02?1:0,
- N64_status.data1&0x08?1:0,
- N64_status.data1&0x04?1:0,
- N64_status.data1&0x01?1:0,
- N64_status.data1&0x02?1:0,
- N64_status.stick_x,
- N64_status.stick_y);
- Serial.println(out);
- }
- #endif ENABLE_SERIAL
- void translate_raw_data()
- {
- memset(&N64_status, 0, sizeof(N64_status));
- for (int i = 0; i < 8; i++) {
- N64_status.data1 |= N64_raw_dump[i] ? (0x80 >> i) : 0;
- N64_status.data2 |= N64_raw_dump[8 + i] ? (0x80 >> i) : 0;
- N64_status.stick_x |= N64_raw_dump[16 + i] ? (0x80 >> i) : 0;
- N64_status.stick_y |= N64_raw_dump[24 + i] ? (0x80 >> i) : 0;
- }
- }
- void N64toGC()
- {
- gc_Buffer[0] = gc_Buffer[1] = 0;//no buttons
- gc_Buffer[1] |= 1 << 7;//dummy
- gc_Buffer[4] = 128;//c stick centered
- gc_Buffer[5] = 128 + (N64_status.data2 & 32 ? -127 : 0) + (N64_status.data2 & 0x08 ? 127 : 0);//l, c up -> c stick down, c stick up
- gc_Buffer[0] |= (N64_status.data1 & 16 ? 1 : 0) << 4;//start -> start
- gc_Buffer[1] |= (N64_status.data1 & 32 ? 1 : 0) << 6;//z -> l
- gc_Buffer[0] |= (N64_status.data1 & 64 ? 1 : 0) << 1;//b -> b
- gc_Buffer[0] |= (N64_status.data1 & 128 ? 1 : 0) << 0;//a -> a
- gc_Buffer[1] |= (N64_status.data2 & 16 ? 1 : 0) << 5;//r -> r
- gc_Buffer[1] |= (N64_status.data2 & 0x04 ? 1 : 0) << 4;//c down -> z
- gc_Buffer[0] |= (N64_status.data2 & 0x01 ? 1 : 0) << 2;//c right -> x
- gc_Buffer[0] |= (N64_status.data2 & 0x02 ? 1 : 0) << 3;//c left -> y
- gc_Buffer[1] |= (N64_status.data1 & 0x08 ? 1 : 0) << 3;//up -> up
- gc_Buffer[1] |= (N64_status.data1 & 0x04 ? 1 : 0) << 2;//down -> down
- gc_Buffer[1] |= (N64_status.data1 & 0x01 ? 1 : 0) << 1;//right -> right
- gc_Buffer[1] |= (N64_status.data1 & 0x02 ? 1 : 0) << 0;//left -> left
- gc_Buffer[2] = (N64_status.stick_x + 128);//stick x -> stick x
- gc_Buffer[3] = (N64_status.stick_y + 128);//stick y -> stick z
- }
- void getN64()
- {
- unsigned char command[] = {0x01};
- unsigned char command2[] = {0x01};
- // don't want interrupts getting in the way
- noInterrupts();
- // send those 3 bytes
- N64_send(command, 1);
- // read in data and dump it to N64_raw_dump
- N64_get();
- interrupts();
- }
- void gc_Send(unsigned char *buffer, char length, bool wide_stop)
- {
- asm volatile (";Starting GC Send Routine");
- // Send these bytes
- char bits;
- bool bit;
- // This routine is very carefully timed by examining the assembly output.
- // Do not change any statements, it could throw the timings off
- //
- // We get 16 cycles per microsecond, which should be plenty, but we need to
- // be conservative. Most assembly ops take 1 cycle, but a few take 2
- //
- // I use manually constructed for-loops out of gotos so I have more control
- // over the outputted assembly. I can insert nops where it was impossible
- // with a for loop
- asm volatile (";Starting outer for loop");
- outer_loop:
- {
- asm volatile (";Starting inner for loop");
- bits = 8;
- inner_loop:
- {
- // Starting a bit, set the line low
- asm volatile (";Setting line to low");
- GC_LOW; // 1 op, 2 cycles
- asm volatile (";branching");
- if (*buffer >> 7) {
- asm volatile (";Bit is a 1");
- // 1 bit
- // remain low for 1us, then go high for 3us
- // nop block 1
- asm volatile ("nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\n");
- asm volatile (";Setting line to high");
- GC_HIGH;
- // nop block 2
- // we'll wait only 2us to sync up with both conditions
- // at the bottom of the if statement
- asm volatile ("nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\n"
- );
- } else {
- asm volatile (";Bit is a 0");
- // 0 bit
- // remain low for 3us, then go high for 1us
- // nop block 3
- asm volatile ("nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\n"
- "nop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\n");
- asm volatile (";Setting line to high");
- GC_HIGH;
- // wait for 1us
- asm volatile ("; end of conditional branch, need to wait 1us more before next bit");
- }
- // end of the if, the line is high and needs to remain
- // high for exactly 16 more cycles, regardless of the previous
- // branch path
- asm volatile (";finishing inner loop body");
- --bits;
- if (bits != 0) {
- // nop block 4
- // this block is why a for loop was impossible
- asm volatile ("nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\n");
- // rotate bits
- asm volatile (";rotating out bits");
- *buffer <<= 1;
- goto inner_loop;
- } // fall out of inner loop
- }
- asm volatile (";continuing outer loop");
- asm volatile ("nop\nnop\nnop\nnop\n");
- // In this case: the inner loop exits and the outer loop iterates,
- // there are /exactly/ 16 cycles taken up by the necessary operations.
- // So no nops are needed here (that was lucky!)
- --length;
- if (length != 0) {
- asm volatile ("nop\nnop\nnop\nnop\n");
- ++buffer;
- goto outer_loop;
- } // fall out of outer loop
- }
- // send a single stop (1) bit
- // nop block 5
- asm volatile ("nop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\n");
- GC_LOW;
- // wait 1 us, 16 cycles, then raise the line
- // take another 3 off for the wide_stop check
- // 16-2-3=11
- // nop block 6
- asm volatile ("nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\n"
- "nop\nnop\nnop\nnop\n");
- if (wide_stop) {
- asm volatile (";another 1us for extra wide stop bit\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\n");
- }
- GC_HIGH;
- }
- void get_GC_Command(int ms) {
- gc_Command = 0x00;
- int bitcount;
- char *bitbin = gc_Raw_Dump;
- int idle_wait;
- int test = 2500;
- func_top:
- gc_Command = 0;
- bitcount = 8;
- if (ms > 0) {
- while (test > 0) {
- if (!GC_QUERY) {
- needCommand = true;
- goto read_jump;
- }
- test--;
- }
- if (needCommand == false) {
- return;
- }
- }
- // wait to make sure the line is idle before
- // we begin listening
- if (needCommand == false) {
- for (idle_wait = 32; idle_wait > 0; --idle_wait) {
- if (!GC_QUERY) {
- idle_wait = 32;
- }
- }
- }
- read_loop:
- // wait for the line to go low
- while (GC_QUERY) {}
- read_jump:
- // wait approx 2.5us and poll the line
- asm volatile (
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\n"
- );
- if (GC_QUERY)
- gc_Command |= 0x01;
- --bitcount;
- if (bitcount == 0)
- goto read_more;
- gc_Command <<= 1;
- // wait for line to go high again
- // I don't want this to execute if the loop is exiting, so
- // I couldn't use a traditional for-loop
- while (!GC_QUERY) {}
- goto read_loop;
- read_more:
- if (gc_Command == 0x40) {
- bitcount = 1;
- } else {
- bitcount = 1;
- }
- // make sure the line is high. Hopefully we didn't already
- // miss the high-to-low transition
- while (!GC_QUERY) {}
- read_loop2:
- for (idle_wait = 12; idle_wait > 0; --idle_wait) {
- if (!GC_QUERY) {
- idle_wait = 12;
- }
- }
- return;
- // wait for the line to go low
- while (GC_QUERY) {}
- // wait approx 2.5us and poll the line
- asm volatile (
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\nnop\nnop\n"
- "nop\nnop\nnop\n"
- );
- if (GC_QUERY) {
- //gc_Command |= 0x01;
- //goto bit_test;
- }
- --bitcount;
- if (bitcount == 0) {
- //wait for the line to go high
- while (!GC_QUERY) {}
- return;
- }
- gc_Command <<= 1;
- // wait for line to go high again
- while (!GC_QUERY) {}
- goto read_loop2;
- bit_test:
- if (!GC_QUERY) {
- //Serial.println(bitcount);
- gc_Command = 0xEE;
- return;
- }
- test--;
- if (test > 0) {
- goto bit_test;
- }
- return;
- }
- #ifdef ENABLE_JOYSTICK
- void update_joystick()
- {
- int i;
- signed char jx=0,jy=0;
- jx|=(unsigned char)N64_status.stick_x;
- jy|=(unsigned char)N64_status.stick_y;
- float JX=jx;
- float JY=-jy;
- Gamepad.xAxis(4096 * 4 + JX);
- Gamepad.yAxis(4096 * 4 + JY);
- for(i=0;i<8;i++)
- {
- if (N64_raw_dump[i])
- Gamepad.press(i+1);
- else
- Gamepad.release(i+1);
- }
- for(i=0;i<6;i++)
- {
- if (N64_raw_dump[10+i])
- Gamepad.press(i+9);
- else
- Gamepad.release(i+9);
- }
- unsigned char pov_byte=N64_status.data1&0x0F;
- int pov=-1;
- switch (pov_byte)
- {
- default: //Centered
- pov=0;
- break;
- case 1: //RIGHT
- pov=3;
- break;
- case 2: //LEFT
- pov=7;
- break;
- case 4: //DOWN
- pov=5;
- break;
- case 8: //UP
- pov=1;
- break;
- case 10: //UP-LEFT
- pov=8;
- break;
- case 6: //DOWN-LEFT
- pov=6;
- break;
- case 9: //UP-RIGHT
- pov=2;
- break;
- case 5: //DOWN-RIGHT
- pov=4;
- break;
- }
- Gamepad.dPad1(pov);
- }
- #endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement