attach(class method)

27 Sep 2010

How does one attach a class method instead of a void (*fptr2)(void) static function? Like to the Ticker

 

Thanks Jason

27 Sep 2010

perhaps you could revive this thread to which I'm still hoping someone will answer (I actually gave up and just switched back from C++ to C)

http://mbed.org/forum/bugs-suggestions/topic/865/?page=1#comment-4349

27 Sep 2010 . Edited: 27 Sep 2010

Hi Jason

You need to provide an instance as well as the method name. In my example below, the instance is "this", the special case for the currently in use object ie. the attach is called from another method within the class called ElectricityMonitor.

 

    // attach ticker
    _sampleTicker.attach_us(this, &ElectricityMonitor::Sample, 1000000 / SAMPLE_FREQUENCY);


I hope that helps (not a C++ expert myself).

Regards
Daniel

27 Sep 2010 . Edited: 27 Sep 2010

Hi Jason, Andy,

Daniel has it spot on. To add to his example, here is one where you attach a different class method:

#include "mbed.h"

class Foo {
public:
    void bar() {}
};

Ticker t;
Foo f;

int main() {
    t.attach(&f, &Foo::bar, 1.0);
}

I know C++ method pointers are not intuitive at first. The main things you need to remember are:

  • To call a method, you need both the pointer to method/function, and the object to call it on
  • Pointers to methods include the type of the class i.e. a pointer to a void function of class Foo is not the same as on of class Bar, hence the need for templates (this is a really annoying *feature* of C++)

So, if you look at http://mbed.org/projects/libraries/api/mbed/trunk/Ticker.h#Ticker.attach you see the prototype is:

template<typename T>
void attach(T *tptr, void (T::*mptr)(void), float t)

So you pass the object (this) pointer "tptr" you are attaching to, and the pointer to the void method "mptr" you're attaching, which will be something like &Class::method.

Please say if this clears things up,

Simon

27 Sep 2010

Thanks Guys! :)

22 Oct 2010

Hi Simon,

OK, I've come back to this after some delay and I'm sorry to say that no, it hasn't cleared it up for me. The basic problem is that you have described how to call a .attach() function as a user. That I understand, always have. What I don't understand is how to store and use them.

To put it another way, I am writing a library. Other users will call my .attach method. How do I then store these two values in my class and, more importantly, how do I make a call to these methods from an extern "C" ISR? How does the C portion of an ISR resolve those two pieces of information into a callable address at runtime?

I've managed to do al of this using straight C function pointers without any problems. It's the class::method that I'm struggling with. All I've found from Google is that trying to resolve a "function address" of a class/method that a C function can call at runtime, well, not really an option.

Everyone knows that C++ can call C libraries using the extern "C" declaration, it's the opposite of this I'm trying to do and still can't see it.

I know you guys are not about to publish the source code for your Mbed libraries (I'm not even going to go down that road) but what would be useful is you publish, say, a cut down version of Ticker that shows (a) how you store the args passed to .attach() and then (b) how the ISR invokes that class/method when the interrupt occurs.

Help us "stand on the shoulders of giants" by publishing a "giant example" please :)   (yes, I read Elektor too)

 

 

22 Oct 2010

Hi Andy,

Ok, I understand your question now!

Yes, C++ is not very good at this, so I wrote something called FunctionPointer. This is a class that you can attach a static function or member function to, and call a method to invoke it. e.g.:

#include "mbed.h"

void foobar() {}

class Foo {
public:
    void bar() {}
};

Foo f;

FunctionPointer p;

int main() {
    p.attach(&foobar);
    p.call();
    p.attach(&f, &Foo::bar);
    p.call();
}
Hope that helps,

Simon

22 Oct 2010

Hi Simon,

Thanks for the quick reply. I'll have a play with FunctionPointer. Are there any docs on it or is it "an internal Mbed thing" that's there, just publicly undocumented?

Have to say, I've been writting embedded code and device drivers for 25yrs and I've basically always used a simple "rule of thumb" as to which tools I use to get something done. If it's a "desktop GUI" application then I go with C++ and a strong framework (usually Qt4), if it's a uC then it's ass/C. The thing about the Mbed is the "blur" between the two.

The project I've been working on is almost 99% C (there's some C++, but that's just machine independant libs). But what I would really like to do is convert those parts of my project that can be abstracted into a libraries that can be reused by others in a generalised way. The biggest problem is amlost everything in my project is interrupt driven in one manner or another (for example I'm using USB Host, all Uarts, both SSPs with multiple devices attached to each SSP, GPIOirqs, the list goes on!)

regards,

--Andy

11 Jan 2011

Simon,

Your answer to Andy helps me out for a similar issue I've been working on (allowing code to "attach" a member function to an interrupt service routine so that my library can call it when data is available), but I don't see a way to attach a function which takes parameters (or at least, I don't see how to pass the parameters with the "p.call()" syntax) e.g.:

#include "mbed.h"

void foobar( float x, y ) {}

class Foo {
public:
    void bar(float x,y) {}
};

Foo f;

FunctionPointer p;

int main() {
    p.attach(&foobar);
    float a = 0.1;
    float b = 1.3;
    p.call(a, b);
    p.attach(&f, &Foo::bar);
    p.call(a, b);
}

Is there any way to do this, or does my attached routine need to call back to the object to get the data it needs (which seems inefficient in an ISR), e.g.:

#include "mbed.h"

void foobar( void ) {
    float x = getXValue();
    float y = getYValue();
    ...
}

FunctionPointer p;

int main() {
    p.attach(&foobar);
    p.call();
}

Thanks,

-Owen

11 Jan 2011

Owen,

I used FunctionPointer.h for a while until I needed what you are trying to do. So I switched to something that looks like this:-

#include "mbed.h"

class myDummyClass;

class Foo {
  public:

    Foo() {
      obj = NULL;
      method = NULL;
    }

    int test(int a, int b) {
      int x = 0;
      if (obj && method) {
        x = (obj->*method)(a, b);
      }
      return x;
    }

    template<class T> 
    int myAttach(T* item, int (T::*method)(int, int)) {
        obj    = (myDummyClass *)item;
        method = (int (myDummyClass::*)(int, int))method;        
    }

  protected:
    myDummyClass  *obj;
    int (myDummyClass::*method)(int, int);
};

class Bar {
  public:
    int myCallback(int a, int b) { return a + b; }
};

int main() {
  Foo foo;
  Bar bar;

  foo.myAttach(&Bar, &Bar::myCallback);
  printf("Test = %d\n", foo.test(1, 2));
  while (1);
}

Haven't tested the above, it's just from memory. But it should give you the idea.

18 Jan 2011

I just published FPointer. Maybe of use.

19 Jan 2011

I also just created these two cookbook pages which maybe of use to others: /cookbook/FunctionPointer and /cookbook/FPointer