Go Down

Topic: why use callbacks (Read 4817 times) previous topic - next topic

joeblogs

Hi i cant wrap my head around why you would use callbacks

how is
Code: [Select]

typedef void(*test_callback) (void);

test_callback func1()
{
Serial.println("func1");
}

void func2()
{
Serial.println("func2 start");

func1();

Serial.println("func2 end");
}


//in the program call func2;
func2();

any different from
Code: [Select]


void func1()
{
Serial.println("func1");
}

void func2()
{
Serial.println("func2 start");

func1();

Serial.println("func2 end");
}


//in the program call func2;
func2();

SergeS

There is no difference when all code written by you, but there is big difference when you are using library written by somebody else, and some events need to be tripped by some conditions, in this case event from library code may call callback function in your code.

Whandall

The first version produces more warnings, it only has the name callback in them, it does not use any.

The function that should return a function pointer does not return any value.
Ah, this is obviously some strange usage of the word 'safe' that I wasn't previously aware of. (D.Adams)

joeblogs

serge,
why would you not just use the public interface of a class to run said code

Quote
it does not use any.
any what?

SergeS

#4
May 30, 2017, 01:28 am Last Edit: May 30, 2017, 01:34 am by SergeS
serge,
why would you not just use the public interface of a class to run said code
any what?
You do not need to have classes and interfaces in order to call callback-functions, callbacks are not only for OOP.

joeblogs

sorry i dont want to drag this out, but if not using classes. why wouldnt you include the header file and then call the function you want to run.

could anyone give me tell me in what situation you would use a callback because it was the best option

BulldogLowell

When you want to defer a function that is triggered by a subsequent event. That trigger can be a timer or an interrupt, for example.

Callbacks are VERY common and used a lot in async activity.

SergeS

sorry i dont want to drag this out, but if not using classes. why wouldnt you include the header file and then call the function you want to run.

could anyone give me tell me in what situation you would use a callback because it was the best option
I said - "not only for OOP" , I did not say "not using classes".
If you are planning to use interfaces - you have to make your own class, inherited from existing one.
If you are planning to use callbacks - you do not need to inherit, all you need is just to declare your own function and set it as a callback.

The best option to use callbacks is definitelly when you are using some library code which written on that way to enforce you to use callbacks :-)

In case if you are writing both, library and main code, I believe there is no better solution if you are writing some lightweight classes (good sample - simple timer) based on idea nobody will inherit from it, but you need to have some custom events.

zhomeslice

Hi i cant wrap my head around why you would use callbacks
The most common use of a callback function i know of with arduino is with attachInterrupt() function. it uses your function when an event occurs outside of your normal program and you get to tell it what you want done.
the blink function is stored inside of attach interrupts as a pointer to your function and is called when the interrupt occurs.
Code: [Select]
The most common use of a callback function is with attachInterrupt()
const byte ledPin = 13;
const byte interruptPin = 2;
volatile byte state = LOW;

void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), blink, CHANGE);
}

void loop() {
  digitalWrite(ledPin, state);
}

void blink() {
  state = !state;
}

Heres some discussions I had on this forum: https://forum.arduino.cc/index.php?topic=436961.0
and an incredible resource by Nick on function pointers can be found here: http://www.gammon.com.au/callbacks
HC

joeblogs

got it

so say for example a class function that is of type 'callback' gives you the ability to use that function in a handler. even though the class object may not exist at compile time?

ie.

class with callback function
Code: [Select]

typedef void(*test_callback)(void);

class InputRecorder
{
public:

test_callback test_func()
{
int i = 1;
}
};



function which creates class object
Code: [Select]

void data_recorder_run()
{
InputRecorder DataRec;   // <--classs object doesnt exist prior to calling function

while(program_state == OptID::Opt1)
{
DataRec.flow_control();
}
}

 and handler
Code: [Select]

void PIOC_Handler(void)
{
uint32_t status = INPUT_PIN_PORT->PIO_ISR;

DataRec.test_func();
}


because the class function has been typedef'd as callback now i can use the function in the handler, where as before the class object had to exist at compile time to have access to its functions/data.

Delta_G

sorry i dont want to drag this out, but if not using classes. why wouldnt you include the header file and then call the function you want to run.

could anyone give me tell me in what situation you would use a callback because it was the best option
OK, but lets say the function you want to run has to call some function from your code.  Imagine I wrote a custom class for sequencing led light patterns.  But all it does is sequence the patters.  You have to actually write the code for the patterns themselves, the class only controls showing those patterns in a certain order.  I might do this so that you can use it for multiple different styles of led strips as long as you can write functions to set the colors to what you want.  

So when you call the code in the class, you need to give it the code to make the pattern.  So you might call the code to add a pattern into the sequence and pass a pointer to the function you wrote in your code that actually tells your particular lights to come on and what color to be.  And that would be an example of a callback.  You are telling the library code that when it decides to light up that specific pattern to "call back" to your code for the function to light the strips.  
|| | ||| | || | ||  ~Woodstock

Please do not PM with technical questions or comments.  Keep Arduino stuff out on the boards where it belongs.

joeblogs

so you can pass a function as an argument in a function

callback my_callback()
{
  foo++;
}


other_function(num, my_callback() )
{
   if(foo > num) {x = y}
}

joeblogs

thanks for the help.

nicks info was pretty informative. the use of unnamed functions and array indexing looks real handy.

as far as debugging goes are there any pitfalls to using callbacks?

zhomeslice

so you can pass a function as an argument in a function
This is an example of passing a function as an argument in a function
Code: [Select]
/*** This code could be hidden within a class or library somewhere ***/
typedef void (*voidFuncPtr)(void);// Create a type to point to a funciton.
static voidFuncPtr  _CallBackFuncitonPointer; // Create an instance of the empty function pointer

void BlinkIt(voidFuncPtr CallBackFuncitonPointer) {
  _CallBackFuncitonPointer = CallBackFuncitonPointer; // assign a function to the empty function pointer
}
void Blink(unsigned long msDelaTime) {
  if (_CallBackFuncitonPointer) {
    static unsigned long _ATimer;
    if ( (unsigned long)(millis() - _ATimer) >= (msDelaTime)) {
      _ATimer = millis();
      _CallBackFuncitonPointer(); // call the function we assigned to the once empty function pointer
    }
  }
}
/***********************************************************************/
// include "MyLibrary.h" for example that contains the above code


void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  BlinkIt(MySpecialBlinkFunction); // Set my function into the above function pointer
}

void loop() {
  Blink(1000); // Call blink function with the  below function within with 1 second interval
}

void MySpecialBlinkFunction (){
   digitalWrite(13, !digitalRead(13));
}


Z
HC

pert

I think it's reasonable to use a callback for an application such as attachInterrupt() but generally I feel they're not very beginner friendly. You have this function that gets called out of nowhere which makes it hard to understand the program flow from reading the code. I know they confused me when I first encountered them in the PubSubClient library. In that case I would prefer to just call the function from my own code according to a return value from a function of the library.

Go Up