5

In a project that we intended to write in C++, we use a C-library. This C library provides functions to register callbacks, that are called on each interrupt. We register our callbacks inside the constructor. So we basically have the following (simplified) structure:

OurClass::OurClass() {
  //the registerISRCallback is the C function, that accepts as first parameter the pin,
  //the interrupt is expected on and as second parameter a function pointer:
  //void (*callbackFunction)(int number, int time)
  registerISRCallback(SCLK, handle_interrupt);
}

void OurClass::handle_interrupt(int pin, int time) {
  //example: Blink a Led on the instance-LedPin
}

the problem however is twofold:

  1. because it is a member function, the handle_interrupt method has the signature void (OurClass::*)(int, int). Therefore it is not possible to use it like this.
  2. this class can be instantiated multiple times, so using a singleton would also not work, because our callback may differ per instance (each instance could for example have a different LedPin.

are there any more solutions to use this C API function inside our class and keep the code clean and readable?

456c526f
  • 123
  • 6
  • 3
    its not only because of C. Also in C++ you'd need an instance to call a member function. If someone expcepts a free function as call back you cannot hand them a member function. – 463035818_is_not_an_ai Nov 16 '22 at 11:17
  • 3
    Keep a global map from pin to instance. You can't force a library to work with an incompatible model. Bear in mind that to be super clean and standard compatible with C, the callback will have to be an `extern "C"` function too, so members (static or not) are a non-starter. – StoryTeller - Unslander Monica Nov 16 '22 at 11:18
  • 1
    If the function to register a call-back does not provide an extra parameter then this can not be done. With an extra parameter eg `void*` you can pass a pointer to the class and use a static member function for the call-back. – Richard Critten Nov 16 '22 at 11:18
  • 1
    Does this answer your question? [Using a C++ class member function as a C callback function](https://stackoverflow.com/questions/1000663/using-a-c-class-member-function-as-a-c-callback-function) – VLL Nov 16 '22 at 11:19
  • 1
    If you have multiple instances registering in their constructors for the interrupt, then what do you expect to happen when the interrupt occurs. Pessimistically I expect only the laster one registered to be called. Did you try (in C, no instances) to register more than one call back to the interrupt? That is possible (if the calling code implements a list), but probably costly for anything that is worth an interrupt. – Yunnosch Nov 16 '22 at 11:20
  • What it the purpose of the pins ? Is it free to use ? Are your class instances assigned to respective pins ? –  Nov 16 '22 at 11:32
  • std::map> pinMap; extern "C" void handle_interrupt(int pin, int time){ (pinMap[pin].first->*pinMap[pin].second)(time); } – QuentinUK Nov 16 '22 at 11:48
  • You have a **global** handler for a **global** event but what you want is **local** callbacks. What are you even trying to achieve here? It sounds wrong on design level. – Agent_L Nov 16 '22 at 12:01

2 Answers2

3

Your class may integrate a static method that you pass as a C callback function (provided the calling conventions are made compatible; if not possible, wrap it in a pure C call).

In addition, let your class keep a static table of the created instances, in correspondence to the pins. When a callback is invoked, by knowing the pin, you will know which instance to activate.

1

Create a C-style API (C outside, C++ inside), which itself registers as a single callback and allows to register multiple C++ callbacks. That would require some list-handling.
When the interrupt occurs, call all of them and let them decide whether they need to react, according to the callback parameters.

Alternatively, see the more luxurious proposal (mapping pin to one of multiple callbacks) in the comment by Story Teller, which basically does the detection of which callback is needed centrally.

Yunnosch
  • 26,130
  • 9
  • 42
  • 54