From df56f94815e01c401280bae44946dafd4e0511d0 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sun, 3 Feb 2019 20:29:40 +0000 Subject: [PATCH] Added OFFSET template parameter --- .../FunctionInterruptSimulation.cpp | 142 +++++++++--------- .../FunctionInterruptSimulation.vcxproj | 6 +- include/etl/callback_service.h | 84 ++++++----- test/test_callback_service.cpp | 8 +- 4 files changed, 124 insertions(+), 116 deletions(-) diff --git a/examples/FunctionInterruptSimulation/FunctionInterruptSimulation.cpp b/examples/FunctionInterruptSimulation/FunctionInterruptSimulation.cpp index 5f0adb99..d7fffbdf 100644 --- a/examples/FunctionInterruptSimulation/FunctionInterruptSimulation.cpp +++ b/examples/FunctionInterruptSimulation/FunctionInterruptSimulation.cpp @@ -1,58 +1,61 @@ #include -#include -#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* timer1_callback; // A pointer to a callback taking no parameters. -etl::ifunction* timer2_callback; // A pointer to a callback taking no parameters. -etl::ifunction* timer3_callback; // A pointer to a callback taking no parameters. -etl::ifunction* uart1_rx_callback; // A pointer to a callback taking a char parameter. -etl::ifunction* uart2_rx_callback; // A pointer to a callback taking a char parameter. +typedef etl::callback_service 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(); } // Function called from the timer2 interrupt vector. - void Timer2Interrupt() + void TIM2_IRQHandler() { - (*timer2_callback)(); + interruptVectors.callback(); } // Function called from the timer3 interrupt vector. - void Timer3Interrupt() + void TIM3_IRQHandler() { - (*timer3_callback)(); + interruptVectors.callback(); } - // 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(); } - // 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(); } } @@ -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 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 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 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_member_callback; -etl::function_fv<&Timer::StaticTimerInterruptHandler> timer_static_callback; -etl::function_imp uart1_callback; -etl::function_imp 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 timer_free_callback; +etl::function_fp unhandled_callback; //******************************** // Test it out. @@ -129,21 +135,17 @@ etl::function_imp 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(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; } - - diff --git a/examples/FunctionInterruptSimulation/vs2017/FunctionInterruptSimulation.vcxproj b/examples/FunctionInterruptSimulation/vs2017/FunctionInterruptSimulation.vcxproj index 3c2ce147..ca2c92e1 100644 --- a/examples/FunctionInterruptSimulation/vs2017/FunctionInterruptSimulation.vcxproj +++ b/examples/FunctionInterruptSimulation/vs2017/FunctionInterruptSimulation.vcxproj @@ -29,7 +29,7 @@ {5157DB15-C255-4E47-9FB1-AF388437F90F} Win32Proj FunctionInterruptSimulation - 10.0.15063.0 + 10.0.17763.0 @@ -104,12 +104,12 @@ - Use + NotUsing Level3 Disabled _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true - ../../../src + ../../../include;%(AdditionalIncludeDirectories) Console diff --git a/include/etl/callback_service.h b/include/etl/callback_service.h index d7122030..effdc53c 100644 --- a/include/etl/callback_service.h +++ b/include/etl/callback_service.h @@ -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 + template class callback_service { public: @@ -53,7 +55,7 @@ namespace etl /// Sets all callbacks to the internal default. //************************************************************************* callback_service() - : unhandled_callback(*this, &callback_service::unhandled), + : unhandled_callback(*this, &callback_service::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 void register_callback(etl::ifunction& 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& 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 - 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 + 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, size_t> unhandled_callback; + etl::function, size_t> unhandled_callback; /// Pointer to the user defined 'unhandled' callback. etl::ifunction* p_unhandled; /// Lookup table of callbacks. - etl::array*, NUMBER_OF_CALLBACKS> lookup; + etl::array*, RANGE> lookup; }; } diff --git a/test/test_callback_service.cpp b/test/test_callback_service.cpp index 900c4fae..67de9b16 100644 --- a/test/test_callback_service.cpp +++ b/test/test_callback_service.cpp @@ -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 Service; //***************************************************************************** bool global_called = false; @@ -119,10 +122,9 @@ namespace { enum { - GLOBAL, + GLOBAL = OFFSET, MEMBER1, MEMBER2, - UNHANDLED, OUT_OF_RANGE };