A C++ template library for embedded applications
Designed and maintained
by
Aster Consulting Ltd
Join the ETL community
MIT licensed

etl::callback_service


The following code can be found in

examples\FunctionInterruptSimulation


This code demonstrates using the callback service for five example ARM interrupts.

Timer1 interrupt is handled by an instance of class Timer. The member callback function is wrapped by the most efficient
version of etl::function which all of the information it needs at compile time.

Timer2 interrupt is handled by a global function.

Timer3 has no entry in the callback service and will therefore trigger execution of the unhandled handler.

USART1 and USART2 interrupts are handled by instances of Uart.
There callbacks are defined withing the class and are initialised in the Uart constructor.

#include <iostream>

#include "etl/function.h"
#include "etl/callback_service.h"

enum VectorId
{
  TIM1_CC_IRQ_HANDLER = 42,
  TIM2_IRQ_HANDLER    = 43,
  TIM3_IRQ_HANDLER    = 44,
  USART1_IRQ_HANDLER  = 52,
  USART2_IRQ_HANDLER  = 53,
  VECTOR_ID_END,
  OFFSET              = TIM1_CC_IRQ_HANDLER,
  RANGE               = VECTOR_ID_END - VECTOR_ID_OFFSET,
  };

typedef etl::callback_service<VECTOR_ID_RANGE, VECTOR_ID_OFFSET> InterruptVectors;

// Ensure that the callback service is initialised before use.
InterruptVectors& GetInterruptVectorsInstance()
{
  static InterruptVectors interruptVectors;

  return interruptVectors;
}

extern "C"
{
  InterruptVectors& interruptVectors = GetInterruptVectorsInstance();

  // Function called from the timer1 interrupt vector.
  void TIM1_CC_IRQHandler()
  {
    interruptVectors.callback<TIM1_CC_IRQ_HANDLER>();
  }

  // Function called from the timer2 interrupt vector.
  void TIM2_IRQHandler()
  {
    interruptVectors.callback<TIM2_IRQ_HANDLER>();
  }

  // Function called from the timer3 interrupt vector.
  void TIM3_IRQHandler()
  {
    interruptVectors.callback<TIM3_IRQ_HANDLER>();
  }

  // Function called from the usart1 interrupt vector.
  void USART1_IRQHandler()
  {
    interruptVectors.callback<USART1_IRQ_HANDLER>();

  }

  // Function called from the usart2 interrupt vector.
  void USART2_IRQHandler()
  {
    interruptVectors.callback<USART2_IRQ_HANDLER>();
  }
}

//********************************
// Timer driver.
//********************************
class Timer
{
public:

  // Handler for interrupts from the timer.
  void InterruptHandler(const size_t id)
  {
    std::cout << "Timer interrupt (member) : ID " << id << "\n";
  }
};

//********************************
// Free function timer driver.
//********************************
void FreeTimerInterruptHandler(const size_t id)
{
  std::cout << "Timer interrupt (free)   : ID " << id << "\n";
}

//********************************
// UART driver.
//********************************
class Uart
{
public:

  // Constructor.
  Uart(int port_id, int interruptId)
    : port_id(port_id),
      callback(*this)
  {
    GetInterruptVectorsInstance().register_callback(interruptId, callback);
  }

  // Handler for interrupts from the UART.
  void InterruptHandler(const size_t id)
  {
    std::cout << "UART" << port_id << "                    : ID " << id << "\n";
  }

  // Callback for the interrupt handler.
  etl::function_mp<Uart, size_t, &Uart::InterruptHandler> callback;

  int port_id;
};

// 'Unhandled' interrupt handler.
void UnhandledInterrupt(const size_t id)
{
  std::cout << "Unhandled Interrupt      : ID " << id << "\n";
}

// Declare the driver instances.
Timer timer;
Uart  uart1(0, USART1_IRQ_HANDLER);
Uart  uart2(1, USART2_IRQ_HANDLER);

// Declare a global callback for the timer.
// Uses the most efficient callback type for a class, as everthing is known at compile time.
etl::function_imp<Timer, size_t, timer, &Timer::InterruptHandler> timer_member_callback;

// Declare the callbacks for the free functions.
etl::function_fp<size_t, FreeTimerInterruptHandler> timer_free_callback;
etl::function_fp<size_t, UnhandledInterrupt>        unhandled_callback;

//********************************
// Test it out.
//********************************
int main()
{
  // Setup the callbacks.
  InterruptVectors& interruptVectors = GetInterruptVectorsInstance();

  interruptVectors.register_callback<TIM1_CC_IRQ_HANDLER>(timer_member_callback);
  interruptVectors.register_callback<TIM2_IRQ_HANDLER>(timer_free_callback);
  interruptVectors.register_unhandled_callback(unhandled_callback);

  // Simulate the interrupts.
  TIM1_CC_IRQHandler();
  TIM2_IRQHandler();
  USART1_IRQHandler();
  USART2_IRQHandler();
  TIM3_IRQHandler(); // Unhandled!

  return 0;
}

____________________________________________________________________________________________________

Output

Timer interrupt (member) : ID 42
Timer interrupt (free)   : ID 43
UART0                    : ID 52
UART1                    : ID 53
Unhandled Interrupt      : ID 44
Tutorial