diff --git a/examples/FunctionInterruptSimulation/FunctionInterruptSimulation.cpp b/examples/FunctionInterruptSimulation/FunctionInterruptSimulation.cpp new file mode 100644 index 00000000..5f0adb99 --- /dev/null +++ b/examples/FunctionInterruptSimulation/FunctionInterruptSimulation.cpp @@ -0,0 +1,149 @@ +#include +#include + +#include "function.h" + +//******************************** +// Fake UART Rx register. +//******************************** +char get_char() +{ + static char c = 'A'; + return c++; +} + +//******************************** +// 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. + +extern "C" +{ + // Function called from the timer1 interrupt vector. + void Timer1Interrupt() + { + (*timer1_callback)(); + } + + // Function called from the timer2 interrupt vector. + void Timer2Interrupt() + { + (*timer2_callback)(); + } + + // Function called from the timer3 interrupt vector. + void Timer3Interrupt() + { + (*timer3_callback)(); + } + + // Function called from the UART1 rx interrupt vector. + void Uart1RxInterrupt() + { + (*uart1_rx_callback)(get_char()); + } + + // Function called from the UART2 rx interrupt vector. + void Uart2RxInterrupt() + { + (*uart2_rx_callback)(get_char()); + } +} + +//******************************** +// Timer driver. +//******************************** +class Timer +{ +public: + + // Constructor. + Timer() + { + } + + // Handler for interrupts from the timer. + void MemberTimerInterruptHandler() + { + std::cout << "Timer interrupt (member)\n"; + } + + // Static handler for interrupts from the timer. + static void StaticTimerInterruptHandler() + { + std::cout << "Timer interrupt (static)\n"; + } +}; + +//******************************** +// Free function timer driver. +//******************************** +void FreeTimerInterruptHandler() +{ + std::cout << "Timer interrupt (free)\n"; +} + +etl::function_fv free_callback; + +//******************************** +// UART driver. +//******************************** +class Uart +{ +public: + + // Constructor. + Uart(int port_id) + : port_id(port_id) + { + } + + // Handler for rx interrupts from the UART. + void RxInterruptHandler(char c) + { + std::cout << "UART" << port_id << " Rx char interrupt : Received '" << c << "'\n"; + } + + int port_id; +}; + +// Declare the driver instances. +Timer timer; +Uart uart1(0); +Uart uart2(1); + +etl::function_imv timer_member_callback; +etl::function_fv<&Timer::StaticTimerInterruptHandler> timer_static_callback; +etl::function_imp uart1_callback; +etl::function_imp uart2_callback; + +//******************************** +// Test it out. +//******************************** +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; + + // Simulate the interrupts. + Timer1Interrupt(); + Timer2Interrupt(); + Timer3Interrupt(); + Uart1RxInterrupt(); + Uart2RxInterrupt(); + + return 0; +} + + diff --git a/examples/FunctionInterruptSimulation/etl_user.h b/examples/FunctionInterruptSimulation/etl_user.h new file mode 100644 index 00000000..8ff4c6fe --- /dev/null +++ b/examples/FunctionInterruptSimulation/etl_user.h @@ -0,0 +1,3 @@ + +#define ETL_THROW_EXCEPTIONS +#define ETL_VERBOSE_ERRORS \ No newline at end of file diff --git a/examples/FunctionInterruptSimulation/vs2017/FunctionInterruptSimulation.sln b/examples/FunctionInterruptSimulation/vs2017/FunctionInterruptSimulation.sln new file mode 100644 index 00000000..e19d8e7f --- /dev/null +++ b/examples/FunctionInterruptSimulation/vs2017/FunctionInterruptSimulation.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26730.16 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FunctionInterruptSimulation", "FunctionInterruptSimulation.vcxproj", "{2873A2D7-5112-4941-83AA-F98751BE5289}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2873A2D7-5112-4941-83AA-F98751BE5289}.Debug|x64.ActiveCfg = Debug|x64 + {2873A2D7-5112-4941-83AA-F98751BE5289}.Debug|x64.Build.0 = Debug|x64 + {2873A2D7-5112-4941-83AA-F98751BE5289}.Debug|x86.ActiveCfg = Debug|Win32 + {2873A2D7-5112-4941-83AA-F98751BE5289}.Debug|x86.Build.0 = Debug|Win32 + {2873A2D7-5112-4941-83AA-F98751BE5289}.Release|x64.ActiveCfg = Release|x64 + {2873A2D7-5112-4941-83AA-F98751BE5289}.Release|x64.Build.0 = Release|x64 + {2873A2D7-5112-4941-83AA-F98751BE5289}.Release|x86.ActiveCfg = Release|Win32 + {2873A2D7-5112-4941-83AA-F98751BE5289}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {C8193019-E546-4904-A25F-27FC525CC526} + EndGlobalSection +EndGlobal diff --git a/examples/FunctionInterruptSimulation/vs2017/FunctionInterruptSimulation.vcxproj b/examples/FunctionInterruptSimulation/vs2017/FunctionInterruptSimulation.vcxproj new file mode 100644 index 00000000..50cf05be --- /dev/null +++ b/examples/FunctionInterruptSimulation/vs2017/FunctionInterruptSimulation.vcxproj @@ -0,0 +1,155 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {2873A2D7-5112-4941-83AA-F98751BE5289} + Win32Proj + FunctionInterruptSimulation + 10.0.15063.0 + + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + NotUsing + Level3 + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + ../../../src;%(AdditionalIncludeDirectories) + + + Console + true + + + + + Use + Level3 + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Use + Level3 + MaxSpeed + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/FunctionInterruptSimulation/vs2017/FunctionInterruptSimulation.vcxproj.filters b/examples/FunctionInterruptSimulation/vs2017/FunctionInterruptSimulation.vcxproj.filters new file mode 100644 index 00000000..91680b76 --- /dev/null +++ b/examples/FunctionInterruptSimulation/vs2017/FunctionInterruptSimulation.vcxproj.filters @@ -0,0 +1,27 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + + + Header Files + + + \ No newline at end of file diff --git a/src/function.h b/src/function.h index 005c799f..198a23e9 100644 --- a/src/function.h +++ b/src/function.h @@ -295,6 +295,61 @@ namespace etl TObject* p_object; ///< Pointer to the object that contains the function. }; + //*************************************************************************** + ///\ingroup function + /// A derived function template that takes an object type and parameter type. + ///\tparam TObject The object type that contains the member function. + ///\tparam TParameter The parameter type accepted by the member function. + //*************************************************************************** + template + class function_imp : public ifunction + { + public: + + typedef TObject object_type; ///< The type of object. + typedef TParameter parameter_type; ///< The type of parameter sent to the function. + + //************************************************************************* + /// The function operator that calls the destination function. + ///\param data The data to pass to the function. + //************************************************************************* + virtual void operator ()(TParameter data) + { + // Call the object's member function with the data. + (Instance.*Function)(data); + } + }; + + //*************************************************************************** + ///\ingroup function + /// A derived function template that takes an object type and parameter type. + ///\tparam TObject The object type that contains the member function. + ///\tparam TParameter The parameter type accepted by the member function. + //*************************************************************************** + template + class function_imv : public ifunction + { + public: + + typedef TObject object_type; ///< The type of object. + typedef void parameter_type; ///< The type of parameter sent to the function. + + //************************************************************************* + /// Constructor. + ///\param object Reference to the object + //************************************************************************* + + //************************************************************************* + /// The function operator that calls the destination function. + ///\param data The data to pass to the function. + //************************************************************************* + virtual void operator ()() + { + // Call the object's member function. + (Instance.*Function)(); + } + }; + //*************************************************************************** ///\ingroup function /// A derived function template that takes a parameter type. diff --git a/test/test_function.cpp b/test/test_function.cpp index 750a7ff3..d82e3cae 100644 --- a/test/test_function.cpp +++ b/test/test_function.cpp @@ -120,6 +120,8 @@ public: } }; +Test test_static; + //***************************************************************************** // Initialises the test results. //***************************************************************************** @@ -269,5 +271,41 @@ namespace CHECK(function_called); CHECK(parameter_correct); } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_instance_member_void_compile_time) + { + function_called = false; + + etl::function_imv function; + + call(function); + + CHECK(function_called); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_instance_member_parameter_compile_time) + { + function_called = false; + + etl::function_imp function; + + call(function); + + CHECK(function_called); + } + + //************************************************************************* + TEST_FIXTURE(SetupFixture, test_instance_member_reference_compile_time) + { + function_called = false; + + etl::function_imp function; + + call(function); + + CHECK(function_called); + } }; } \ No newline at end of file