[abandoned] using attachInterrupt that uses a member function in a library

I know that there are literally dozens of posts on this already and I have read them but I just don't seem to understand what exactly they are saying. I am hoping that one of you our there in the genius sphere can explain it like you were teaching a small semi-literate child.

I have been reading and experimenting all day and the more I read on the forums the more confused I get and the more I experiment the more frustrated I am becoming. I am completely baffled as to what exactly is the problem and why I can't make this work.

Here's my issue. I am writing a library that includes an interrupt. Inside this interrupt I need to call a function from the library. Every time I try it throws out different error message which don't make any since to me. For instance it says that it can't call member function without object but the member function being called is in an object. I know I'm doing something stupid because there is no way it is this difficult. In Arduino this would be a piece of cake but trying to move some of my code over to libraries has proven to be quite a different issue. Here's a sample code of what I want to do. Can someone please tell me what in the world I need to do to make it work.

*.h

class CharlieLibrary{
	public:
	
	CharlieLibrary();
	
	void DoStuff();
	static void InterruptStuff();
};

*.cpp

#include <CharlieLibrary.h>

CharlieLibrary::CharlieLibrary(){
	attachInterrupt(2,InterruptStuff,RISING);
}
	
void CharlieLibrary::DoStuff(){
	//	do important stuff
	
	Serial.println("please God compile")
}

static void CharlieLibrary::InterruptStuff(){
	DoStuff();
}

Arduino code

CharlieLibrary test;

void Setup(){
	Serial.begin(9600);
}

I am hoping that one of you our there in the genius sphere can explain it like you were teaching a small semi-literate child.

You can't use a member function as an ISR unless it is a static member. It's that simple.

If it is a static member then it doesn't have access to any of the non-static member variables.

The problem is like this:

Imagine you have an animal class, and it defines an interrupt. You have two instances, cat and dog. An ISR can take no parameters and it can return no values. All it can do is run code. So if there is an ISR in the animal class and it gets triggered, which instance of the function should it call? The one in cat or the one in dog? You'd have to pass an argument to tell it which one and an ISR can't take any arguments.

In your case you have a static member function. great, so all instances of the class share that function. There's no ambiguity and that function can be an ISR.

But that function tries to call a member function. You can't do that without having an instance of the class.

And that's the why.

How to fix is simple. Define a function that isn't part of the class that calls the class function you want to call. Unless your library already defines an instance of the class, then this will probably have to be done in the sketch because you'll need the instance.

OR

Make the whole class static. That means everything. That means that you can only ever have one instance of the class in any program. That might be your intention. I don't know.

SO do you want to be able to have more than one CharlieLibrary instance in your program? Or will there only ever be one?

If one, then you can make the whole thing static, but it would probably be easier to just write the library without the class.

Thank you so much for the rapid response and I apologize for not replying back sooner, I might have fallen asleep at my desk. I think I understand the concept that you are conveying, and I don't want to sound overly dumb or intentionally obtuse but I can't quite grasp the solution you provided for how to fix it. I will start by answering your question about what my goal or rather what I'm trying to accomplish is. Currently my code is 8000+ lines across 12 different tabs in Arduino controlling an army of automated functions and pieces of the code are used across a variable menagerie of devices. I want to take a few thousand lines of that code that is used throughout my systems and convert it to various libraries to make each of the individual device codes less cumbersome and easy to trouble shoot without dealing with code that has nothing to do with the current task.

While my ISR is short it still needs to modify some global variables, read or write to one of my spi devices, and flip some flags that I have. I am only calling a single instance of the class to which all of these functions are members, but there are a number of global variables that get changed within the class. I will openly admit that I am probably the worlds weakest programmer when it comes to classes and objects.

I just can't seem to translate the solutions you provided into actual code.

In my mind I read your solution and I think ok this must be the solution, but it just causes other errors.

*.h

static void InterruptStuff();

class CharlieLibrary{
	public:
	
	CharlieLibrary();
	
	void DoStuff();
};

*.cpp

#include <CharlieLibrary.h>

