Go Down

Topic: How to use class-specific variables in a function? (Read 1 time) previous topic - next topic

Greenbean209

I'm new to using classes and making libraries. I'm working on a project that desperately needs to be broken out. So I'm making a library and therefore creating a class that I can access my functions in.

The library is for communications via tx/rx with a GameCube controller

Basically I have a "read" function and a "translate" function. The read dumps bits and bytes into an array. Translate reorganizes the data into a struct array called gc_status.

to "see" the button statuses you would call gc_status.button1.

so here is a pseudo version of my class
Code: [Select]

class GCpad
{
public:
  GCpad(int pin);
  void read();
  void translate();
private:
  int _pin;
};


void translate looks something like this:

Code: [Select]

void translate() {
//bitwise and array stuff I dont quite understand
//eventually it produces something along these lines
gc_status.button1 = (some value);
};


What i would like to make the translate funtion at some point say "button1 = gc_status.button1" but how would I make it so that I can refer to button1 in the instance of the class. Such as:
GCpad controller1(pin)
and the button would be:
controller1.button1

How can I do this??

PaulS

Quote
How can I do this??

You have not provided near enough details on your class and struct. From what you have shown, there is no relationship between an instance of the GCpad class and anything with a button1 member. Nor does the class appear to have a gc_status member.

This is not snippets-are-us. They are down the road a ways. We want to see all of your code.

winner10920

That seems like you want a struct where you can have controller1.button1, controller1.button2, controller1.button3 etc
that should be a relatively simple c code thing however I only looked it up once and don't know the specifics of making a variable like that,
looking up struct on google should get you started atleast

michael_x

Quote
Such as:
GCpad controller1(pin)
and the button would be:   controller1.button1

How can I do this??


You can define a public member variable Button1 in your class:
and set it with your translate() member function
Code: [Select]
class GCpad
{
public:
bool button1;
void translate()
   {  ...
       button1 = HIGH;
   }
}


However, properties as you probably know them from other languages are hard to do in plain c++.
Either you don't mind having the variable settable from outside, or you rather have a method getButton().

BTW: a struct is a class (without methods), why not make your data struct just private variables of your class ?
If there are multiple instances of the class but only a global instance of the struct, make the data variables static.
But I understand you just use the class to have your library look Arduino style and support a single instance anyway.

Greenbean209

#4
Aug 16, 2012, 04:35 pm Last Edit: Aug 16, 2012, 05:53 pm by Greenbean209 Reason: 1

This is not snippets-are-us. They are down the road a ways. We want to see all of your code.


Calm yourself. The reason I dont post the whole code is because its horrible and I barely understand some of it. Like I said some functions desperately need to be broken out. I said pseudo code did I not?

Although I could be more clear..
Yes the struct is defined outside of the class. Data is dumped into it via the void translate(). The data in it can change after every read and every translate, making it a more volatile place. Not so good if you have more that one controller. Thats why id like to integrate in the translate function a way to store them as variables accessable by referencing controller1.button1. Do you get that?



You can define a public member variable Button1 in your class:
and set it with your translate() member function
Code: [Select]
class GCpad
{
public:
bool button1;
void translate()
  {  ...
      button1 = HIGH;
  }
}


However, properties as you probably know them from other languages are hard to do in plain c++.
Either you don't mind having the variable settable from outside, or you rather have a method getButton().

BTW: a struct is a class (without methods), why not make your data struct just private variables of your class ?
If there are multiple instances of the class but only a global instance of the struct, make the data variables static.
But I understand you just use the class to have your library look Arduino style and support a single instance anyway.


While yeah it would make sense to make the struct private, id rather not because I dont understand it fully, maybe sometime later. In the mean time its well enough to have it globally accessable. Id just like to pin down those values at a specific time.

So yes what you posted is very nearly what I want. I just wanted to make sure that if in my translate function I say "button1 = gc_status.data1"
When I try to reference button1 later, would I type. "controller1.button1"? following the way you stated in your code.

And yes exactly im making it look pretty. Someone else can come and optimize it when I finally post it, but im just trying to get it to work without taking up a global variable like "bool button1" ya know?

Edit: so what if I did this?:
Code: [Select]

class GCpad {
public:
  GCpad(int pin);
  struct gc_status {
      bool data1
      bool data2
      int data3
      };
  void translate();
private:
  int _pin;
};


If I wanted to reference data in that struct would I type
controller1.gc_status.data1??

michael_x

Quote
im just trying to get it to work without taking up a global variable like "bool button1" ya know?


No, dunno.

Quote
Data is dumped into it via the void translate(). The data in it can change after every read and every translate, making it a more volatile place. Not so good if you have more that one controller.


I understand internally you want to stick with a global variable, but you want to expose it as a member variable ?
Isn't that more complicated than necessary / useful ?
If more than one controller can change the same data you should read this global variable directly.

Alternatives:
-- bool GCpad::getButton() returns the value of that global variable.
-- its a static variable GCPad.button  common to all instances. Updated by any controller.
-- its a  bool&   ( reference ) type variable. 

Greenbean209

#6
Aug 16, 2012, 06:59 pm Last Edit: Aug 16, 2012, 07:02 pm by Greenbean209 Reason: 1
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:
Code: [Select]

#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:
Code: [Select]

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:
Code: [Select]

#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?


PeterH

Wouldn't it make more sense for your translate() method to return the translated results? Then you don't need the additional call to access the results, and your original question about how to store them becomes moot.
I only provide help via the forum - please do not contact me for private consultancy.

Greenbean209

For one thing I want to keep the translate raw data in function intact because I didn't write it. Second then the method would have to return an array of over 17 entries. Thirdly I'm working with the end user in mind so I would like to keep the methods for referencing the button states in "English".

Also I'm looking for an answer to my question of how can I implement variables?

Specifically if I define an int or bool in the public or private how do I write to it in a method? What would I write?

Arrch


Specifically if I define an int or bool in the public or private how do I write to it in a method? What would I write?

You mean like this?

Code: [Select]
Class foo
{
  public:
    foo(int someVar);
  private:
    int myVar;
}


Code: [Select]
foo::foo(int someVar)
{
    myVar = someVar;
}

lloyddean

I'm a big fan of completely cross platform (Wiring in this case) code of which this driver is not!

PeterH


Specifically if I define an int or bool in the public or private how do I write to it in a method? What would I write?


That part is easy and has been explained at least twice in this thread. But what you were trying to do in your original post seemed to be access a 'struct array' and it was unclear whether this was a struct, an array, a struct with an array in it, an array of structs, or what. Of course the syntax for dealing with that depends entirely on what your data structure is - and your code didn't include that.
I only provide help via the forum - please do not contact me for private consultancy.

Nick Gammon


This is not snippets-are-us. They are down the road a ways. We want to see all of your code.


I like it. Snippets-R-Us. Not.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

Nick Gammon


Also I'm looking for an answer to my question of how can I implement variables?

Specifically if I define an int or bool in the public or private how do I write to it in a method? What would I write?


You assign to it. What else would you do?
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

Greenbean209

I give up on this thread. But I'll call it solved because mister Arrch over there did answer my question. The whole deal with the struct, I now just going to replace it by defining its vars in the class.

Go Up