etl/docs/tutorials/callback-service.md
John Wellbelove e1c8a5db11 Added more documentation
Tweaks to CSS
2026-05-06 07:59:33 +01:00

189 lines
4.8 KiB
Markdown

---
title: "callback_service"
---
{{< callout type="warning">}}
**Deprecated**.
This documentation is for reference only.
Use `etl::delegate_service` for new code.
{{< /callout >}}
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.
```cpp
#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
```