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 <iostream>
#include <iomanip>
#include "function.h" #include "etl/function.h"
#include "etl/callback_service.h"
//******************************** enum VectorId
// Fake UART Rx register.
//********************************
char get_char()
{ {
static char c = 'A'; TIM1_CC_IRQ_HANDLER = 42,
return c++; 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
};
//******************************** typedef etl::callback_service<VECTOR_ID_RANGE, VECTOR_ID_OFFSET> InterruptVectors;
// Interrupt vectors & callbacks.
//******************************** // Ensure that the callback service is initialised before use.
// Callback interfaces. InterruptVectors& GetInterruptVectorsInstance()
// 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. static InterruptVectors interruptVectors;
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. return interruptVectors;
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.
extern "C" extern "C"
{ {
InterruptVectors& interruptVectors = GetInterruptVectorsInstance();
// Function called from the timer1 interrupt vector. // 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. // 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. // 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. // Function called from the usart1 interrupt vector.
void Uart1RxInterrupt() void USART1_IRQHandler()
{ {
(*uart1_rx_callback)(get_char()); interruptVectors.callback<USART1_IRQ_HANDLER>();
} }
// Function called from the UART2 rx interrupt vector. // Function called from the usart2 interrupt vector.
void Uart2RxInterrupt() void USART2_IRQHandler()
{ {
(*uart2_rx_callback)(get_char()); interruptVectors.callback<USART2_IRQ_HANDLER>();
} }
} }
@ -63,34 +66,29 @@ class Timer
{ {
public: public:
// Constructor. Timer(int interruptId)
Timer() : callback(*this)
{ {
GetInterruptVectorsInstance().register_callback(interruptId, callback);
} }
// Handler for interrupts from the timer. // 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. etl::function_mp<Timer, size_t, &Timer::InterruptHandler> callback;
static void StaticTimerInterruptHandler()
{
std::cout << "Timer interrupt (static)\n";
}
}; };
//******************************** //********************************
// Free function timer driver. // 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. // UART driver.
//******************************** //********************************
@ -99,29 +97,37 @@ class Uart
public: public:
// Constructor. // Constructor.
Uart(int port_id) Uart(int port_id, int interruptId)
: port_id(port_id) : port_id(port_id),
callback(*this)
{ {
GetInterruptVectorsInstance().register_callback(interruptId, callback);
} }
// Handler for rx interrupts from the UART. // Handler for interrupts from the UART.
void RxInterruptHandler(char c) 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; int port_id;
}; };
// Declare the driver instances. void UnhandledInterrupt(const size_t id)
Timer timer; {
Uart uart1(0); std::cout << "Unhandled Interrupt : ID " << id << "\n";
Uart uart2(1); }
etl::function_imv<Timer, timer, &Timer::MemberTimerInterruptHandler> timer_member_callback; // Declare the driver instances.
etl::function_fv<&Timer::StaticTimerInterruptHandler> timer_static_callback; Timer timer(TIM1_CC_IRQ_HANDLER);
etl::function_imp<Uart, char, uart1, &Uart::RxInterruptHandler> uart1_callback; Uart uart1(0, USART1_IRQ_HANDLER);
etl::function_imp<Uart, char, uart2, &Uart::RxInterruptHandler> uart2_callback; 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. // Test it out.
@ -129,21 +135,17 @@ etl::function_imp<Uart, char, uart2, &Uart::RxInterruptHandler> uart2_callb
int main() int main()
{ {
// Setup the callbacks. // Setup the callbacks.
// This may be part of the cross platform interface. InterruptVectors& interruptVectors = GetInterruptVectorsInstance();
timer1_callback = &timer_member_callback;
timer2_callback = &timer_static_callback; interruptVectors.register_callback<TIM2_IRQ_HANDLER>(timer_free_callback);
timer3_callback = &free_callback; interruptVectors.register_unhandled_callback(unhandled_callback);
uart1_rx_callback = &uart1_callback;
uart2_rx_callback = &uart2_callback;
// Simulate the interrupts. // Simulate the interrupts.
Timer1Interrupt(); TIM1_CC_IRQHandler();
Timer2Interrupt(); TIM2_IRQHandler();
Timer3Interrupt(); USART1_IRQHandler();
Uart1RxInterrupt(); USART2_IRQHandler();
Uart2RxInterrupt(); TIM3_IRQHandler(); // Unhandled!
return 0; return 0;
} }

View File

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

View File

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