0

I'm trying to create a class that uses attachInterrupt, but get this error msg:

 In member function 'void ledDoor::attach()':
ClosetLedStrip:31:82: error: invalid use of non-static member function
         attachInterrupt(digitalPinToInterrupt(_sensorPin), detection_door, CHANGE);
                                                                                  ^
exit status 1
invalid use of non-static member function

I found few answers regarding static member, but it was not clear for my needs.

Appreciate help,

#define USE_SLEEP true

#if USE_SLEEP
#include <avr/sleep.h>
#endif

#define sensorPin_1 2
#define sensorPin_2 3
#define RelayON HIGH
#define doorOpen HIGH

#define pwrdown_timeOut 10*(1000*60) // mins to powerdown

// volatile boolean detectDoor_1_Open = false;
//volatile boolean detectDoor_2_Open = false;
const int relayPin1 = 4;
const int relayPin2 = 5;


class ledDoor {




private:
int _sensorPin;
int _interruptPin;
int _relPin;

void  attach(){
        attachInterrupt(digitalPinToInterrupt(_sensorPin), detection_door, CHANGE);
}

void detection_door(){
    #if USE_SLEEP
        sleep_disable();
    #endif

        detachInterrupt(digitalPinToInterrupt(_sensorPin));
        if (digitalRead(_sensorPin) == doorOpen) {
                _doorOpen = true;
        }
        else {// trun off
                _doorOpen = false;
        }
        attach();
}

public:
bool volatile _doorOpen;
ledDoor(int sensorPin, int relPin){
        _sensorPin=sensorPin;
        _relPin=relPin;

        pinMode(_relPin, OUTPUT);
        pinMode(_sensorPin, INPUT); // sensor io
        attach();
}
void go2sleep() {
  #if USE_SLEEP
        sleep_enable();
        set_sleep_mode(SLEEP_MODE_PWR_DOWN);
        sleep_cpu();
  #endif

}
void switchLeds(){
        if (_doorOpen == true) {
                digitalWrite(_relPin, RelayON);
        }
        else{
                digitalWrite(_relPin, !RelayON);
        }
}

};

ledDoor door1(sensorPin_1, relayPin1);
ledDoor door2(sensorPin_2, relayPin2);

void setup() {
        Serial.begin(9600);
        Serial.println("UP");    
}


void loop() {
        door1.switchLeds();
        door2.switchLeds();

  #if USE_SLEEP
        door1.go2sleep();
        door2.go2sleep();
  #endif
}
  • 1
    perhaps the reason that you cannot find a satisfactory answer is because you do not ask a question – jsotola May 6 '19 at 5:34
1

Firstly, if detection_door is a non-static member function, then C++ simply has no such expression syntax as just detection_door. Such functions have to either be called (with () operator) or be taken address of (with & operator). You can't just say detection_door. That's meaningless, which is what the compiler is telling you.

Secondly, as you already realized, regardless of the syntax a non-static class member function cannot be used as an interrupt handler. You need a freestanding ("ordinary") function as a handler or a static class member. Non-static class methods are beasts of completely different and incompatible nature.

I see that you have multiple ledDoor objects that you want to attach to interrupts independently.

At the level of attachInterrupt and void (void) handlers you will not be able to use a single interrupt handler function and then properly dispatch the handling to multiple individual objects. The high-level attachInterrupt mechanism is insufficient to work around this limitation in a proper way. (At ISR level you can do that, the same way Servo.h handles multiple servos, but it is more complicated.)

For this reason, in your case, as long as you want to stay at attachInterrupt level, it is better to just implement two separate interrupt handlers as external functions that will call your class methods for your existing global objects

ledDoor door1(sensorPin_1, relayPin1);
ledDoor door2(sensorPin_2, relayPin2);

void handler_door1()
{
  door1.detection_door();
}

void handler_door2()
{
  door2.detection_door();
}

and then just attach these handlers to your desired pins in a regular way.

static in this case can only change things in a purely cosmetic way.


On the second thought one can wrap the above into a quasi-elegant implementation that might look as follows

constexpr unsigned N_PINS = 16; // Range of attachable pin numbers

class ledDoor 
{
  // ...

  static ledDoor *self[N_PINS];
  static void (*const HANDLERS[N_PINS])();

  template <unsigned PIN> static void handler() 
  { // This is the actual interrupt handler that will dispatch the call to
    // the `detection_door` method of the proper class object
    self[PIN]->detection_door();
  }

  // ...

  void attach()
  {
    self[_sensorPin] = this;
    attachInterrupt(digitalPinToInterrupt(_sensorPin), HANDLERS[_sensorPin], CHANGE);
  }

  void detection_door()
  {
    // Your code
  }
};

And somewhere in one of the .cpp files

// Definitions and initializers for static members

ledDoor *ledDoor::self[N_PINS] = {};

void (*const ledDoor::HANDLERS[N_PINS])() = 
{
  ledDoor::handler<0>,
  ledDoor::handler<1>,
  // ...and so on...
  ledDoor::handler<15>
};

This uses a dedicated callback for each pin. Maybe a better idea would be to use interrupt number (i.e. the result of digitalPinToInterrupt) for indexing instead of pin number.

The same thing can be rewritten through lambdas instead of a template. I.e. one can get rid of ledDoor::handler<> template and instead initialize the HANDLERS array as

void (*const ledDoor::HANDLERS[N_PINS])() = 
{
  [](){ ledDoor::self[0]->detection_door(); },
  [](){ ledDoor::self[1]->detection_door(); },
  // ...and so on...
  [](){ ledDoor::self[15]->detection_door(); }
};

Note that this approach is a bit more memory wasteful that it could have been, since it uses a number of static tables of pre-determined size. In essense this is a slightly different implementation of the same "gluing" approach as described here.

|improve this answer|||||
  • Where do you write ‘AttachInterrupt’? – Guy . D May 1 '19 at 15:49
  • 1
    @Guy . D: Wherever you are ready to do that. In setup(), for example. – AnT May 1 '19 at 15:54

Not the answer you're looking for? Browse other questions tagged or ask your own question.