Pages: [1] 2   Go Down
Author Topic: How to use class-specific variables in a function?  (Read 1008 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 33
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
class GCpad
{
public:
  GCpad(int pin);
  void read();
  void translate();
private:
  int _pin;
};

void translate looks something like this:

Code:
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??
Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 547
Posts: 45954
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Offline Offline
Edison Member
*
Karma: 4
Posts: 1722
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

Germany
Offline Offline
Faraday Member
**
Karma: 49
Posts: 2718
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
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.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 33
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
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:
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??
« Last Edit: August 16, 2012, 10:53:28 am by Greenbean209 » Logged

Germany
Offline Offline
Faraday Member
**
Karma: 49
Posts: 2718
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.   
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 33
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

« Last Edit: August 16, 2012, 12:02:17 pm by Greenbean209 » Logged

UK
Offline Offline
Shannon Member
****
Karma: 183
Posts: 11114
-
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

I only provide help via the forum - please do not contact me for private consultancy.

Offline Offline
Newbie
*
Karma: 0
Posts: 33
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

California
Offline Offline
Faraday Member
**
Karma: 82
Posts: 3123
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
Class foo
{
  public:
    foo(int someVar);
  private:
    int myVar;
}

Code:
foo::foo(int someVar)
{
    myVar = someVar;
}
Logged

Des Moines, WA - USA
Offline Offline
God Member
*****
Karma: 25
Posts: 779
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

UK
Offline Offline
Shannon Member
****
Karma: 183
Posts: 11114
-
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

I only provide help via the forum - please do not contact me for private consultancy.

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Offline Offline
Newbie
*
Karma: 0
Posts: 33
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Pages: [1] 2   Go Up
Jump to: