Trouble Setting ISR in Custom Library

Hi all,

Within the constructor of my cpp file, I'm trying to set an ISR to a function within the library. However, I get the error message

cannot convert 'RC::readreceiverhigh' from type 'void (RC::)()' to type 'void (*)()'

upon compilation. Is it not possible to call an ISR from within the library itself?

The relevant code:

attachInterrupt(ReceiverInterrupt_1, readreceiverhigh, RISING);
void RC::readreceiverhigh()
{
  RXTimerPoint1 = micros();
}

Any ideas? Thanks!

I'm trying to set an ISR to a function within the library.

Class functions are usually referred to a methods.

When the interrupt is triggered, which instance of the class is supposed to care?

While you might assert that there will only ever be one instance of the class, the compiler doesn't know that, and can not assure that that will always be the case.

Therefore, it is up to your class to decide which instance of the class cares, at the time that the interrupt happens.

You do that by making the callback function static, and in the callback function, invoking the proper instance's method.

If there will ever only be one instance of the class, is a class even needed?

Thanks for the reply,

What you've said is a little too foreign to me.

By making the callback function static, I get error messages that you can't do that.

By invoking the proper instance's method, do you mean to use the name of the class object when calling "readreceiverhigh"?

Thanks,
Chris

By making the callback function static, I get error messages that you can't do that.

I doubt that. More likely, you were told that you couldn't access non-static members of the class from a static function. That is true.

Suppose that you have a hotel, and the hotel has some employees that are instances of the Doorman class. A customer driving up is an interrupt, and is supposed to trigger a doorman to come running.

But which one? As a group (the Doorman class) needs to decide that. The class gets the interrupt, and decides which instance (which doorman) goes running.

That is the problem that you face. Some specific instance of the RC class needs to deal with the interrupt, but the class needs to decide which one.

In the doorman case, there is probably a doorman-on-duty pointer that keeps track of which instance is up. There would be static methods to allow a specific instance of the class to register as the doorman-on-duty, and to resign as the doorman-on-duty.

You need to implement a similar mechanism to allow a specific instance of the class to register as the instance to deal with the interrupt.

You've changed your code. You need to re-post it.

See: http://forum.arduino.cc/index.php?topic=311968.0

This has come up quite recently.

I made a post about calling an ISR from a class.

Thanks so much! That tutorial is great, I've bookmarked it. I'll implement glue routines in the future.

I think I've fixed it now, but I've run across another error:
In function RC::readreceiverhigh()': undefined reference to RC::RXTimerPoint1'
I'm not quite sure what I've done wrong, so I'm just going to post my code. I think that my variables, since they're static, should be visible, but it seems like they're not.

/*
  RC.cpp - Library for interacting with radio control equipment
  Created by Christopher Lansdale, September 4, 2015
  Version 1.0 - Last updated September 4, 2015
*/

#include "RC.h"

//Must declare your variables out here to see them in all the functions!!!!!!!
 float RXTimerPoint1;
 float RXTimerPoint2;
 float RXPulseLength;

int ReceiverInterrupt_1;
int ReceiverInterrupt_2;
int RXAllowPin;
int ArduinoAllowPin;

RC::RC(int RXInterrupt_1, int RXInterrupt_2, int RXAllowPinPassIn, int ArduinoAllowPinPassIn)
{
	ReceiverInterrupt_1 = RXInterrupt_1;
	ReceiverInterrupt_2 = RXInterrupt_2;
	RXAllowPin = RXAllowPinPassIn;
	ArduinoAllowPin = ArduinoAllowPinPassIn;

	attachInterrupt(ReceiverInterrupt_1, &readreceiverhigh, RISING);
	attachInterrupt(ReceiverInterrupt_2, &readreceiverlow, FALLING);

	pinMode(RXAllowPin, OUTPUT);
	pinMode(ArduinoAllowPin, OUTPUT);
}

void RC::readreceiverhigh()
{
  RXTimerPoint1 = micros();
}

void RC::readreceiverlow()
{
  if(RXTimerPoint1)
    {
      RXTimerPoint2 = micros();
      RXPulseLength = RXTimerPoint2 - RXTimerPoint1;

      SetRCOutputSource(ReadReceiver());
    }
}

int RC::ReadReceiver()
{
  if ((RXPulseLength > 1400)&&(RXPulseLength < 1700))
    {
      return(1);
    }
  if ((RXPulseLength < 1300) && (RXPulseLength > 1100))
    {
      return(0);
    }
  if ((RXPulseLength<1100)||(RXPulseLength>1700))
    {
      return(2);
    }
}

void RC::SetRCOutputSource (int TXRXorNeither)
{
  switch(TXRXorNeither)
  {
    case 0:
      digitalWrite(ArduinoAllowPin, HIGH);
      digitalWrite(RXAllowPin, LOW);
    break;
    
    case 1:
      digitalWrite(ArduinoAllowPin, LOW);
      digitalWrite(RXAllowPin, HIGH);
    break;

    case 2:
      digitalWrite(ArduinoAllowPin, LOW);
      digitalWrite(RXAllowPin, HIGH);
    break;
  }
}
/*
  RC.h - Library for interacting with radio control equipment
  Created by Christopher Lansdale, September 4, 2015
  Version 1.0 - Last updated September 4, 2015
*/

#ifndef RC_h
#define RC_h

#include "Arduino.h"

class RC
{
  public:
	RC(int RXInterrupt_1, int RXInterrupt_2, int RXAllowPinPassIn, int ArduinoAllowPinPassIn);

  private:
    static void readreceiverhigh();
	static void readreceiverlow();
	static void SetRCOutputSource(int TXRXorNeither);
	static int ReadReceiver();

	static float RXTimerPoint1;
	static float RXTimerPoint2;
	static float RXPulseLength;

	static int ReceiverInterrupt_1;
	static int ReceiverInterrupt_2;
	static int RXAllowPin;
	static int ArduinoAllowPin;
};


#endif

I'm going to do more research, but if you see something wrong, please point it out!

Your static class variables need to be declared, in RC.cpp as class variables. ie.

//Must declare your variables out here to see them in all the functions!!!!!!!
 float RC::RXTimerPoint1;
 float RC::RXTimerPoint2;
 float RC::RXPulseLength;

int RC::ReceiverInterrupt_1;
int RC::ReceiverInterrupt_2;
int RC::RXAllowPin;
int RC::ArduinoAllowPin;

You had them there without the "RC::" part. That made them ordinary (non-class) variables.

float RXTimerPoint1;
...
RXTimerPoint1 = micros();

You calculations based on RXtimerPoint1 are almost certainly not going to work as you expect due to that assignment....

Regards,
Ray L.