static void InterruptStuff(){
	CharlieLibrary::DoStuff();
}


CharlieLibrary::CharlieLibrary(){
	attachInterrupt(2,InterruptStuff,RISING);
}
	
void CharlieLibrary::DoStuff(){
	//	do important stuff
	
	Serial.println("please God compile")
}

Arduino Code:

CharlieLibrary test;

void Setup(){
	Serial.begin(9600);
}

Is there any chance you know of an example code online somewhere that shows this being done. Please forgive me for not knowing or understanding this. I am very much still learning.

Serial is a good example of the kind of thing you need to do. There is only ever one Serial. You don't create it. It's already created for you. It uses interrupts to do its work. Those interrupts call the one-and-only Serial object to do work.

Not that I'm suggesting you dig into the Serial library to understand it - it's too complex for a beginner. Something like SPI may be easier to understand. If you open up the SPI library, you will see how it creates an SPI object for you inside the .h file.

So your complex system that you don't want to share, does it have only one of these special objects? Or do you create a new one for each sensor or whatever?

You're going to hate me for this. But I'm going to tell you how to fix it and then I'm going to tell you why you need to start over instead of fixing it.

static void InterruptStuff(){
	CharlieLibrary::DoStuff();
}

Since DoStuff() isn't static, you can't call it like that. You have to have an instance of the class.

Step 1: Get rid of the constructor and put this line in a function you can call from setup:

CharlieLibrary::CharlieLibrary(){
	attachInterrupt(2,InterruptStuff,RISING);
}

Then add the static keyword to DoStuff and have your interrupt call that directly.

But wait, next post has more. You got bigger problems.

global variables that get changed within the class

No no no no no no no no no.

Classes ONLY modify what they own. Classes should not need anything that doesn't live in them. While it will technically work that way, it's really bad practice and it will bite you in the end. This is a recipe for very confusing code. Far worse than just having a big huge thing that's hard to look for. Nothing is worse than a variable getting modified where you don't expect it to.

If this code needs to interact with the rest of your code in that way then you need to just make it not a class. You can make a library that doesn't contain a class. Most do, but it isn't a rule.

I would make it a namespace so you know it won't clash with any other names. So you can still have that advantage of the class.

But if it needs to interact with global variables then it either needs to take pointers to those as members or it needs to not be a class. In your case, it really needs to be not a class.

While my ISR is short it still needs to modify some global variables, read or write to one of my spi devices, and flip some flags that I have.

Be very sure you know what you're doing before you mess with SPI in the ISR. It's not like Serial where you can't do it at all. But there are some considerations there if you don't want to lose transmissions.

static void InterruptStuff();

class CharlieLibrary{
	public:
	
	CharlieLibrary();
	
	void DoStuff();
};

One last item I forgot. InterruptStuff shouldn't be static. Since it isn't part of a class the static means something different here. Here it means that it is only available inside this one file. So that will keep you from calling it from your main code.

Hi Morgan,

Thank you for the recommendation on the SPI library, and fair enough for calling me out on not sharing my entire code. I unfortunately can't share it because the person I developed it for is a little paranoid about IP and I'm trying to respect his wishes, even though he ignored me when I told him to hire a professional programmer rather than a physicist. Plus who would want to sort through that monstrosity of a program :). I figured the example code I provided would demonstrate both my problem and my objective. I apologize if it is inadequate to the task.

This is object is the only one that has to handle interrupts. All of the other ones do far more simple tasks, just lots and lots of different ones. The object in questions is handling my wireless communications and dynamic mesh networking. Using it in the Arduino code works flawlessly but my plan to simplify my code by making it into libraries has had pretty much the exact opposite effect and made it far more complicated. Well for now anyway.

Hi Delta_G,

Perhaps I misspoke or misunderstand objects (which is truly more likely). All of the variables being modified are called and created within the object. Inputs and outputs from methods being used by other functions libraries or the main code are done using pointers. I like the idea of not using classes at all. I am definitely going to look into that.

