0

I am trying to disable some code based on whether the code creates an Object or not (or calls a function or whatever). Sounds a bit strange, I know.

In my library it is possible to create 2 objects, each object needs an interrupt service routine like:

ISR(TIMER0_COMPA_vect) {
  // do some stuff if the interrupt happens
}

The ISR can only be created once but it could be possible that the user just creates one or none of my objects, so the ISR shouldn't be created in the first place to not block the creation of one by the user. I know it would be easy to encapsulate the code like this

#ifdef OBJECT1
  ISR(TIMER0_COMPA_vect) {
    // do some stuff if the interrupt happens
  }
#endif

but that forces the user to keep track of the objects she/he created. Is there an option to let the preprocessor decide if, let's say, the constructor is called once or even existent? A little bit like something like this

Foo:Foo() {
  #define USE_FOO
  //Some code
}

#ifdef USE_FOO
ISR(TIMER0_COMPA_vect) {
  // do some stuff if the interrupt happens
}
#endif

EDIT:

Based on the answers i got, I try to clarify my question a bit:

Foo1:Foo1() {
    //Some object constructor code
}

Foo2:Foo2() {
    //Some object constructor code
}

ISR(TIMER1_COMPA_vect) {
    //some interrupt code
}

ISR(TIMER2_COMPA_vect) {
    //some interrupt code
}

int main() {
    Foo2 foo2;
}

If this is the code we are talking about, the function ISR(TIMER1_COMPA_vect) shouldn't be compiled at all. The ISR MUST be absent.

PS: if you need more information, I can provide more but I tried to keep the problem as basic as possible

Jarod42
  • 203,559
  • 14
  • 181
  • 302
0xhexdec
  • 17
  • 6
  • 1
    Are you trying to implement a Singleton (a class which can have only one instance alive at any given time)? Using macros is definitely not the way to do so. – Yksisarvinen Jul 20 '18 at 14:02
  • The problem is not the Object itself, the problem is the associated ISR. I'm not trying to implement the singleton pattern or something else like that. The problem is only the existance of the ISR function at runtime. If somebody creates an object, the ISR MUST be there, if the object is absence, it MUST NOT be there. – 0xhexdec Jul 20 '18 at 14:07
  • It smells of some bad design decisions. Why would unused function have any impact on the code? – Yksisarvinen Jul 20 '18 at 14:18
  • Well ISR isn't a function, it's a macro to enable the catch of interrupts and set the pointer to the defined function. In short: if an interrupt happens, the uC jumps immediately to the memory adress of the defined function. If i define the ISR and someone else wants to use the ISR in an other way, she/he can't because its already defined by me. – 0xhexdec Jul 20 '18 at 14:28
  • Split into library ? So you might expect the users using Foo1.dll to really Create Foo1 object. – Jarod42 Jul 20 '18 at 16:57

3 Answers3

1

Typically what you would do for this type of situation is compile the code for such an object into a library. The linker is smart enough to detect if your main program depends on any function from the library. If it does, it will load the entire compilation unit (i.e. the .c or .cpp file) of that function into your program. Any ISRs that it finds in the compilation unit will be added to your program. If you don't use any functions from the library, the ISRs will not be added.

For example, put something like this in foo1.h:

#pragma once
class Foo1 {
public:
  Foo1();
};

Put something like this in foo1.cpp:

#include <foo1.h>

ISR(TIMER1_COMPA_vect) {
}

Foo1::Foo1() {
}

Now you should compile foo1.cpp into foo1.o using avr-gcc. Next, use avr-ar to store foo1.o in an archive named foo1.a. Then, compile your main program with avr-gcc, and provide foo1.a as an argument. Make sure the foo1.a argument comes after main.cpp.

David Grayson
  • 84,103
  • 24
  • 152
  • 189
0

As you stated your problem sounds strange but if you want to do something only once let's say in the constructor you can go with a simple but very ugly thing like this using local static variable

Foo:Foo() {
  static bool init = true;
  if( init ) {
    //Some code for ISR init
    init = false;
  }
}

This way your special ISR initialization will take place only once, whatever the number of Foo object you or your user construct

EDIT:

I think there is no way to achieve what you want, at least no clean way.

Imo your problem comes from your ISR macro which actually does two things:

  • Initializing your ISR vector (ISR registration)
  • Defining your ISR handler (ISR handler)

To solve your problem I suggest you to split this into two macros then:

  • ISR registration goes in you Foo1 / Foo2 constructor -> use a global field or whatever mechanism to initialize only once or keep track internally of what has happened or so
  • Keep another macro ISR_HANDLER with only the handler definition

Your handlers can then remain defined and should have no influence if it is not registered by any of the Foo classes

floppy12
  • 1,045
  • 6
  • 12
0

You may need to create a singleton. There are numerous examples. A singleton is a class that constructs itself, once only. The constructors are private and a static method checks a "global" variable to see if the class has already been constructed if not it will construct itself once only. You will may need to consider threading issues although for construction you can simply reference the class early before you have created multiple classes. For multiple users of an interrupt you typically use some sort of dispatcher that the objects register with and then all classes interested in the interrupt are called. The dispatcher may be a singleton. Typically a client of a dispatcher implements an interface. As part of registration with the dispatcher the class tell the dispatcher its "this" pointer and the dispatcher can call the methods implemented from the interface as though they were called as normal. There is no need for the client to have static methods. There are probably patterns for this stuff but I cannot name any.