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

This commit is contained in:
John Wellbelove 2018-09-08 15:45:19 +01:00
commit d1a63fd507
9 changed files with 721 additions and 7 deletions

View File

@ -69,7 +69,11 @@ SOFTWARE.
#endif
#if defined(ETL_COMPILER_GCC)
#define GCC_VERSION ((__GNUC__ * 10000) + (__GNUC_MINOR__ * 100) + __GNUC_PATCHLEVEL__)
#define ETL_COMPILER_VERSION __GNUC__
#define ETL_COMPILER_FULL_VERSION ((__GNUC__ * 10000) + (__GNUC_MINOR__ * 100) + __GNUC_PATCHLEVEL__)
#elif defined ETL_COMPILER_MICROSOFT
#define ETL_COMPILER_VERSION _MSC_VER
#define ETL_COMPILER_FULL_VERSION _MSC_FULL_VER
#endif
#if ETL_CPP11_SUPPORTED
@ -84,4 +88,10 @@ SOFTWARE.
#define ETL_IF_CONSTEXPR
#endif
#if ETL_CPP11_SUPPORTED
#define ETL_DELETE = delete
#else
#define ETL_DELETE
#endif
#endif

289
include/etl/state_chart.h Normal file
View File

@ -0,0 +1,289 @@
/******************************************************************************
The MIT License(MIT)
Embedded Template Library.
https://github.com/ETLCPP/etl
https://www.etlcpp.com
Copyright(c) 2018 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_STATE_CHART_INCLUDED
#define ETL_STATE_CHART_INCLUDED
#include <stdint.h>
#include "etl/platform.h"
#include "etl/nullptr.h"
#include "etl/array.h"
#include "etl/array_view.h"
namespace etl
{
//***************************************************************************
/// Simple Finite State Machine Interface
//***************************************************************************
class istate_chart
{
public:
typedef uint32_t state_id_t;
typedef uint32_t event_id_t;
virtual state_id_t get_state_id() const = 0;
virtual void process_event(const event_id_t event_id) = 0;
virtual ~istate_chart()
{
}
};
//***************************************************************************
/// Simple Finite State Machine
//***************************************************************************
template <typename TObject>
class state_chart : public istate_chart
{
public:
//*************************************************************************
/// Transition definition
//*************************************************************************
struct transition
{
transition(const event_id_t event_id_,
const state_id_t current_state_id_,
const state_id_t next_state_id_,
void (TObject::* const action_)() = nullptr,
bool (TObject::* const guard_)() = nullptr)
: event_id(event_id_),
current_state_id(current_state_id_),
next_state_id(next_state_id_),
action(action_),
guard(guard_)
{
}
const event_id_t event_id;
const state_id_t current_state_id;
const state_id_t next_state_id;
void (TObject::* const action)();
bool (TObject::* const guard)();
};
//*************************************************************************
/// State definition
//*************************************************************************
struct state
{
state(const state_id_t state_id_,
void (TObject::* const on_entry_)() = nullptr,
void (TObject::* const on_exit_)() = nullptr)
: state_id(state_id_),
on_entry(on_entry_),
on_exit(on_exit_)
{
}
state_id_t state_id;
void (TObject::* const on_entry)();
void (TObject::* const on_exit)();
};
//*************************************************************************
/// Constructor.
/// \tparam TRANSITION_TABLE_SIZE The transition table size.
/// \param object_ A reference to the implementation object.
/// \param transition_table_ The table of transitions.
/// \param state_id_ The initial state id.
//*************************************************************************
template <const uint32_t TRANSITION_TABLE_SIZE>
state_chart(TObject& object_,
const etl::array<transition, TRANSITION_TABLE_SIZE>& transition_table_,
const state_id_t state_id_)
: object(object_),
current_state_id(state_id_),
transition_table(transition_table_.begin(), transition_table_.end())
{
}
//*************************************************************************
/// Sets the state table.
/// \tparam STATE_TABLE_SIZE The state table size.
/// \param state_table_ A reference to the state table.
//*************************************************************************
template <const uint32_t STATE_TABLE_SIZE>
void set_state_table(const etl::array<state, STATE_TABLE_SIZE>& state_table_)
{
state_table.assign(state_table_.begin(), state_table_.end());
}
//*************************************************************************
/// Gets a reference to the implementation object.
/// \return Reference to the implementation object.
//*************************************************************************
TObject& get_object()
{
return object;
}
//*************************************************************************
/// Gets a const reference to the implementation object.
/// \return Const reference to the implementation object.
//*************************************************************************
const TObject& get_object() const
{
return object;
}
//*************************************************************************
/// Gets the current state id.
/// \return The current state id.
//*************************************************************************
state_id_t get_state_id() const
{
return current_state_id;
}
//*************************************************************************
/// Gets the current state id.
/// \return The current state id.
//*************************************************************************
const state* find_state(state_id_t state_id)
{
if (state_table.empty())
{
return state_table.end();
}
else
{
return std::find_if(state_table.begin(),
state_table.end(),
is_state(state_id));
}
}
//*************************************************************************
/// Processes the specified event.
/// The state machine will action the <b>first</b> item in the transition table
/// that satisfies the conditions for executing the action.
/// \param event_id The id of the event to process.
//*************************************************************************
void process_event(const event_id_t event_id)
{
// Scan the transition table.
const transition* t = std::find_if(transition_table.begin(),
transition_table.end(),
is_transition(event_id, current_state_id));
// Found an entry?
if (t != transition_table.end())
{
// Shall we execute the transition?
if ((t->guard == nullptr) || ((object.*t->guard)()))
{
const bool to_new_state = (current_state_id != t->next_state_id);
// Execute the state exit if necessary.
if (to_new_state)
{
// See if we have a state item for the current state.
const state* s = find_state(current_state_id);
// If the current state has an 'on_exit' then call it.
if ((s != state_table.end()) && (s->on_exit != nullptr))
{
(object.*(s->on_exit))();
}
}
// Shall we execute the action?
if (t->action != nullptr)
{
(object.*t->action)();
}
// Execute the state entry if necessary.
if (to_new_state)
{
// See if we have a state item for the next state.
const state* s = find_state(t->next_state_id);
// If the new state has an 'on_entry' then call it.
if ((s != state_table.end()) && (s->on_entry != nullptr))
{
(object.*(s->on_entry))();
}
}
current_state_id = t->next_state_id;
}
}
}
private:
//*************************************************************************
struct is_transition
{
is_transition(event_id_t event_id_, state_id_t state_id_)
: event_id(event_id_),
state_id(state_id_)
{
}
bool operator()(const transition& t) const
{
return (t.event_id == event_id) && (t.current_state_id == state_id);
}
const event_id_t event_id;
const state_id_t state_id;
};
//*************************************************************************
struct is_state
{
is_state(state_id_t state_id_)
: state_id(state_id_)
{
}
bool operator()(const state& s) const
{
return (s.state_id == state_id);
}
const state_id_t state_id;
};
// Disabled
state_chart(const state_chart&) ETL_DELETE;
state_chart& operator =(const state_chart&) ETL_DELETE;
TObject& object; ///< The object that supplies guard and action member functions.
state_id_t current_state_id; ///< The current state id.
const etl::array_view<const transition> transition_table; ///< The table of transitions.
etl::array_view<const state> state_table; ///< The table of states.
};
}
#endif

View File

@ -37,13 +37,13 @@ SOFTWARE.
/// Definitions of the ETL version
///\ingroup utilities
#define ETL_VERSION "11.16.5"
#define ETL_VERSION_W L"11.16.5"
#define ETL_VERSION_U16 u"11.16.5"
#define ETL_VERSION_U32 U"11.16.5"
#define ETL_VERSION "11.17.0"
#define ETL_VERSION_W L"11.17.0"
#define ETL_VERSION_U16 u"11.17.0"
#define ETL_VERSION_U32 U"11.17.0"
#define ETL_VERSION_MAJOR 11
#define ETL_VERSION_MINOR 16
#define ETL_VERSION_PATCH 5
#define ETL_VERSION_MINOR 17
#define ETL_VERSION_PATCH 0
#define ETL_VERSION_VALUE ((ETL_VERSION_MAJOR * 10000) + (ETL_VERSION_MINOR * 100) + ETL_VERSION_PATCH)
#endif

View File

@ -1,3 +1,11 @@
===============================================================================
11.17.0
Added etl::state_chart
===============================================================================
11.16.6
Fixed implementations of key_comp and value_comp for maps and sets
===============================================================================
11.16.5
Added 'ull' suffix to 64bit literals

View File

@ -279,6 +279,7 @@
<Unit filename="../../include/etl/spsc_queue_mutex.h" />
<Unit filename="../../include/etl/sqrt.h" />
<Unit filename="../../include/etl/stack.h" />
<Unit filename="../../include/etl/state_chart.h" />
<Unit filename="../../include/etl/static_assert.h" />
<Unit filename="../../include/etl/stl/algorithm.h" />
<Unit filename="../../include/etl/stl/alternate/algorithm.h" />
@ -423,6 +424,7 @@
<Unit filename="../test_set.cpp" />
<Unit filename="../test_smallest.cpp" />
<Unit filename="../test_stack.cpp" />
<Unit filename="../test_state_chart.cpp" />
<Unit filename="../test_string_char.cpp" />
<Unit filename="../test_string_u16.cpp" />
<Unit filename="../test_string_u32.cpp" />

387
test/test_state_chart.cpp Normal file
View File

@ -0,0 +1,387 @@
/******************************************************************************
The MIT License(MIT)
Embedded Template Library.
https://github.com/ETLCPP/etl
https://www.etlcpp.com
Copyright(c) 2018 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/state_chart.h"
#include "etl/enum_type.h"
#include "etl/queue.h"
#include "etl/array.h"
#include <iostream>
namespace
{
//***************************************************************************
// Events
struct EventId
{
enum enum_type
{
START,
STOP,
EMERGENCY_STOP,
STOPPED,
SET_SPEED
};
ETL_DECLARE_ENUM_TYPE(EventId, etl::istate_chart::event_id_t)
ETL_ENUM_TYPE(START, "Start")
ETL_ENUM_TYPE(STOP, "Stop")
ETL_ENUM_TYPE(EMERGENCY_STOP, "Emergency Stop")
ETL_ENUM_TYPE(STOPPED, "Stopped")
ETL_ENUM_TYPE(SET_SPEED, "Set Speed")
ETL_END_ENUM_TYPE
};
//***************************************************************************
// States
struct StateId
{
enum enum_type
{
IDLE,
RUNNING,
WINDING_DOWN,
NUMBER_OF_STATES
};
ETL_DECLARE_ENUM_TYPE(StateId, etl::istate_chart::state_id_t)
ETL_ENUM_TYPE(IDLE, "Idle")
ETL_ENUM_TYPE(RUNNING, "Running")
ETL_ENUM_TYPE(WINDING_DOWN, "Winding Down")
ETL_END_ENUM_TYPE
};
//***********************************
// The motor control FSM.
//***********************************
class MotorControl : public etl::state_chart<MotorControl>
{
public:
MotorControl()
: state_chart<MotorControl>(*this, transitionTable, StateId::IDLE)
{
this->set_state_table(stateTable);
ClearStatistics();
}
//***********************************
void ClearStatistics()
{
startCount = 0;
stopCount = 0;
setSpeedCount = 0;
stoppedCount = 0;
isLampOn = false;
speed = 0;
windingDown = 0;
}
//***********************************
void OnStart()
{
++startCount;
}
//***********************************
void OnStop()
{
++stopCount;
}
//***********************************
void OnStopped()
{
++stoppedCount;
}
//***********************************
void OnSetSpeed()
{
++setSpeedCount;
SetSpeedValue(100);
}
//***********************************
void OnEnterIdle()
{
TurnRunningLampOff();
}
//***********************************
void OnEnterRunning()
{
TurnRunningLampOn();
}
//***********************************
void OnEnterWindingDown()
{
++windingDown;
}
//***********************************
void OnExitWindingDown()
{
--windingDown;
}
//***********************************
void SetSpeedValue(int speed_)
{
speed = speed_;
}
//***********************************
bool Guard()
{
return guard;
}
//***********************************
void TurnRunningLampOn()
{
isLampOn = true;
}
//***********************************
void TurnRunningLampOff()
{
isLampOn = false;
}
int startCount;
int stopCount;
int setSpeedCount;
int stoppedCount;
bool isLampOn;
int speed;
int windingDown;
bool guard;
static const etl::array<MotorControl::transition, 5> transitionTable;
static const etl::array<MotorControl::state, 3> stateTable;
};
//***************************************************************************
const etl::array<MotorControl::transition, 5> MotorControl::transitionTable =
{
MotorControl::transition(EventId::START, StateId::IDLE, StateId::RUNNING, &MotorControl::OnStart, &MotorControl::Guard),
MotorControl::transition(EventId::STOP, StateId::RUNNING, StateId::WINDING_DOWN, &MotorControl::OnStop),
MotorControl::transition(EventId::STOPPED, StateId::WINDING_DOWN, StateId::IDLE, &MotorControl::OnStopped),
MotorControl::transition(EventId::EMERGENCY_STOP, StateId::RUNNING, StateId::IDLE, &MotorControl::OnStop),
MotorControl::transition(EventId::SET_SPEED, StateId::RUNNING, StateId::RUNNING, &MotorControl::OnSetSpeed)
};
//***************************************************************************
const etl::array<MotorControl::state, 3> MotorControl::stateTable =
{
MotorControl::state(StateId::IDLE, &MotorControl::OnEnterIdle, nullptr),
MotorControl::state(StateId::RUNNING, &MotorControl::OnEnterRunning, nullptr),
MotorControl::state(StateId::WINDING_DOWN, &MotorControl::OnEnterWindingDown, &MotorControl::OnExitWindingDown)
};
MotorControl motorControl;
SUITE(test_state_chart_class)
{
//*************************************************************************
TEST(test_state_chart)
{
motorControl.ClearStatistics();
// Now in Idle state.
CHECK_EQUAL(StateId::IDLE, int(motorControl.get_state_id()));
CHECK_EQUAL(false, motorControl.isLampOn);
CHECK_EQUAL(0, motorControl.setSpeedCount);
CHECK_EQUAL(0, motorControl.speed);
CHECK_EQUAL(0, motorControl.startCount);
CHECK_EQUAL(0, motorControl.stopCount);
CHECK_EQUAL(0, motorControl.stoppedCount);
CHECK_EQUAL(0, motorControl.windingDown);
// Send unhandled events.
motorControl.process_event(EventId::STOP);
motorControl.process_event(EventId::STOPPED);
CHECK_EQUAL(StateId::IDLE, motorControl.get_state_id());
CHECK_EQUAL(false, motorControl.isLampOn);
CHECK_EQUAL(0, motorControl.setSpeedCount);
CHECK_EQUAL(0, motorControl.speed);
CHECK_EQUAL(0, motorControl.startCount);
CHECK_EQUAL(0, motorControl.stopCount);
CHECK_EQUAL(0, motorControl.stoppedCount);
// Send Start event.
motorControl.guard = false;
motorControl.process_event(EventId::START);
// Still in Idle state.
CHECK_EQUAL(StateId::IDLE, int(motorControl.get_state_id()));
CHECK_EQUAL(false, motorControl.isLampOn);
CHECK_EQUAL(0, motorControl.setSpeedCount);
CHECK_EQUAL(0, motorControl.speed);
CHECK_EQUAL(0, motorControl.startCount);
CHECK_EQUAL(0, motorControl.stopCount);
CHECK_EQUAL(0, motorControl.stoppedCount);
CHECK_EQUAL(0, motorControl.windingDown);
// Send Start event.
motorControl.guard = true;
motorControl.process_event(EventId::START);
// Now in Running state.
CHECK_EQUAL(StateId::RUNNING, int(motorControl.get_state_id()));
CHECK_EQUAL(true, motorControl.isLampOn);
CHECK_EQUAL(0, motorControl.setSpeedCount);
CHECK_EQUAL(0, motorControl.speed);
CHECK_EQUAL(1, motorControl.startCount);
CHECK_EQUAL(0, motorControl.stopCount);
CHECK_EQUAL(0, motorControl.stoppedCount);
CHECK_EQUAL(0, motorControl.windingDown);
// Send unhandled events.
motorControl.process_event(EventId::START);
motorControl.process_event(EventId::STOPPED);
CHECK_EQUAL(StateId::RUNNING, int(motorControl.get_state_id()));
CHECK_EQUAL(true, motorControl.isLampOn);
CHECK_EQUAL(0, motorControl.setSpeedCount);
CHECK_EQUAL(0, motorControl.speed);
CHECK_EQUAL(1, motorControl.startCount);
CHECK_EQUAL(0, motorControl.stopCount);
CHECK_EQUAL(0, motorControl.stoppedCount);
CHECK_EQUAL(0, motorControl.windingDown);
// Send SetSpeed event.
motorControl.process_event(EventId::SET_SPEED);
// Still in Running state.
CHECK_EQUAL(StateId::RUNNING, int(motorControl.get_state_id()));
CHECK_EQUAL(true, motorControl.isLampOn);
CHECK_EQUAL(1, motorControl.setSpeedCount);
CHECK_EQUAL(100, motorControl.speed);
CHECK_EQUAL(1, motorControl.startCount);
CHECK_EQUAL(0, motorControl.stopCount);
CHECK_EQUAL(0, motorControl.stoppedCount);
CHECK_EQUAL(0, motorControl.windingDown);
// Send Stop event.
motorControl.process_event(EventId::STOP);
// Now in WindingDown state.
CHECK_EQUAL(StateId::WINDING_DOWN, int(motorControl.get_state_id()));
CHECK_EQUAL(true, motorControl.isLampOn);
CHECK_EQUAL(1, motorControl.setSpeedCount);
CHECK_EQUAL(100, motorControl.speed);
CHECK_EQUAL(1, motorControl.startCount);
CHECK_EQUAL(1, motorControl.stopCount);
CHECK_EQUAL(0, motorControl.stoppedCount);
CHECK_EQUAL(1, motorControl.windingDown);
// Send unhandled events.
motorControl.process_event(EventId::START);
motorControl.process_event(EventId::STOP);
CHECK_EQUAL(StateId::WINDING_DOWN, int(motorControl.get_state_id()));
CHECK_EQUAL(true, motorControl.isLampOn);
CHECK_EQUAL(1, motorControl.setSpeedCount);
CHECK_EQUAL(100, motorControl.speed);
CHECK_EQUAL(1, motorControl.startCount);
CHECK_EQUAL(1, motorControl.stopCount);
CHECK_EQUAL(0, motorControl.stoppedCount);
CHECK_EQUAL(1, motorControl.windingDown);
// Send Stopped event.
motorControl.process_event(EventId::STOPPED);
// Now in Idle state.
CHECK_EQUAL(StateId::IDLE, int(motorControl.get_state_id()));
CHECK_EQUAL(false, motorControl.isLampOn);
CHECK_EQUAL(1, motorControl.setSpeedCount);
CHECK_EQUAL(100, motorControl.speed);
CHECK_EQUAL(1, motorControl.startCount);
CHECK_EQUAL(1, motorControl.stopCount);
CHECK_EQUAL(1, motorControl.stoppedCount);
CHECK_EQUAL(0, motorControl.windingDown);
}
//*************************************************************************
TEST(test_fsm_emergency_stop)
{
motorControl.ClearStatistics();
// Now in Idle state.
// Send Start event.
motorControl.process_event(EventId::START);
// Now in Running state.
CHECK_EQUAL(StateId::RUNNING, int(motorControl.get_state_id()));
CHECK_EQUAL(true, motorControl.isLampOn);
CHECK_EQUAL(0, motorControl.setSpeedCount);
CHECK_EQUAL(0, motorControl.speed);
CHECK_EQUAL(1, motorControl.startCount);
CHECK_EQUAL(0, motorControl.stopCount);
CHECK_EQUAL(0, motorControl.stoppedCount);
CHECK_EQUAL(0, motorControl.windingDown);
// Send emergency Stop event.
motorControl.process_event(EventId::EMERGENCY_STOP);
// Now in Idle state.
CHECK_EQUAL(StateId::IDLE, int(motorControl.get_state_id()));
CHECK_EQUAL(false, motorControl.isLampOn);
CHECK_EQUAL(0, motorControl.setSpeedCount);
CHECK_EQUAL(0, motorControl.speed);
CHECK_EQUAL(1, motorControl.startCount);
CHECK_EQUAL(1, motorControl.stopCount);
CHECK_EQUAL(0, motorControl.stoppedCount);
CHECK_EQUAL(0, motorControl.windingDown);
}
};
}

8
test/vs2017/cpp.hint Normal file
View File

@ -0,0 +1,8 @@
// Hint files help the Visual Studio IDE interpret Visual C++ identifiers
// such as names of functions and macros.
// For more information see https://go.microsoft.com/fwlink/?linkid=865984
#define ETL_CONSTEXPR
#define ETL_CONSTEXPR_IF
#define ETL_DELETE

View File

@ -371,6 +371,7 @@
<ClInclude Include="..\..\include\etl\fsm.h" />
<ClInclude Include="..\..\include\etl\fsm_generator.h" />
<ClInclude Include="..\..\include\etl\largest_generator.h" />
<ClInclude Include="..\..\include\etl\state_chart.h" />
<ClInclude Include="..\..\include\etl\math_constants.h" />
<ClInclude Include="..\..\include\etl\memory_model.h" />
<ClInclude Include="..\..\include\etl\message.h" />
@ -728,6 +729,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\test_state_chart.cpp" />
<ClCompile Include="..\test_smallest.cpp" />
<ClCompile Include="..\test_stack.cpp" />
<ClCompile Include="..\test_string_char.cpp" />
@ -768,6 +770,7 @@
<None Include="..\..\include\etl\generate_type_lookup.bat" />
<None Include="..\..\include\etl\generate_type_traits.bat" />
<None Include="..\..\include\etl\generate_variant_pool.bat" />
<None Include="cpp.hint" />
</ItemGroup>
<ItemGroup>
<Text Include="..\..\CMakeLists.txt" />

View File

@ -693,6 +693,9 @@
<ClInclude Include="..\..\include\etl\atomic\atomic_llvm_sync.h">
<Filter>ETL\Utilities\Atomic</Filter>
</ClInclude>
<ClInclude Include="..\..\include\etl\state_chart.h">
<Filter>ETL\Frameworks</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\main.cpp">
@ -1136,6 +1139,9 @@
<ClCompile Include="..\test_no_stl_iterator.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\test_state_chart.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\..\library.properties">
@ -1174,6 +1180,7 @@
<None Include="..\..\include\etl\generate_type_select.bat">
<Filter>Resource Files\Generators</Filter>
</None>
<None Include="cpp.hint" />
</ItemGroup>
<ItemGroup>
<Text Include="..\..\include\etl\file_error_numbers.txt">