if I'm being honest though another hour of this frustration and I will just leave the massive code sections exactly as they are with a whole slew of extra tabs. It's just irritating if I do change something in one Arduino program to have to go device code by device code and make the same change to the same tab in each of the different programs.

All of the variables being modified are called and created within the object.

So why you call them globals then?

I unfortunately can't share it because the person I developed it for is a little paranoid about IP and I'm trying to respect his wishes,

Sorry I don't work on things that aren't open source. You'll have to find someone else to help you.

Tell your friend he is stupid. Hiding the code isn't how you make money in this game. If you hide the code someone like me will copy it. It is inevitable. I don't need to be able to see your source to copy your code. I can just look at how the device works if I want it. Keeping the code a secret used to be the way, but it just doesn't work like that anymore. Unless you're microsoft or google or someone with armies of coders that can stay ahead of people like me, then all you're doing by keeping the code secret is guaranteeing that it won't sell long. Pretty soon they'll be building copies with my free software. Or someone like me.

And judging from the types of questions you are asking, you're not going to write code I (or someone like me) can't just replicate. Protect your IP, but the code isn't the part that matters. I can have that if you share it or not. At least if it is open source you get to keep the credit.

Especially after you advertise here that you’re ok with abusing the open source community for your free programming department. A bit like hitting up the soup kitchen to save on food for your restaurant. I’m here to help people learn to code and make cool projects, not to help people make money off my work without paying me.

Look, I didn't mean to offend you. I'm just being respectful of him the same as I'm being respectful of you and your expertise. I'm sorry it's not open source. I wouldn't figure that with the brain power you clearly have, to just take anyone's code you want on a whim, you wouldn't need a full program to answer what for you should be a simple question like "how do I use interrupts in a library?" You are clearly quite angry that they don't want me sharing their code and have an ax to grind with people that prefer to at least attempt to protect their IP.

Whatever hostility you have towards software IP protection, please direct your anger at Microsoft, Google, or some other global power player, not at fledging new comers who don't know anything yet.

At one point in your life you didn't know how to do this either, and you probably didn't have the same level of bravado in your coding that you have now. I respect other peoples IP just as I respect them, so if I ever get as good at this as you are, and I happen to run across something that you wrote, I won't try to take it. That would just be rude. I appreciate your help so far, but I think I'll take my inquiry else where.

Not hostility. Not angry. Just don't like being taken advantage of.

and I happen to run across something that you wrote, I won't try to take it. That would just be rude

Why would that be rude? My code is open source. You're free to use it as you like. Just respect the license on anything that I've put license on.

See, that's the key. It's not about keeping it secret. If you keep it secret and I copy it then there's nothing you can do. If you open source it and license it and I copy it then you can sue me if I use it in a way you don't like. Sounds backwards, but that's the way things work.

Be smart if you really want to protect IP.

I'm not mad, I'm just telling you that your friend is mistaken if he thinks he is protecting anything this way.

I do hope that you don't feel taken advantage of, I'm just trying to learn, which I believe is the point of these forums. In this case I'm trying to learn libraries in the hopes of making future programming easier. I will convey your suggestion about licensing, as it sounds like excellent advice, but until he changes his mind, I'm bound by my word.

Charlie1985:
I do hope that you don't feel taken advantage of

I do. I feel like someone wanted to cheap out on hiring a programmer and decided to try to use me for free.

To me it is just like going to the Salvation Army and pretending to be poor so you can get free clothes to stock your second hand store.

I’m not here to make profits for other people unless they’re paying me. The free help (at least from me) is for people just learning to code and making cool stuff and sharing it.

So to be clear you feel taken advantage of by someone asking for help online in an open forum that is meant to be used by people asking for help on problems.

if someone is asking for help and you don't want to be of assistance perhaps you should consider not responding. Then you won't feel taken advantage of.

You chose to respond to a question that I posted. If you only want to be paid for your advice then get payment upfront and don't reply to people asking for help in a free forum

Asking for help in a public forum isn't taking advantage of anyone. I was just being polite but I think you should really do a personal inventory on your belief system.

again I apologize that you feel slighted but I see no problem in posting a question to get advice or thoughts