Intro

Callback functions are one the most powerful mechanisms in C. A callback function is any code that is passed as an argument to some other code, in such a way that this last code is able to call back, i.e., to execute, the code passed as argument.

In C, callback functions are implemented using function pointers. These function pointers hold the address of the function to be called back, thus allowing the code that receives it as argument to call it back.

In what concerns embedded systems, callback functions can be used to

Example

The code in Callback_Example.zip contains a simple example of a module with a function to be installed as an Interrupt Service Routine (ISR). The structure in the module allows the user to create a function that will be called by the ISR (the callback function), thus defining what will be the response to the interruption, without modifying the code in the module. The functions in the module allow the user to install any code he or she writes as the code to be run in response to the interruption.

Code

The module is stored in mod.c and mod.h and it contains two functions: initmodule() and module_service_routine(). Only initmodule() is public; module_service_routine() is internal to the module.

module_service_routine is the Interrupt Service Routine, that will be called by the system in response to an interrupt. In this example, the only action performed by module_service_routine is to call the user provided code. The address of the user defined callback function is stored in fp.

void module_service_routine(int signal)
{
  /* Test if fp has been initialized */
  if (fp == NULL)
  {
    /* If not, signal error */
    fprintf(stderr,"Error: fp called with no init.");
    exit(-1);
  }
  else{
    /* If OK, call *fp */
    (*fp)();
  }
}

initmodule receives the user defined function as the argument and sets the function pointer fp. Additionally, it installs module_service_routine as the Interrupt Service Routine (or handler) to SIGTSTP. SIGTSTP is the signal generated by pressing Ctrl-Z on the keyboard in Unix systems.

void initmodule(void (*user_fp))
{
  /* Install Ctrl-Z handler */
  signal(SIGTSTP, module_service_routine);

  /* Initialize the function pointer */
  fp = user_fp;

}

This structure allows to create a main program that defines the function that will be called when Ctrl-Z is pressed, without having, in the main program, any reference to interrupt servicing. The program contains an infinite loop, that will print a dot (‘.’) sign every second. Every time Ctrl-Z is pressed, the program will run the user defined function that was passed as argument to initmodule.

int main (char nargin , char vararg[])
{
  printf("Callback demo.\n");
  printf("Type Ctrl-Z to generate an interruption.\n");
  printf("Ctrl-C terminates the programa.\n");

  /*
   * The argument passed to initmodule will be the function called
   * by the interrupt service routine.
   * It corresponds to a user function, executed when an interrupt is raised.
   *
   * In this example, it can be either function1 or function2.
   */
  initmodule(function2);

  /* Main loop, just for signalling that the program is alive... */
  while(1){
    sleep(1);
    printf(".");
    fflush(stdout);
  }
}

In this case, function2 is a user defined function:

void function2(void)
{
  printf("This is function 2!\n");
  return;
}

Resources

The example code is available here:
Callback_Example.zip