Pages: [1]   Go Down
Author Topic: Issue with passing objects to function  (Read 1041 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,

I'm trying to write a generic wait a certain time unless an event happens function where I can pass in the event happens function.  Here's what I've got so far (simplified).

Code:
boolean wait( unsigned long time,  boolean(*u)(void)) 
{
  return(u());
}

As an aside, I have created a class called Input which does similar stuff to the Button class.  I want to call the wait function like this example.

Code:
wait( 3000, Modeswitch.on );

Modeswitch is instantiated from Input and on returns true if conditions in the object are met.  I get the following compilation error

error: argument of type 'boolean (Input:smiley()' does not match 'boolean (*)()'

What am I doing wrong?  I've looked at many tutorials on passing objects/functions and I can't work this out.

Thanks
Jeff
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 549
Posts: 46113
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
error: argument of type 'boolean (Input:smiley()' does not match 'boolean (*)()'
I find it hard to believe that the compiler generated an error message with a smiley face in it.

Quote
What am I doing wrong?  I've looked at many tutorials on passing objects/functions and I can't work this out.
For starters, you are not posting any code.
Logged

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

Correct it didn't.  error: argument of type 'boolean (Input : : ) ( ) ' does not match 'boolean (*)()  Added spaces to avoid similes

Here's the code for Input Object - I'm assuming you don't need the header file.
Code:
/*
  Input.cpp
 */

#include "Arduino.h"
#include "Input.h"

Input::Input(byte pin, boolean invert)
{
  pinMode(pin,INPUT);
  _pin=pin;
  digitalWrite(pin,HIGH);
  _invert=invert;
  if(digitalRead(pin)==HIGH) _oldstate=__ON;
  else _oldstate=__OFF;
}


void Input::update()
{
  byte i;
  boolean state=false;
  for (i=0; i<25 ;++i)
  {
    if (digitalRead(_pin) == HIGH) state=true;
    delay(2);
  }
  // Update _oldstate with changes.
  if (_oldstate==__OFF && !state) _oldstate=__OFF;
  else if (_oldstate==__ON && state ) _oldstate=__ON;
  else if (_oldstate==__OFF && state) _oldstate=__PRESSED;
  else if(_oldstate==__PRESSED && state) _oldstate=__ON;
  else if(_oldstate==__ON && !state) _oldstate=__RELEASED;
  else if(_oldstate==__RELEASED && !state) _oldstate=__OFF;
  else  _oldstate=__OFF; // must be fault so reset to Off
}


boolean Input::on()
{
  update();
  if( _oldstate==__ON && !_invert) return(true);
  else if (_oldstate==__OFF && _invert) return(true);
  else return(false);
}


boolean Input::off()
{
  update();
  if( _oldstate==__OFF && !_invert) return(true);
  else if (_oldstate==__ON && _invert) return(true);
  else return(false);


and here's the program

Code:
#include "Relay.h"
#include "Input.h"

Relay Water(9,500,LOW);
Input Modeswitch(10, false);

boolean wait( unsigned long time,  boolean(*test)(void)) 
{
  unsigned long i;
  boolean temp=true;
  for (i=0;i<(time/50);++i)
    if(test())
    {
      temp=false;
      i=time;
    }
  return(temp);
}


void setup()
{
  Water.off();   
}


void loop()
{
  if (wait( 3000, Modeswitch.on ))
  {
    Water.on();
  }
  else Water.off();
  delay(2000);
}

Thanks.
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 549
Posts: 46113
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I'm assuming you don't need the header file.
Bad assumption. The header file is actually the most important piece.
Logged

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

Here it is

Code:
/*
  Input.h
*/
#ifndef Input_h
#define Input_h

#include "Arduino.h"

class Input {
  public:
   Input (byte pin, boolean invert);
   boolean on();
   boolean off();
  private:
   byte _pin;
   byte _oldstate;
   boolean _invert;
   void update();
};

#endif

Thanks
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 549
Posts: 46113
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I can't get your code to compile. The Relay.h and Relay.cpp files are missing. I commented out the instance and calls, and added a #include "Input.h" to the sketch. Still, I get:
Code:
Input.cpp: In constructor 'Input::Input(byte, boolean)':
Input.cpp:13: error: '__ON' was not declared in this scope
Input.cpp:14: error: '__OFF' was not declared in this scope
Input.cpp: In member function 'void Input::update()':
Input.cpp:27: error: '__OFF' was not declared in this scope
Input.cpp:28: error: '__ON' was not declared in this scope
Input.cpp:29: error: '__PRESSED' was not declared in this scope
Input.cpp:30: error: '__PRESSED' was not declared in this scope
Input.cpp:31: error: '__RELEASED' was not declared in this scope
Input.cpp:32: error: '__RELEASED' was not declared in this scope
Input.cpp: In member function 'boolean Input::on()':
Input.cpp:39: error: '__ON' was not declared in this scope
Input.cpp:40: error: '__OFF' was not declared in this scope
Input.cpp: In member function 'boolean Input::off()':
Input.cpp:47: error: '__OFF' was not declared in this scope
Input.cpp:48: error: '__ON' was not declared in this scope

What you need to do is make the methods that you want to pass to the wait function static. That means that there is just one instance of the method, not one per instance of the class. This, of course, means that the static methods can not access non-static instance data directly. So, the method needs some way of knowing what instance it is to operate on.
Logged

Essex, UK
Offline Offline
Full Member
***
Karma: 4
Posts: 150
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Your function pointer needs to be scoped to the class it's coming from. Adapt your code to this general pattern and it will work.

Code:
struct foo {
  bool func() {}
};

void bar(bool (foo::*)()) {
}

void usage() {
  bar(&foo::func);
}

Note that you can use plain function pointer syntax if you make the method static.

EDIT: since this area of C++ is one of the more mind-bending in terms of syntactical gymnastics. Here's a more complete example with an actual call being made:

Code:
struct foo {
  bool func() {}
} myfoo;

typedef bool (foo::*funcptr)();

void bar(foo& objref,funcptr methodptr) {
  (objref.*methodptr)();
}

void usage() {
  bar(myfoo,&foo::func);
}
« Last Edit: May 07, 2012, 06:24:34 am by Andy Brown » Logged

Home of the Nokia QVGA TFT LCD hacks: http://andybrown.me.uk

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

Thanks,  not pretending understand but I'll give it a go.

PaulS:  For some reason this was left off the cut-n-paste for Input.cpp.  It should compile with this in it.

Code:
const byte __ON=100;
const byte __OFF=101;
const byte __PRESSED=102;
const byte __RELEASED=103;
Logged

Seattle, WA
Offline Offline
God Member
*****
Karma: 8
Posts: 673
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Or you could simply make a global function "bool modeswitch_on() { return Modeswitch.on; }", and pass that into wait.  Probably going to make the code more understandable.
Logged


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

Thanks that seemed to compile.  Yet to test on board.

Andy:  Thanks for your input,  I couldn't get it to compile and thats really down to my lack of understanding of the syntax and your example.
Logged

Seattle, WA
Offline Offline
God Member
*****
Karma: 8
Posts: 673
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

As an aside...  Someday hopefully Arduino will turn on c++11, in which case we can do this:

Code:
  if (wait( 3000, []{ return Modeswitch.on; } ))
  {
    Water.on();
  }

Which is actually only a few characters away from exactly what you want to do.
Logged


Pages: [1]   Go Up
Jump to: