Added OFFSET template parameter

This commit is contained in:
John Wellbelove 2019-02-03 20:29:40 +00:00
parent 2cef994d5b
commit df56f94815
4 changed files with 124 additions and 116 deletions

View File

@ -1,58 +1,61 @@
#include <iostream>
#include <iomanip>
#include "function.h"
#include "etl/function.h"
#include "etl/callback_service.h"
//********************************
// Fake UART Rx register.
//********************************
char get_char()
enum VectorId
{
static char c = 'A';
return c++;
}
TIM1_CC_IRQ_HANDLER = 42,
TIM2_IRQ_HANDLER = 43,
TIM3_IRQ_HANDLER = 44,
USART1_IRQ_HANDLER = 52,
USART2_IRQ_HANDLER = 53,
VECTOR_ID_RANGE = USART2_IRQ_HANDLER - TIM1_CC_IRQ_HANDLER + 1,
VECTOR_ID_OFFSET = TIM1_CC_IRQ_HANDLER
};
//********************************
// Interrupt vectors & callbacks.
//********************************
// Callback interfaces.
// Note that they do not require any knowledge about the callee apart from the parameter type.
etl::ifunction<void>* timer1_callback; // A pointer to a callback taking no parameters.
etl::ifunction<void>* timer2_callback; // A pointer to a callback taking no parameters.
etl::ifunction<void>* timer3_callback; // A pointer to a callback taking no parameters.
etl::ifunction<char>* uart1_rx_callback; // A pointer to a callback taking a char parameter.
etl::ifunction<char>* uart2_rx_callback; // A pointer to a callback taking a char parameter.
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 Timer1Interrupt()
void TIM1_CC_IRQHandler()
{
(*timer1_callback)();
interruptVectors.callback<TIM1_CC_IRQ_HANDLER>();
}
// Function called from the timer2 interrupt vector.
void Timer2Interrupt()
void TIM2_IRQHandler()
{
(*timer2_callback)();
interruptVectors.callback<TIM2_IRQ_HANDLER>();
}
// Function called from the timer3 interrupt vector.
void Timer3Interrupt()
void TIM3_IRQHandler()
{
(*timer3_callback)();
interruptVectors.callback<TIM3_IRQ_HANDLER>();
}
// Function called from the UART1 rx interrupt vector.
void Uart1RxInterrupt()
// Function called from the usart1 interrupt vector.
void USART1_IRQHandler()
{
(*uart1_rx_callback)(get_char());
interruptVectors.callback<USART1_IRQ_HANDLER>();
}
// Function called from the UART2 rx interrupt vector.
void Uart2RxInterrupt()
// Function called from the usart2 interrupt vector.
void USART2_IRQHandler()
{
(*uart2_rx_callback)(get_char());
interruptVectors.callback<USART2_IRQ_HANDLER>();
}
}
@ -63,34 +66,29 @@ class Timer
{
public:
// Constructor.
Timer()
Timer(int interruptId)
: callback(*this)
{
GetInterruptVectorsInstance().register_callback(interruptId, callback);
}
// Handler for interrupts from the timer.
void MemberTimerInterruptHandler()
void InterruptHandler(const size_t id)
{
std::cout << "Timer interrupt (member)\n";
std::cout << "Timer interrupt (member) : ID " << id << "\n";
}
// Static handler for interrupts from the timer.
static void StaticTimerInterruptHandler()
{
std::cout << "Timer interrupt (static)\n";
}
etl::function_mp<Timer, size_t, &Timer::InterruptHandler> callback;
};
//********************************
// Free function timer driver.
//********************************
void FreeTimerInterruptHandler()
void FreeTimerInterruptHandler(const size_t id)
{
std::cout << "Timer interrupt (free)\n";
std::cout << "Timer interrupt (free) : ID " << id << "\n";
}
etl::function_fv<FreeTimerInterruptHandler> free_callback;
//********************************
// UART driver.
//********************************
@ -99,29 +97,37 @@ class Uart
public:
// Constructor.
Uart(int port_id)
: port_id(port_id)
Uart(int port_id, int interruptId)
: port_id(port_id),
callback(*this)
{
GetInterruptVectorsInstance().register_callback(interruptId, callback);
}
// Handler for rx interrupts from the UART.
void RxInterruptHandler(char c)
// Handler for interrupts from the UART.
void InterruptHandler(const size_t id)
{
std::cout << "UART" << port_id << " Rx char interrupt : Received '" << c << "'\n";
std::cout << "UART" << port_id << " : ID " << id << "\n";
}
etl::function_mp<Uart, size_t, &Uart::InterruptHandler> callback;
int port_id;
};
// Declare the driver instances.
Timer timer;
Uart uart1(0);
Uart uart2(1);
void UnhandledInterrupt(const size_t id)
{
std::cout << "Unhandled Interrupt : ID " << id << "\n";
}
etl::function_imv<Timer, timer, &Timer::MemberTimerInterruptHandler> timer_member_callback;
etl::function_fv<&Timer::StaticTimerInterruptHandler> timer_static_callback;
etl::function_imp<Uart, char, uart1, &Uart::RxInterruptHandler> uart1_callback;
etl::function_imp<Uart, char, uart2, &Uart::RxInterruptHandler> uart2_callback;
// Declare the driver instances.
Timer timer(TIM1_CC_IRQ_HANDLER);
Uart uart1(0, USART1_IRQ_HANDLER);
Uart uart2(1, USART2_IRQ_HANDLER);
// 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.
@ -129,21 +135,17 @@ etl::function_imp<Uart, char, uart2, &Uart::RxInterruptHandler> uart2_callb
int main()
{
// Setup the callbacks.
// This may be part of the cross platform interface.
timer1_callback = &timer_member_callback;
timer2_callback = &timer_static_callback;
timer3_callback = &free_callback;
uart1_rx_callback = &uart1_callback;
uart2_rx_callback = &uart2_callback;
InterruptVectors& interruptVectors = GetInterruptVectorsInstance();
interruptVectors.register_callback<TIM2_IRQ_HANDLER>(timer_free_callback);
interruptVectors.register_unhandled_callback(unhandled_callback);
// Simulate the interrupts.
Timer1Interrupt();
Timer2Interrupt();
Timer3Interrupt();
Uart1RxInterrupt();
Uart2RxInterrupt();
TIM1_CC_IRQHandler();
TIM2_IRQHandler();
USART1_IRQHandler();
USART2_IRQHandler();
TIM3_IRQHandler(); // Unhandled!
return 0;
}

View File

@ -29,7 +29,7 @@
<ProjectGuid>{5157DB15-C255-4E47-9FB1-AF388437F90F}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>FunctionInterruptSimulation</RootNamespace>
<WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
@ -104,12 +104,12 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>../../../src</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>../../../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>

View File

@ -31,6 +31,7 @@ SOFTWARE.
#ifndef ETL_CALLBACK_SERVICE_INCLUDED
#define ETL_CALLBACK_SERVICE_INCLUDED
#include "platform.h"
#include "nullptr.h"
#include "static_assert.h"
#include "function.h"
@ -40,10 +41,11 @@ namespace etl
{
//***************************************************************************
/// An indexed callback service.
/// \tparam NUMBER_OF_CALLBACKS The number of callbacks to handle.
/// The callback ids must range between 0 and NUMBER_OF_CALLBACKS - 1.
/// \tparam RANGE The number of callbacks to handle.
/// \tparam OFFSET The lowest callback id value.
/// The callback ids must range between OFFSET and OFFSET + RANGE - 1.
//***************************************************************************
template <const size_t NUMBER_OF_CALLBACKS>
template <const size_t RANGE, size_t OFFSET = 0U>
class callback_service
{
public:
@ -53,7 +55,7 @@ namespace etl
/// Sets all callbacks to the internal default.
//*************************************************************************
callback_service()
: unhandled_callback(*this, &callback_service<NUMBER_OF_CALLBACKS>::unhandled),
: unhandled_callback(*this, &callback_service<RANGE, OFFSET>::unhandled),
p_unhandled(nullptr)
{
lookup.fill(&unhandled_callback);
@ -63,14 +65,15 @@ namespace etl
/// Registers a callback for the specified id.
/// Compile time assert if the id is out of range.
/// \tparam ID The id of the callback.
/// \param callback reference to the callback.
/// \param callback Reference to the callback.
//*************************************************************************
template <const size_t ID>
void register_callback(etl::ifunction<size_t>& callback)
{
ETL_STATIC_ASSERT(ID < NUMBER_OF_CALLBACKS, "Callback Id out of range");
ETL_STATIC_ASSERT(ID < (OFFSET + RANGE), "Callback Id out of range");
ETL_STATIC_ASSERT(ID >= OFFSET, "Callback Id out of range");
lookup[ID] = &callback;
lookup[ID - OFFSET] = &callback;
}
//*************************************************************************
@ -81,38 +84,9 @@ namespace etl
//*************************************************************************
void register_callback(const size_t id, etl::ifunction<size_t>& callback)
{
if (id < NUMBER_OF_CALLBACKS)
if ((id >= OFFSET) && (id < (OFFSET + RANGE)))
{
lookup[id] = &callback;
}
}
//*************************************************************************
/// Executes the callback function for the index.
/// Compile time assert if the id is out of range.
/// \tparam ID The id of the callback.
//*************************************************************************
template <const size_t ID>
void callback()
{
ETL_STATIC_ASSERT(ID < NUMBER_OF_CALLBACKS, "Callback Id out of range");
(*lookup[ID])(ID);
}
//*************************************************************************
/// Executes the callback function for the index.
/// \param id Id of the callback.
//*************************************************************************
void callback(const size_t id)
{
if (id < NUMBER_OF_CALLBACKS)
{
(*lookup[id])(id);
}
else
{
unhandled(id);
lookup[id - OFFSET] = &callback;
}
}
@ -125,6 +99,36 @@ namespace etl
p_unhandled = &callback;
}
//*************************************************************************
/// Executes the callback function for the index.
/// Compile time assert if the id is out of range.
/// \tparam ID The id of the callback.
//*************************************************************************
template <const size_t ID>
void callback()
{
ETL_STATIC_ASSERT(ID < (OFFSET + RANGE), "Callback Id out of range");
ETL_STATIC_ASSERT(ID >= OFFSET, "Callback Id out of range");
(*lookup[ID - OFFSET])(ID);
}
//*************************************************************************
/// Executes the callback function for the index.
/// \param id Id of the callback.
//*************************************************************************
void callback(const size_t id)
{
if ((id >= OFFSET) && (id < (OFFSET + RANGE)))
{
(*lookup[id - OFFSET])(id);
}
else
{
unhandled(id);
}
}
private:
//*************************************************************************
@ -140,13 +144,13 @@ namespace etl
}
/// The default callback for unhandled ids.
etl::function<callback_service<NUMBER_OF_CALLBACKS>, size_t> unhandled_callback;
etl::function<callback_service<RANGE, OFFSET>, size_t> unhandled_callback;
/// Pointer to the user defined 'unhandled' callback.
etl::ifunction<size_t>* p_unhandled;
/// Lookup table of callbacks.
etl::array<etl::ifunction<size_t>*, NUMBER_OF_CALLBACKS> lookup;
etl::array<etl::ifunction<size_t>*, RANGE> lookup;
};
}

View File

@ -33,7 +33,10 @@ SOFTWARE.
namespace
{
typedef etl::callback_service<3> Service;
const size_t SIZE = 3U;
const size_t OFFSET = 5U;
typedef etl::callback_service<SIZE, OFFSET> Service;
//*****************************************************************************
bool global_called = false;
@ -119,10 +122,9 @@ namespace
{
enum
{
GLOBAL,
GLOBAL = OFFSET,
MEMBER1,
MEMBER2,
UNHANDLED,
OUT_OF_RANGE
};