Merge remote-tracking branch 'origin/feature/callback_service' into development

This commit is contained in:
John Wellbelove 2019-02-04 21:07:20 +00:00
commit 2173751474
9 changed files with 584 additions and 75 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

@ -0,0 +1,159 @@
///\file
/******************************************************************************
The MIT License(MIT)
Embedded Template Library.
https://github.com/ETLCPP/etl
https://www.etlcpp.com
Copyright(c) 2019 jwellbelove
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#ifndef ETL_CALLBACK_SERVICE_INCLUDED
#define ETL_CALLBACK_SERVICE_INCLUDED
#include "platform.h"
#include "nullptr.h"
#include "static_assert.h"
#include "function.h"
#include "array.h"
namespace etl
{
//***************************************************************************
/// An indexed callback service.
/// \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 RANGE, const size_t OFFSET = 0U>
class callback_service
{
public:
//*************************************************************************
/// Reset the callback service.
/// Sets all callbacks to the internal default.
//*************************************************************************
callback_service()
: unhandled_callback(*this),
p_unhandled(nullptr)
{
lookup.fill(&unhandled_callback);
}
//*************************************************************************
/// 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.
//*************************************************************************
template <const size_t ID>
void register_callback(etl::ifunction<size_t>& 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] = &callback;
}
//*************************************************************************
/// Registers a callback for the specified id.
/// No action if the id is out of range.
/// \param id Id of the callback.
/// \param callback Reference to the callback.
//*************************************************************************
void register_callback(const size_t id, etl::ifunction<size_t>& callback)
{
if ((id >= OFFSET) && (id < (OFFSET + RANGE)))
{
lookup[id - OFFSET] = &callback;
}
}
//*************************************************************************
/// Registers an alternative callback for unhandled ids.
/// \param callback A reference to the user supplied 'unhandled' callback.
//*************************************************************************
void register_unhandled_callback(etl::ifunction<size_t>& 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:
//*************************************************************************
/// The default callback function.
/// Calls the user defined 'unhandled' callback if it exists.
//*************************************************************************
void unhandled(size_t id)
{
if (p_unhandled != nullptr)
{
(*p_unhandled)(id);
}
}
/// The default callback for unhandled ids.
etl::function_mp<callback_service<RANGE, OFFSET>,
size_t,
&callback_service<RANGE, OFFSET>::unhandled> 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>*, RANGE> lookup;
};
}
#endif

View File

@ -38,8 +38,8 @@ SOFTWARE.
///\ingroup utilities
#define ETL_VERSION_MAJOR 14
#define ETL_VERSION_MINOR 7
#define ETL_VERSION_PATCH 2
#define ETL_VERSION_MINOR 8
#define ETL_VERSION_PATCH 0
#define ETL_VERSION ETL_STRINGIFY(ETL_VERSION_MAJOR) ETL_STRINGIFY(ETL_VERSION_MINOR) ETL_STRINGIFY(ETL_VERSION_PATCH)
#define ETL_VERSION_W ETL_WIDE_STRING(ETL_CONCAT(ETL_CONCAT(ETL_VERSION_MAJOR, ETL_VERSION_MINOR), ETL_VERSION_PATCH))

View File

@ -1,3 +1,8 @@
===============================================================================
14.8.0
Added etl::callback_service
Useful for abstracting the interrupt system from C++ handlers.
===============================================================================
14.7.2
Added #include <new> to message_router.h for improved cross platform compatibility.

View File

@ -161,6 +161,7 @@
<Unit filename="../../include/etl/bloom_filter.h" />
<Unit filename="../../include/etl/c/ecl_timer.h" />
<Unit filename="../../include/etl/callback.h" />
<Unit filename="../../include/etl/callback_service.h" />
<Unit filename="../../include/etl/callback_timer.h" />
<Unit filename="../../include/etl/char_traits.h" />
<Unit filename="../../include/etl/checksum.h" />
@ -341,6 +342,7 @@
<Unit filename="../test_bloom_filter.cpp" />
<Unit filename="../test_bsd_checksum.cpp" />
<Unit filename="../test_c_timer_framework.cpp" />
<Unit filename="../test_callback_service.cpp" />
<Unit filename="../test_callback_timer.cpp" />
<Unit filename="../test_checksum.cpp" />
<Unit filename="../test_compare.cpp" />

View File

@ -0,0 +1,333 @@
/******************************************************************************
The MIT License(MIT)
Embedded Template Library.
https://github.com/ETLCPP/etl
https://www.etlcpp.com
Copyright(c) 2019 jwellbelove
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#include "UnitTest++.h"
#include "etl/function.h"
#include "etl/callback_service.h"
namespace
{
const size_t SIZE = 3U;
const size_t OFFSET = 5U;
typedef etl::callback_service<SIZE, OFFSET> Service;
//*****************************************************************************
bool global_called = false;
bool member1_called = false;
bool member2_called = false;
bool unhandled_called = false;
size_t called_id = UINT_MAX;
//*****************************************************************************
// The global function taking no parameters.
//*****************************************************************************
void global(size_t id)
{
global_called = true;
called_id = id;
}
//*****************************************************************************
// The external unhandled callback.
//*****************************************************************************
void unhandled(size_t id)
{
unhandled_called = true;
called_id = id;
}
//*****************************************************************************
// The test class with member functions.
//*****************************************************************************
class Test
{
public:
Test()
: callback(*this)
{
}
void member1(size_t id)
{
member1_called = true;
called_id = id;
}
void member2(size_t id)
{
member2_called = true;
called_id = id;
}
// Callback for 'member1'.
etl::function_mp<Test, size_t, &Test::member1> callback;
};
Test test;
// Callback for 'member2'.
etl::function_imp<Test, size_t, test, &Test::member2> member_callback;
// Callback for 'global'.
etl::function_fp<size_t, global> global_callback;
// Callback for 'unhandled'.
etl::function_fp<size_t, unhandled> unhandled_callback;
}
//*****************************************************************************
// Initialises the test results.
//*****************************************************************************
struct SetupFixture
{
SetupFixture()
{
called_id = UINT_MAX;
global_called = false;
member1_called = false;
member2_called = false;
unhandled_called = false;
}
};
namespace
{
enum
{
GLOBAL = OFFSET,
MEMBER1,
MEMBER2,
OUT_OF_RANGE
};
SUITE(test_callback_service)
{
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_callback_global_compile_time)
{
Service service;
service.register_callback<GLOBAL>(global_callback);
service.register_callback<MEMBER1>(test.callback);
service.register_callback<MEMBER2>(member_callback);
service.callback<GLOBAL>();
CHECK_EQUAL(GLOBAL, called_id);
CHECK(global_called);
CHECK(!member1_called);
CHECK(!member2_called);
CHECK(!unhandled_called);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_callback_global_run_time)
{
Service service;
service.register_callback(GLOBAL, global_callback);
service.register_callback(MEMBER1, test.callback);
service.register_callback(MEMBER2, member_callback);
service.callback(GLOBAL);
CHECK_EQUAL(GLOBAL, called_id);
CHECK(global_called);
CHECK(!member1_called);
CHECK(!member2_called);
CHECK(!unhandled_called);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_callback_member1_compile_time)
{
Service service;
service.register_callback<GLOBAL>(global_callback);
service.register_callback<MEMBER1>(test.callback);
service.register_callback<MEMBER2>(member_callback);
service.callback<MEMBER1>();
CHECK_EQUAL(MEMBER1, called_id);
CHECK(!global_called);
CHECK(member1_called);
CHECK(!member2_called);
CHECK(!unhandled_called);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_callback_member1_run_time)
{
Service service;
service.register_callback(GLOBAL, global_callback);
service.register_callback(MEMBER1, test.callback);
service.register_callback(MEMBER2, member_callback);
service.callback(MEMBER1);
CHECK_EQUAL(MEMBER1, called_id);
CHECK(!global_called);
CHECK(member1_called);
CHECK(!member2_called);
CHECK(!unhandled_called);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_callback_member2_compile_time)
{
Service service;
service.register_callback<GLOBAL>(global_callback);
service.register_callback<MEMBER1>(test.callback);
service.register_callback<MEMBER2>(member_callback);
service.callback<MEMBER2>();
CHECK_EQUAL(MEMBER2, called_id);
CHECK(!global_called);
CHECK(!member1_called);
CHECK(member2_called);
CHECK(!unhandled_called);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_callback_unhandled_out_of_range_run_time_default)
{
Service service;
service.register_callback<GLOBAL>(global_callback);
service.register_callback<MEMBER1>(test.callback);
service.register_callback<MEMBER2>(member_callback);
service.callback(OUT_OF_RANGE);
CHECK_EQUAL(UINT_MAX, called_id);
CHECK(!global_called);
CHECK(!member1_called);
CHECK(!member2_called);
CHECK(!unhandled_called);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_callback_unhandled_out_of_range_run_time_user_supplied)
{
Service service;
service.register_callback<GLOBAL>(global_callback);
service.register_callback<MEMBER1>(test.callback);
service.register_callback<MEMBER2>(member_callback);
service.register_unhandled_callback(unhandled_callback);
service.callback(OUT_OF_RANGE);
CHECK_EQUAL(OUT_OF_RANGE, called_id);
CHECK(!global_called);
CHECK(!member1_called);
CHECK(!member2_called);
CHECK(unhandled_called);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_callback_unhandled_not_registered_compile_time_default)
{
Service service;
service.register_callback<GLOBAL>(global_callback);
service.register_callback<MEMBER2>(member_callback);
service.callback<MEMBER1>();
CHECK_EQUAL(UINT_MAX, called_id);
CHECK(!global_called);
CHECK(!member1_called);
CHECK(!member2_called);
CHECK(!unhandled_called);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_callback_unhandled_not_registered_run_time_default)
{
Service service;
service.register_callback(GLOBAL, global_callback);
service.register_callback(MEMBER2, member_callback);
service.callback(MEMBER1);
CHECK_EQUAL(UINT_MAX, called_id);
CHECK(!global_called);
CHECK(!member1_called);
CHECK(!member2_called);
CHECK(!unhandled_called);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_callback_not_registered_compile_time_user_supplied)
{
Service service;
service.register_callback<GLOBAL>(global_callback);
service.register_callback<MEMBER2>(member_callback);
service.register_unhandled_callback(unhandled_callback);
service.callback<MEMBER1>();
CHECK_EQUAL(MEMBER1, called_id);
CHECK(!global_called);
CHECK(!member1_called);
CHECK(!member2_called);
CHECK(unhandled_called);
}
//*************************************************************************
TEST_FIXTURE(SetupFixture, test_callback_unhandled_run_time_user_supplied)
{
Service service;
service.register_callback(GLOBAL, global_callback);
service.register_callback(MEMBER2, member_callback);
service.register_unhandled_callback(unhandled_callback);
service.callback(MEMBER1);
CHECK_EQUAL(MEMBER1, called_id);
CHECK(!global_called);
CHECK(!member1_called);
CHECK(!member2_called);
CHECK(unhandled_called);
}
};
}

View File

@ -373,6 +373,7 @@
<ClInclude Include="..\..\include\etl\c\ecl_timer.h" />
<ClInclude Include="..\..\include\etl\fsm.h" />
<ClInclude Include="..\..\include\etl\fsm_generator.h" />
<ClInclude Include="..\..\include\etl\callback_service.h" />
<ClInclude Include="..\..\include\etl\largest_generator.h" />
<ClInclude Include="..\..\include\etl\absolute.h" />
<ClInclude Include="..\..\include\etl\scaled_rounding.h" />
@ -565,6 +566,7 @@
<ClCompile Include="..\murmurhash3.cpp" />
<ClCompile Include="..\test_algorithm.cpp" />
<ClCompile Include="..\test_alignment.cpp" />
<ClCompile Include="..\test_callback_service.cpp" />
<ClCompile Include="..\test_cumulative_moving_average.cpp" />
<ClCompile Include="..\test_forward_list_shared_pool.cpp" />
<ClCompile Include="..\test_bit_stream.cpp" />

View File

@ -723,6 +723,9 @@
<ClInclude Include="..\data.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="..\..\include\etl\callback_service.h">
<Filter>ETL\Frameworks</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\main.cpp">
@ -1145,6 +1148,9 @@
<ClCompile Include="..\test_cumulative_moving_average.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\test_callback_service.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\..\library.properties">