You went over my head that time...
Ok ill reveal more of my code so you can see what im working with, the code is derived from a sketch made by someone else. their method use a few steps.
1. gc_get(); //this creates a gc_raw_dump array
2. gc_translate_raw_data(); //this takes the raw dump, assembles the bits into bytes and puts it into struct gc_status
Here is the way the author defined these things:
#define GC_PIN 19
#define GC_PIN_DIR DDRD
// these two macros set arduino pin 2 to input or output, which with an
// external 1K pull-up resistor to the 3.3V rail, is like pulling it high or
// low. These operations translate to 1 op code, which takes 2 cycles
#define GC_HIGH DDRD &= ~0x04
#define GC_LOW DDRD |= 0x04
#define GC_QUERY (PIND & 0x04)
//refers to PD3 on ATMega2560
// 8 bytes of data that we get from the controller
struct {
// bits: 0, 0, 0, start, y, x, b, a
unsigned char data1;
// bits: 1, L, R, Z, Dup, Ddown, Dright, Dleft
unsigned char data2;
unsigned char stick_x;
unsigned char stick_y;
unsigned char cstick_x;
unsigned char cstick_y;
unsigned char left;
unsigned char right;
}
gc_status;
char gc_raw_dump[65]; // 1 received bit per byte
// Zero points for the GC controller stick
unsigned char zero_x;
unsigned char zero_y;
void gc_send(unsigned char *buffer, char length);
void gc_get();
void print_gc_status();
void translate_raw_data();
void translate_raw_data()
{
// The get_gc_status function sloppily dumps its data 1 bit per byte
// into the get_status_extended char array. It's our job to go through
// that and put each piece neatly into the struct gc_status
int i;
memset(&gc_status, 0, sizeof(gc_status));
// line 1
// bits: 0, 0, 0, start, y, x, b a
for (i=0; i<8; i++) {
gc_status.data1 |= gc_raw_dump[i] ? (0x80 >> i) : 0;
}
// line 2
// bits: 1, l, r, z, dup, ddown, dright, dleft
for (i=0; i<8; i++) {
gc_status.data2 |= gc_raw_dump[8+i] ? (0x80 >> i) : 0;
}
// line 3
// bits: joystick x value
// These are 8 bit values centered at 0x80 (128)
for (i=0; i<8; i++) {
gc_status.stick_x |= gc_raw_dump[16+i] ? (0x80 >> i) : 0;
}
for (i=0; i<8; i++) {
gc_status.stick_y |= gc_raw_dump[24+i] ? (0x80 >> i) : 0;
}
for (i=0; i<8; i++) {
gc_status.cstick_x |= gc_raw_dump[32+i] ? (0x80 >> i) : 0;
}
for (i=0; i<8; i++) {
gc_status.cstick_y |= gc_raw_dump[40+i] ? (0x80 >> i) : 0;
}
for (i=0; i<8; i++) {
gc_status.left |= gc_raw_dump[48+i] ? (0x80 >> i) : 0;
}
for (i=0; i<8; i++) {
gc_status.right |= gc_raw_dump[56+i] ? (0x80 >> i) : 0;
}
}
void gc_get()
{
// listen for the expected 8 bytes of data back from the controller and
// blast it out to the gc_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 gc_status struct.
asm volatile (";Starting to listen");
unsigned char timeout;
char bitcount = 64;
char *bitbin = gc_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 (GC_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 = GC_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 (!GC_QUERY) {
if (!--timeout)
return;
}
goto read_loop;
}
As of now my robot implements this code like this:
void loop {
int i;
unsigned char data, addr;
// clear out incomming raw data buffer
// this should be unnecessary
//memset(gc_raw_dump, 0, sizeof(gc_raw_dump));
//memset(n64_raw_dump, 0, sizeof(n64_raw_dump));
// Command to send to the gamecube
// The last bit is rumble, flip it to rumble
// yes this does need to be inside the loop, the
// array gets mutilated when it goes through gc_send
unsigned char command[] = {
0x40, 0x03, 0x00 };
if (rumble) {
command[2] = 0x01;
}
// turn on the led, so we can visually see things are happening
digitalWrite(13, HIGH);
// don't want interrupts getting in the way
noInterrupts();
// send those 3 bytes
gc_send(command, 3);
// read in data and dump it to gc_raw_dump
gc_get();
// end of time sensitive code
interrupts();
digitalWrite(13, LOW);
translate_raw_data();
bool gc_start = (gc_status.data1 & 0x10 ? 1:0);
bool gc_y = (gc_status.data1 & 0x08 ? 1:0);
bool gc_x = (gc_status.data1 & 0x04 ? 1:0);
bool gc_b = (gc_status.data1 & 0x02 ? 1:0);
bool gc_a = (gc_status.data1 & 0x01 ? 1:0);
bool gc_l = (gc_status.data2 & 0x40 ? 1:0);
bool gc_r = (gc_status.data2 & 0x20 ? 1:0);
bool gc_z = (gc_status.data2 & 0x10 ? 1:0);
bool gc_dUP = (gc_status.data2 & 0x08 ? 1:0);
bool gc_dDOWN = (gc_status.data2 & 0x04 ? 1:0);
bool gc_dRIGHT = (gc_status.data2 & 0x02 ? 1:0);
bool gc_dLEFT = (gc_status.data2 & 0x01 ? 1:0);
int gc_xJoy = (gc_status.stick_x);
int gc_yJoy = (gc_status.stick_y);
int gc_xCjoy = (gc_status.cstick_x);
int gc_yCjoy = (gc_status.cstick_y);
int gc_lTrig = (gc_status.left);
int gc_rTrig = (gc_status.right)
}
as you can see, the only way for me to easily use the button values in my code is by referencing a part of the gc_status struct and the saving it as a int for easy access.
To make it easier for the end-user, id like to simply have them implement a read and translate command like so:
#include "GCtroller.h"
GCpad controller1(19);
void setup() {
controller1.init(); //code to prepare pins and confirm comms.
}
void loop() {
controller1.read(); //includes void gc_get and other supporting commands
controller1.translate(); // translates and places data in an understandable format
controller1.start(); //returns start button state
controller1.JoyX(); //returns JoyX position
}
I guess my main problem is what do I do with that gc_status struct? Can I make it private and write to it using the translate command? That would allow it maintain its data whether there are 1 or 2 controllers correct?
But can you even put a struct in a class?
If you can is it silly to do so?
Or should I just take the entries from the struct and place them as declarations in private and then remove the struct?