diff --git a/.gitignore b/.gitignore index f652b45..2697e09 100644 --- a/.gitignore +++ b/.gitignore @@ -297,3 +297,291 @@ __pycache__/ *.btm.cs *.odx.cs *.xsd.cs +/References/boost/accumulators +/References/boost/function_types +/References/boost/functional +/References/boost/function +/References/boost/format +/References/boost/flyweight +/References/boost/filesystem +/References/boost/exception +/References/boost/endian +/References/boost/dynamic_bitset +/References/boost/detail +/References/boost/date_time +/References/boost/coroutine2 +/References/boost/coroutine +/References/boost/core +/References/boost/convert +/References/boost/context +/References/boost/container +/References/boost/config +/References/boost/concept_check +/References/boost/concept +/References/boost/compatibility/cpp_c_headers +/References/boost/circular_buffer +/References/boost/chrono +/References/boost/bind +/References/boost/bimap +/References/boost/atomic +/References/boost/assign +/References/boost/asio +/References/boost/archive +/References/boost/align +/References/boost/algorithm +/References/boost/iostreams +/References/boost/io +/References/boost/intrusive +/References/boost/interprocess +/References/boost/integer +/References/boost/icl +/References/boost/heap +/References/boost/graph +/References/boost/gil +/References/boost/geometry +/References/boost/fusion +/References/boost/mpl +/References/boost/mpi +/References/boost/move +/References/boost/math +/References/boost/logic +/References/boost/lockfree +/References/boost/local_function +/References/boost/locale +/References/boost/lexical_cast +/References/boost/lambda +/References/boost/iterator +/References/boost/pool +/References/boost/polygon +/References/boost/phoenix +/References/boost/pending +/References/boost/parameter +/References/boost/optional +/References/boost/numeric +/References/boost/multi_index +/References/boost/multi_array +/References/boost/multiprecision +/References/boost/msm +/References/boost/ratio +/References/boost/range +/References/boost/random +/References/boost/python +/References/boost/ptr_container +/References/boost/proto +/References/boost/property_tree +/References/boost/property_map +/References/boost/program_options +/References/boost/preprocessor +/References/boost/predef +/References/boost/timer +/References/boost/thread +/References/boost/test +/References/boost/system +/References/boost/statechart +/References/boost/spirit +/References/boost/sort +/References/boost/smart_ptr +/References/boost/signals2 +/References/boost/signals +/References/boost/serialization +/References/boost/regex +/References/boost/variant +/References/boost/uuid +/References/boost/utility +/References/boost/unordered +/References/boost/units +/References/boost/type_traits +/References/boost/type_index +/References/boost/type_erasure +/References/boost/typeof +/References/boost/tuple +/References/boost/tti +/References/boost/tr1 +/References/boost/xpressive +/References/boost/weak_ptr.hpp +/References/boost/wave.hpp +/References/boost/wave +/References/boost/vmd +/References/boost/visit_each.hpp +/References/boost/version.hpp +/References/boost/variant.hpp +/References/boost/utility.hpp +/References/boost/unordered_set.hpp +/References/boost/unordered_map.hpp +/References/boost/type_traits.hpp +/References/boost/type_index.hpp +/References/boost/type.hpp +/References/boost/token_iterator.hpp +/References/boost/token_functions.hpp +/References/boost/tokenizer.hpp +/References/boost/timer.hpp +/References/boost/throw_exception.hpp +/References/boost/thread.hpp +/References/boost/swap.hpp +/References/boost/static_assert.hpp +/References/boost/spirit.hpp +/References/boost/smart_ptr.hpp +/References/boost/signals2.hpp +/References/boost/signals.hpp +/References/boost/signal.hpp +/References/boost/shared_ptr.hpp +/References/boost/shared_container_iterator.hpp +/References/boost/shared_array.hpp +/References/boost/scope_exit.hpp +/References/boost/scoped_ptr.hpp +/References/boost/scoped_array.hpp +/References/boost/regex_fwd.hpp +/References/boost/regex.hpp +/References/boost/regex.h +/References/boost/ref.hpp +/References/boost/rational.hpp +/References/boost/ratio.hpp +/References/boost/range.hpp +/References/boost/random.hpp +/References/boost/python.hpp +/References/boost/progress.hpp +/References/boost/program_options.hpp +/References/boost/preprocessor.hpp +/References/boost/predef.h +/References/boost/polymorphic_pointer_cast.hpp +/References/boost/polymorphic_cast.hpp +/References/boost/pointer_to_other.hpp +/References/boost/pointer_cast.hpp +/References/boost/pointee.hpp +/References/boost/phoenix.hpp +/References/boost/parameter.hpp +/References/boost/optional.hpp +/References/boost/operators.hpp +/References/boost/non_type.hpp +/References/boost/none_t.hpp +/References/boost/none.hpp +/References/boost/nondet_random.hpp +/References/boost/noncopyable.hpp +/References/boost/next_prior.hpp +/References/boost/multi_index_container_fwd.hpp +/References/boost/multi_index_container.hpp +/References/boost/multi_array.hpp +/References/boost/mpi.hpp +/References/boost/mem_fn.hpp +/References/boost/memory_order.hpp +/References/boost/math_fwd.hpp +/References/boost/make_unique.hpp +/References/boost/make_shared.hpp +/References/boost/make_default.hpp +/References/boost/local_function.hpp +/References/boost/locale.hpp +/References/boost/limits.hpp +/References/boost/lexical_cast.hpp +/References/boost/last_value.hpp +/References/boost/iterator_adaptors.hpp +/References/boost/iterator.hpp +/References/boost/is_placeholder.hpp +/References/boost/io_fwd.hpp +/References/boost/intrusive_ptr.hpp +/References/boost/integer_traits.hpp +/References/boost/integer_fwd.hpp +/References/boost/integer.hpp +/References/boost/indirect_reference.hpp +/References/boost/implicit_cast.hpp +/References/boost/get_pointer.hpp +/References/boost/geometry.hpp +/References/boost/generator_iterator.hpp +/References/boost/function_output_iterator.hpp +/References/boost/function_equal.hpp +/References/boost/functional.hpp +/References/boost/function.hpp +/References/boost/format.hpp +/References/boost/foreach_fwd.hpp +/References/boost/foreach.hpp +/References/boost/flyweight.hpp +/References/boost/filesystem.hpp +/References/boost/exception_ptr.hpp +/References/boost/enable_shared_from_this.hpp +/References/boost/dynamic_bitset_fwd.hpp +/References/boost/dynamic_bitset.hpp +/References/boost/date_time.hpp +/References/boost/cxx11_char_types.hpp +/References/boost/current_function.hpp +/References/boost/cstdlib.hpp +/References/boost/cstdint.hpp +/References/boost/cstdfloat.hpp +/References/boost/cregex.hpp +/References/boost/crc.hpp +/References/boost/convert.hpp +/References/boost/config.hpp +/References/boost/concept_check.hpp +/References/boost/concept_archetype.hpp +/References/boost/compressed_pair.hpp +/References/boost/circular_buffer_fwd.hpp +/References/boost/circular_buffer.hpp +/References/boost/chrono.hpp +/References/boost/checked_delete.hpp +/References/boost/cerrno.hpp +/References/boost/cast.hpp +/References/boost/call_traits.hpp +/References/boost/blank_fwd.hpp +/References/boost/blank.hpp +/References/boost/bind.hpp +/References/boost/bimap.hpp +/References/boost/atomic.hpp +/References/boost/assign.hpp +/References/boost/assert.hpp +/References/boost/asio.hpp +/References/boost/array.hpp +/References/boost/any.hpp +/References/boost/aligned_storage.hpp +/References/boost/align.hpp +/References/pugixml/pugixml.hpp +/References/pugixml/pugixml.cpp +/References/pugixml/pugiconfig.hpp +/tmp/Hermes_Debug_x86 +/References/lib32 +/References/lib64 +/References/boost/winapi +/References/boost/stacktrace.hpp +/References/boost/stacktrace +/References/boost/qvm +/References/boost/process.hpp +/References/boost/process +/References/boost/poly_collection +/References/boost/operators_v1.hpp +/References/boost/mp11.hpp +/References/boost/mp11 +/References/boost/metaparse.hpp +/References/boost/metaparse +/References/boost/hof.hpp +/References/boost/hof +/References/boost/hana.hpp +/References/boost/hana +/References/boost/fiber +/References/boost/dll.hpp +/References/boost/dll +/References/boost/contract_macro.hpp +/References/boost/contract.hpp +/References/boost/contract +/References/boost/container_hash +/References/boost/compute.hpp +/References/boost/compute +/References/boost/callable_traits.hpp +/References/boost/callable_traits +/References/boost/beast.hpp +/References/boost/beast +/src/include/HermesStringView.hpp.bak +/src/include/HermesDataConversion.hpp.bak +/src/include/HermesData.hpp.bak +/src/include/HermesData.h.bak +/src/include/Hermes.hpp.bak +/src/Hermes/VerticalService.cpp.bak +/src/Hermes/VerticalClientSession.h.bak +/src/Hermes/VerticalClientSession.cpp.bak +/src/Hermes/VerticalClient.cpp.bak +/src/Hermes/SenderEnvelope.cpp.bak +/src/Hermes/MessageSerialization.cpp.bak +/src/Hermes/Downstream.cpp.bak +/src/Hermes/Makefile.bak +/References/boost +/src/Hermes/pugixml +/version +/tmp/Hermes_Debug_x64 +/src/Hermes/pugixml.notUse +/tmp diff --git a/src/Hermes.sln b/src/Hermes.sln index be29d7c..a84f522 100644 --- a/src/Hermes.sln +++ b/src/Hermes.sln @@ -1,19 +1,11 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 +# Visual Studio 15 +VisualStudioVersion = 15.0.28010.2050 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Hermes", "Hermes\Hermes.vcxproj", "{A52420C5-D236-47B7-883E-2166E83C2F43}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BoostTestHermes", "test\BoostTestHermes\BoostTestHermes.vcxproj", "{B4CB35B8-B453-4B1E-8469-5A8059F2CE25}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HermesTest", "test\HermesTest\HermesTest.vcxproj", "{A0FE866F-50A9-4CEF-876F-1B8251C6F1C5}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HermesDotNet", "HermesDotNet\HermesDotNet.vcxproj", "{EB6C775D-6A4E-4708-A4A9-3365DE88D625}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HermesDotNetTest", "HermesDotNetTest\HermesDotNetTest.csproj", "{500DB8FC-4FAE-49C5-B9A6-D8ED7F224E9D}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HermesManInTheMiddle", "HermesManInTheMiddle\HermesManInTheMiddle.vcxproj", "{6C404C67-FD84-4775-92D0-B45609CA760A}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BoostTestHermes", "..\test\BoostTestHermes\BoostTestHermes.vcxproj", "{B4CB35B8-B453-4B1E-8469-5A8059F2CE25}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -45,74 +37,11 @@ Global {B4CB35B8-B453-4B1E-8469-5A8059F2CE25}.Release|x64.Build.0 = Release|x64 {B4CB35B8-B453-4B1E-8469-5A8059F2CE25}.Release|x86.ActiveCfg = Release|Win32 {B4CB35B8-B453-4B1E-8469-5A8059F2CE25}.Release|x86.Build.0 = Release|Win32 - {A0FE866F-50A9-4CEF-876F-1B8251C6F1C5}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {A0FE866F-50A9-4CEF-876F-1B8251C6F1C5}.Debug|x64.ActiveCfg = Debug|x64 - {A0FE866F-50A9-4CEF-876F-1B8251C6F1C5}.Debug|x64.Build.0 = Debug|x64 - {A0FE866F-50A9-4CEF-876F-1B8251C6F1C5}.Debug|x86.ActiveCfg = Debug|Win32 - {A0FE866F-50A9-4CEF-876F-1B8251C6F1C5}.Debug|x86.Build.0 = Debug|Win32 - {A0FE866F-50A9-4CEF-876F-1B8251C6F1C5}.Release|Any CPU.ActiveCfg = Release|Win32 - {A0FE866F-50A9-4CEF-876F-1B8251C6F1C5}.Release|x64.ActiveCfg = Release|x64 - {A0FE866F-50A9-4CEF-876F-1B8251C6F1C5}.Release|x64.Build.0 = Release|x64 - {A0FE866F-50A9-4CEF-876F-1B8251C6F1C5}.Release|x86.ActiveCfg = Release|Win32 - {A0FE866F-50A9-4CEF-876F-1B8251C6F1C5}.Release|x86.Build.0 = Release|Win32 - {EB6C775D-6A4E-4708-A4A9-3365DE88D625}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {EB6C775D-6A4E-4708-A4A9-3365DE88D625}.Debug|x64.ActiveCfg = Debug|x64 - {EB6C775D-6A4E-4708-A4A9-3365DE88D625}.Debug|x64.Build.0 = Debug|x64 - {EB6C775D-6A4E-4708-A4A9-3365DE88D625}.Debug|x86.ActiveCfg = Debug|Win32 - {EB6C775D-6A4E-4708-A4A9-3365DE88D625}.Debug|x86.Build.0 = Debug|Win32 - {EB6C775D-6A4E-4708-A4A9-3365DE88D625}.Release|Any CPU.ActiveCfg = Release|Win32 - {EB6C775D-6A4E-4708-A4A9-3365DE88D625}.Release|x64.ActiveCfg = Release|x64 - {EB6C775D-6A4E-4708-A4A9-3365DE88D625}.Release|x64.Build.0 = Release|x64 - {EB6C775D-6A4E-4708-A4A9-3365DE88D625}.Release|x86.ActiveCfg = Release|Win32 - {EB6C775D-6A4E-4708-A4A9-3365DE88D625}.Release|x86.Build.0 = Release|Win32 - {500DB8FC-4FAE-49C5-B9A6-D8ED7F224E9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {500DB8FC-4FAE-49C5-B9A6-D8ED7F224E9D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {500DB8FC-4FAE-49C5-B9A6-D8ED7F224E9D}.Debug|x64.ActiveCfg = Debug|x64 - {500DB8FC-4FAE-49C5-B9A6-D8ED7F224E9D}.Debug|x64.Build.0 = Debug|x64 - {500DB8FC-4FAE-49C5-B9A6-D8ED7F224E9D}.Debug|x86.ActiveCfg = Debug|x86 - {500DB8FC-4FAE-49C5-B9A6-D8ED7F224E9D}.Debug|x86.Build.0 = Debug|x86 - {500DB8FC-4FAE-49C5-B9A6-D8ED7F224E9D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {500DB8FC-4FAE-49C5-B9A6-D8ED7F224E9D}.Release|Any CPU.Build.0 = Release|Any CPU - {500DB8FC-4FAE-49C5-B9A6-D8ED7F224E9D}.Release|x64.ActiveCfg = Release|x64 - {500DB8FC-4FAE-49C5-B9A6-D8ED7F224E9D}.Release|x64.Build.0 = Release|x64 - {500DB8FC-4FAE-49C5-B9A6-D8ED7F224E9D}.Release|x86.ActiveCfg = Release|x86 - {500DB8FC-4FAE-49C5-B9A6-D8ED7F224E9D}.Release|x86.Build.0 = Release|x86 - {6C404C67-FD84-4775-92D0-B45609CA760A}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {6C404C67-FD84-4775-92D0-B45609CA760A}.Debug|x64.ActiveCfg = Debug|x64 - {6C404C67-FD84-4775-92D0-B45609CA760A}.Debug|x64.Build.0 = Debug|x64 - {6C404C67-FD84-4775-92D0-B45609CA760A}.Debug|x86.ActiveCfg = Debug|Win32 - {6C404C67-FD84-4775-92D0-B45609CA760A}.Debug|x86.Build.0 = Debug|Win32 - {6C404C67-FD84-4775-92D0-B45609CA760A}.Release|Any CPU.ActiveCfg = Release|Win32 - {6C404C67-FD84-4775-92D0-B45609CA760A}.Release|x64.ActiveCfg = Release|x64 - {6C404C67-FD84-4775-92D0-B45609CA760A}.Release|x64.Build.0 = Release|x64 - {6C404C67-FD84-4775-92D0-B45609CA760A}.Release|x86.ActiveCfg = Release|Win32 - {6C404C67-FD84-4775-92D0-B45609CA760A}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection - GlobalSection(TeamFoundationVersionControl) = preSolution - SccNumberOfProjects = 7 - SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} - SccTeamFoundationServer = http://tfs.siplaceworld.net:8080/tfs/defaultcollection - SccLocalPath0 = . - SccProjectUniqueName1 = Hermes\\Hermes.vcxproj - SccProjectName1 = Hermes - SccLocalPath1 = Hermes - SccProjectUniqueName2 = test\\BoostTestHermes\\BoostTestHermes.vcxproj - SccProjectName2 = test/BoostTestHermes - SccLocalPath2 = test\\BoostTestHermes - SccProjectUniqueName3 = test\\HermesTest\\HermesTest.vcxproj - SccProjectName3 = test/HermesTest - SccLocalPath3 = test\\HermesTest - SccProjectUniqueName4 = HermesDotNet\\HermesDotNet.vcxproj - SccProjectName4 = HermesDotNet - SccLocalPath4 = HermesDotNet - SccProjectUniqueName5 = HermesDotNetTest\\HermesDotNetTest.csproj - SccProjectName5 = HermesDotNetTest - SccLocalPath5 = HermesDotNetTest - SccProjectUniqueName6 = HermesManInTheMiddle\\HermesManInTheMiddle.vcxproj - SccProjectName6 = HermesManInTheMiddle - SccLocalPath6 = HermesManInTheMiddle + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {1C997128-625F-459D-A033-A1C34AC68751} EndGlobalSection EndGlobal diff --git a/src/Hermes/ApiCallback.h b/src/Hermes/ApiCallback.h index 53c92a1..e803811 100644 --- a/src/Hermes/ApiCallback.h +++ b/src/Hermes/ApiCallback.h @@ -42,4 +42,4 @@ namespace Hermes -} +} \ No newline at end of file diff --git a/src/Hermes/AsioClient.cpp b/src/Hermes/AsioClient.cpp index 8e0c657..6e3e6c9 100644 --- a/src/Hermes/AsioClient.cpp +++ b/src/Hermes/AsioClient.cpp @@ -114,7 +114,7 @@ namespace Hermes m_socket.m_connectionInfo.m_port = endpoint.port(); m_socket.m_connectionInfo.m_hostName = itEndpoint->host_name(); - m_socket.m_service.Inform(m_socket.m_sessionId, "Connecting to ", m_socket.m_connectionInfo, " ..."); + m_socket.m_service.Log(m_socket.m_sessionId, "Connecting to ", m_socket.m_connectionInfo, " ..."); m_socket.m_socket.async_connect(endpoint, [spThis = shared_from_this()](const boost::system::error_code& ec) { @@ -142,6 +142,7 @@ namespace Hermes return; } + m_socket.m_service.Inform(m_socket.m_sessionId, "OnConnected ", m_socket.m_connectionInfo); m_socket.m_pCallback->OnConnected(m_socket.m_connectionInfo); m_socket.StartReceiving(); } @@ -152,7 +153,7 @@ namespace Hermes return; m_socket.m_timer.expires_from_now( - boost::posix_time::seconds(m_socket.m_configuration.m_retryDelayInSeconds)); + boost::posix_time::milliseconds(static_cast(1000.0 * m_socket.m_configuration.m_retryDelayInSeconds))); m_socket.m_timer.async_wait([spThis = shared_from_this()](const boost::system::error_code& ec) { if (spThis->m_socket.Closed()) diff --git a/src/Hermes/AsioServer.cpp b/src/Hermes/AsioServer.cpp index 0c038e5..3f62222 100644 --- a/src/Hermes/AsioServer.cpp +++ b/src/Hermes/AsioServer.cpp @@ -17,7 +17,7 @@ limitations under the License. #include "stdafx.h" #include "AsioSocket.h" #include "IService.h" -#include "Serializer.h" +#include "MessageSerialization.h" #include "StringBuilder.h" #include @@ -277,6 +277,8 @@ namespace Hermes spSocket->m_connectionInfo.m_hostName = itResolved->host_name(); } + spSocket->m_service.Inform(spSocket->m_sessionId, "OnAccepted ", spSocket->m_connectionInfo); + if (!configuration.m_hostName.empty()) { asio::ip::tcp::resolver::query query(asio::ip::tcp::v4(), configuration.m_hostName, ""); @@ -332,7 +334,7 @@ namespace Hermes boost::system::error_code ecDummy; m_spResources->m_acceptor.close(ecDummy); - m_spResources->m_timer.expires_from_now(boost::posix_time::seconds(configuration.m_retryDelayInSeconds)); + m_spResources->m_timer.expires_from_now(boost::posix_time::milliseconds(static_cast(1000.0 * configuration.m_retryDelayInSeconds))); m_spResources->m_timer.async_wait([this, spResources = m_spResources](const boost::system::error_code& ec) { if (spResources->m_closed) diff --git a/src/Hermes/AsioSocket.h b/src/Hermes/AsioSocket.h index ddd03e1..53430cb 100644 --- a/src/Hermes/AsioSocket.h +++ b/src/Hermes/AsioSocket.h @@ -20,7 +20,7 @@ limitations under the License. #include "Network.h" #include "IService.h" #include "Network.h" -#include "Serializer.h" +#include "MessageSerialization.h" #include "StringBuilder.h" #include @@ -39,6 +39,12 @@ namespace Hermes return service.Alarm(sessionId, EErrorCode::eNETWORK_ERROR, trace..., ": ", ec.message(), '(', ec.value(), ')'); } + template + void Info(IAsioService& service, unsigned sessionId, const boost::system::error_code& ec, const Ts&... trace) + { + service.Inform(sessionId, trace..., ": ", ec.message(), '(', ec.value(), ')'); + } + struct AsioSocket { unsigned m_sessionId; @@ -106,6 +112,13 @@ namespace Hermes return Hermes::Alarm(m_service, m_sessionId, ec, trace...); } + template + Error Info(const boost::system::error_code& ec, const Ts&... trace) + { + Hermes::Info(m_service, m_sessionId, ec, trace...); + return Error{}; + } + private: template @@ -116,7 +129,7 @@ namespace Hermes // consider closed connections not to be an error: bool isError = (asio::error::eof != ec) && (asio::error::connection_reset != ec); - auto error = isError ? Alarm(ec, trace...) : Error(); + auto error = isError ? Alarm(ec, trace...) : Info(ec, trace...); auto* pCallback = Close_(); if (!pCallback) @@ -158,7 +171,7 @@ namespace Hermes void OnReceive_(const boost::system::error_code& ec, std::size_t size) { - StringView data(&m_receivedData.front(), size); + StringSpan data(&m_receivedData.front(), size); if (size) { @@ -193,7 +206,7 @@ namespace Hermes if (!m_configuration.m_checkAlivePeriodInSeconds) return; - m_timer.expires_from_now(boost::posix_time::seconds(m_configuration.m_checkAlivePeriodInSeconds)); + m_timer.expires_from_now(boost::posix_time::milliseconds(static_cast(1000.0 * m_configuration.m_checkAlivePeriodInSeconds))); m_timer.async_wait([spThis = shared_from_this()](const boost::system::error_code& ec) { spThis->OnCheckAliveTrigger_(ec); diff --git a/src/Hermes/BasicPugiSerialization.h b/src/Hermes/BasicPugiSerialization.h new file mode 100644 index 0000000..5846386 --- /dev/null +++ b/src/Hermes/BasicPugiSerialization.h @@ -0,0 +1,179 @@ +#pragma once + +#include +#include + +#ifdef _WINDOWS +#include "pugixml/pugixml.hpp" +#else +# include "pugixml.hpp" +#endif + +#include + +namespace Hermes +{ + template + struct PugiSerializer; + + template<> struct PugiSerializer + { + using AsAttributeTag = int; + + static void WriteAttribute(pugi::xml_attribute attr, const std::string& value) + { + attr.set_value(value.c_str()); + } + static void ReadAttribute(pugi::xml_attribute attr, Error&, std::string& value) + { + value = attr.as_string(); + } + }; + + template<> struct PugiSerializer + { + using AsAttributeTag = int; + + static void WriteAttribute(pugi::xml_attribute attr, int value) + { + attr.set_value(value); + } + static void ReadAttribute(pugi::xml_attribute attr, Error&, int& value) + { + value = attr.as_int(); + } + }; + + template<> struct PugiSerializer + { + using AsAttributeTag = int; + + static void WriteAttribute(pugi::xml_attribute attr, unsigned int value) + { + attr.set_value(value); + } + static void ReadAttribute(pugi::xml_attribute attr, Error&, unsigned int& value) + { + value = attr.as_uint(); + } + }; + + template<> struct PugiSerializer + { + using AsAttributeTag = int; + + static void WriteAttribute(pugi::xml_attribute attr, unsigned short value) + { + attr.set_value(value); + } + static void ReadAttribute(pugi::xml_attribute attr, Error&, unsigned short& value) + { + value = static_cast(attr.as_int()); + } + }; + + template<> struct PugiSerializer + { + using AsAttributeTag = int; + + static void WriteAttribute(pugi::xml_attribute attr, double value) + { + // Standard states that we should have 3 trailing decimals + std::stringstream stream; + stream << std::fixed << std::setprecision(3) << value; + attr.set_value(stream.str().c_str()); + } + static void ReadAttribute(pugi::xml_attribute attr, Error&, double& value) + { + value = attr.as_double(); + } + }; + + template struct PugiSerializer::value>> + { + using AsAttributeTag = int; + + static void WriteAttribute(pugi::xml_attribute attr, E value) + { + attr.set_value(static_cast(value)); + } + static void ReadAttribute(pugi::xml_attribute attr, Error&, E& value) + { + int i = attr.as_int(); + if (0 <= i && i < static_cast(size(E()))) + { + value = static_cast(i); + return; + } + value = E{}; // all our enums (must!) have a sensible default value + } + }; + + + void Serialize(pugi::xml_node parent, const char* name, const std::string& value) + { + PugiSerializer::WriteAttribute(parent.append_attribute(name), value); + } + + template + void Serialize(pugi::xml_node parent, const char* name, T value, typename PugiSerializer::AsAttributeTag = 0) + { + PugiSerializer::WriteAttribute(parent.append_attribute(name), value); + } + + template + void Serialize(pugi::xml_node parent, const char* name, const T& value, typename PugiSerializer::AsElementTag = 0) + { + PugiSerializer::WriteElement(parent.append_child(name), value); + } + + template + void Serialize(pugi::xml_node parent, const char* name, const Optional& value) + { + if (!value) + return; + + Serialize(parent, name, *value); + } + + template + void Deserialize(pugi::xml_node parent, const char* name, Error& error, T& value, typename PugiSerializer::AsAttributeTag = 0) + { + auto attribute = parent.attribute(name); + if (attribute) + return PugiSerializer::ReadAttribute(attribute, error, value); + + error = {EErrorCode::ePEER_ERROR, std::string("missing attribute ") + name}; + } + + template + void Deserialize(pugi::xml_node parent, const char* name, Error& error, T& value, typename PugiSerializer::AsElementTag = 0) + { + auto element = parent.child(name); + if (element) + return PugiSerializer::ReadElement(element, error, value); + + error = {EErrorCode::ePEER_ERROR, std::string("missing element ") + name}; + } + + template + void Deserialize(pugi::xml_node parent, const char* name, Error& error, Optional& value, typename PugiSerializer::AsAttributeTag = 0) + { + auto attribute = parent.attribute(name); + if (!attribute) + return; + + PugiSerializer::ReadAttribute(attribute, error, *value.emplace()); + } + + template + void Deserialize(pugi::xml_node parent, const char* name, Error& error, Optional& value, typename PugiSerializer::AsElementTag = 0) + { + auto element = parent.child(name); + if (!element) + return; + + PugiSerializer::ReadElement(element, error, *value.emplace()); + } + +} diff --git a/src/Hermes/ConfigurationClient.cpp b/src/Hermes/ConfigurationClient.cpp index 181b937..a9ad00d 100644 --- a/src/Hermes/ConfigurationClient.cpp +++ b/src/Hermes/ConfigurationClient.cpp @@ -19,7 +19,8 @@ limitations under the License. #include #include "ApiCallback.h" -#include "Serializer.h" +#include "MessageDispatcher.h" +#include "Service.h" #include "StringBuilder.h" #include @@ -44,19 +45,19 @@ namespace { std::string m_traceName; std::string m_hostName; - asio::io_service m_asioService; + Service m_service; + asio::io_service& m_asioService{m_service.GetUnderlyingService()}; asio::ip::tcp::socket m_socket{m_asioService}; + MessageDispatcher m_dispatcher{0U, m_service}; unsigned m_timeoutInSeconds = 10U; CurrentConfigurationCallback m_configurationCallback; NotificationCallback m_notificationCallback; ErrorCallback m_errorCallback; - TraceCallback m_traceCallback; static const std::size_t cCHUNK_SIZE = 4096; std::array m_receivedData; - std::string m_receiveBuffer; bool m_receiving = false; @@ -65,31 +66,37 @@ namespace const CurrentConfigurationCallback& configurationCallback, const NotificationCallback& notificationCallback, const ErrorCallback& errorCallback, - const TraceCallback& traceCallback) : + const HermesTraceCallback& traceCallback) : m_traceName(traceName), m_hostName(hostName), + m_service(traceCallback), m_timeoutInSeconds(timeoutInSeconds), m_configurationCallback(configurationCallback), m_notificationCallback(notificationCallback), - m_errorCallback(errorCallback), - m_traceCallback(traceCallback) - {} - - template - void GenerateError(EErrorCode errorCode, const Ts&... params) + m_errorCallback(errorCallback) { - std::string errorString = BuildString(params...); - m_traceCallback(0U, eHERMES_TRACE_ERROR, ToC(errorString)); - Error error(errorCode, errorString); - auto apiError = ToC(error); - m_errorCallback(&apiError); + m_dispatcher.Add([this](const auto& data) -> Error + { + m_receiving = false; + const Converter2C converter (data); + m_configurationCallback(0U, converter.CPointer()); + return{}; + + }); + m_dispatcher.Add([this](const auto& data) -> Error + { + const Converter2C converter(data); + m_notificationCallback(0U, converter.CPointer()); + return{}; + }); } template - void Trace(ETraceType type, const Ts&...params) + void GenerateError(EErrorCode errorCode, const Ts&... params) { - std::string trace = BuildString(params...); - m_traceCallback(0U, ToC(type), ToC(trace)); + auto error = m_service.Alarm(0U, errorCode, params...); + const Converter2C converter(error); + m_errorCallback(converter.CPointer()); } bool Connect() @@ -149,7 +156,7 @@ namespace GenerateError(EErrorCode::eNETWORK_ERROR, "asio::write: ", ec.message()); return; } - m_traceCallback(0U, eHERMES_TRACE_SENT, ToC(msgString)); + m_service.Trace(ETraceType::eSENT, 0U, msgString); m_receiving = true; @@ -162,7 +169,7 @@ namespace return; m_receiving = false; - GenerateError(EErrorCode::eTIMEOUT, "asio::receive", ec.message()); + GenerateError(EErrorCode::eTIMEOUT, "asio::receive: ", ec.message()); }); while (m_receiving) @@ -184,47 +191,16 @@ namespace if (ecReceive) { m_receiving = false; - return GenerateError(EErrorCode::eNETWORK_ERROR, "asio::async_receive", ecReceive.message()); + return GenerateError(EErrorCode::eNETWORK_ERROR, "asio::async_receive: ", ecReceive.message()); } - Trace(ETraceType::eRECEIVED, StringView{&m_receivedData[0], size}); - m_receiveBuffer.append(&m_receivedData[0], size); - Trace(ETraceType::eDEBUG, "m_receiveBuffer=", m_receiveBuffer); + m_service.Trace(ETraceType::eRECEIVED, 0U, StringView{&m_receivedData[0], size}); - std::string messageXml; - while (TakeMessage(messageXml, m_receiveBuffer)) + if (auto error = m_dispatcher.Dispatch(StringSpan{&m_receivedData[0], size})) { - Trace(ETraceType::eDEBUG, "messageXml=", messageXml, "\nm_receiveBuffer=", m_receiveBuffer); - - const auto& variant = Deserialize(messageXml); - if (const auto* pData = boost::get(&variant)) - { - m_receiving = false; - GenerateError(EErrorCode::ePEER_ERROR, m_traceName, pData->m_text); - return; - } - if (const auto* pData = boost::get(&variant)) - { - m_receiving = false; - auto apiData = ToC(*pData); - return m_configurationCallback(0U, &apiData); - return; - } - if (const auto* pData = boost::get(&variant)) - { - auto apiData = ToC(*pData); - m_notificationCallback(0U, &apiData); - continue; - } - - Trace(ETraceType::eWARNING, "Unexpected message"); + m_receiving = false; + m_service.Alarm(0U, EErrorCode::ePEER_ERROR, error.m_text); } - - if (m_receiveBuffer.size() <= cMAX_MESSAGE_SIZE) - return; - - m_receiving = false; - GenerateError(EErrorCode::ePEER_ERROR, m_traceName, "Maximum message size exceeded"); } }; } @@ -246,7 +222,7 @@ void SetHermesConfiguration(HermesStringView hostName, const HermesSetConfigurat asio::write(helper.m_socket, asio::buffer(xmlString.data(), xmlString.size()), ec); if (ec) return helper.GenerateError(EErrorCode::eNETWORK_ERROR, "asio::write", ec.message()); - helper.m_traceCallback(0U, eHERMES_TRACE_SENT, ToC(xmlString)); + helper.m_service.Trace(ETraceType::eSENT, 0U, xmlString); helper.GetConfiguration(); } diff --git a/src/Hermes/ConfigurationService.cpp b/src/Hermes/ConfigurationService.cpp index 3e6a376..6627489 100644 --- a/src/Hermes/ConfigurationService.cpp +++ b/src/Hermes/ConfigurationService.cpp @@ -130,11 +130,13 @@ struct HermesConfigurationService : IAcceptorCallback, IConfigurationServiceSess void RemoveSessions_(const NotificationData& data) { - for (auto& entry : m_sessionMap) + auto sessionMap = std::move(m_sessionMap); + m_sessionMap.clear(); + + for (auto& entry : sessionMap) { entry.second.Disconnect(data); } - m_sessionMap.clear(); } //================= IAcceptorCallback ========================= @@ -157,30 +159,30 @@ struct HermesConfigurationService : IAcceptorCallback, IConfigurationServiceSess } //================= IConfigurationServiceSessionCallback ========================= - void OnSocketConnected(unsigned sessionId, const ConnectionInfo& connectionInfo) override + void OnSocketConnected(unsigned sessionId, const ConnectionInfo& data) override { - auto apiConnectionInfo = ToC(connectionInfo); - m_connectedCallback(sessionId, eHERMES_SOCKET_CONNECTED, &apiConnectionInfo); + const Converter2C converter(data); + m_connectedCallback(sessionId, eHERMES_STATE_SOCKET_CONNECTED, converter.CPointer()); } virtual void OnGet(unsigned sessionId, const ConnectionInfo& connectionInfo, const GetConfigurationData& data, IGetConfigurationResponse& responder) override { - HermesConnectionInfo apiConnectionInfo = ToC(connectionInfo); - HermesGetConfigurationData apiData = ToC(data); + const Converter2C connectionConverter(connectionInfo); + const Converter2C dataConverter(data); CallbackScope scope(m_pGetConfigurationResponder, responder); - m_getConfigurationCallback(sessionId, &apiConnectionInfo, &apiData); + m_getConfigurationCallback(sessionId, dataConverter.CPointer(), connectionConverter.CPointer()); } virtual void OnSet(unsigned sessionId, const ConnectionInfo& connectionInfo, - const SetConfigurationData& configuration, ISetConfigurationResponse& responder) override + const SetConfigurationData& data, ISetConfigurationResponse& responder) override { - auto apiConnectionInfo = ToC(connectionInfo); - auto apiConfiguration = ToC(configuration); + const Converter2C connectionConverter(connectionInfo); + const Converter2C dataConverter(data); CallbackScope scope(m_pSetConfigurationResponder, responder); - m_setConfigurationCallback(sessionId, &apiConnectionInfo, &apiConfiguration); + m_setConfigurationCallback(sessionId, dataConverter.CPointer(), connectionConverter.CPointer()); } virtual void OnDisconnected(unsigned sessionId, const Error& error) override @@ -189,8 +191,8 @@ struct HermesConfigurationService : IAcceptorCallback, IConfigurationServiceSess if (!m_sessionMap.erase(sessionId)) return; - auto apiError = ToC(error); - m_disconnectedCallback(sessionId, eHERMES_DISCONNECTED, &apiError); + const Converter2C converter(error); + m_disconnectedCallback(sessionId, eHERMES_STATE_DISCONNECTED, converter.CPointer()); } }; diff --git a/src/Hermes/ConfigurationServiceSerializer.cpp b/src/Hermes/ConfigurationServiceSerializer.cpp index 9735da8..901afd8 100644 --- a/src/Hermes/ConfigurationServiceSerializer.cpp +++ b/src/Hermes/ConfigurationServiceSerializer.cpp @@ -19,7 +19,7 @@ limitations under the License. #include "Network.h" #include "IService.h" -#include "Serializer.h" +#include "MessageDispatcher.h" namespace Hermes { @@ -29,7 +29,7 @@ namespace Hermes IAsioService& m_service; IServerSocket& m_socket; IConfigurationServiceSerializerCallback* m_pCallback = nullptr; - std::string m_receiveBuffer; + MessageDispatcher m_dispatcher{m_sessionId, m_service}; bool m_connected = false; ConfigurationServiceSerializer(unsigned sessionId, IAsioService& service, @@ -37,7 +37,10 @@ namespace Hermes m_sessionId(sessionId), m_service(service), m_socket(socket) - {} + { + m_dispatcher.Add([this](const auto& data) { m_pCallback->On(data); }); + m_dispatcher.Add([this](const auto& data) { m_pCallback->On(data); }); + } // ISocketCallback void OnConnected(const ConnectionInfo& connectionInfo) override @@ -46,47 +49,13 @@ namespace Hermes m_pCallback->OnSocketConnected(connectionInfo); } - void OnReceived(StringView dataView) override + void OnReceived(StringSpan xmlData) override { - m_receiveBuffer.append(dataView.data(), dataView.size()); - m_service.Log(m_sessionId, "m_receiveBuffer=", m_receiveBuffer); - - std::string messageXml; - while (TakeMessage(messageXml, m_receiveBuffer)) - { - m_service.Log(m_sessionId, "messageXml=", messageXml, "\nm_receiveBuffer=", m_receiveBuffer); - - const auto& variant = Deserialize(messageXml); - - if (const auto* pData = boost::get(&variant)) - { - auto error = m_service.Alarm(m_sessionId, EErrorCode::ePEER_ERROR, pData->m_text); - Signal(NotificationData(ENotificationCode::ePROTOCOL_ERROR, ESeverity::eFATAL, error.m_text)); - m_socket.Close(); - m_pCallback->OnDisconnected(error); - return; - } - - if (const auto* pData = boost::get(&variant)) - { - m_service.Log(m_sessionId, "SetConfigurationData=", *pData); - m_pCallback->On(*pData); - continue; - } - if (const auto* pData = boost::get(&variant)) - { - m_service.Log(m_sessionId, "GetConfigurationData=", *pData); - m_pCallback->On(*pData); - continue; - } - - m_service.Warn(m_sessionId, "Unexpected message"); - } - - if (m_receiveBuffer.size() <= cMAX_MESSAGE_SIZE) + auto error = m_dispatcher.Dispatch(xmlData); + if (!error) return; - auto error = m_service.Alarm(m_sessionId, EErrorCode::ePEER_ERROR, "Maximum message size exceeded"); + error = m_service.Alarm(m_sessionId, EErrorCode::ePEER_ERROR, error.m_text); Signal(NotificationData(ENotificationCode::ePROTOCOL_ERROR, ESeverity::eFATAL, error.m_text)); m_socket.Close(); m_pCallback->OnDisconnected(error); diff --git a/src/Hermes/ConfigurationServiceSession.cpp b/src/Hermes/ConfigurationServiceSession.cpp index c57ac81..cf15b11 100644 --- a/src/Hermes/ConfigurationServiceSession.cpp +++ b/src/Hermes/ConfigurationServiceSession.cpp @@ -133,4 +133,4 @@ namespace Hermes void ConfigurationServiceSession::Disconnect(const NotificationData& data) { m_spImpl->m_upSerializer->Disconnect(data); } -} +} \ No newline at end of file diff --git a/src/Hermes/DeserializationHelpers.h b/src/Hermes/DeserializationHelpers.h index ba1bb05..6a2a0b8 100644 --- a/src/Hermes/DeserializationHelpers.h +++ b/src/Hermes/DeserializationHelpers.h @@ -3,7 +3,11 @@ #include "IService.h" #include "StringSpan.h" -#include +#ifdef _WINDOWS +#include "pugixml/pugixml.hpp" +#else +#include "pugixml.hpp" +#endif #include diff --git a/src/Hermes/Downstream.cpp b/src/Hermes/Downstream.cpp index e6a1f99..ed7667d 100644 --- a/src/Hermes/Downstream.cpp +++ b/src/Hermes/Downstream.cpp @@ -21,7 +21,7 @@ limitations under the License. #include "ApiCallback.h" #include "Network.h" #include "DownstreamSession.h" -#include "Serializer.h" +#include "MessageDispatcher.h" #include "Service.h" #include "StringBuilder.h" @@ -47,7 +47,9 @@ struct HermesDownstream : IAcceptorCallback, ISessionCallback ApiCallback m_revokeMachineReadyCallback; ApiCallback m_startTransportCallback; ApiCallback m_stopTransportCallback; + ApiCallback m_queryBoardInfoCallback; ApiCallback m_notificationCallback; + ApiCallback m_commandCallback; ApiCallback m_stateCallback; ApiCallback m_checkAliveCallback; ApiCallback m_disconnectedCallback; @@ -63,7 +65,9 @@ struct HermesDownstream : IAcceptorCallback, ISessionCallback m_revokeMachineReadyCallback(callbacks.m_revokeMachineReadyCallback), m_startTransportCallback(callbacks.m_startTransportCallback), m_stopTransportCallback(callbacks.m_stopTransportCallback), + m_queryBoardInfoCallback(callbacks.m_queryBoardInfoCallback), m_notificationCallback(callbacks.m_notificationCallback), + m_commandCallback(callbacks.m_commandCallback), m_stateCallback(callbacks.m_stateCallback), m_checkAliveCallback(callbacks.m_checkAliveCallback), m_disconnectedCallback(callbacks.m_disconnectedCallback) @@ -85,12 +89,13 @@ struct HermesDownstream : IAcceptorCallback, ISessionCallback return; m_enabled = true; + RemoveCurrentSession_(NotificationData(ENotificationCode::eCONNECTION_RESET_BECAUSE_OF_CHANGED_CONFIGURATION, ESeverity::eINFO, "ConfigurationChanged")); m_settings = settings; NetworkConfiguration networkConfiguration; - networkConfiguration.m_hostName = m_settings.m_optionalClientAddress; + networkConfiguration.m_hostName = m_settings.m_optionalClientAddress.value_or(""); networkConfiguration.m_port = m_settings.m_port; networkConfiguration.m_checkAlivePeriodInSeconds = m_settings.m_checkAlivePeriodInSeconds; networkConfiguration.m_retryDelayInSeconds = m_settings.m_reconnectWaitTimeInSeconds; @@ -99,21 +104,15 @@ struct HermesDownstream : IAcceptorCallback, ISessionCallback } template - void Signal(unsigned sessionId, const DataT& data) + void Signal(unsigned sessionId, const DataT& data, StringView rawXml) { - m_service.Log(sessionId, "Signal(", data, ')'); + m_service.Log(sessionId, "Signal(", data, ',', rawXml, ')'); - auto pSession = Session_(sessionId); + auto* pSession = Session_(sessionId); if (!pSession) return m_service.Log(sessionId, "No matching session"); - pSession->Signal(data); - } - - void Reset(const NotificationData& notificationData) - { - m_service.Log(0U, "Reset(", notificationData, ')'); - RemoveCurrentSession_(notificationData); + pSession->Signal(data, rawXml); } void Disable(const NotificationData& notificationData) @@ -140,7 +139,7 @@ struct HermesDownstream : IAcceptorCallback, ISessionCallback //================= IAcceptorCallback ========================= void OnAccepted(std::unique_ptr&& upSocket) override { - auto newSessionId = upSocket->SessionId(); + const auto newSessionId = upSocket->SessionId(); // refuse connection if we have an active one: if (m_upSession) @@ -148,108 +147,137 @@ struct HermesDownstream : IAcceptorCallback, ISessionCallback m_service.Warn(m_upSession->Id(), "Due to existing session, refusing to accept new session with id=", newSessionId); // assemble a notification - const auto& connectionInfo = m_upSession->PeerConnectionInfo(); std::ostringstream oss; - oss << connectionInfo; - NotificationData notification(ENotificationCode::eCONNECTION_REFUSED_BECAUSE_OF_ESTABLISHED_CONNECTION, ESeverity::eWARNING + oss << "Refusing connection to " << upSocket->GetConnectionInfo() + << " due to established connection to " << m_upSession->PeerConnectionInfo(); + + NotificationData notification(ENotificationCode::eCONNECTION_REFUSED_BECAUSE_OF_ESTABLISHED_CONNECTION, ESeverity::eERROR , oss.str()); const auto& xmlString = Serialize(notification); upSocket->Send(xmlString); // send a check alive to the current connection to reduce time for timeout detection: - m_upSession->Signal(CheckAliveData()); + CheckAliveData checkAliveData{}; + m_upSession->Signal(checkAliveData, Serialize(checkAliveData)); return; } - m_service.Log(newSessionId, "OnAccepted"); m_upSession = std::make_unique(std::move(upSocket), m_service, m_settings); m_upSession->Connect(*this); } //================= ISessionCallback ========================= - void OnSocketConnected(unsigned sessionId, EState state, const ConnectionInfo& connectionInfo) override + void OnSocketConnected(unsigned sessionId, EState state, const ConnectionInfo& in_data) override { - auto* pSession = Session_(sessionId); + const auto* pSession = Session_(sessionId); if (!pSession) return; - auto apiData = ToC(connectionInfo); - m_connectedCallback(sessionId, ToC(state), &apiData); + const Converter2C converter(in_data); + m_connectedCallback(sessionId, ToC(state), converter.CPointer()); } - void On(unsigned sessionId, EState state, const ServiceDescription& in_data) override + void On(unsigned sessionId, EState state, const ServiceDescriptionData& in_data) override { - auto* pSession = Session_(sessionId); + const auto* pSession = Session_(sessionId); if (!pSession) return; - auto apiData = ToC(in_data); - m_serviceDescriptionCallback(sessionId, ToC(state), &apiData); + const Converter2C converter(in_data); + m_serviceDescriptionCallback(sessionId, ToC(state), converter.CPointer()); } void On(unsigned sessionId, EState state, const MachineReadyData& in_data) override { - auto* pSession = Session_(sessionId); + const auto* pSession = Session_(sessionId); if (!pSession) return; - auto apiData = ToC(in_data); - m_machineReadyCallback(sessionId, ToC(state), &apiData); + const Converter2C converter(in_data); + m_machineReadyCallback(sessionId, ToC(state), converter.CPointer()); } void On(unsigned sessionId, EState state, const RevokeMachineReadyData& in_data) override { - auto pSession = Session_(sessionId); + const auto* pSession = Session_(sessionId); if (!pSession) return; - auto apiData = ToC(in_data); - m_revokeMachineReadyCallback(sessionId, ToC(state), &apiData); + const Converter2C converter(in_data); + m_revokeMachineReadyCallback(sessionId, ToC(state), converter.CPointer()); } void On(unsigned sessionId, EState state, const StartTransportData& in_data) override { - auto pSession = Session_(sessionId); + const auto* pSession = Session_(sessionId); if (!pSession) return; - auto apiData = ToC(in_data); - m_startTransportCallback(sessionId, ToC(state), &apiData); + const Converter2C converter(in_data); + m_startTransportCallback(sessionId, ToC(state), converter.CPointer()); } void On(unsigned sessionId, EState state, const StopTransportData& in_data) override { - auto pSession = Session_(sessionId); + const auto* pSession = Session_(sessionId); + if (!pSession) + return; + + const Converter2C converter(in_data); + m_stopTransportCallback(sessionId, ToC(state), converter.CPointer()); + } + + void On(unsigned sessionId, EState, const QueryBoardInfoData& in_data) override + { + const auto* pSession = Session_(sessionId); if (!pSession) return; - auto apiData = ToC(in_data); - m_stopTransportCallback(sessionId, ToC(state), &apiData); + const Converter2C converter(in_data); + m_queryBoardInfoCallback(sessionId, converter.CPointer()); } void On(unsigned sessionId, EState, const NotificationData& in_data) override { - auto pSession = Session_(sessionId); + const auto* pSession = Session_(sessionId); + if (!pSession) + return; + + const Converter2C converter(in_data); + m_notificationCallback(sessionId, converter.CPointer()); + } + + void On(unsigned sessionId, EState, const CommandData& in_data) override + { + const auto* pSession = Session_(sessionId); if (!pSession) return; - auto apiData = ToC(in_data); - m_notificationCallback(sessionId, &apiData); + const Converter2C converter(in_data); + m_commandCallback(sessionId, converter.CPointer()); } void On(unsigned sessionId, EState, const CheckAliveData& in_data) override { - auto pSession = Session_(sessionId); + const auto* pSession = Session_(sessionId); if (!pSession) return; - auto apiData = ToC(in_data); - m_checkAliveCallback(sessionId, &apiData); + if (in_data.m_optionalType + && *in_data.m_optionalType == ECheckAliveType::ePING + && m_settings.m_checkAliveResponseMode == ECheckAliveResponseMode::eAUTO) + { + CheckAliveData data{in_data}; + data.m_optionalType = ECheckAliveType::ePONG; + m_service.Post([this, sessionId, data = std::move(data)]() { Signal(sessionId, data, Serialize(data)); }); + } + const Converter2C converter(in_data); + m_checkAliveCallback(sessionId, converter.CPointer()); } void OnState(unsigned sessionId, EState state) override { - auto pSession = Session_(sessionId); + const auto* pSession = Session_(sessionId); if (!pSession) return; @@ -258,13 +286,13 @@ struct HermesDownstream : IAcceptorCallback, ISessionCallback void OnDisconnected(unsigned sessionId, EState, const Error& error) override { - auto pSession = Session_(sessionId); + const auto* pSession = Session_(sessionId); if (!pSession) return; m_upSession.reset(); - auto apiError = ToC(error); - m_disconnectedCallback(sessionId, eHERMES_DISCONNECTED, &apiError); + const Converter2C converter(error); + m_disconnectedCallback(sessionId, eHERMES_STATE_DISCONNECTED, converter.CPointer()); } //=================== internal ========================= @@ -277,18 +305,29 @@ struct HermesDownstream : IAcceptorCallback, ISessionCallback return nullptr; } - void RemoveCurrentSession_(const NotificationData& notificationData) + void RemoveCurrentSession_() { if (!m_upSession) return; - m_upSession->Disconnect(notificationData); - Error error; - auto apiError = ToC(error); - m_disconnectedCallback(m_upSession->Id(), eHERMES_DISCONNECTED, &apiError); + auto sessionId = m_upSession->Id(); + m_service.Log(sessionId, "RemoveCurrentSession_()"); + m_upSession->Disconnect(); + const Error error; + const Converter2C converter(error); + m_disconnectedCallback(sessionId, eHERMES_STATE_DISCONNECTED, converter.CPointer()); m_upSession.reset(); } + void RemoveCurrentSession_(const NotificationData& data) + { + if (!m_upSession) + return; + + m_upSession->Signal(data, Serialize(data)); + RemoveCurrentSession_(); + } + }; //===================== implementation of public C functions ==================== @@ -300,7 +339,6 @@ HermesDownstream* CreateHermesDownstream(uint32_t laneId, const HermesDownstream void RunHermesDownstream(HermesDownstream* pDownstream) { pDownstream->m_service.Log(0U, "RunHermesDownstream"); - pDownstream->m_service.Run(); } @@ -321,19 +359,18 @@ void EnableHermesDownstream(HermesDownstream* pDownstream, const HermesDownstrea void PostHermesDownstream(HermesDownstream* pDownstream, HermesVoidCallback voidCallback) { pDownstream->m_service.Log(0U, "PostHermesDownstream"); - pDownstream->m_service.Post([voidCallback] { voidCallback.m_pCall(voidCallback.m_pData); }); } -void SignalHermesDownstreamServiceDescription(HermesDownstream* pDownstream, uint32_t sessionId, const HermesServiceDescription* pData) +void SignalHermesDownstreamServiceDescription(HermesDownstream* pDownstream, uint32_t sessionId, const HermesServiceDescriptionData* pData) { pDownstream->m_service.Log(sessionId, "SignalHermesDownstreamServiceDescription"); pDownstream->m_service.Post([pDownstream, sessionId, data = ToCpp(*pData)]() { - pDownstream->Signal(sessionId, data); + pDownstream->Signal(sessionId, data, Serialize(data)); }); } @@ -342,7 +379,7 @@ void SignalHermesBoardAvailable(HermesDownstream* pDownstream, uint32_t sessionI pDownstream->m_service.Log(sessionId, "SignalHermesBoardAvailable"); pDownstream->m_service.Post([pDownstream, sessionId, data = ToCpp(*pData)]() { - pDownstream->Signal(sessionId, data); + pDownstream->Signal(sessionId, data, Serialize(data)); }); } @@ -351,7 +388,7 @@ void SignalHermesRevokeBoardAvailable(HermesDownstream* pDownstream, uint32_t se pDownstream->m_service.Log(sessionId, "SignalHermesRevokeBoardAvailable"); pDownstream->m_service.Post([pDownstream, sessionId, data = ToCpp(*pData)]() { - pDownstream->Signal(sessionId, data); + pDownstream->Signal(sessionId, data, Serialize(data)); }); } @@ -359,47 +396,109 @@ void SignalHermesRevokeBoardAvailable(HermesDownstream* pDownstream, uint32_t se void SignalHermesTransportFinished(HermesDownstream* pDownstream, uint32_t sessionId, const HermesTransportFinishedData* pData) { pDownstream->m_service.Log(sessionId, "SignalHermesTransportFinished"); + pDownstream->m_service.Post([pDownstream, sessionId, data = ToCpp(*pData)]() + { + pDownstream->Signal(sessionId, data, Serialize(data)); + }); +} +void SignalHermesBoardForecast(HermesDownstream* pDownstream, uint32_t sessionId, const HermesBoardForecastData* pData) +{ + pDownstream->m_service.Log(sessionId, "SignalHermesBoardForecast"); + pDownstream->m_service.Post([pDownstream, sessionId, data = ToCpp(*pData)]() + { + pDownstream->Signal(sessionId, data, Serialize(data)); + }); +} + +void SignalHermesSendBoardInfo(HermesDownstream* pDownstream, uint32_t sessionId, const HermesSendBoardInfoData* pData) +{ + pDownstream->m_service.Log(sessionId, "SignalHermesSendBoardInfo"); pDownstream->m_service.Post([pDownstream, sessionId, data = ToCpp(*pData)]() { - pDownstream->Signal(sessionId, data); + pDownstream->Signal(sessionId, data, Serialize(data)); }); } void SignalHermesDownstreamNotification(HermesDownstream* pDownstream, uint32_t sessionId, const HermesNotificationData* pData) { pDownstream->m_service.Log(0U, "SignalHermesDownstreamNotification"); + pDownstream->m_service.Post([pDownstream, sessionId, data = ToCpp(*pData)]() + { + pDownstream->Signal(sessionId, data, Serialize(data)); + }); +} + +void SignalHermesDownstreamCommand(HermesDownstream* pDownstream, uint32_t sessionId, const HermesCommandData* pData) +{ + pDownstream->m_service.Log(0U, "SignalHermesDownstreamCommand"); pDownstream->m_service.Post([pDownstream, sessionId, data = ToCpp(*pData)]() { - pDownstream->Signal(sessionId, data); + pDownstream->Signal(sessionId, data, Serialize(data)); }); } void SignalHermesDownstreamCheckAlive(HermesDownstream* pDownstream, uint32_t sessionId, const HermesCheckAliveData* pData) { pDownstream->m_service.Log(0U, "SignalHermesDownstreamCheckAlive"); - pDownstream->m_service.Post([pDownstream, sessionId, data = ToCpp(*pData)]() { - pDownstream->Signal(sessionId, data); + pDownstream->Signal(sessionId, data, Serialize(data)); }); } void ResetHermesDownstream(HermesDownstream* pDownstream, const HermesNotificationData* pData) { pDownstream->m_service.Log(0U, "ResetHermesDownstream"); - pDownstream->m_service.Post([pDownstream, data = ToCpp(*pData)]() { - pDownstream->Reset(data); + pDownstream->RemoveCurrentSession_(data); + }); +} + +void SignalHermesDownstreamRawXml(HermesDownstream* pDownstream, uint32_t sessionId, HermesStringView rawXml) +{ + pDownstream->m_service.Log(sessionId, "SignalHermesDownstreamRawXml"); + pDownstream->m_service.Post([pDownstream, sessionId, xmlData = std::string(rawXml.m_pData, rawXml.m_size)]() mutable + { + MessageDispatcher dispatcher{sessionId, pDownstream->m_service}; + auto parseData = xmlData; + + bool wasDispatched = false; + dispatcher.Add([&](const auto& data) { wasDispatched = true; pDownstream->Signal(sessionId, data, xmlData); }); + dispatcher.Add([&](const auto& data) { wasDispatched = true; pDownstream->Signal(sessionId, data, xmlData); }); + dispatcher.Add([&](const auto& data) { wasDispatched = true; pDownstream->Signal(sessionId, data, xmlData); }); + dispatcher.Add([&](const auto& data) { wasDispatched = true; pDownstream->Signal(sessionId, data, xmlData); }); + dispatcher.Add([&](const auto& data) { wasDispatched = true; pDownstream->Signal(sessionId, data, xmlData); }); + dispatcher.Add([&](const auto& data) { wasDispatched = true; pDownstream->Signal(sessionId, data, xmlData); }); + dispatcher.Add([&](const auto& data) { wasDispatched = true; pDownstream->Signal(sessionId, data, xmlData); }); + dispatcher.Add([&](const auto& data) { wasDispatched = true; pDownstream->Signal(sessionId, data, xmlData); }); + + dispatcher.Dispatch(parseData); + if (wasDispatched) + return; + + pDownstream->Signal(sessionId, NotificationData{}, xmlData); + }); +} + +void ResetHermesDownstreamRawXml(HermesDownstream* pDownstream, HermesStringView rawXml) +{ + pDownstream->m_service.Log(0U, "ResetHermesDownstreamRawXml"); + pDownstream->m_service.Post([pDownstream, data = std::string(rawXml.m_pData, rawXml.m_size)]() mutable + { + if (!data.empty() && pDownstream->m_upSession) + { + pDownstream->m_upSession->Signal(NotificationData(), data); + } + pDownstream->RemoveCurrentSession_(); }); } void DisableHermesDownstream(HermesDownstream* pDownstream, const HermesNotificationData* pData) { pDownstream->m_service.Log(0U, "DisableHermesDownstream"); - pDownstream->m_service.Post([pDownstream, data = ToCpp(*pData)]() { pDownstream->Disable(data); @@ -409,7 +508,6 @@ void DisableHermesDownstream(HermesDownstream* pDownstream, const HermesNotifica void StopHermesDownstream(HermesDownstream* pDownstream) { pDownstream->m_service.Log(0U, "StopHermesDownstream"); - pDownstream->m_service.Post([pDownstream]() { pDownstream->Stop(); @@ -422,7 +520,6 @@ void DeleteHermesDownstream(HermesDownstream* pDownstream) return; pDownstream->m_service.Log(0U, "DeleteHermesDownstream"); - pDownstream->m_service.Stop(); delete pDownstream; } diff --git a/src/Hermes/DownstreamSerializer.cpp b/src/Hermes/DownstreamSerializer.cpp index b99d80a..3e7ce82 100644 --- a/src/Hermes/DownstreamSerializer.cpp +++ b/src/Hermes/DownstreamSerializer.cpp @@ -19,8 +19,7 @@ limitations under the License. #include "Network.h" #include "IService.h" -#include "Serializer.h" -#include "StringBuilder.h" +#include "MessageDispatcher.h" namespace Hermes { @@ -32,14 +31,23 @@ namespace Hermes IAsioService& m_service; IServerSocket& m_socket; ISerializerCallback* m_pCallback = nullptr; - std::string m_receiveBuffer; + MessageDispatcher m_dispatcher{m_sessionId, m_service}; Serializer(unsigned sessionId, IAsioService& service, IServerSocket& socket) : m_sessionId(sessionId), - m_service(service), m_socket(socket) - {} + { + m_dispatcher.Add([this](const auto& data) { m_pCallback->On(data); }); + m_dispatcher.Add([this](const auto& data) { m_pCallback->On(data); }); + m_dispatcher.Add([this](const auto& data) { m_pCallback->On(data); }); + m_dispatcher.Add([this](const auto& data) { m_pCallback->On(data); }); + m_dispatcher.Add([this](const auto& data) { m_pCallback->On(data); }); + m_dispatcher.Add([this](const auto& data) { m_pCallback->On(data); }); + m_dispatcher.Add([this](const auto& data) { m_pCallback->On(data); }); + m_dispatcher.Add([this](const auto& data) { m_pCallback->On(data); }); + m_dispatcher.Add([this](const auto& data) { m_pCallback->On(data); }); + } // ISocketCallback void OnConnected(const ConnectionInfo& connectionInfo) override @@ -47,79 +55,14 @@ namespace Hermes m_pCallback->OnSocketConnected(connectionInfo); } - void OnReceived(StringView dataView) override + void OnReceived(StringSpan xmlData) override { - m_receiveBuffer.append(dataView.data(), dataView.size()); - m_service.Log(m_sessionId, "m_receiveBuffer[", dataView.size(), "]=", m_receiveBuffer); - - std::string messageXml; - while (TakeMessage(messageXml, m_receiveBuffer)) - { - m_service.Log(m_sessionId, "messageXml[", messageXml.size(), "]=", messageXml, - "\nm_receiveBuffer[", m_receiveBuffer.size(), "]=", m_receiveBuffer); - - const auto& variant = Deserialize(messageXml); - - if (const auto* pData = boost::get(&variant)) - { - auto error = m_service.Alarm(m_sessionId, EErrorCode::ePEER_ERROR, pData->m_text); - Signal(NotificationData(ENotificationCode::ePROTOCOL_ERROR, ESeverity::eFATAL, error.m_text)); - m_socket.Close(); - m_pCallback->OnDisconnected(error); - return; - } - - if (const auto* pData = boost::get(&variant)) - { - m_service.Log(m_sessionId, "CheckAliveData=", *pData); - m_pCallback->On(*pData); - continue; - } - if (const auto* pData = boost::get(&variant)) - { - m_service.Log(m_sessionId, "ServiceDescription=", *pData); - m_pCallback->On(*pData); - continue; - } - if (const auto* pData = boost::get(&variant)) - { - m_service.Log(m_sessionId, "NotificationData=", *pData); - m_pCallback->On(*pData); - continue; - } - if (const auto* pData = boost::get(&variant)) - { - m_service.Log(m_sessionId, "MachineReadyData=", *pData); - m_pCallback->On(*pData); - continue; - } - if (const auto* pData = boost::get(&variant)) - { - m_service.Log(m_sessionId, "RevokeMachineReadyData=", *pData); - m_pCallback->On(*pData); - continue; - } - if (const auto* pData = boost::get(&variant)) - { - m_service.Log(m_sessionId, "StartTransportData=", *pData); - m_pCallback->On(*pData); - continue; - } - if (const auto* pData = boost::get(&variant)) - { - m_service.Log(m_sessionId, "StopTransportData=", *pData); - m_pCallback->On(*pData); - continue; - } - - m_service.Warn(m_sessionId, "Unexpected message"); - } - - if (m_receiveBuffer.size() <= cMAX_MESSAGE_SIZE) + auto error = m_dispatcher.Dispatch(xmlData); + if (!error) return; - auto error = m_service.Alarm(m_sessionId, EErrorCode::ePEER_ERROR, "Maximum message size exceeded"); - Signal(NotificationData(ENotificationCode::ePROTOCOL_ERROR, ESeverity::eFATAL, error.m_text)); + error = m_service.Alarm(m_sessionId, EErrorCode::ePEER_ERROR, error.m_text); + Signal(Serialize(NotificationData(ENotificationCode::ePROTOCOL_ERROR, ESeverity::eFATAL, error.m_text))); m_socket.Close(); m_pCallback->OnDisconnected(error); } @@ -138,40 +81,9 @@ namespace Hermes m_socket.Connect(wpOwner, *this); } - void Signal(const ServiceDescription& data) override - { - const auto& xmlString = Serialize(data); - Send_(xmlString); - } - - void Signal(const BoardAvailableData& data) override - { - const auto& xmlString = Serialize(data); - Send_(xmlString); - } - - void Signal(const RevokeBoardAvailableData& data) override - { - const auto& xmlString = Serialize(data); - Send_(xmlString); - } - - void Signal(const TransportFinishedData& data) override - { - const auto& xmlString = Serialize(data); - Send_(xmlString); - } - - void Signal(const NotificationData& data) override - { - const auto& xmlString = Serialize(data); - Send_(xmlString); - } - - void Signal(const CheckAliveData& data) override + void Signal(StringView rawXml) { - const auto& xmlString = Serialize(data); - Send_(xmlString); + m_socket.Send(rawXml); } void Disconnect() override diff --git a/src/Hermes/DownstreamSerializer.h b/src/Hermes/DownstreamSerializer.h index 1bc6c28..f629bd5 100644 --- a/src/Hermes/DownstreamSerializer.h +++ b/src/Hermes/DownstreamSerializer.h @@ -33,12 +33,7 @@ namespace Hermes struct ISerializer { virtual void Connect(std::weak_ptr wpOwner, ISerializerCallback&) = 0; - virtual void Signal(const ServiceDescription&) = 0; - virtual void Signal(const BoardAvailableData&) = 0; - virtual void Signal(const RevokeBoardAvailableData&) = 0; - virtual void Signal(const TransportFinishedData&) = 0; - virtual void Signal(const NotificationData&) = 0; - virtual void Signal(const CheckAliveData&) = 0; + virtual void Signal(StringView rawXml) = 0; virtual void Disconnect() = 0; virtual ~ISerializer() = default; @@ -47,12 +42,14 @@ namespace Hermes struct ISerializerCallback { virtual void OnSocketConnected(const ConnectionInfo&) = 0; - virtual void On(const ServiceDescription&) = 0; + virtual void On(const ServiceDescriptionData&) = 0; virtual void On(const MachineReadyData&) = 0; virtual void On(const RevokeMachineReadyData&) = 0; virtual void On(const StartTransportData&) = 0; virtual void On(const StopTransportData&) = 0; + virtual void On(const QueryBoardInfoData&) = 0; virtual void On(const NotificationData&) = 0; + virtual void On(const CommandData&) = 0; virtual void On(const CheckAliveData&) = 0; virtual void OnDisconnected(const Error&) = 0; diff --git a/src/Hermes/DownstreamSession.cpp b/src/Hermes/DownstreamSession.cpp index 41d9f7c..383da48 100644 --- a/src/Hermes/DownstreamSession.cpp +++ b/src/Hermes/DownstreamSession.cpp @@ -42,11 +42,11 @@ namespace Hermes std::unique_ptr m_upSocket; std::unique_ptr m_upSerializer; std::unique_ptr m_upStateMachine; - Optional m_optionalPeerServiceDescription; + Optional m_optionalPeerServiceDescriptionData; ConnectionInfo m_peerConnectionInfo; ISessionCallback* m_pCallback{nullptr}; - bool m_hasServiceDescription{false}; + bool m_hasServiceDescriptionData{false}; Impl(std::unique_ptr&& upSocket, IAsioService& service, const DownstreamSettings& configuration) : m_id(upSocket->SessionId()), @@ -72,9 +72,9 @@ namespace Hermes m_pCallback->OnSocketConnected(m_id, state, connectionInfo); } - template void Signal_(const DataT& data) + template void Signal_(const DataT& data, StringView rawXml) { - m_upStateMachine->Signal(data); + m_upStateMachine->Signal(data, rawXml); } template void On_(EState state, const DataT& data) @@ -85,9 +85,9 @@ namespace Hermes m_pCallback->On(m_id, state, data); } - void On(EState state, const ServiceDescription& data) + void On(EState state, const ServiceDescriptionData& data) { - m_optionalPeerServiceDescription = data; + m_optionalPeerServiceDescriptionData = data; On_(state, data); } @@ -95,7 +95,9 @@ namespace Hermes void On(EState state, const RevokeMachineReadyData& data) override { On_(state, data); } void On(EState state, const StartTransportData& data) override { On_(state, data); } void On(EState state, const StopTransportData& data) override { On_(state, data); } + void On(EState state, const QueryBoardInfoData& data) override { On_(state, data); } void On(EState state, const NotificationData& data) override { On_(state, data); } + void On(EState state, const CommandData& data) override { On_(state, data); } void On(EState state, const CheckAliveData& data) override { On_(state, data); } void OnState(EState state) override { @@ -135,9 +137,9 @@ namespace Hermes } unsigned Session::Id() const { return m_spImpl->m_id; } - const Optional& Session::OptionalPeerServiceDescription() const + const Optional& Session::OptionalPeerServiceDescriptionData() const { - return m_spImpl->m_optionalPeerServiceDescription; + return m_spImpl->m_optionalPeerServiceDescriptionData; } const ConnectionInfo& Session::PeerConnectionInfo() const { return m_spImpl->m_peerConnectionInfo; } @@ -148,17 +150,20 @@ namespace Hermes m_spImpl->m_upStateMachine->Connect(m_spImpl, *m_spImpl); } - void Session::Signal(const ServiceDescription& data) { m_spImpl->Signal_(data); } - void Session::Signal(const BoardAvailableData& data) { m_spImpl->Signal_(data); } - void Session::Signal(const RevokeBoardAvailableData& data) { m_spImpl->Signal_(data); } - void Session::Signal(const TransportFinishedData& data) { m_spImpl->Signal_(data); } - void Session::Signal(const NotificationData& data) { m_spImpl->Signal_(data); } - void Session::Signal(const CheckAliveData& data) { m_spImpl->Signal_(data); } - - void Session::Disconnect(const NotificationData& data) + void Session::Signal(const ServiceDescriptionData& data, StringView rawXml) { m_spImpl->Signal_(data, rawXml); } + void Session::Signal(const BoardAvailableData& data, StringView rawXml) { m_spImpl->Signal_(data, rawXml); } + void Session::Signal(const RevokeBoardAvailableData& data, StringView rawXml) { m_spImpl->Signal_(data, rawXml); } + void Session::Signal(const TransportFinishedData& data, StringView rawXml) { m_spImpl->Signal_(data, rawXml); } + void Session::Signal(const BoardForecastData& data, StringView rawXml) { m_spImpl->Signal_(data, rawXml); } + void Session::Signal(const SendBoardInfoData& data, StringView rawXml) { m_spImpl->Signal_(data, rawXml); } + void Session::Signal(const NotificationData& data, StringView rawXml) { m_spImpl->Signal_(data, rawXml); } + void Session::Signal(const CommandData& data, StringView rawXml) { m_spImpl->Signal_(data, rawXml); } + void Session::Signal(const CheckAliveData& data, StringView rawXml) { m_spImpl->Signal_(data, rawXml); } + + void Session::Disconnect() { m_spImpl->m_pCallback = nullptr; - m_spImpl->m_upStateMachine->Disconnect(data); + m_spImpl->m_upStateMachine->Disconnect(); } } -} +} \ No newline at end of file diff --git a/src/Hermes/DownstreamSession.h b/src/Hermes/DownstreamSession.h index d68dc70..ac79ba3 100644 --- a/src/Hermes/DownstreamSession.h +++ b/src/Hermes/DownstreamSession.h @@ -41,17 +41,20 @@ namespace Hermes explicit operator bool() const { return bool(m_spImpl); } unsigned Id() const; - const Optional& OptionalPeerServiceDescription() const; + const Optional& OptionalPeerServiceDescriptionData() const; const ConnectionInfo& PeerConnectionInfo() const; void Connect(ISessionCallback&); - void Signal(const ServiceDescription&); - void Signal(const BoardAvailableData&); - void Signal(const RevokeBoardAvailableData&); - void Signal(const TransportFinishedData&); - void Signal(const NotificationData&); - void Signal(const CheckAliveData&); - void Disconnect(const NotificationData&); + void Signal(const ServiceDescriptionData&, StringView rawXml); + void Signal(const BoardAvailableData&, StringView rawXml); + void Signal(const RevokeBoardAvailableData&, StringView rawXml); + void Signal(const TransportFinishedData&, StringView rawXml); + void Signal(const BoardForecastData&, StringView rawXml); + void Signal(const SendBoardInfoData&, StringView rawXml); + void Signal(const NotificationData&, StringView rawXml); + void Signal(const CommandData&, StringView rawXml); + void Signal(const CheckAliveData&, StringView rawXml); + void Disconnect(); private: struct Impl; @@ -62,12 +65,14 @@ namespace Hermes struct ISessionCallback { virtual void OnSocketConnected(unsigned id, EState, const ConnectionInfo&) = 0; - virtual void On(unsigned id, EState, const ServiceDescription&) = 0; + virtual void On(unsigned id, EState, const ServiceDescriptionData&) = 0; virtual void On(unsigned id, EState, const MachineReadyData&) = 0; virtual void On(unsigned id, EState, const RevokeMachineReadyData&) = 0; virtual void On(unsigned id, EState, const StartTransportData&) = 0; virtual void On(unsigned id, EState, const StopTransportData&) = 0; + virtual void On(unsigned id, EState, const QueryBoardInfoData&) = 0; virtual void On(unsigned id, EState, const NotificationData&) = 0; + virtual void On(unsigned id, EState, const CommandData&) = 0; virtual void On(unsigned id, EState, const CheckAliveData&) = 0; virtual void OnState(unsigned id, EState) = 0; virtual void OnDisconnected(unsigned id, EState, const Error&) = 0; @@ -75,4 +80,4 @@ namespace Hermes } -} +} \ No newline at end of file diff --git a/src/Hermes/DownstreamStateMachine.cpp b/src/Hermes/DownstreamStateMachine.cpp index 9366280..42ae9c1 100644 --- a/src/Hermes/DownstreamStateMachine.cpp +++ b/src/Hermes/DownstreamStateMachine.cpp @@ -20,6 +20,7 @@ limitations under the License. #include "DownstreamSerializer.h" #include "IService.h" +#include "MessageSerialization.h" #include "StringBuilder.h" #include @@ -64,7 +65,7 @@ namespace Hermes if (m_state != EState::eNOT_CONNECTED) { - m_forward.Signal(NotificationData(ENotificationCode::eUNSPECIFIC, ESeverity::eFATAL, "SoftwareError")); + m_forward.Signal(Serialize(NotificationData(ENotificationCode::eUNSPECIFIC, ESeverity::eFATAL, "SoftwareError"))); } m_state = EState::eDISCONNECTED; @@ -83,7 +84,7 @@ namespace Hermes m_state = EState::eDISCONNECTED; m_pCallback->OnDisconnected(m_state, error); - m_forward.Signal(NotificationData(ENotificationCode::ePROTOCOL_ERROR, ESeverity::eFATAL, error.m_text)); + m_forward.Signal(Serialize(NotificationData(ENotificationCode::ePROTOCOL_ERROR, ESeverity::eFATAL, error.m_text))); m_forward.Disconnect(); } @@ -96,37 +97,37 @@ namespace Hermes m_forward.Connect(std::move(wpOwner), *this); } - void Signal(const ServiceDescription& data) override + void Signal(const ServiceDescriptionData&, StringView rawXml) override { switch (m_state) { case EState::eSERVICE_DESCRIPTION_DOWNSTREAM: m_state = EState::eNOT_AVAILABLE_NOT_READY; m_pCallback->OnState(m_state); - m_forward.Signal(data); + m_forward.Signal(rawXml); return; default: if (DisconnectedDueToIllegalClientEvent_("ServiceDescription")) return; - m_forward.Signal(data); + m_forward.Signal(rawXml); } } - void Signal(const BoardAvailableData& data) override + void Signal(const BoardAvailableData&, StringView rawXml) override { switch (m_state) { case EState::eNOT_AVAILABLE_NOT_READY: m_state = EState::eBOARD_AVAILABLE; m_pCallback->OnState(m_state); - m_forward.Signal(data); + m_forward.Signal(rawXml); return; case EState::eMACHINE_READY: m_state = EState::eAVAILABLE_AND_READY; m_pCallback->OnState(m_state); - m_forward.Signal(data); + m_forward.Signal(rawXml); return; case EState::eTRANSPORTING: @@ -136,24 +137,24 @@ namespace Hermes default: if (DisconnectedDueToIllegalClientEvent_("BoardAvailable")) return; - m_forward.Signal(data); + m_forward.Signal(rawXml); } } - void Signal(const RevokeBoardAvailableData& data) override + void Signal(const RevokeBoardAvailableData&, StringView rawXml) override { switch (m_state) { case EState::eBOARD_AVAILABLE: m_state = EState::eNOT_AVAILABLE_NOT_READY; m_pCallback->OnState(m_state); - m_forward.Signal(data); + m_forward.Signal(rawXml); return; case EState::eAVAILABLE_AND_READY: m_state = EState::eMACHINE_READY; m_pCallback->OnState(m_state); - m_forward.Signal(data); + m_forward.Signal(rawXml); return; case EState::eTRANSPORTING: @@ -163,34 +164,53 @@ namespace Hermes default: if (DisconnectedDueToIllegalClientEvent_("RevokeBoardAvailable")) return; - m_forward.Signal(data); + m_forward.Signal(rawXml); } } - void Signal(const TransportFinishedData& data) override + void Signal(const TransportFinishedData&, StringView rawXml) override { switch (m_state) { case EState::eTRANSPORTING: m_state = EState::eTRANSPORT_FINISHED; m_pCallback->OnState(m_state); - m_forward.Signal(data); + m_forward.Signal(rawXml); return; case EState::eTRANSPORT_STOPPED: m_state = EState::eNOT_AVAILABLE_NOT_READY; m_pCallback->OnState(m_state); - m_forward.Signal(data); + m_forward.Signal(rawXml); return; default: if (DisconnectedDueToIllegalClientEvent_("TransportFinished")) return; - m_forward.Signal(data); + m_forward.Signal(rawXml); } } - void Signal(const NotificationData& data) override + // Board forecast is suppressed if we are not in a valid state for it. + // This is different from other calls from client side in an illegal state + // because from client perspective, it is very hand to handle it correctly. + void Signal(const BoardForecastData&, StringView rawXml) override + { + switch (m_state) + { + case EState::eNOT_AVAILABLE_NOT_READY: + case EState::eMACHINE_READY: + m_forward.Signal(rawXml); + return; + + default: + if (m_checkState == ECheckState::eSEND_AND_RECEIVE) + return; + m_forward.Signal(rawXml); + } + } + + void Signal(const SendBoardInfoData&, StringView rawXml) override { switch (m_state) { @@ -199,12 +219,12 @@ namespace Hermes return; default: - m_forward.Signal(data); + m_forward.Signal(rawXml); return; } } - void Signal(const CheckAliveData& data) override + void Signal(const NotificationData&, StringView rawXml) override { switch (m_state) { @@ -213,28 +233,49 @@ namespace Hermes return; default: - m_forward.Signal(data); + m_forward.Signal(rawXml); return; } } - void Disconnect(const NotificationData& data) override + void Signal(const CommandData&, StringView rawXml) override { switch (m_state) { + case EState::eNOT_CONNECTED: case EState::eDISCONNECTED: return; + default: + m_forward.Signal(rawXml); + return; + } + } + + void Signal(const CheckAliveData&, StringView rawXml) override + { + switch (m_state) + { case EState::eNOT_CONNECTED: - m_state = EState::eDISCONNECTED; - m_pCallback->OnState(m_state); - m_forward.Disconnect(); + case EState::eDISCONNECTED: + return; + + default: + m_forward.Signal(rawXml); + return; + } + } + + void Disconnect() override + { + switch (m_state) + { + case EState::eDISCONNECTED: return; default: m_state = EState::eDISCONNECTED; m_pCallback->OnState(m_state); - m_forward.Signal(data); m_forward.Disconnect(); } } @@ -254,7 +295,7 @@ namespace Hermes } } - void On(const ServiceDescription& data) override + void On(const ServiceDescriptionData& data) override { switch (m_state) { @@ -352,17 +393,42 @@ namespace Hermes } } + void On(const QueryBoardInfoData& data) override + { + switch (m_state) + { + case EState::eNOT_CONNECTED: + case EState::eDISCONNECTED: + return; + + default: + m_pCallback->On(m_state, data); + } + } + void On(const NotificationData& data) override { switch (m_state) { case EState::eNOT_CONNECTED: case EState::eDISCONNECTED: - return OnUnexpectedPeerEvent_("Notification"); + return; default: m_pCallback->On(m_state, data); + } + } + + void On(const CommandData& data) override + { + switch (m_state) + { + case EState::eNOT_CONNECTED: + case EState::eDISCONNECTED: return; + + default: + m_pCallback->On(m_state, data); } } @@ -372,11 +438,10 @@ namespace Hermes { case EState::eNOT_CONNECTED: case EState::eDISCONNECTED: - return OnUnexpectedPeerEvent_("Notification"); + return; default: m_pCallback->On(m_state, data); - return; } } diff --git a/src/Hermes/DownstreamStateMachine.h b/src/Hermes/DownstreamStateMachine.h index 3c85709..100d444 100644 --- a/src/Hermes/DownstreamStateMachine.h +++ b/src/Hermes/DownstreamStateMachine.h @@ -32,13 +32,16 @@ namespace Hermes struct IStateMachine { virtual void Connect(std::weak_ptr wpOwner, IStateMachineCallback&) = 0; - virtual void Signal(const ServiceDescription&) = 0; - virtual void Signal(const BoardAvailableData&) = 0; - virtual void Signal(const RevokeBoardAvailableData&) = 0; - virtual void Signal(const TransportFinishedData&) = 0; - virtual void Signal(const NotificationData&) = 0; - virtual void Signal(const CheckAliveData&) = 0; - virtual void Disconnect(const NotificationData&) = 0; + virtual void Signal(const ServiceDescriptionData&, StringView rawXml) = 0; + virtual void Signal(const BoardAvailableData&, StringView rawXml) = 0; + virtual void Signal(const RevokeBoardAvailableData&, StringView rawXml) = 0; + virtual void Signal(const TransportFinishedData&, StringView rawXml) = 0; + virtual void Signal(const BoardForecastData&, StringView rawXml) = 0; + virtual void Signal(const SendBoardInfoData&, StringView rawXml) = 0; + virtual void Signal(const NotificationData&, StringView rawXml) = 0; + virtual void Signal(const CommandData&, StringView rawXml) = 0; + virtual void Signal(const CheckAliveData&, StringView rawXml) = 0; + virtual void Disconnect() = 0; virtual ~IStateMachine() = default; }; @@ -46,12 +49,14 @@ namespace Hermes struct IStateMachineCallback { virtual void OnSocketConnected(EState, const ConnectionInfo&) = 0; - virtual void On(EState, const ServiceDescription&) = 0; + virtual void On(EState, const ServiceDescriptionData&) = 0; virtual void On(EState, const MachineReadyData&) = 0; virtual void On(EState, const RevokeMachineReadyData&) = 0; virtual void On(EState, const StartTransportData&) = 0; virtual void On(EState, const StopTransportData&) = 0; + virtual void On(EState, const QueryBoardInfoData&) = 0; virtual void On(EState, const NotificationData&) = 0; + virtual void On(EState, const CommandData&) = 0; virtual void On(EState, const CheckAliveData&) = 0; virtual void OnState(EState) = 0; virtual void OnDisconnected(EState, const Error&) = 0; diff --git a/src/Hermes/GeneratedHermesGuid.cpp b/src/Hermes/GeneratedHermesGuid.cpp deleted file mode 100644 index 7f8ea25..0000000 --- a/src/Hermes/GeneratedHermesGuid.cpp +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) ASM Assembly Systems GmbH & Co. KG -#include "stdafx.h" - -#include - -#include -#include - -namespace -{ - namespace Detail - { - char ToChar(int i) - { - return static_cast(i <= 9 ? '0' + i : 'a' - 10 + i); - } - } -} - -void GenerateHermesGuid(char* pBuffer) -{ - auto uuid = boost::uuids::random_generator()(); - auto i = 0U; - for (auto it = uuid.begin(); it != uuid.end(); ++it, ++i) - { - *pBuffer++ = Detail::ToChar(((*it) >> 4) & 0x0F); - *pBuffer++ = Detail::ToChar(*it & 0x0F); - if (i == 3 || i == 5 || i == 7 || i == 9) - { - *pBuffer++ = '-'; - } - } -} - - - diff --git a/src/Hermes/Hermes.vcxproj b/src/Hermes/Hermes.vcxproj index d427dba..495ad7e 100644 --- a/src/Hermes/Hermes.vcxproj +++ b/src/Hermes/Hermes.vcxproj @@ -26,32 +26,32 @@ SAK Win32Proj Hermes - 8.1 + 10.0 DynamicLibrary true - v140 + v143 NotSet DynamicLibrary false - v140 + v143 true NotSet DynamicLibrary true - v140 + v143 NotSet DynamicLibrary false - v140 + v143 true NotSet @@ -75,22 +75,22 @@ true - ..\..\bin\$(Configuration)\$(PlatformTarget)\ + ..\..\bin\$(PlatformTarget)\$(Configuration)\ ..\..\tmp\$(ProjectName)_$(Configuration)_$(PlatformTarget)\ true - ..\..\bin\$(Configuration)\$(PlatformTarget)\ + ..\..\bin\$(PlatformTarget)\$(Configuration)\ ..\..\tmp\$(ProjectName)_$(Configuration)_$(PlatformTarget)\ false - ..\..\bin\$(Configuration)\$(PlatformTarget)\ + ..\..\bin\$(PlatformTarget)\$(Configuration)\ ..\..\tmp\$(ProjectName)_$(Configuration)_$(PlatformTarget)\ false - ..\..\bin\$(Configuration)\$(PlatformTarget)\ + ..\..\bin\$(PlatformTarget)\$(Configuration)\ ..\..\tmp\$(ProjectName)_$(Configuration)_$(PlatformTarget)\ @@ -101,12 +101,14 @@ HERMES_LIB;_DEBUG;_WINDOWS;_USRDLL;HERMES_EXPORTS;%(PreprocessorDefinitions) $(ProjectDir)\..\..\References; $(ProjectDir)\..\include MultiThreadedDebug + /Zc:threadSafeInit- + stdcpp20 Windows true $(ProjectDir)\..\..\lib\$(Configuration)\$(PlatformTarget)\$(TargetName).lib - ..\..\References\static_runtime_libs.$(Configuration).$(PlatformTarget)\ + ..\..\References\lib32 @@ -118,12 +120,14 @@ HERMES_LIB;_DEBUG;_WINDOWS;_USRDLL;HERMES_EXPORTS;%(PreprocessorDefinitions) $(ProjectDir)\..\..\References; $(ProjectDir)\..\include MultiThreadedDebug + /Zc:threadSafeInit- + stdcpp20 Windows true $(ProjectDir)\..\..\lib\$(Configuration)\$(PlatformTarget)\$(TargetName).lib - ..\..\References\static_runtime_libs.$(Configuration).$(PlatformTarget)\ + ..\..\References\lib64 @@ -134,6 +138,8 @@ HERMES_LIB;NDEBUG;_WINDOWS;_USRDLL;HERMES_EXPORTS;%(PreprocessorDefinitions) $(ProjectDir)\..\..\References; $(ProjectDir)\..\include MultiThreaded + /Zc:threadSafeInit- + stdcpp20 Windows @@ -141,7 +147,7 @@ true true $(ProjectDir)\..\..\lib\$(Configuration)\$(PlatformTarget)\$(TargetName).lib - ..\..\References\static_runtime_libs.$(Configuration).$(PlatformTarget)\ + ..\..\References\lib32 @@ -154,6 +160,8 @@ HERMES_LIB;NDEBUG;_WINDOWS;_USRDLL;HERMES_EXPORTS;%(PreprocessorDefinitions) $(ProjectDir)\..\..\References; $(ProjectDir)\..\include MultiThreaded + /Zc:threadSafeInit- + stdcpp20 Windows @@ -161,12 +169,12 @@ true true $(ProjectDir)\..\..\lib\$(Configuration)\$(PlatformTarget)\$(TargetName).lib - ..\..\References\static_runtime_libs.$(Configuration).$(PlatformTarget)\ + ..\..\References\lib64 - - + + @@ -174,24 +182,33 @@ + + + + - + + - + + + + + @@ -206,25 +223,31 @@ + + + + - Create Create Create Create - - - + + + + + + diff --git a/src/Hermes/Hermes.vcxproj.filters b/src/Hermes/Hermes.vcxproj.filters index 5d77f83..7df317a 100644 --- a/src/Hermes/Hermes.vcxproj.filters +++ b/src/Hermes/Hermes.vcxproj.filters @@ -1,10 +1,6 @@  - - {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 - {1206491f-c7dc-4ff7-9428-24ec0363de3a} @@ -27,23 +23,26 @@ {a1b6f957-3633-4457-8869-555143b5cdba} - - {2bb8285b-5879-4db8-bea3-899d4ff1438c} - {217b355f-4db9-4366-8f3e-2fc173b41223} {4035d6a8-f053-4d09-92f9-856f89ef72d0} + + {b1011605-5304-4521-bc19-57db95f24442} + + + {3a3fc53b-b1ec-4d42-9082-17db5afd9423} + + + {2c66b745-fc16-4ca7-937b-d360d6105e07} + PrecompiledHeaders - - Serialization - Service @@ -65,9 +64,6 @@ Downstream - - Upstream - Upstream @@ -77,12 +73,6 @@ Upstream - - Serialization\pugixml - - - Serialization\pugixml - Configuration @@ -119,14 +109,50 @@ Public + + Public + + + Public + + + Infra + + + Serialization + + + Serialization + + + Serialization + + + Serialization + + + Serialization + + + VerticalService + + + VerticalService + + + VerticalClient + + + VerticalClient + + + Service + PrecompiledHeaders - - Serialization - NetworkCommunication @@ -157,9 +183,6 @@ Upstream - - Serialization\pugixml - Configuration @@ -175,10 +198,38 @@ Serialization - - - - Resource Files - + + Serialization + + + Serialization + + + Serialization + + + Serialization + + + VerticalService + + + VerticalService + + + VerticalService + + + VerticalClient + + + VerticalClient + + + VerticalClient + + + Pugixml + \ No newline at end of file diff --git a/src/Hermes/IService.h b/src/Hermes/IService.h index afbefdd..0145270 100644 --- a/src/Hermes/IService.h +++ b/src/Hermes/IService.h @@ -25,10 +25,12 @@ limitations under the License. #include #include -namespace boost +#include + +/*namespace boost causes compile errors with Linux -> remove or encapsulate with #ifdef _WINDOWS? { - namespace asio { class io_service; } -} + namespace asio { class io_context; using io_service = io_context; } +}*/ namespace Hermes diff --git a/src/Hermes/Makefile b/src/Hermes/Makefile index b51fe1c..945f602 100644 --- a/src/Hermes/Makefile +++ b/src/Hermes/Makefile @@ -3,7 +3,7 @@ ifeq ($(DEBUG),1) DBGFLAGS = -O0 -g3 -D_DEBUG endif -VERSION= 1:0 +VERSION= 3:1 CFLAGS = -std=c++17 LFLAGS = -lpugixml @@ -19,9 +19,13 @@ EXECUTABLE=libhermes.la LINK=libtool --mode=link g++ -shared -rpath /usr/lib64 -version-info $(VERSION) #-fvisibility=hidden-export-symbols-regex 'Hermes' -OBJECTS = ConfigurationClient.lo ConfigurationService.lo ConfigurationServiceSerializer.lo ConfigurationServiceSession.lo \ - Downstream.lo DownstreamSerializer.lo DownstreamSession.lo DownstreamStateMachine.lo Serialization.lo Serializer.lo Upstream.lo \ - UpstreamSerializer.lo UpstreamSession.lo UpstreamStateMachine.lo AsioServer.lo AsioClient.lo +OBJECTS = AsioClient.lo AsioServer.lo ConfigurationClient.lo ConfigurationService.lo ConfigurationServiceSerializer.lo \ + ConfigurationServiceSession.lo DeserializationHelper.lo Downstream.lo DownstreamSerializer.lo DownstreamSession.lo DownstreamStateMachine.lo \ + MessageDispatcher.lo MessageSerialization.lo SenderEnvelope.lo Serialization.lo Upstream.lo \ + UpstreamSerializer.lo UpstreamSession.lo UpstreamStateMachine.lo \ + VerticalClient.lo VerticalClientSerializer.lo VerticalClientSession.lo VerticalService.lo \ + VerticalServiceSerializer.lo VerticalServiceSession.lo + default: $(EXECUTABLE) diff --git a/src/Hermes/MessageDispatcher.cpp b/src/Hermes/MessageDispatcher.cpp new file mode 100644 index 0000000..d8cc751 --- /dev/null +++ b/src/Hermes/MessageDispatcher.cpp @@ -0,0 +1,120 @@ +#include "stdafx.h" + +#include "MessageDispatcher.h" + +namespace +{ + const std::string cHERMES = "Hermes"; + const std::size_t cHERMES_SIZE = 6U; + const std::string cHERMES_END_TAG = "' + std::size_t endIndex = buffer.find('>', endTagIndex + cHERMES_END_TAG.size()); + if (endIndex == std::string::npos) + return{}; + + auto msgBuffer = buffer.substr(0U, endIndex + 1); + buffer = buffer.substr(endIndex + 1); + + return msgBuffer; + } + + Error ParseXmlMessage_(StringSpan message, pugi::xml_document* pDoc, pugi::xml_node* pNode) + { + auto parseResult = pDoc->load_buffer_inplace(message.data(), message.size(), pugi::parse_default, pugi::encoding_utf8); + if (!parseResult) + return Error{EErrorCode::eCLIENT_ERROR, + std::string(parseResult.description()) + " at offset " + std::to_string(parseResult.offset)}; + pugi::xml_node envelopeNode = pDoc->first_child(); + *pNode = envelopeNode.first_child(); + if (!*pNode) + return Error{EErrorCode::eCLIENT_ERROR, std::string("Missing message type node")}; + + return{}; + } + + void MessageDispatcher::Add(StringView tag, Callback&& callback) + { + m_map.emplace(tag, std::move(callback)); + } + + Error MessageDispatcher::Dispatch(StringSpan xmlData) + { + if (!m_buffer.empty()) + { + m_buffer.append(xmlData.data(), xmlData.size()); + xmlData = m_buffer; + } + + for (StringSpan xmlMessage = TakeMessage_(xmlData); !xmlMessage.empty(); xmlMessage = TakeMessage_(xmlData)) + { + pugi::xml_document xmlDocument; + pugi::xml_node dataNode; + if (auto error = ParseXmlMessage_(xmlMessage, &xmlDocument, &dataNode)) + return error; + + StringView tag = dataNode.name(); + auto itFound = m_map.find(tag.data()); + if (itFound == m_map.end()) + { + m_service.Warn(m_sessionId, "Unexpected message ", tag); + continue; + } + if (auto error = (itFound->second)(dataNode)) + return error; + } + + if (xmlData.size() > cMAX_MESSAGE_SIZE) + return{EErrorCode::ePEER_ERROR, ": Maximum message size exceeded"}; + + // do the housekeeping for the buffer and the view into it: + if (xmlData.empty()) + { + m_buffer.clear(); + } + else if (m_buffer.empty()) + { + m_buffer.assign(xmlData.data(), xmlData.size()); + } + else // view and buffer overlap + { + m_buffer.erase(0U, xmlData.data() - m_buffer.data()); + } + return{}; + } + +} + diff --git a/src/Hermes/MessageDispatcher.h b/src/Hermes/MessageDispatcher.h new file mode 100644 index 0000000..686b0d4 --- /dev/null +++ b/src/Hermes/MessageDispatcher.h @@ -0,0 +1,63 @@ +#pragma once + +#include "IService.h" +#include "MessageSerialization.h" +#include "StringSpan.h" + +#ifdef _WINDOWS +#include "pugixml/pugixml.hpp" +#else +#include "pugixml.hpp" +#endif + +#include +#include + +namespace Hermes +{ + struct Error; + + class MessageDispatcher + { + public: + + explicit MessageDispatcher(unsigned sessionId, IAsioService& asioService) : + m_sessionId(sessionId), + m_service(asioService) + {} + + MessageDispatcher(const MessageDispatcher&) = delete; + MessageDispatcher& operator=(const MessageDispatcher&) = delete; + + ~MessageDispatcher() = default; + + using Callback = std::function; + + void Add(StringView tag, Callback&& callback); + Error Dispatch(StringSpan input); + + template + void Add(CallbackT&& callback) + { + Add(SerializationTraits::cTAG_VIEW, + [this, callback = std::forward(callback)](pugi::xml_node xmlNode)->Error + { + DataT data; + auto error = Deserialize(xmlNode, data); + if (error) + return error; + m_service.Log(m_sessionId, SerializationTraits::cTAG_VIEW, ':', data); + callback(data); + return{}; + }); + } + + private: + + std::string m_buffer; + std::map, std::less<>> m_map; + unsigned m_sessionId; + IAsioService& m_service; + }; + +} diff --git a/src/Hermes/MessageSerialization.cpp b/src/Hermes/MessageSerialization.cpp new file mode 100644 index 0000000..0dfff6b --- /dev/null +++ b/src/Hermes/MessageSerialization.cpp @@ -0,0 +1,1170 @@ +#include "stdafx.h" + +#include "MessageSerialization.h" + +#include "BasicPugiSerialization.h" +#include "SenderEnvelope.h" + +#include +#include +#include + +namespace Hermes +{ + template<> struct PugiSerializer + { + using AsElementTag = int; + + static void WriteElement(pugi::xml_node parent, const SubBoard& data) + { + Serialize(parent, "Pos", data.m_pos); + Serialize(parent, "Bc", data.m_optionalBc); + Serialize(parent, "St", data.m_st); + } + + static void ReadElement(pugi::xml_node parent, Error& error, SubBoard& data) + { + Deserialize(parent, "Pos", error, data.m_pos); + Deserialize(parent, "Bc", error, data.m_optionalBc); + Deserialize(parent, "St", error, data.m_st); + } + }; + + // SubBoards are special in that they are optional vectors + void Serialize(pugi::xml_node parent, const char* name, const SubBoards& subBoards) + { + if (subBoards.empty()) + return; + + auto subBoardsNode = parent.append_child(name); + + for (const auto& item : subBoards) + { + Serialize(subBoardsNode, "SB", item); + } + } + + void Deserialize(pugi::xml_node parent, const char* name, Error& error, SubBoards& subBoards) + { + const auto subBoardsNode = parent.child(name); + if (!subBoardsNode) + return; + + for (const auto& node : subBoardsNode.children("SB")) + { + subBoards.emplace_back(); + PugiSerializer::ReadElement(node, error, subBoards.back()); + } + } + + template<> struct PugiSerializer + { + using AsElementTag = int; + + static void WriteElement(pugi::xml_node, const FeatureBoardForecast&) {} + static void ReadElement(pugi::xml_node, Error&, FeatureBoardForecast&) {} + }; + + template<> struct PugiSerializer + { + using AsElementTag = int; + + static void WriteElement(pugi::xml_node, const FeatureCheckAliveResponse&) {} + static void ReadElement(pugi::xml_node, Error&, FeatureCheckAliveResponse&) {} + }; + + template<> struct PugiSerializer + { + using AsElementTag = int; + + static void WriteElement(pugi::xml_node, const FeatureQueryBoardInfo&) {} + static void ReadElement(pugi::xml_node, Error&, FeatureQueryBoardInfo&) {} + }; + + template<> struct PugiSerializer + { + using AsElementTag = int; + + static void WriteElement(pugi::xml_node, const FeatureSendBoardInfo&) {} + static void ReadElement(pugi::xml_node, Error&, FeatureSendBoardInfo&) {} + }; + + template<> struct PugiSerializer + { + using AsElementTag = int; + + static void WriteElement(pugi::xml_node, const FeatureCommand&) {} + static void ReadElement(pugi::xml_node, Error&, FeatureCommand&) {} + }; + + template<> struct PugiSerializer + { + using AsElementTag = int; + + static void WriteElement(pugi::xml_node parent, const SupportedFeatures& data) + { + Serialize(parent, "FeatureBoardForecast", data.m_optionalFeatureBoardForecast); + Serialize(parent, "FeatureCheckAliveResponse", data.m_optionalFeatureCheckAliveResponse); + Serialize(parent, "FeatureQueryBoardInfo", data.m_optionalFeatureQueryBoardInfo); + Serialize(parent, "FeatureSendBoardInfo", data.m_optionalFeatureSendBoardInfo); + Serialize(parent, "FeatureCommand", data.m_optionalFeatureCommand); + } + + static void ReadElement(pugi::xml_node parent, Error& error, SupportedFeatures& data) + { + Deserialize(parent, "FeatureBoardForecast", error, data.m_optionalFeatureBoardForecast); + Deserialize(parent, "FeatureCheckAliveResponse", error, data.m_optionalFeatureCheckAliveResponse); + Deserialize(parent, "FeatureQueryBoardInfo", error, data.m_optionalFeatureQueryBoardInfo); + Deserialize(parent, "FeatureSendBoardInfo", error, data.m_optionalFeatureSendBoardInfo); + Deserialize(parent, "FeatureCommand", error, data.m_optionalFeatureCommand); + } + }; + + template<> struct PugiSerializer + { + using AsElementTag = int; + + static void WriteElement(pugi::xml_node parent, const UpstreamConfiguration& data) + { + Serialize(parent, "UpstreamLaneId", data.m_upstreamLaneId); + Serialize(parent, "UpstreamInterfaceId", data.m_optionalUpstreamInterfaceId); + Serialize(parent, "HostAddress", data.m_hostAddress); + Serialize(parent, "Port", data.m_port); + } + + static void ReadElement(pugi::xml_node parent, Error& error, UpstreamConfiguration& data) + { + Deserialize(parent, "UpstreamLaneId", error, data.m_upstreamLaneId); + Deserialize(parent, "UpstreamInterfaceId", error, data.m_optionalUpstreamInterfaceId); + Deserialize(parent, "HostAddress", error, data.m_hostAddress); + Deserialize(parent, "Port", error, data.m_port); + } + }; + + template<> struct PugiSerializer + { + using AsElementTag = int; + + static void WriteElement(pugi::xml_node parent, const DownstreamConfiguration& data) + { + Serialize(parent, "DownstreamLaneId", data.m_downstreamLaneId); + Serialize(parent, "DownstreamInterfaceId", data.m_optionalDownstreamInterfaceId); + Serialize(parent, "ClientAddress", data.m_optionalClientAddress); + Serialize(parent, "Port", data.m_port); + } + + static void ReadElement(pugi::xml_node parent, Error& error, DownstreamConfiguration& data) + { + Deserialize(parent, "DownstreamLaneId", error, data.m_downstreamLaneId); + Deserialize(parent, "DownstreamInterfaceId", error, data.m_optionalDownstreamInterfaceId); + Deserialize(parent, "ClientAddress", error, data.m_optionalClientAddress); + Deserialize(parent, "Port", error, data.m_port); + } + }; + + template<> struct PugiSerializer + { + using AsElementTag = int; + + static void WriteElement(pugi::xml_node parent, const UpstreamConfigurations& data) + { + for (const auto& item : data) + { + Serialize(parent, "UpstreamConfiguration", item); + } + } + static void ReadElement(pugi::xml_node parent, Error& error, UpstreamConfigurations& data) + { + for (const auto& node : parent.children("UpstreamConfiguration")) + { + data.emplace_back(); + PugiSerializer::ReadElement(node, error, data.back()); + } + } + }; + + template<> struct PugiSerializer + { + using AsElementTag = int; + + static void WriteElement(pugi::xml_node parent, const DownstreamConfigurations& data) + { + for (const auto& item : data) + { + Serialize(parent, "DownstreamConfiguration", item); + } + } + static void ReadElement(pugi::xml_node parent, Error& error, DownstreamConfigurations& data) + { + for (const auto& node : parent.children("DownstreamConfiguration")) + { + data.emplace_back(); + PugiSerializer::ReadElement(node, error, data.back()); + } + } + }; + + template<> struct PugiSerializer + { + using AsElementTag = int; + + static void WriteElement(pugi::xml_node, const FeatureConfiguration&) {} + static void ReadElement(pugi::xml_node, Error&, FeatureConfiguration&) {} + }; + + template<> struct PugiSerializer + { + using AsElementTag = int; + + static void WriteElement(pugi::xml_node, const FeatureBoardTracking&) {} + static void ReadElement(pugi::xml_node, Error&, FeatureBoardTracking&) {} + }; + + template<> struct PugiSerializer + { + using AsElementTag = int; + + static void WriteElement(pugi::xml_node, const FeatureQueryWorkOrderInfo&) {} + static void ReadElement(pugi::xml_node, Error&, FeatureQueryWorkOrderInfo&) {} + }; + + template<> struct PugiSerializer + { + using AsElementTag = int; + + static void WriteElement(pugi::xml_node, const FeatureSendWorkOrderInfo&) {} + static void ReadElement(pugi::xml_node, Error&, FeatureSendWorkOrderInfo&) {} + }; + + template<> struct PugiSerializer + { + using AsElementTag = int; + + static void WriteElement(pugi::xml_node, const FeatureReplyWorkOrderInfo&) {} + static void ReadElement(pugi::xml_node, Error&, FeatureReplyWorkOrderInfo&) {} + }; + + template<> struct PugiSerializer + { + using AsElementTag = int; + + static void WriteElement(pugi::xml_node, const FeatureQueryHermesCapabilities&) {} + static void ReadElement(pugi::xml_node, Error&, FeatureQueryHermesCapabilities&) {} + }; + + template<> struct PugiSerializer + { + using AsElementTag = int; + + static void WriteElement(pugi::xml_node, const FeatureSendHermesCapabilities&) {} + static void ReadElement(pugi::xml_node, Error&, FeatureSendHermesCapabilities&) {} + }; + + template<> struct PugiSerializer + { + using AsElementTag = int; + + static void WriteElement(pugi::xml_node parent, const SupervisoryFeatures& data) + { + Serialize(parent, "FeatureConfiguration", data.m_optionalFeatureConfiguration); + Serialize(parent, "FeatureCheckAliveResponse", data.m_optionalFeatureCheckAliveResponse); + Serialize(parent, "FeatureBoardTracking", data.m_optionalFeatureBoardTracking); + Serialize(parent, "FeatureQueryWorkOrderInfo", data.m_optionalFeatureQueryWorkOrderInfo); + Serialize(parent, "FeatureSendWorkOrderInfo", data.m_optionalFeatureSendWorkOrderInfo); + Serialize(parent, "FeatureReplyWorkOrderInfo", data.m_optionalFeatureReplyWorkOrderInfo); + Serialize(parent, "FeatureQueryHermesCapabilities", data.m_optionalFeatureQueryHermesCapabilities); + Serialize(parent, "FeatureSendHermesCapabilities", data.m_optionalFeatureSendHermesCapabilities); + } + + static void ReadElement(pugi::xml_node parent, Error& error, SupervisoryFeatures& data) + { + Deserialize(parent, "FeatureConfiguration", error, data.m_optionalFeatureConfiguration); + Deserialize(parent, "FeatureCheckAliveResponse", error, data.m_optionalFeatureCheckAliveResponse); + Deserialize(parent, "FeatureBoardTracking", error, data.m_optionalFeatureBoardTracking); + Deserialize(parent, "FeatureQueryWorkOrderInfo", error, data.m_optionalFeatureQueryWorkOrderInfo); + Deserialize(parent, "FeatureSendWorkOrderInfo", error, data.m_optionalFeatureSendWorkOrderInfo); + Deserialize(parent, "FeatureReplyWorkOrderInfo", error, data.m_optionalFeatureReplyWorkOrderInfo); + Deserialize(parent, "FeatureQueryHermesCapabilities", error, data.m_optionalFeatureQueryHermesCapabilities); + Deserialize(parent, "FeatureSendHermesCapabilities", error, data.m_optionalFeatureSendHermesCapabilities); + } + }; + + template<> struct PugiSerializer + { + using AsElementTag = int; + + static void WriteElement(pugi::xml_node, const MessageCheckAliveResponse&) {} + static void ReadElement(pugi::xml_node, Error&, MessageCheckAliveResponse&) {} + }; + + template<> struct PugiSerializer + { + using AsElementTag = int; + + static void WriteElement(pugi::xml_node, const MessageBoardForecast&) {} + static void ReadElement(pugi::xml_node, Error&, MessageBoardForecast&) {} + }; + + template<> struct PugiSerializer + { + using AsElementTag = int; + + static void WriteElement(pugi::xml_node, const MessageQueryBoardInfo&) {} + static void ReadElement(pugi::xml_node, Error&, MessageQueryBoardInfo&) {} + }; + + template<> struct PugiSerializer + { + using AsElementTag = int; + + static void WriteElement(pugi::xml_node, const MessageSendBoardInfo&) {} + static void ReadElement(pugi::xml_node, Error&, MessageSendBoardInfo&) {} + }; + template<> struct PugiSerializer + { + using AsElementTag = int; + + static void WriteElement(pugi::xml_node, const MessageBoardArrived&) {} + static void ReadElement(pugi::xml_node, Error&, MessageBoardArrived&) {} + }; + + template<> struct PugiSerializer + { + using AsElementTag = int; + + static void WriteElement(pugi::xml_node, const MessageBoardDeparted&) {} + static void ReadElement(pugi::xml_node, Error&, MessageBoardDeparted&) {} + }; + + template<> struct PugiSerializer + { + using AsElementTag = int; + + static void WriteElement(pugi::xml_node, const MessageQueryWorkOrderInfo&) {} + static void ReadElement(pugi::xml_node, Error&, MessageQueryWorkOrderInfo&) {} + }; + + template<> struct PugiSerializer + { + using AsElementTag = int; + + static void WriteElement(pugi::xml_node, const MessageReplyWorkOrderInfo&) {} + static void ReadElement(pugi::xml_node, Error&, MessageReplyWorkOrderInfo&) {} + }; + + template<> struct PugiSerializer + { + using AsElementTag = int; + + static void WriteElement(pugi::xml_node, const MessageCommand&) {} + static void ReadElement(pugi::xml_node, Error&, MessageCommand&) {} + }; + + template<> struct PugiSerializer + { + using AsElementTag = int; + + static void WriteElement(pugi::xml_node parent, const OptionalMessages& data) + { + Serialize(parent, "MessageCheckAliveResponse", data.m_optionalMessageCheckAliveResponse); + Serialize(parent, "MessageBoardForecast", data.m_optionalMessageBoardForecast); + Serialize(parent, "MessageQueryBoardInfo", data.m_optionalMessageQueryBoardInfo); + Serialize(parent, "MessageSendBoardInfo", data.m_optionalMessageSendBoardInfo); + Serialize(parent, "MessageBoardArrived", data.m_optionalMessageBoardArrived); + Serialize(parent, "MessageBoardDeparted", data.m_optionalMessageBoardDeparted); + Serialize(parent, "MessageQueryWorkOrderInfo", data.m_optionalMessageQueryWorkOrderInfo); + Serialize(parent, "MessageReplyWorkOrderInfo", data.m_optionalMessageReplyWorkOrderInfo); + Serialize(parent, "MessageCommand", data.m_optionalMessageCommand); + } + + static void ReadElement(pugi::xml_node parent, Error& error, OptionalMessages& data) + { + Deserialize(parent, "MessageCheckAliveResponse", error, data.m_optionalMessageCheckAliveResponse); + Deserialize(parent, "MessageBoardForecast", error, data.m_optionalMessageBoardForecast); + Deserialize(parent, "MessageQueryBoardInfo", error, data.m_optionalMessageQueryBoardInfo); + Deserialize(parent, "MessageSendBoardInfo", error, data.m_optionalMessageSendBoardInfo); + Deserialize(parent, "MessageBoardArrived", error, data.m_optionalMessageBoardArrived); + Deserialize(parent, "MessageBoardDeparted", error, data.m_optionalMessageBoardDeparted); + Deserialize(parent, "MessageQueryWorkOrderInfo", error, data.m_optionalMessageQueryWorkOrderInfo); + Deserialize(parent, "MessageReplyWorkOrderInfo", error, data.m_optionalMessageReplyWorkOrderInfo); + Deserialize(parent, "MessageCommand", error, data.m_optionalMessageCommand); + } + }; + + template<> struct PugiSerializer + { + using AsElementTag = int; + + static void WriteElement(pugi::xml_node parent, const Attributes& data) + { + Serialize(parent, "ProductTypeId", data.m_productTypeId); + Serialize(parent, "TopBarcode", data.m_topBarcode); + Serialize(parent, "BottomBarcode", data.m_bottomBarcode); + Serialize(parent, "Length", data.m_length); + Serialize(parent, "Width", data.m_width); + Serialize(parent, "Thickness", data.m_thickness); + Serialize(parent, "ConveyorSpeed", data.m_conveyorSpeed); + Serialize(parent, "TopClearanceHeight", data.m_topClearanceHeight); + Serialize(parent, "BottomClearanceHeight", data.m_bottomClearanceHeight); + Serialize(parent, "Weight", data.m_weight); + Serialize(parent, "WorkOrderId", data.m_workOrderId); + Serialize(parent, "BatchId", data.m_batchId); + Serialize(parent, "Route", data.m_route); + Serialize(parent, "Action", data.m_action); + Serialize(parent, "SubBoards", data.m_subBoards); + } + + static void ReadElement(pugi::xml_node parent, Error& error, Attributes& data) + { + Deserialize(parent, "ProductTypeId", error, data.m_productTypeId); + Deserialize(parent, "TopBarcode", error, data.m_topBarcode); + Deserialize(parent, "BottomBarcode", error, data.m_bottomBarcode); + Deserialize(parent, "Length", error, data.m_length); + Deserialize(parent, "Width", error, data.m_width); + Deserialize(parent, "Thickness", error, data.m_thickness); + Deserialize(parent, "ConveyorSpeed", error, data.m_conveyorSpeed); + Deserialize(parent, "TopClearanceHeight", error, data.m_topClearanceHeight); + Deserialize(parent, "BottomClearanceHeight", error, data.m_bottomClearanceHeight); + Deserialize(parent, "Weight", error, data.m_weight); + Deserialize(parent, "WorkOrderId", error, data.m_workOrderId); + Deserialize(parent, "BatchId", error, data.m_batchId); + Deserialize(parent, "Route", error, data.m_route); + Deserialize(parent, "Action", error, data.m_action); + Deserialize(parent, "SubBoards", error, data.m_subBoards); + } + }; +} + +std::string Hermes::Serialize(const ServiceDescriptionData& data) +{ + SenderEnvelope envelope(Hermes::SerializationTraits::cTAG_VIEW); + Serialize(envelope.DataNode(), "LaneId", data.m_laneId); + Serialize(envelope.DataNode(), "MachineId", data.m_machineId); + Serialize(envelope.DataNode(), "InterfaceId", data.m_optionalInterfaceId); + Serialize(envelope.DataNode(), "Version", data.m_version); + Serialize(envelope.DataNode(), "SupportedFeatures", data.m_supportedFeatures); + return envelope.ToXmlString(); +} + + +std::string Serialize_(const Hermes::BoardAvailableData& data, bool includeSubBoards) +{ + using namespace Hermes; + SenderEnvelope envelope(Hermes::SerializationTraits::cTAG_VIEW); + Serialize(envelope.DataNode(), "BoardId", data.m_boardId); + Serialize(envelope.DataNode(), "BoardIdCreatedBy", data.m_boardIdCreatedBy); + Serialize(envelope.DataNode(), "FailedBoard", data.m_failedBoard); + Serialize(envelope.DataNode(), "ProductTypeId", data.m_optionalProductTypeId); + Serialize(envelope.DataNode(), "FlippedBoard", data.m_flippedBoard); + Serialize(envelope.DataNode(), "TopBarcode", data.m_optionalTopBarcode); + Serialize(envelope.DataNode(), "BottomBarcode", data.m_optionalBottomBarcode); + Serialize(envelope.DataNode(), "Length", data.m_optionalLengthInMM); + Serialize(envelope.DataNode(), "Width", data.m_optionalWidthInMM); + Serialize(envelope.DataNode(), "Thickness", data.m_optionalThicknessInMM); + Serialize(envelope.DataNode(), "ConveyorSpeed", data.m_optionalConveyorSpeedInMMPerSecs); + Serialize(envelope.DataNode(), "TopClearanceHeight", data.m_optionalTopClearanceHeightInMM); + Serialize(envelope.DataNode(), "BottomClearanceHeight", data.m_optionalBottomClearanceHeightInMM); + Serialize(envelope.DataNode(), "Weight", data.m_optionalWeightInGrams); + Serialize(envelope.DataNode(), "WorkOrderId", data.m_optionalWorkOrderId); + Serialize(envelope.DataNode(), "BatchId", data.m_optionalBatchId); + Serialize(envelope.DataNode(), "Route", data.m_optionalRoute); + Serialize(envelope.DataNode(), "Action", data.m_optionalAction); + if (includeSubBoards) + { + Serialize(envelope.DataNode(), "SubBoards", data.m_optionalSubBoards); + } + return envelope.ToXmlString(); +} + +std::string Hermes::Serialize(const BoardAvailableData& data) +{ + auto str{ Serialize_(data, true) }; + if (str.size() <= cMAX_MESSAGE_SIZE) + return str; + + return Serialize_(data, false); +} + +std::string Hermes::Serialize(const RevokeBoardAvailableData&) +{ + SenderEnvelope envelope(Hermes::SerializationTraits::cTAG_VIEW); + return envelope.ToXmlString(); +} + +std::string Hermes::Serialize(const MachineReadyData& data) +{ + SenderEnvelope envelope(Hermes::SerializationTraits::cTAG_VIEW); + Serialize(envelope.DataNode(), "FailedBoard", data.m_failedBoard); + Serialize(envelope.DataNode(), "ForecastId", data.m_optionalForecastId); + Serialize(envelope.DataNode(), "BoardId", data.m_optionalBoardId); + Serialize(envelope.DataNode(), "ProductTypeId", data.m_optionalProductTypeId); + Serialize(envelope.DataNode(), "FlippedBoard", data.m_optionalFlippedBoard); + Serialize(envelope.DataNode(), "TopBarcode", data.m_optionalTopBarcode); + Serialize(envelope.DataNode(), "BottomBarcode", data.m_optionalBottomBarcode); + Serialize(envelope.DataNode(), "Length", data.m_optionalLengthInMM); + Serialize(envelope.DataNode(), "Width", data.m_optionalWidthInMM); + Serialize(envelope.DataNode(), "Thickness", data.m_optionalThicknessInMM); + Serialize(envelope.DataNode(), "ConveyorSpeed", data.m_optionalConveyorSpeedInMMPerSecs); + Serialize(envelope.DataNode(), "TopClearanceHeight", data.m_optionalTopClearanceHeightInMM); + Serialize(envelope.DataNode(), "BottomClearanceHeight", data.m_optionalBottomClearanceHeightInMM); + Serialize(envelope.DataNode(), "Weight", data.m_optionalWeightInGrams); + Serialize(envelope.DataNode(), "WorkOrderId", data.m_optionalWorkOrderId); + Serialize(envelope.DataNode(), "BatchId", data.m_optionalBatchId); + return envelope.ToXmlString(); +} + +std::string Hermes::Serialize(const RevokeMachineReadyData&) +{ + SenderEnvelope envelope(Hermes::SerializationTraits::cTAG_VIEW); + return envelope.ToXmlString(); +} + +std::string Hermes::Serialize(const StartTransportData& data) +{ + SenderEnvelope envelope(Hermes::SerializationTraits::cTAG_VIEW); + Serialize(envelope.DataNode(), "BoardId", data.m_boardId); + Serialize(envelope.DataNode(), "ConveyorSpeed", data.m_optionalConveyorSpeedInMMPerSecs); + return envelope.ToXmlString(); +} + +std::string Hermes::Serialize(const TransportFinishedData& data) +{ + SenderEnvelope envelope(Hermes::SerializationTraits::cTAG_VIEW); + Serialize(envelope.DataNode(), "TransferState", data.m_transferState); + Serialize(envelope.DataNode(), "BoardId", data.m_boardId); + return envelope.ToXmlString(); +} + +std::string Hermes::Serialize(const StopTransportData& data) +{ + SenderEnvelope envelope(Hermes::SerializationTraits::cTAG_VIEW); + Serialize(envelope.DataNode(), "TransferState", data.m_transferState); + Serialize(envelope.DataNode(), "BoardId", data.m_boardId); + return envelope.ToXmlString(); +} + +std::string Hermes::Serialize(const NotificationData& data) +{ + SenderEnvelope envelope(Hermes::SerializationTraits::cTAG_VIEW); + Serialize(envelope.DataNode(), "NotificationCode", data.m_notificationCode); + Serialize(envelope.DataNode(), "Severity", data.m_severity); + Serialize(envelope.DataNode(), "Description", data.m_description); + return envelope.ToXmlString(); +} + +std::string Hermes::Serialize(const CheckAliveData& data) +{ + SenderEnvelope envelope(Hermes::SerializationTraits::cTAG_VIEW); + Serialize(envelope.DataNode(), "Type", data.m_optionalType); + Serialize(envelope.DataNode(), "Id", data.m_optionalId); + return envelope.ToXmlString(); +} + +std::string Hermes::Serialize(const GetConfigurationData&) +{ + SenderEnvelope envelope(Hermes::SerializationTraits::cTAG_VIEW); + return envelope.ToXmlString(); +} + +std::string Hermes::Serialize(const SetConfigurationData& data) +{ + SenderEnvelope envelope(Hermes::SerializationTraits::cTAG_VIEW); + Serialize(envelope.DataNode(), "MachineId", data.m_machineId); + Serialize(envelope.DataNode(), "SupervisorySystemPort", data.m_optionalSupervisorySystemPort); + Serialize(envelope.DataNode(), "UpstreamConfigurations", data.m_upstreamConfigurations); + Serialize(envelope.DataNode(), "DownstreamConfigurations", data.m_downstreamConfigurations); + return envelope.ToXmlString(); +} + +std::string Hermes::Serialize(const CurrentConfigurationData& data) +{ + SenderEnvelope envelope(Hermes::SerializationTraits::cTAG_VIEW); + Serialize(envelope.DataNode(), "MachineId", data.m_optionalMachineId); + Serialize(envelope.DataNode(), "SupervisorySystemPort", data.m_optionalSupervisorySystemPort); + Serialize(envelope.DataNode(), "UpstreamConfigurations", data.m_upstreamConfigurations); + Serialize(envelope.DataNode(), "DownstreamConfigurations", data.m_downstreamConfigurations); + return envelope.ToXmlString(); +} + +std::string Hermes::Serialize(const BoardForecastData& data) +{ + SenderEnvelope envelope(Hermes::SerializationTraits::cTAG_VIEW); + Serialize(envelope.DataNode(), "ForecastId", data.m_optionalForecastId); + Serialize(envelope.DataNode(), "TimeUntilAvailable", data.m_optionalTimeUntilAvailableInSeconds); + Serialize(envelope.DataNode(), "BoardId", data.m_optionalBoardId); + Serialize(envelope.DataNode(), "BoardIdCreatedBy", data.m_optionalBoardIdCreatedBy); + Serialize(envelope.DataNode(), "FailedBoard", data.m_failedBoard); + Serialize(envelope.DataNode(), "ProductTypeId", data.m_optionalProductTypeId); + Serialize(envelope.DataNode(), "FlippedBoard", data.m_flippedBoard); + Serialize(envelope.DataNode(), "TopBarcode", data.m_optionalTopBarcode); + Serialize(envelope.DataNode(), "BottomBarcode", data.m_optionalBottomBarcode); + Serialize(envelope.DataNode(), "Length", data.m_optionalLengthInMM); + Serialize(envelope.DataNode(), "Width", data.m_optionalWidthInMM); + Serialize(envelope.DataNode(), "Thickness", data.m_optionalThicknessInMM); + Serialize(envelope.DataNode(), "ConveyorSpeed", data.m_optionalConveyorSpeedInMMPerSecs); + Serialize(envelope.DataNode(), "TopClearanceHeight", data.m_optionalTopClearanceHeightInMM); + Serialize(envelope.DataNode(), "BottomClearanceHeight", data.m_optionalBottomClearanceHeightInMM); + Serialize(envelope.DataNode(), "Weight", data.m_optionalWeightInGrams); + Serialize(envelope.DataNode(), "WorkOrderId", data.m_optionalWorkOrderId); + Serialize(envelope.DataNode(), "BatchId", data.m_optionalBatchId); + return envelope.ToXmlString(); +} + +std::string Hermes::Serialize(const QueryBoardInfoData& data) +{ + SenderEnvelope envelope(Hermes::SerializationTraits::cTAG_VIEW); + Serialize(envelope.DataNode(), "TopBarcode", data.m_optionalTopBarcode); + Serialize(envelope.DataNode(), "BottomBarcode", data.m_optionalBottomBarcode); + return envelope.ToXmlString(); +} + +std::string Serialize_(const Hermes::SendBoardInfoData& data, bool includeSubBoards) +{ + using namespace Hermes; + + SenderEnvelope envelope(Hermes::SerializationTraits::cTAG_VIEW); + Serialize(envelope.DataNode(), "BoardId", data.m_optionalBoardId); + Serialize(envelope.DataNode(), "BoardIdCreatedBy", data.m_optionalBoardIdCreatedBy); + Serialize(envelope.DataNode(), "FailedBoard", data.m_optionalFailedBoard); + Serialize(envelope.DataNode(), "ProductTypeId", data.m_optionalProductTypeId); + Serialize(envelope.DataNode(), "FlippedBoard", data.m_optionalFlippedBoard); + Serialize(envelope.DataNode(), "TopBarcode", data.m_optionalTopBarcode); + Serialize(envelope.DataNode(), "BottomBarcode", data.m_optionalBottomBarcode); + Serialize(envelope.DataNode(), "Length", data.m_optionalLengthInMM); + Serialize(envelope.DataNode(), "Width", data.m_optionalWidthInMM); + Serialize(envelope.DataNode(), "Thickness", data.m_optionalThicknessInMM); + Serialize(envelope.DataNode(), "ConveyorSpeed", data.m_optionalConveyorSpeedInMMPerSecs); + Serialize(envelope.DataNode(), "TopClearanceHeight", data.m_optionalTopClearanceHeightInMM); + Serialize(envelope.DataNode(), "BottomClearanceHeight", data.m_optionalBottomClearanceHeightInMM); + Serialize(envelope.DataNode(), "Weight", data.m_optionalWeightInGrams); + Serialize(envelope.DataNode(), "WorkOrderId", data.m_optionalWorkOrderId); + Serialize(envelope.DataNode(), "BatchId", data.m_optionalBatchId); + Serialize(envelope.DataNode(), "Route", data.m_optionalRoute); + Serialize(envelope.DataNode(), "Action", data.m_optionalAction); + if (includeSubBoards) + { + Serialize(envelope.DataNode(), "SubBoards", data.m_optionalSubBoards); + } + return envelope.ToXmlString(); +} + +std::string Hermes::Serialize(const SendBoardInfoData& data) +{ + auto str{ Serialize_(data, true) }; + if (str.size() <= cMAX_MESSAGE_SIZE) + return str; + + return Serialize_(data, false); +} + +std::string Hermes::Serialize(const SupervisoryServiceDescriptionData& data) +{ + SenderEnvelope envelope(Hermes::SerializationTraits::cTAG_VIEW); + Serialize(envelope.DataNode(), "SystemId", data.m_systemId); + Serialize(envelope.DataNode(), "Version", data.m_version); + Serialize(envelope.DataNode(), "SupportedFeatures", data.m_supportedFeatures); + return envelope.ToXmlString(); +} + +std::string Serialize_(const Hermes::BoardArrivedData& data, bool includeSubBoards) +{ + using namespace Hermes; + SenderEnvelope envelope(Hermes::SerializationTraits::cTAG_VIEW); + Serialize(envelope.DataNode(), "MachineId", data.m_machineId); + Serialize(envelope.DataNode(), "UpstreamLaneId", data.m_upstreamLaneId); + Serialize(envelope.DataNode(), "UpstreamInterfaceId", data.m_optionalUpstreamInterfaceId); + Serialize(envelope.DataNode(), "MagazineId", data.m_optionalMagazineId); + Serialize(envelope.DataNode(), "SlotId", data.m_optionalSlotId); + Serialize(envelope.DataNode(), "BoardTransfer", data.m_boardTransfer); + Serialize(envelope.DataNode(), "BoardId", data.m_boardId); + Serialize(envelope.DataNode(), "BoardIdCreatedBy", data.m_boardIdCreatedBy); + Serialize(envelope.DataNode(), "FailedBoard", data.m_failedBoard); + Serialize(envelope.DataNode(), "ProductTypeId", data.m_optionalProductTypeId); + Serialize(envelope.DataNode(), "FlippedBoard", data.m_flippedBoard); + Serialize(envelope.DataNode(), "TopBarcode", data.m_optionalTopBarcode); + Serialize(envelope.DataNode(), "BottomBarcode", data.m_optionalBottomBarcode); + Serialize(envelope.DataNode(), "Length", data.m_optionalLengthInMM); + Serialize(envelope.DataNode(), "Width", data.m_optionalWidthInMM); + Serialize(envelope.DataNode(), "Thickness", data.m_optionalThicknessInMM); + Serialize(envelope.DataNode(), "ConveyorSpeed", data.m_optionalConveyorSpeedInMMPerSecs); + Serialize(envelope.DataNode(), "TopClearanceHeight", data.m_optionalTopClearanceHeightInMM); + Serialize(envelope.DataNode(), "BottomClearanceHeight", data.m_optionalBottomClearanceHeightInMM); + Serialize(envelope.DataNode(), "Weight", data.m_optionalWeightInGrams); + Serialize(envelope.DataNode(), "WorkOrderId", data.m_optionalWorkOrderId); + Serialize(envelope.DataNode(), "BatchId", data.m_optionalBatchId); + Serialize(envelope.DataNode(), "Route", data.m_optionalRoute); + Serialize(envelope.DataNode(), "Action", data.m_optionalAction); + if (includeSubBoards) + { + Serialize(envelope.DataNode(), "SubBoards", data.m_optionalSubBoards); + } + return envelope.ToXmlString(); +} + +std::string Hermes::Serialize(const BoardArrivedData& data) +{ + auto str{ Serialize_(data, true) }; + if (str.size() <= cMAX_MESSAGE_SIZE) + return str; + + return Serialize_(data, false); +} + +std::string Serialize_(const Hermes::BoardDepartedData& data, bool includeSubBoards) +{ + using namespace Hermes; + SenderEnvelope envelope(Hermes::SerializationTraits::cTAG_VIEW); + Serialize(envelope.DataNode(), "MachineId", data.m_machineId); + Serialize(envelope.DataNode(), "DownstreamLaneId", data.m_downstreamLaneId); + Serialize(envelope.DataNode(), "DownstreamInterfaceId", data.m_optionalDownstreamInterfaceId); + Serialize(envelope.DataNode(), "MagazineId", data.m_optionalMagazineId); + Serialize(envelope.DataNode(), "SlotId", data.m_optionalSlotId); + Serialize(envelope.DataNode(), "BoardTransfer", data.m_boardTransfer); + Serialize(envelope.DataNode(), "BoardId", data.m_boardId); + Serialize(envelope.DataNode(), "BoardIdCreatedBy", data.m_boardIdCreatedBy); + Serialize(envelope.DataNode(), "FailedBoard", data.m_failedBoard); + Serialize(envelope.DataNode(), "ProductTypeId", data.m_optionalProductTypeId); + Serialize(envelope.DataNode(), "FlippedBoard", data.m_flippedBoard); + Serialize(envelope.DataNode(), "TopBarcode", data.m_optionalTopBarcode); + Serialize(envelope.DataNode(), "BottomBarcode", data.m_optionalBottomBarcode); + Serialize(envelope.DataNode(), "Length", data.m_optionalLengthInMM); + Serialize(envelope.DataNode(), "Width", data.m_optionalWidthInMM); + Serialize(envelope.DataNode(), "Thickness", data.m_optionalThicknessInMM); + Serialize(envelope.DataNode(), "ConveyorSpeed", data.m_optionalConveyorSpeedInMMPerSecs); + Serialize(envelope.DataNode(), "TopClearanceHeight", data.m_optionalTopClearanceHeightInMM); + Serialize(envelope.DataNode(), "BottomClearanceHeight", data.m_optionalBottomClearanceHeightInMM); + Serialize(envelope.DataNode(), "Weight", data.m_optionalWeightInGrams); + Serialize(envelope.DataNode(), "WorkOrderId", data.m_optionalWorkOrderId); + Serialize(envelope.DataNode(), "BatchId", data.m_optionalBatchId); + Serialize(envelope.DataNode(), "Route", data.m_optionalRoute); + Serialize(envelope.DataNode(), "Action", data.m_optionalAction); + if (includeSubBoards) + { + Serialize(envelope.DataNode(), "SubBoards", data.m_optionalSubBoards); + } + return envelope.ToXmlString(); +} + +std::string Hermes::Serialize(const BoardDepartedData& data) +{ + auto str{ Serialize_(data, true) }; + if (str.size() <= cMAX_MESSAGE_SIZE) + return str; + + return Serialize_(data, false); +} + +std::string Hermes::Serialize(const QueryWorkOrderInfoData& data) +{ + SenderEnvelope envelope(Hermes::SerializationTraits::cTAG_VIEW); + Serialize(envelope.DataNode(), "QueryId", data.m_optionalQueryId); + Serialize(envelope.DataNode(), "MachineId", data.m_machineId); + Serialize(envelope.DataNode(), "MagazineId", data.m_optionalMagazineId); + Serialize(envelope.DataNode(), "SlotId", data.m_optionalSlotId); + Serialize(envelope.DataNode(), "Barcode", data.m_optionalBarcode); + Serialize(envelope.DataNode(), "WorkOrderId", data.m_optionalWorkOrderId); + Serialize(envelope.DataNode(), "BatchId", data.m_optionalBatchId); + return envelope.ToXmlString(); +} + +std::string Serialize_(const Hermes::SendWorkOrderInfoData& data, bool includeSubBoards) +{ + using namespace Hermes; + SenderEnvelope envelope(Hermes::SerializationTraits::cTAG_VIEW); + Serialize(envelope.DataNode(), "QueryId", data.m_optionalQueryId); + Serialize(envelope.DataNode(), "WorkOrderId", data.m_optionalWorkOrderId); + Serialize(envelope.DataNode(), "BatchId", data.m_optionalBatchId); + Serialize(envelope.DataNode(), "BoardId", data.m_optionalBoardId); + Serialize(envelope.DataNode(), "BoardIdCreatedBy", data.m_optionalBoardIdCreatedBy); + Serialize(envelope.DataNode(), "FailedBoard", data.m_optionalFailedBoard); + Serialize(envelope.DataNode(), "ProductTypeId", data.m_optionalProductTypeId); + Serialize(envelope.DataNode(), "FlippedBoard", data.m_optionalFlippedBoard); + Serialize(envelope.DataNode(), "TopBarcode", data.m_optionalTopBarcode); + Serialize(envelope.DataNode(), "BottomBarcode", data.m_optionalBottomBarcode); + Serialize(envelope.DataNode(), "Length", data.m_optionalLengthInMM); + Serialize(envelope.DataNode(), "Width", data.m_optionalWidthInMM); + Serialize(envelope.DataNode(), "Thickness", data.m_optionalThicknessInMM); + Serialize(envelope.DataNode(), "ConveyorSpeed", data.m_optionalConveyorSpeedInMMPerSecs); + Serialize(envelope.DataNode(), "TopClearanceHeight", data.m_optionalTopClearanceHeightInMM); + Serialize(envelope.DataNode(), "BottomClearanceHeight", data.m_optionalBottomClearanceHeightInMM); + Serialize(envelope.DataNode(), "Weight", data.m_optionalWeightInGrams); + Serialize(envelope.DataNode(), "Route", data.m_optionalRoute); + if (includeSubBoards) + { + Serialize(envelope.DataNode(), "SubBoards", data.m_optionalSubBoards); + } + return envelope.ToXmlString(); +} + +std::string Hermes::Serialize(const SendWorkOrderInfoData& data) +{ + auto str{ Serialize_(data, true) }; + if (str.size() <= cMAX_MESSAGE_SIZE) + return str; + + return Serialize_(data, false); +} + +std::string Hermes::Serialize(const ReplyWorkOrderInfoData& data) +{ + SenderEnvelope envelope(Hermes::SerializationTraits::cTAG_VIEW); + Serialize(envelope.DataNode(), "WorkOrderId", data.m_workOrderId); + Serialize(envelope.DataNode(), "BatchId", data.m_optionalBatchId); + Serialize(envelope.DataNode(), "Status", data.m_status); + return envelope.ToXmlString(); +} + +std::string Hermes::Serialize(const QueryHermesCapabilitiesData&) +{ + SenderEnvelope envelope(Hermes::SerializationTraits::cTAG_VIEW); + + return envelope.ToXmlString(); +} + +std::string Hermes::Serialize(const SendHermesCapabilitiesData& data) +{ + SenderEnvelope envelope(Hermes::SerializationTraits::cTAG_VIEW); + Serialize(envelope.DataNode(), "OptionalMessages", data.m_optionalMessages); + Serialize(envelope.DataNode(), "Attributes", data.m_attributes); + + return envelope.ToXmlString(); +} + +std::string Hermes::Serialize(const CommandData& data) +{ + SenderEnvelope envelope(Hermes::SerializationTraits::cTAG_VIEW); + Serialize(envelope.DataNode(), "Command", data.m_command); + return envelope.ToXmlString(); +} + +Hermes::Error Hermes::Deserialize(pugi::xml_node xmlNode, ServiceDescriptionData& data) +{ + Error error; + Deserialize(xmlNode, "LaneId", error, data.m_laneId); + Deserialize(xmlNode, "MachineId", error, data.m_machineId); + Deserialize(xmlNode, "InterfaceId", error, data.m_optionalInterfaceId); + Deserialize(xmlNode, "Version", error, data.m_version); + Deserialize(xmlNode, "SupportedFeatures", error, data.m_supportedFeatures); + return error; +} + +Hermes::Error Hermes::Deserialize(pugi::xml_node xmlNode, BoardAvailableData& data) +{ + Error error; + Deserialize(xmlNode, "BoardId", error, data.m_boardId); + Deserialize(xmlNode, "BoardIdCreatedBy", error, data.m_boardIdCreatedBy); + Deserialize(xmlNode, "FailedBoard", error, data.m_failedBoard); + Deserialize(xmlNode, "ProductTypeId", error, data.m_optionalProductTypeId); + Deserialize(xmlNode, "FlippedBoard", error, data.m_flippedBoard); + Deserialize(xmlNode, "TopBarcode", error, data.m_optionalTopBarcode); + Deserialize(xmlNode, "BottomBarcode", error, data.m_optionalBottomBarcode); + Deserialize(xmlNode, "Length", error, data.m_optionalLengthInMM); + Deserialize(xmlNode, "Width", error, data.m_optionalWidthInMM); + Deserialize(xmlNode, "Thickness", error, data.m_optionalThicknessInMM); + Deserialize(xmlNode, "ConveyorSpeed", error, data.m_optionalConveyorSpeedInMMPerSecs); + Deserialize(xmlNode, "TopClearanceHeight", error, data.m_optionalTopClearanceHeightInMM); + Deserialize(xmlNode, "BottomClearanceHeight", error, data.m_optionalBottomClearanceHeightInMM); + Deserialize(xmlNode, "Weight", error, data.m_optionalWeightInGrams); + Deserialize(xmlNode, "WorkOrderId", error, data.m_optionalWorkOrderId); + Deserialize(xmlNode, "BatchId", error, data.m_optionalBatchId); + Deserialize(xmlNode, "Route", error, data.m_optionalRoute); + Deserialize(xmlNode, "Action", error, data.m_optionalAction); + Deserialize(xmlNode, "SubBoards", error, data.m_optionalSubBoards); + return error; +} + +Hermes::Error Hermes::Deserialize(pugi::xml_node, RevokeBoardAvailableData&) +{ + Error error; + return error; +} + +Hermes::Error Hermes::Deserialize(pugi::xml_node xmlNode, MachineReadyData& data) +{ + Error error; + Deserialize(xmlNode, "FailedBoard", error, data.m_failedBoard); + Deserialize(xmlNode, "ForecastId", error, data.m_optionalForecastId); + Deserialize(xmlNode, "BoardId", error, data.m_optionalBoardId); + Deserialize(xmlNode, "ProductTypeId", error, data.m_optionalProductTypeId); + Deserialize(xmlNode, "FlippedBoard", error, data.m_optionalFlippedBoard); + Deserialize(xmlNode, "TopBarcode", error, data.m_optionalTopBarcode); + Deserialize(xmlNode, "BottomBarcode", error, data.m_optionalBottomBarcode); + Deserialize(xmlNode, "Length", error, data.m_optionalLengthInMM); + Deserialize(xmlNode, "Width", error, data.m_optionalWidthInMM); + Deserialize(xmlNode, "Thickness", error, data.m_optionalThicknessInMM); + Deserialize(xmlNode, "ConveyorSpeed", error, data.m_optionalConveyorSpeedInMMPerSecs); + Deserialize(xmlNode, "TopClearanceHeight", error, data.m_optionalTopClearanceHeightInMM); + Deserialize(xmlNode, "BottomClearanceHeight", error, data.m_optionalBottomClearanceHeightInMM); + Deserialize(xmlNode, "Weight", error, data.m_optionalWeightInGrams); + Deserialize(xmlNode, "WorkOrderId", error, data.m_optionalWorkOrderId); + Deserialize(xmlNode, "BatchId", error, data.m_optionalBatchId); + return error; +} + +Hermes::Error Hermes::Deserialize(pugi::xml_node, RevokeMachineReadyData&) +{ + Error error; + return error; +} + +Hermes::Error Hermes::Deserialize(pugi::xml_node xmlNode, StartTransportData& data) +{ + Error error; + Deserialize(xmlNode, "BoardId", error, data.m_boardId); + Deserialize(xmlNode, "ConveyorSpeed", error, data.m_optionalConveyorSpeedInMMPerSecs); + return error; +} + +Hermes::Error Hermes::Deserialize(pugi::xml_node xmlNode, StopTransportData& data) +{ + Error error; + Deserialize(xmlNode, "TransferState", error, data.m_transferState); + Deserialize(xmlNode, "BoardId", error, data.m_boardId); + return error; +} + +Hermes::Error Hermes::Deserialize(pugi::xml_node xmlNode, TransportFinishedData& data) +{ + Error error; + Deserialize(xmlNode, "TransferState", error, data.m_transferState); + Deserialize(xmlNode, "BoardId", error, data.m_boardId); + return error; +} + +Hermes::Error Hermes::Deserialize(pugi::xml_node xmlNode, NotificationData& data) +{ + Error error; + Deserialize(xmlNode, "NotificationCode", error, data.m_notificationCode); + Deserialize(xmlNode, "Severity", error, data.m_severity); + Deserialize(xmlNode, "Description", error, data.m_description); + return error; +} + +Hermes::Error Hermes::Deserialize(pugi::xml_node xmlNode, CheckAliveData& data) +{ + Error error; + Deserialize(xmlNode, "Type", error, data.m_optionalType); + Deserialize(xmlNode, "Id", error, data.m_optionalId); + return error; +} + +Hermes::Error Hermes::Deserialize(pugi::xml_node xmlNode, SetConfigurationData& data) +{ + Error error; + Deserialize(xmlNode, "MachineId", error, data.m_machineId); + Deserialize(xmlNode, "SupervisorySystemPort", error, data.m_optionalSupervisorySystemPort); + Deserialize(xmlNode, "UpstreamConfigurations", error, data.m_upstreamConfigurations); + Deserialize(xmlNode, "DownstreamConfigurations", error, data.m_downstreamConfigurations); + return{}; +} + +Hermes::Error Hermes::Deserialize(pugi::xml_node, GetConfigurationData&) +{ + Error error; + return error; +} + +Hermes::Error Hermes::Deserialize(pugi::xml_node xmlNode, CurrentConfigurationData& data) +{ + Error error; + Deserialize(xmlNode, "MachineId", error, data.m_optionalMachineId); + Deserialize(xmlNode, "SupervisorySystemPort", error, data.m_optionalSupervisorySystemPort); + Deserialize(xmlNode, "UpstreamConfigurations", error, data.m_upstreamConfigurations); + Deserialize(xmlNode, "DownstreamConfigurations", error, data.m_downstreamConfigurations); + return{}; +} + +Hermes::Error Hermes::Deserialize(pugi::xml_node xmlNode, BoardForecastData& data) +{ + Error error; + Deserialize(xmlNode, "ForecastId", error, data.m_optionalForecastId); + Deserialize(xmlNode, "TimeUntilAvailable", error, data.m_optionalTimeUntilAvailableInSeconds); + Deserialize(xmlNode, "BoardId", error, data.m_optionalBoardId); + Deserialize(xmlNode, "BoardIdCreatedBy", error, data.m_optionalBoardIdCreatedBy); + Deserialize(xmlNode, "FailedBoard", error, data.m_failedBoard); + Deserialize(xmlNode, "ProductTypeId", error, data.m_optionalProductTypeId); + Deserialize(xmlNode, "FlippedBoard", error, data.m_flippedBoard); + Deserialize(xmlNode, "TopBarcode", error, data.m_optionalTopBarcode); + Deserialize(xmlNode, "BottomBarcode", error, data.m_optionalBottomBarcode); + Deserialize(xmlNode, "Length", error, data.m_optionalLengthInMM); + Deserialize(xmlNode, "Width", error, data.m_optionalWidthInMM); + Deserialize(xmlNode, "Thickness", error, data.m_optionalThicknessInMM); + Deserialize(xmlNode, "ConveyorSpeed", error, data.m_optionalConveyorSpeedInMMPerSecs); + Deserialize(xmlNode, "TopClearanceHeight", error, data.m_optionalTopClearanceHeightInMM); + Deserialize(xmlNode, "BottomClearanceHeight", error, data.m_optionalBottomClearanceHeightInMM); + Deserialize(xmlNode, "Weight", error, data.m_optionalWeightInGrams); + Deserialize(xmlNode, "WorkOrderId", error, data.m_optionalWorkOrderId); + Deserialize(xmlNode, "BatchId", error, data.m_optionalBatchId); + return error; +} + +Hermes::Error Hermes::Deserialize(pugi::xml_node xmlNode, QueryBoardInfoData& data) +{ + Error error; + Deserialize(xmlNode, "TopBarcode", error, data.m_optionalTopBarcode); + Deserialize(xmlNode, "BottomBarcode", error, data.m_optionalBottomBarcode); + return error; +} + +Hermes::Error Hermes::Deserialize(pugi::xml_node xmlNode, SendBoardInfoData& data) +{ + Error error; + Deserialize(xmlNode, "BoardId", error, data.m_optionalBoardId); + Deserialize(xmlNode, "BoardIdCreatedBy", error, data.m_optionalBoardIdCreatedBy); + Deserialize(xmlNode, "FailedBoard", error, data.m_optionalFailedBoard); + Deserialize(xmlNode, "ProductTypeId", error, data.m_optionalProductTypeId); + Deserialize(xmlNode, "FlippedBoard", error, data.m_optionalFlippedBoard); + Deserialize(xmlNode, "TopBarcode", error, data.m_optionalTopBarcode); + Deserialize(xmlNode, "BottomBarcode", error, data.m_optionalBottomBarcode); + Deserialize(xmlNode, "Length", error, data.m_optionalLengthInMM); + Deserialize(xmlNode, "Width", error, data.m_optionalWidthInMM); + Deserialize(xmlNode, "Thickness", error, data.m_optionalThicknessInMM); + Deserialize(xmlNode, "ConveyorSpeed", error, data.m_optionalConveyorSpeedInMMPerSecs); + Deserialize(xmlNode, "TopClearanceHeight", error, data.m_optionalTopClearanceHeightInMM); + Deserialize(xmlNode, "BottomClearanceHeight", error, data.m_optionalBottomClearanceHeightInMM); + Deserialize(xmlNode, "Weight", error, data.m_optionalWeightInGrams); + Deserialize(xmlNode, "WorkOrderId", error, data.m_optionalWorkOrderId); + Deserialize(xmlNode, "BatchId", error, data.m_optionalBatchId); + Deserialize(xmlNode, "Route", error, data.m_optionalRoute); + Deserialize(xmlNode, "Action", error, data.m_optionalAction); + Deserialize(xmlNode, "SubBoards", error, data.m_optionalSubBoards); + return error; +} + +Hermes::Error Hermes::Deserialize(pugi::xml_node xmlNode, SupervisoryServiceDescriptionData& data) +{ + Error error; + Deserialize(xmlNode, "SystemId", error, data.m_systemId); + Deserialize(xmlNode, "Version", error, data.m_version); + Deserialize(xmlNode, "SupportedFeatures", error, data.m_supportedFeatures); + return error; +} + +Hermes::Error Hermes::Deserialize(pugi::xml_node xmlNode, BoardArrivedData& data) +{ + Error error; + Deserialize(xmlNode, "MachineId", error, data.m_machineId); + Deserialize(xmlNode, "UpstreamLaneId", error, data.m_upstreamLaneId); + Deserialize(xmlNode, "UpstreamInterfaceId", error, data.m_optionalUpstreamInterfaceId); + Deserialize(xmlNode, "MagazineId", error, data.m_optionalMagazineId); + Deserialize(xmlNode, "SlotId", error, data.m_optionalSlotId); + Deserialize(xmlNode, "BoardTransfer", error, data.m_boardTransfer); + Deserialize(xmlNode, "BoardId", error, data.m_boardId); + Deserialize(xmlNode, "BoardIdCreatedBy", error, data.m_boardIdCreatedBy); + Deserialize(xmlNode, "FailedBoard", error, data.m_failedBoard); + Deserialize(xmlNode, "ProductTypeId", error, data.m_optionalProductTypeId); + Deserialize(xmlNode, "FlippedBoard", error, data.m_flippedBoard); + Deserialize(xmlNode, "TopBarcode", error, data.m_optionalTopBarcode); + Deserialize(xmlNode, "BottomBarcode", error, data.m_optionalBottomBarcode); + Deserialize(xmlNode, "Length", error, data.m_optionalLengthInMM); + Deserialize(xmlNode, "Width", error, data.m_optionalWidthInMM); + Deserialize(xmlNode, "Thickness", error, data.m_optionalThicknessInMM); + Deserialize(xmlNode, "ConveyorSpeed", error, data.m_optionalConveyorSpeedInMMPerSecs); + Deserialize(xmlNode, "TopClearanceHeight", error, data.m_optionalTopClearanceHeightInMM); + Deserialize(xmlNode, "BottomClearanceHeight", error, data.m_optionalBottomClearanceHeightInMM); + Deserialize(xmlNode, "Weight", error, data.m_optionalWeightInGrams); + Deserialize(xmlNode, "WorkOrderId", error, data.m_optionalWorkOrderId); + Deserialize(xmlNode, "BatchId", error, data.m_optionalBatchId); + Deserialize(xmlNode, "Route", error, data.m_optionalRoute); + Deserialize(xmlNode, "Action", error, data.m_optionalAction); + Deserialize(xmlNode, "SubBoards", error, data.m_optionalSubBoards); + return error; +} + +Hermes::Error Hermes::Deserialize(pugi::xml_node xmlNode, BoardDepartedData& data) +{ + Error error; + Deserialize(xmlNode, "MachineId", error, data.m_machineId); + Deserialize(xmlNode, "DownstreamLaneId", error, data.m_downstreamLaneId); + Deserialize(xmlNode, "DownstreamInterfaceId", error, data.m_optionalDownstreamInterfaceId); + Deserialize(xmlNode, "MagazineId", error, data.m_optionalMagazineId); + Deserialize(xmlNode, "SlotId", error, data.m_optionalSlotId); + Deserialize(xmlNode, "BoardTransfer", error, data.m_boardTransfer); + Deserialize(xmlNode, "BoardId", error, data.m_boardId); + Deserialize(xmlNode, "BoardIdCreatedBy", error, data.m_boardIdCreatedBy); + Deserialize(xmlNode, "FailedBoard", error, data.m_failedBoard); + Deserialize(xmlNode, "ProductTypeId", error, data.m_optionalProductTypeId); + Deserialize(xmlNode, "FlippedBoard", error, data.m_flippedBoard); + Deserialize(xmlNode, "TopBarcode", error, data.m_optionalTopBarcode); + Deserialize(xmlNode, "BottomBarcode", error, data.m_optionalBottomBarcode); + Deserialize(xmlNode, "Length", error, data.m_optionalLengthInMM); + Deserialize(xmlNode, "Width", error, data.m_optionalWidthInMM); + Deserialize(xmlNode, "Thickness", error, data.m_optionalThicknessInMM); + Deserialize(xmlNode, "ConveyorSpeed", error, data.m_optionalConveyorSpeedInMMPerSecs); + Deserialize(xmlNode, "TopClearanceHeight", error, data.m_optionalTopClearanceHeightInMM); + Deserialize(xmlNode, "BottomClearanceHeight", error, data.m_optionalBottomClearanceHeightInMM); + Deserialize(xmlNode, "Weight", error, data.m_optionalWeightInGrams); + Deserialize(xmlNode, "WorkOrderId", error, data.m_optionalWorkOrderId); + Deserialize(xmlNode, "BatchId", error, data.m_optionalBatchId); + Deserialize(xmlNode, "Route", error, data.m_optionalRoute); + Deserialize(xmlNode, "Action", error, data.m_optionalAction); + Deserialize(xmlNode, "SubBoards", error, data.m_optionalSubBoards); + return error; +} + +Hermes::Error Hermes::Deserialize(pugi::xml_node xmlNode, QueryWorkOrderInfoData& data) +{ + Error error; + Deserialize(xmlNode, "QueryId", error, data.m_optionalQueryId); + Deserialize(xmlNode, "MachineId", error, data.m_machineId); + Deserialize(xmlNode, "MagazineId", error, data.m_optionalMagazineId); + Deserialize(xmlNode, "SlotId", error, data.m_optionalSlotId); + Deserialize(xmlNode, "Barcode", error, data.m_optionalBarcode); + Deserialize(xmlNode, "WorkOrderId", error, data.m_optionalWorkOrderId); + Deserialize(xmlNode, "BatchId", error, data.m_optionalBatchId); + return error; +} + +Hermes::Error Hermes::Deserialize(pugi::xml_node xmlNode, SendWorkOrderInfoData& data) +{ + Error error; + Deserialize(xmlNode, "QueryId", error, data.m_optionalQueryId); + Deserialize(xmlNode, "WorkOrderId", error, data.m_optionalWorkOrderId); + Deserialize(xmlNode, "BatchId", error, data.m_optionalBatchId); + Deserialize(xmlNode, "BoardId", error, data.m_optionalBoardId); + Deserialize(xmlNode, "BoardIdCreatedBy", error, data.m_optionalBoardIdCreatedBy); + Deserialize(xmlNode, "FailedBoard", error, data.m_optionalFailedBoard); + Deserialize(xmlNode, "ProductTypeId", error, data.m_optionalProductTypeId); + Deserialize(xmlNode, "FlippedBoard", error, data.m_optionalFlippedBoard); + Deserialize(xmlNode, "TopBarcode", error, data.m_optionalTopBarcode); + Deserialize(xmlNode, "BottomBarcode", error, data.m_optionalBottomBarcode); + Deserialize(xmlNode, "Length", error, data.m_optionalLengthInMM); + Deserialize(xmlNode, "Width", error, data.m_optionalWidthInMM); + Deserialize(xmlNode, "Thickness", error, data.m_optionalThicknessInMM); + Deserialize(xmlNode, "ConveyorSpeed", error, data.m_optionalConveyorSpeedInMMPerSecs); + Deserialize(xmlNode, "TopClearanceHeight", error, data.m_optionalTopClearanceHeightInMM); + Deserialize(xmlNode, "BottomClearanceHeight", error, data.m_optionalBottomClearanceHeightInMM); + Deserialize(xmlNode, "Weight", error, data.m_optionalWeightInGrams); + Deserialize(xmlNode, "Route", error, data.m_optionalRoute); + Deserialize(xmlNode, "SubBoards", error, data.m_optionalSubBoards); + return error; +} + +Hermes::Error Hermes::Deserialize(pugi::xml_node xmlNode, ReplyWorkOrderInfoData& data) +{ + Error error; + Deserialize(xmlNode, "WorkOrderId", error, data.m_workOrderId); + Deserialize(xmlNode, "BatchId", error, data.m_optionalBatchId); + Deserialize(xmlNode, "Status", error, data.m_status); + return error; +} + +Hermes::Error Hermes::Deserialize(pugi::xml_node xmlNode, CommandData& data) +{ + Error error; + Deserialize(xmlNode, "Command", error, data.m_command); + return error; +} + +Hermes::Error Hermes::Deserialize(pugi::xml_node /*xmlNode*/, QueryHermesCapabilitiesData& /*data*/) +{ + return { EErrorCode::eSUCCESS, "" }; +} + +Hermes::Error Hermes::Deserialize(pugi::xml_node xmlNode, SendHermesCapabilitiesData& data) +{ + Error error; + Deserialize(xmlNode, "OptionalMessages", error, data.m_optionalMessages); + Deserialize(xmlNode, "Attributes", error, data.m_attributes); + return error; +} diff --git a/src/Hermes/MessageSerialization.h b/src/Hermes/MessageSerialization.h new file mode 100644 index 0000000..3658f4b --- /dev/null +++ b/src/Hermes/MessageSerialization.h @@ -0,0 +1,270 @@ +#pragma once + +#include + +#ifdef _WINDOWS +#include "pugixml/pugixml.hpp" +#else +#include "pugixml.hpp" +#endif + +#include + + +namespace Hermes +{ + template struct SerializationTraits; + + template<> struct SerializationTraits + { + using Data = ServiceDescriptionData; + + static constexpr const char cTAG[] = "ServiceDescription"; + static constexpr StringView cTAG_VIEW = StringView{cTAG, sizeof(cTAG) - 1U}; + }; + + template<> struct SerializationTraits + { + using Data = BoardAvailableData; + + static constexpr const char cTAG[] = "BoardAvailable"; + static constexpr StringView cTAG_VIEW = StringView{cTAG, sizeof(cTAG) - 1U}; + }; + + template<> struct SerializationTraits + { + using Data = RevokeBoardAvailableData; + + static constexpr const char cTAG[] = "RevokeBoardAvailable"; + static constexpr StringView cTAG_VIEW = StringView{cTAG, sizeof(cTAG) - 1U}; + }; + + template<> struct SerializationTraits + { + using Data = MachineReadyData; + + static constexpr const char cTAG[] = "MachineReady"; + static constexpr StringView cTAG_VIEW = StringView{cTAG, sizeof(cTAG) - 1U}; + }; + + template<> struct SerializationTraits + { + using Data = RevokeMachineReadyData; + + static constexpr const char cTAG[] = "RevokeMachineReady"; + static constexpr StringView cTAG_VIEW = StringView{cTAG, sizeof(cTAG) - 1U}; + }; + + template<> struct SerializationTraits + { + using Data = StartTransportData; + + static constexpr const char cTAG[] = "StartTransport"; + static constexpr StringView cTAG_VIEW = StringView{cTAG, sizeof(cTAG) - 1U}; + }; + + template<> struct SerializationTraits + { + using Data = TransportFinishedData; + + static constexpr const char cTAG[] = "TransportFinished"; + static constexpr StringView cTAG_VIEW = StringView{cTAG, sizeof(cTAG) - 1U}; + }; + + template<> struct SerializationTraits + { + using Data = StopTransportData; + + static constexpr const char cTAG[] = "StopTransport"; + static constexpr StringView cTAG_VIEW = StringView{cTAG, sizeof(cTAG) - 1U}; + }; + + template<> struct SerializationTraits + { + using Data = NotificationData; + + static constexpr const char cTAG[] = "Notification"; + static constexpr StringView cTAG_VIEW = StringView{cTAG, sizeof(cTAG) - 1U}; + }; + + template<> struct SerializationTraits + { + using Data = CheckAliveData; + + static constexpr const char cTAG[] = "CheckAlive"; + static constexpr StringView cTAG_VIEW = StringView{cTAG, sizeof(cTAG) - 1U}; + }; + + template<> struct SerializationTraits + { + using Data = GetConfigurationData; + + static constexpr const char cTAG[] = "GetConfiguration"; + static constexpr StringView cTAG_VIEW = StringView{cTAG, sizeof(cTAG) - 1U}; + }; + + template<> struct SerializationTraits + { + using Data = ServiceDescriptionData; + + static constexpr const char cTAG[] = "SetConfiguration"; + static constexpr StringView cTAG_VIEW = StringView{cTAG, sizeof(cTAG) - 1U}; + }; + + template<> struct SerializationTraits + { + using Data = CurrentConfigurationData; + + static constexpr const char cTAG[] = "CurrentConfiguration"; + static constexpr StringView cTAG_VIEW = StringView{cTAG, sizeof(cTAG) - 1U}; + }; + + template<> struct SerializationTraits + { + using Data = CurrentConfigurationData; + + static constexpr const char cTAG[] = "BoardForecast"; + static constexpr StringView cTAG_VIEW = StringView{cTAG, sizeof(cTAG) - 1U}; + }; + + template<> struct SerializationTraits + { + using Data = CurrentConfigurationData; + + static constexpr const char cTAG[] = "QueryBoardInfo"; + static constexpr StringView cTAG_VIEW = StringView{cTAG, sizeof(cTAG) - 1U}; + }; + + template<> struct SerializationTraits + { + using Data = CurrentConfigurationData; + + static constexpr const char cTAG[] = "SendBoardInfo"; + static constexpr StringView cTAG_VIEW = StringView{cTAG, sizeof(cTAG) - 1U}; + }; + + template<> struct SerializationTraits + { + using Data = CurrentConfigurationData; + + static constexpr const char cTAG[] = "SupervisoryServiceDescription"; + static constexpr StringView cTAG_VIEW = StringView{cTAG, sizeof(cTAG) - 1U}; + }; + + template<> struct SerializationTraits + { + using Data = CurrentConfigurationData; + + static constexpr const char cTAG[] = "BoardArrived"; + static constexpr StringView cTAG_VIEW = StringView{cTAG, sizeof(cTAG) - 1U}; + }; + + template<> struct SerializationTraits + { + using Data = CurrentConfigurationData; + + static constexpr const char cTAG[] = "BoardDeparted"; + static constexpr StringView cTAG_VIEW = StringView{cTAG, sizeof(cTAG) - 1U}; + }; + + template<> struct SerializationTraits + { + using Data = CurrentConfigurationData; + + static constexpr const char cTAG[] = "QueryWorkOrderInfo"; + static constexpr StringView cTAG_VIEW = StringView{cTAG, sizeof(cTAG) - 1U}; + }; + + template<> struct SerializationTraits + { + using Data = CurrentConfigurationData; + + static constexpr const char cTAG[] = "SendWorkOrderInfo"; + static constexpr StringView cTAG_VIEW = StringView{cTAG, sizeof(cTAG) - 1U}; + }; + + template<> struct SerializationTraits + { + using Data = CurrentConfigurationData; + + static constexpr const char cTAG[] = "ReplyWorkOrderInfo"; + static constexpr StringView cTAG_VIEW = StringView{ cTAG, sizeof(cTAG) - 1U }; + }; + + template<> struct SerializationTraits + { + using Data = CurrentConfigurationData; + + static constexpr const char cTAG[] = "QueryHermesCapabilities"; + static constexpr StringView cTAG_VIEW = StringView{ cTAG, sizeof(cTAG) - 1U }; + }; + + template<> struct SerializationTraits + { + using Data = CurrentConfigurationData; + + static constexpr const char cTAG[] = "SendHermesCapabilities"; + static constexpr StringView cTAG_VIEW = StringView{ cTAG, sizeof(cTAG) - 1U }; + }; + + template<> struct SerializationTraits + { + using Data = CurrentConfigurationData; + + static constexpr const char cTAG[] = "Command"; + static constexpr StringView cTAG_VIEW = StringView{ cTAG, sizeof(cTAG) - 1U }; + }; + + std::string Serialize(const ServiceDescriptionData&); + std::string Serialize(const BoardAvailableData&); + std::string Serialize(const RevokeBoardAvailableData&); + std::string Serialize(const MachineReadyData&); + std::string Serialize(const RevokeMachineReadyData&); + std::string Serialize(const StartTransportData&); + std::string Serialize(const TransportFinishedData&); + std::string Serialize(const StopTransportData&); + std::string Serialize(const NotificationData&); + std::string Serialize(const CheckAliveData&); + std::string Serialize(const GetConfigurationData&); + std::string Serialize(const SetConfigurationData&); + std::string Serialize(const CurrentConfigurationData&); + std::string Serialize(const BoardForecastData&); + std::string Serialize(const QueryBoardInfoData&); + std::string Serialize(const SendBoardInfoData&); + std::string Serialize(const SupervisoryServiceDescriptionData&); + std::string Serialize(const BoardArrivedData&); + std::string Serialize(const BoardDepartedData&); + std::string Serialize(const QueryWorkOrderInfoData&); + std::string Serialize(const SendWorkOrderInfoData&); + std::string Serialize(const ReplyWorkOrderInfoData&); + std::string Serialize(const QueryHermesCapabilitiesData&); + std::string Serialize(const SendHermesCapabilitiesData&); + std::string Serialize(const CommandData&); + + Error Deserialize(pugi::xml_node, ServiceDescriptionData&); + Error Deserialize(pugi::xml_node, BoardAvailableData&); + Error Deserialize(pugi::xml_node, RevokeBoardAvailableData&); + Error Deserialize(pugi::xml_node, MachineReadyData&); + Error Deserialize(pugi::xml_node, RevokeMachineReadyData&); + Error Deserialize(pugi::xml_node, StartTransportData&); + Error Deserialize(pugi::xml_node, TransportFinishedData&); + Error Deserialize(pugi::xml_node, StopTransportData&); + Error Deserialize(pugi::xml_node, NotificationData&); + Error Deserialize(pugi::xml_node, CheckAliveData&); + Error Deserialize(pugi::xml_node, GetConfigurationData&); + Error Deserialize(pugi::xml_node, SetConfigurationData&); + Error Deserialize(pugi::xml_node, CurrentConfigurationData&); + Error Deserialize(pugi::xml_node, BoardForecastData&); + Error Deserialize(pugi::xml_node, QueryBoardInfoData&); + Error Deserialize(pugi::xml_node, SendBoardInfoData&); + Error Deserialize(pugi::xml_node, SupervisoryServiceDescriptionData&); + Error Deserialize(pugi::xml_node, BoardArrivedData&); + Error Deserialize(pugi::xml_node, BoardDepartedData&); + Error Deserialize(pugi::xml_node, QueryWorkOrderInfoData&); + Error Deserialize(pugi::xml_node, SendWorkOrderInfoData&); + Error Deserialize(pugi::xml_node, ReplyWorkOrderInfoData&); + Error Deserialize(pugi::xml_node, QueryHermesCapabilitiesData&); + Error Deserialize(pugi::xml_node, SendHermesCapabilitiesData&); + Error Deserialize(pugi::xml_node, CommandData&); + +} diff --git a/src/Hermes/Network.h b/src/Hermes/Network.h index 7d915fb..ccf7b4c 100644 --- a/src/Hermes/Network.h +++ b/src/Hermes/Network.h @@ -18,6 +18,7 @@ limitations under the License. #pragma once #include +#include "StringSpan.h" #include #include @@ -28,7 +29,7 @@ limitations under the License. namespace Hermes { struct ConnectionInfo; - class Error; + struct Error; struct IAsioService; using IAsioServiceSp = std::shared_ptr; struct IDataForward; struct NetworkConfiguration; @@ -50,7 +51,7 @@ namespace Hermes struct ISocketCallback { virtual void OnConnected(const ConnectionInfo&) = 0; - virtual void OnReceived(StringView dataView) = 0; + virtual void OnReceived(StringSpan data) = 0; virtual void OnDisconnected(const Error&) = 0; protected: @@ -83,8 +84,8 @@ namespace Hermes { std::string m_hostName; uint16_t m_port = 0U; - unsigned m_retryDelayInSeconds = 10U; - unsigned m_checkAlivePeriodInSeconds = 0U; + double m_retryDelayInSeconds = 10.0; + double m_checkAlivePeriodInSeconds = 60.0; friend bool operator==(const NetworkConfiguration& lhs, const NetworkConfiguration& rhs) { diff --git a/src/Hermes/SenderEnvelope.cpp b/src/Hermes/SenderEnvelope.cpp index 0aa6108..b51acb0 100644 --- a/src/Hermes/SenderEnvelope.cpp +++ b/src/Hermes/SenderEnvelope.cpp @@ -18,11 +18,15 @@ namespace Hermes auto fraction = now - seconds; time_t cnow = std::chrono::system_clock::to_time_t(now); tm local_tm; +#ifdef _WINDOWS localtime_s(&local_tm, &cnow); +#else + localtime_r(&cnow, &local_tm); +#endif std::ostringstream oss; oss << std::put_time(&local_tm, "%Y-%m-%dT%H:%M:%S."); auto milliseconds = std::chrono::duration_cast(fraction); - oss << milliseconds.count(); + oss << std::setw(3) << std::setfill('0') << milliseconds.count(); return oss.str(); } } diff --git a/src/Hermes/SenderEnvelope.h b/src/Hermes/SenderEnvelope.h index 61c0e39..f1664f4 100644 --- a/src/Hermes/SenderEnvelope.h +++ b/src/Hermes/SenderEnvelope.h @@ -1,7 +1,12 @@ #pragma once #include -#include + +#ifdef _WINDOWS +#include "pugixml/pugixml.hpp" +#else +#include "pugixml.hpp" +#endif namespace Hermes { diff --git a/src/Hermes/Serialization.cpp b/src/Hermes/Serialization.cpp index 841a75e..3e6dad0 100644 --- a/src/Hermes/Serialization.cpp +++ b/src/Hermes/Serialization.cpp @@ -15,259 +15,175 @@ limitations under the License. ************************************************************************/ #include "stdafx.h" -#include - -#include -#include "Serializer.h" -#include +#include -#include - - -struct HermesStringHandle -{ - explicit HermesStringHandle(std::string&& rhs) : m_string(std::move(rhs)) {} - explicit HermesStringHandle(const std::string& rhs) : m_string(rhs) {} +#include +#include - std::string m_string; -}; +#include "MessageDispatcher.h" +#include "Service.h" -HermesStringView HermesStringViewFromHandle(HermesStringHandle* pHandle) -{ - return Hermes::ToC(pHandle->m_string); -} -HermesStringHandle* HermesXmlFromServiceDescription(const HermesServiceDescription* pData) -{ - return new HermesStringHandle(Hermes::Serialize(Hermes::ToCpp(*pData))); -} -HermesStringHandle* HermesXmlFromBoardAvailableData(const HermesBoardAvailableData* pData) -{ - return new HermesStringHandle(Hermes::Serialize(Hermes::ToCpp(*pData))); -} -HermesStringHandle* HermesXmlFromRevokeBoardAvailableData(const HermesRevokeBoardAvailableData* pData) +void HermesSerializeServiceDescription(const HermesServiceDescriptionData* pData, HermesSerializationCallback callback) { - return new HermesStringHandle(Hermes::Serialize(Hermes::ToCpp(*pData))); + callback.m_pCall(callback.m_pData, Hermes::ToC(Hermes::Serialize(Hermes::ToCpp(*pData)))); } -HermesStringHandle* HermesXmlFromMachineReadyData(const HermesMachineReadyData* pData) +void HermesSerializeBoardAvailable(const HermesBoardAvailableData* pData, HermesSerializationCallback callback) { - return new HermesStringHandle(Hermes::Serialize(Hermes::ToCpp(*pData))); + callback.m_pCall(callback.m_pData, Hermes::ToC(Hermes::Serialize(Hermes::ToCpp(*pData)))); } -HermesStringHandle* HermesXmlFromRevokeMachineReadyData(const HermesRevokeMachineReadyData* pData) +void HermesSerializeRevokeBoardAvailable(const HermesRevokeBoardAvailableData* pData, HermesSerializationCallback callback) { - return new HermesStringHandle(Hermes::Serialize(Hermes::ToCpp(*pData))); + callback.m_pCall(callback.m_pData, Hermes::ToC(Hermes::Serialize(Hermes::ToCpp(*pData)))); } -HermesStringHandle* HermesXmlFromStartTransportData(const HermesStartTransportData* pData) +void HermesSerializeMachineReady(const HermesMachineReadyData* pData, HermesSerializationCallback callback) { - return new HermesStringHandle(Hermes::Serialize(Hermes::ToCpp(*pData))); + callback.m_pCall(callback.m_pData, Hermes::ToC(Hermes::Serialize(Hermes::ToCpp(*pData)))); } -HermesStringHandle* HermesXmlFromStopTransportData(const HermesStopTransportData* pData) +void HermesSerializeRevokeMachineReady(const HermesRevokeMachineReadyData* pData, HermesSerializationCallback callback) { - return new HermesStringHandle(Hermes::Serialize(Hermes::ToCpp(*pData))); + callback.m_pCall(callback.m_pData, Hermes::ToC(Hermes::Serialize(Hermes::ToCpp(*pData)))); } -HermesStringHandle* HermesXmlFromTransportFinishedData(const HermesTransportFinishedData* pData) +void HermesSerializeStartTransport(const HermesStartTransportData* pData, HermesSerializationCallback callback) { - return new HermesStringHandle(Hermes::Serialize(Hermes::ToCpp(*pData))); + callback.m_pCall(callback.m_pData, Hermes::ToC(Hermes::Serialize(Hermes::ToCpp(*pData)))); } -HermesStringHandle* HermesXmlFromNotificationData(const HermesNotificationData* pData) +void HermesSerializeStopTransport(const HermesStopTransportData* pData, HermesSerializationCallback callback) { - return new HermesStringHandle(Hermes::Serialize(Hermes::ToCpp(*pData))); + callback.m_pCall(callback.m_pData, Hermes::ToC(Hermes::Serialize(Hermes::ToCpp(*pData)))); } -HermesStringHandle* HermesXmlFromCheckAliveData(const HermesCheckAliveData* pData) +void HermesSerializeTransportFinished(const HermesTransportFinishedData* pData, HermesSerializationCallback callback) { - return new HermesStringHandle(Hermes::Serialize(Hermes::ToCpp(*pData))); + callback.m_pCall(callback.m_pData, Hermes::ToC(Hermes::Serialize(Hermes::ToCpp(*pData)))); } -HermesStringHandle* HermesXmlFromGetConfigurationData(const HermesGetConfigurationData* pData) +void HermesSerializeBoardForecast(const HermesBoardForecastData* pData, HermesSerializationCallback callback) { - return new HermesStringHandle(Hermes::Serialize(Hermes::ToCpp(*pData))); + callback.m_pCall(callback.m_pData, Hermes::ToC(Hermes::Serialize(Hermes::ToCpp(*pData)))); } -HermesStringHandle* HermesXmlFromSetConfigurationData(const HermesSetConfigurationData* pData) +void HermesSerializeQueryBoardInfo(const HermesQueryBoardInfoData* pData, HermesSerializationCallback callback) { - return new HermesStringHandle(Hermes::Serialize(Hermes::ToCpp(*pData))); + callback.m_pCall(callback.m_pData, Hermes::ToC(Hermes::Serialize(Hermes::ToCpp(*pData)))); } -HermesStringHandle* HermesXmlFromCurrentConfigurationData(const HermesCurrentConfigurationData* pData) -{ - return new HermesStringHandle(Hermes::Serialize(Hermes::ToCpp(*pData))); -} - -void FreeHermesString(HermesStringHandle* pHandle) +void HermesSerializeSendBoardInfo(const HermesSendBoardInfoData* pData, HermesSerializationCallback callback) { - delete pHandle; -} - -namespace Hermes -{ - namespace - { - template - struct DataHolder - { - DataHolder(const T& cppData) : m_cppData(cppData) {} -#ifdef _WINDOWS - DataHolder(const DataHolder&) = delete; - DataHolder& operator=(const DataHolder&) = delete; -#else - DataHolder(const DataHolder&); - DataHolder& operator=(const DataHolder&); -#endif - DataHolder(DataHolder&& rhs) : m_cppData(std::move(rhs.m_cppData)), m_convertedData(ToC(m_cppData)) {} - DataHolder& operator=(DataHolder&& rhs) - { - m_cppData = std::move(rhs.m_cppData); - m_convertedData = ToC(m_cppData); - return *this; - } - - T m_cppData; - using ConvertedData = decltype(ToC(m_cppData)); - ConvertedData m_convertedData = ToC(m_cppData); - }; - - template<> - struct DataHolder - { - DataHolder() = default; - DataHolder(boost::blank) {} - }; - - template - struct VariantDataHolder : boost::static_visitor<> - { - using Variant = boost::variant...>; - Variant m_variant; - - //template - //VariantDataHolder(T&& m_value) : m_variant(std::forward(m_value)) {} - - template - void operator()(T&& value) - { - m_variant = Variant(std::forward(value)); - } - }; - - using MyVariantDataHolder = VariantDataHolder; - - } + callback.m_pCall(callback.m_pData, Hermes::ToC(Hermes::Serialize(Hermes::ToCpp(*pData)))); } - -struct HermesDataHandle -{ - HermesDataHandle(Hermes::StringView message) - { - auto variant = Hermes::Deserialize(message); - boost::apply_visitor(m_holder, variant); - } - - Hermes::MyVariantDataHolder m_holder; -}; - -HermesDataHandle* HermesDataFromXml(HermesStringView message) +void HermesSerializeNotification(const HermesNotificationData* pData, HermesSerializationCallback callback) { - return new HermesDataHandle(Hermes::ToCpp(message)); + callback.m_pCall(callback.m_pData, Hermes::ToC(Hermes::Serialize(Hermes::ToCpp(*pData)))); } - -const HermesError* HermesErrorFromHandle(HermesDataHandle* pHandle) +void HermesSerializeCheckAlive(const HermesCheckAliveData* pData, HermesSerializationCallback callback) { - if (auto p = boost::get>(&pHandle->m_holder.m_variant)) - return &p->m_convertedData; - return nullptr; + callback.m_pCall(callback.m_pData, Hermes::ToC(Hermes::Serialize(Hermes::ToCpp(*pData)))); } -const HermesServiceDescription* HermesServiceDescriptionFromHandle(HermesDataHandle* pHandle) +void HermesSerializeGetConfiguration(const HermesGetConfigurationData* pData, HermesSerializationCallback callback) { - if (auto p = boost::get>(&pHandle->m_holder.m_variant)) - return &p->m_convertedData; - return nullptr; + callback.m_pCall(callback.m_pData, Hermes::ToC(Hermes::Serialize(Hermes::ToCpp(*pData)))); } -const HermesBoardAvailableData* HermesBoardAvailableDataFromHandle(HermesDataHandle* pHandle) +void HermesSerializeSetConfiguration(const HermesSetConfigurationData* pData, HermesSerializationCallback callback) { - if (auto p = boost::get>(&pHandle->m_holder.m_variant)) - return &p->m_convertedData; - return nullptr; + callback.m_pCall(callback.m_pData, Hermes::ToC(Hermes::Serialize(Hermes::ToCpp(*pData)))); } -const HermesRevokeBoardAvailableData* HermesRevokeBoardAvailableDataFromHandle(HermesDataHandle* pHandle) +void HermesSerializeCurrentConfiguration(const HermesCurrentConfigurationData* pData, HermesSerializationCallback callback) { - if (auto p = boost::get>(&pHandle->m_holder.m_variant)) - return &p->m_convertedData; - return nullptr; + callback.m_pCall(callback.m_pData, Hermes::ToC(Hermes::Serialize(Hermes::ToCpp(*pData)))); } -const HermesMachineReadyData* HermesMachineReadyDataFromHandle(HermesDataHandle* pHandle) +void HermesSerializeSupervisoryServiceDescription(const HermesSupervisoryServiceDescriptionData* pData, HermesSerializationCallback callback) { - if (auto p = boost::get>(&pHandle->m_holder.m_variant)) - return &p->m_convertedData; - return nullptr; + callback.m_pCall(callback.m_pData, Hermes::ToC(Hermes::Serialize(Hermes::ToCpp(*pData)))); } -const HermesRevokeMachineReadyData* HermesRevokeMachineReadyDataFromHandle(HermesDataHandle* pHandle) +void HermesSerializeBoardArrived(const HermesBoardArrivedData* pData, HermesSerializationCallback callback) { - if (auto p = boost::get>(&pHandle->m_holder.m_variant)) - return &p->m_convertedData; - return nullptr; + callback.m_pCall(callback.m_pData, Hermes::ToC(Hermes::Serialize(Hermes::ToCpp(*pData)))); } -const HermesStartTransportData* HermesStartTransportDataFromHandle(HermesDataHandle* pHandle) +void HermesSerializeBoardDeparted(const HermesBoardDepartedData* pData, HermesSerializationCallback callback) { - if (auto p = boost::get>(&pHandle->m_holder.m_variant)) - return &p->m_convertedData; - return nullptr; + callback.m_pCall(callback.m_pData, Hermes::ToC(Hermes::Serialize(Hermes::ToCpp(*pData)))); } -const HermesStopTransportData* HermesStopTransportDataFromHandle(HermesDataHandle* pHandle) +void HermesSerializeQueryWorkOrderInfo(const HermesQueryWorkOrderInfoData* pData, HermesSerializationCallback callback) { - if (auto p = boost::get>(&pHandle->m_holder.m_variant)) - return &p->m_convertedData; - return nullptr; + callback.m_pCall(callback.m_pData, Hermes::ToC(Hermes::Serialize(Hermes::ToCpp(*pData)))); } -const HermesTransportFinishedData* HermesTransportFinishedDataFromHandle(HermesDataHandle* pHandle) +void HermesSerializeSendWorkOrderInfo(const HermesSendWorkOrderInfoData* pData, HermesSerializationCallback callback) { - if (auto p = boost::get>(&pHandle->m_holder.m_variant)) - return &p->m_convertedData; - return nullptr; + callback.m_pCall(callback.m_pData, Hermes::ToC(Hermes::Serialize(Hermes::ToCpp(*pData)))); } -const HermesNotificationData* HermesNotificationDataFromHandle(HermesDataHandle* pHandle) +void HermesSerializeReplyWorkOrderInfo(const HermesReplyWorkOrderInfoData* pData, HermesSerializationCallback callback) { - if (auto p = boost::get>(&pHandle->m_holder.m_variant)) - return &p->m_convertedData; - return nullptr; + callback.m_pCall(callback.m_pData, Hermes::ToC(Hermes::Serialize(Hermes::ToCpp(*pData)))); } -const HermesCheckAliveData* HermesCheckAliveDataFromHandle(HermesDataHandle* pHandle) +void HermesSerializeCommand(const HermesCommandData* pData, HermesSerializationCallback callback) { - if (auto p = boost::get>(&pHandle->m_holder.m_variant)) - return &p->m_convertedData; - return nullptr; + callback.m_pCall(callback.m_pData, Hermes::ToC(Hermes::Serialize(Hermes::ToCpp(*pData)))); } -const HermesGetConfigurationData* HermesGetConfigurationDataFromHandle(HermesDataHandle* pHandle) +void HermesSerializeQueryHermesCapabilities(const HermesQueryHermesCapabilitiesData* pData, HermesSerializationCallback callback) { - if (auto p = boost::get>(&pHandle->m_holder.m_variant)) - return &p->m_convertedData; - return nullptr; + callback.m_pCall(callback.m_pData, Hermes::ToC(Hermes::Serialize(Hermes::ToCpp(*pData)))); } -const HermesSetConfigurationData* HermesSetConfigurationDataFromHandle(HermesDataHandle* pHandle) +void HermesSerializeSendHermesCapabilities(const HermesSendHermesCapabilitiesData* pData, HermesSerializationCallback callback) { - if (auto p = boost::get>(&pHandle->m_holder.m_variant)) - return &p->m_convertedData; - return nullptr; + callback.m_pCall(callback.m_pData, Hermes::ToC(Hermes::Serialize(Hermes::ToCpp(*pData)))); } -const HermesCurrentConfigurationData* HermesCurrentConfigurationDataFromHandle(HermesDataHandle* pHandle) +namespace { - if (auto p = boost::get>(&pHandle->m_holder.m_variant)) - return &p->m_convertedData; - return nullptr; + template + void Add_(Hermes::MessageDispatcher& dispatcher, CallbackT callback) + { + if (!callback.m_pCall) + return; + + dispatcher.Add([callback](const auto& data) + { + Hermes::Converter2C converter(data); + callback.m_pCall(callback.m_pData, converter.CPointer()); + }); + } } -void FreeHermesData(HermesDataHandle* pHandle) -{ - delete pHandle; +void HermesDeserialize(HermesStringView stringView, const HermesDeserializationCallbacks* pCallbacks) +{ + HermesTraceCallback traceCallback{}; + Hermes::Service service{traceCallback}; + Hermes::MessageDispatcher dispatcher{0U, service}; + + Add_(dispatcher, pCallbacks->m_serviceDescriptionCallback); + Add_(dispatcher, pCallbacks->m_boardAvailableCallback); + Add_(dispatcher, pCallbacks->m_revokeBoardAvailableCallback); + Add_(dispatcher, pCallbacks->m_machineReadyCallback); + Add_(dispatcher, pCallbacks->m_revokeMachineReadyCallback); + Add_(dispatcher, pCallbacks->m_startTransportCallback); + Add_(dispatcher, pCallbacks->m_stopTransportCallback); + Add_(dispatcher, pCallbacks->m_transportFinishedCallback); + Add_(dispatcher, pCallbacks->m_boardForecastCallback); + Add_(dispatcher, pCallbacks->m_queryBoardInfoCallback); + Add_(dispatcher, pCallbacks->m_sendBoardInfoCallback); + Add_(dispatcher, pCallbacks->m_checkAliveCallback); + Add_(dispatcher, pCallbacks->m_notificationCallback); + Add_(dispatcher, pCallbacks->m_getConfigurationCallback); + Add_(dispatcher, pCallbacks->m_setConfigurationCallback); + Add_(dispatcher, pCallbacks->m_currentConfigurationCallback); + Add_(dispatcher, pCallbacks->m_supervisoryServiceDescriptionCallback); + Add_(dispatcher, pCallbacks->m_boardArrivedCallback); + Add_(dispatcher, pCallbacks->m_boardDepartedCallback); + Add_(dispatcher, pCallbacks->m_queryWorkOrderInfoCallback); + Add_(dispatcher, pCallbacks->m_sendWorkOrderInfoCallback); + Add_(dispatcher, pCallbacks->m_replyWorkOrderInfoCallback); + Add_(dispatcher, pCallbacks->m_commandCallback); + Add_(dispatcher, pCallbacks->m_queryHermesCapabilitiesCallback); + Add_(dispatcher, pCallbacks->m_sendHermesCapabilitiesCallback); + + std::string xmlParseString{Hermes::ToCpp(stringView)}; + auto error = dispatcher.Dispatch(xmlParseString); + if (!error) + return; + + if (!pCallbacks->m_deserializationErrorCallback.m_pCall) + return; + + const Hermes::Converter2C converter(error); + pCallbacks->m_deserializationErrorCallback.m_pCall(pCallbacks->m_deserializationErrorCallback.m_pData, + converter.CPointer()); } + diff --git a/src/Hermes/Serializer.cpp b/src/Hermes/Serializer.cpp deleted file mode 100644 index 2aca2b4..0000000 --- a/src/Hermes/Serializer.cpp +++ /dev/null @@ -1,537 +0,0 @@ -/*********************************************************************** -Copyright 2018 ASM Assembly Systems GmbH & Co. KG - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -************************************************************************/ - -#include "stdafx.h" - -#include "Serializer.h" - -#include -#include -#include - -namespace Hermes -{ - namespace - { - const StringView sServiceDescriptionTag{"ServiceDescription"}; - const StringView sBoardAvailableDataTag{"BoardAvailable"}; - const StringView sRevokeBoardAvailableTag{"RevokeBoardAvailable"}; - const StringView sMachineReadyTag{"MachineReady"}; - const StringView sRevokeMachineReadyTag{"RevokeMachineReady"}; - const StringView sStartTransportTag{"StartTransport"}; - const StringView sTransportFinishedTag{"TransportFinished"}; - const StringView sStopTransportTag{"StopTransport"}; - const StringView sNotificationTag{"Notification"}; - const StringView sCheckAliveTag{"CheckAlive"}; - const StringView sGetConfigurationTag{"GetConfiguration"}; - const StringView sSetConfigurationTag{"SetConfiguration"}; - const StringView sCurrentConfigurationTag{"CurrentConfiguration"}; - - const StringView Tag_(const ServiceDescription&) { return sServiceDescriptionTag; } - const StringView Tag_(const BoardAvailableData&) { return sBoardAvailableDataTag; } - const StringView Tag_(const RevokeBoardAvailableData&) { return sRevokeBoardAvailableTag; } - const StringView Tag_(const MachineReadyData&) { return sMachineReadyTag; } - const StringView Tag_(const RevokeMachineReadyData&) { return sRevokeMachineReadyTag; } - const StringView Tag_(const StartTransportData&) { return sStartTransportTag; } - const StringView Tag_(const TransportFinishedData&) { return sTransportFinishedTag; } - const StringView Tag_(const StopTransportData&) { return sStopTransportTag; } - const StringView Tag_(const NotificationData&) { return sNotificationTag; } - const StringView Tag_(const CheckAliveData&) { return sCheckAliveTag; } - const StringView Tag_(const GetConfigurationData&) { return sGetConfigurationTag; } - const StringView Tag_(const SetConfigurationData&) { return sSetConfigurationTag; } - const StringView Tag_(const CurrentConfigurationData&) { return sCurrentConfigurationTag; } - - const std::string cHERMES = "Hermes"; - const std::size_t cHERMES_SIZE = 6U; - const std::string cHERMES_END_TAG = "(now); - auto fraction = now - seconds; - time_t cnow = std::chrono::system_clock::to_time_t(now); - tm local_tm; -#ifdef _WINDOWS - localtime_s(&local_tm, &cnow); -#else - localtime_r(&cnow, &local_tm); -#endif - std::stringstream ss; - ss << std::put_time(&local_tm, "%Y-%m-%dT%H:%M:%S."); - auto milliseconds = std::chrono::duration_cast(fraction); - ss << milliseconds.count(); - return ss.str(); - } - - std::string Envelope_(const pugi::xml_node &element) - { - pugi::xml_document domDocument; - auto root = domDocument.append_child(cHERMES.c_str()); - root.append_attribute("Timestamp").set_value(_GetTimeStamp().c_str()); - root.append_copy(element); - std::stringstream ss; - domDocument.save(ss, PUGIXML_TEXT(" "), pugi::format_indent | pugi::format_no_declaration, pugi::encoding_utf8); - return ss.str(); - } - } - - bool TakeMessage(std::string &out_message, std::string &inout_buffer) - { - // find "' - std::size_t endIndex = inout_buffer.find('>', endTagIndex + cHERMES_END_TAG.size()); - if (endIndex == std::string::npos) - return false; - - out_message = inout_buffer.substr(0U, endIndex + 1U); - inout_buffer = inout_buffer.substr(endIndex + 1U); - return true; - } - - // helpers for both CurrentConfigurationMessage and SetConfigurationMessage - void FromXml(std::vector& configs, const pugi::xml_node in_node) - { - configs.clear(); - for (auto const& node : in_node.child("DownstreamConfigurations").children("DownstreamConfiguration")) - { - configs.emplace_back(); - auto& config = configs.back(); - config.m_downstreamLaneId = node.attribute("DownstreamLaneId").as_uint(); - if (const auto& attribute = node.attribute("ClientAddress")) - { - config.m_optionalClientAddress = attribute.as_string(); - } - config.m_port = static_cast(node.attribute("Port").as_uint()); - } - } - - void FromXml(std::vector& configs, const pugi::xml_node in_node) - { - configs.clear(); - for (auto const& node : in_node.child("UpstreamConfigurations").children("UpstreamConfiguration")) - { - configs.emplace_back(); - auto& config = configs.back(); - config.m_upstreamLaneId = node.attribute("UpstreamLaneId").as_uint(); - config.m_hostAddress = node.attribute("HostAddress").as_string(); - config.m_port = static_cast(node.attribute("Port").as_uint()); - } - } - - void ToXml(const std::vector& configs, pugi::xml_node root) - { - pugi::xml_node parentNode = root.append_child("UpstreamConfigurations"); - for (auto const& config : configs) - { - pugi::xml_node node = parentNode.append_child("UpstreamConfiguration"); - node.append_attribute("UpstreamLaneId").set_value(config.m_upstreamLaneId); - node.append_attribute("HostAddress").set_value(config.m_hostAddress.c_str()); - node.append_attribute("Port").set_value(config.m_port); - } - } - - void ToXml(const std::vector& configs, pugi::xml_node root) - { - pugi::xml_node parentNode = root.append_child("DownstreamConfigurations"); - for (auto const& config : configs) - { - pugi::xml_node node = parentNode.append_child("DownstreamConfiguration"); - node.append_attribute("DownstreamLaneId").set_value(config.m_downstreamLaneId); - if (!config.m_optionalClientAddress.empty()) - { - node.append_attribute("ClientAddress").set_value(config.m_optionalClientAddress.c_str()); - } - node.append_attribute("Port").set_value(config.m_port); - - } - } - -} - -std::string Hermes::Serialize(const ServiceDescription& data) -{ - pugi::xml_document doc; - pugi::xml_node rootElement = doc.append_child(Tag_(data).data()); - rootElement.append_attribute("LaneId").set_value(data.m_laneId); - rootElement.append_attribute("MachineId").set_value(data.m_machineId.c_str()); - rootElement.append_attribute("Version").set_value(data.m_version.c_str()); - return Envelope_(rootElement); -} - -std::string Hermes::Serialize(const BoardAvailableData& data) -{ - pugi::xml_document doc; - pugi::xml_node rootElement = doc.append_child(Tag_(data).data()); - //required attributes - rootElement.append_attribute("BoardId").set_value(data.m_boardId.c_str()); - rootElement.append_attribute("BoardIdCreatedBy").set_value(data.m_boardIdCreatedBy.c_str()); - rootElement.append_attribute("FailedBoard").set_value(static_cast(data.m_failedBoard)); - if (const auto& attr = data.m_optionalProductTypeId) - { - rootElement.append_attribute("ProductTypeId").set_value(attr->c_str()); - } - rootElement.append_attribute("FlippedBoard").set_value(static_cast(data.m_flippedBoard)); - if (const auto& attr = data.m_optionalTopBarcode) - { - rootElement.append_attribute("TopBarcode").set_value(attr->c_str()); - } - if (const auto& attr = data.m_optionalBottomBarcode) - { - rootElement.append_attribute("BottomBarcode").set_value(attr->c_str()); - } - if (const auto& attr = data.m_optionalLengthInMM) - rootElement.append_attribute("Length").set_value(*attr); - if (const auto& attr = data.m_optionalWidthInMM) - rootElement.append_attribute("Width").set_value(*attr); - if (const auto& attr = data.m_optionalThicknessInMM) - rootElement.append_attribute("Thickness").set_value(*attr); - if (const auto& attr = data.m_optionalConveyorSpeedInMMPerSecs) - rootElement.append_attribute("ConveyorSpeed").set_value(*attr); - if (const auto& attr = data.m_optionalTopClearanceHeightInMM) - rootElement.append_attribute("TopClearanceHeight").set_value(*attr); - if (const auto& attr = data.m_optionalBottomClearanceHeightInMM) - rootElement.append_attribute("BottomClearanceHeight").set_value(*attr); - return Envelope_(rootElement); -} - -std::string Hermes::Serialize(const RevokeBoardAvailableData& data) -{ - pugi::xml_document doc; - pugi::xml_node rootElement = doc.append_child(Tag_(data).data()); - return Envelope_(rootElement); -} - -std::string Hermes::Serialize(const MachineReadyData& data) -{ - pugi::xml_document doc; - pugi::xml_node rootElement = doc.append_child(Tag_(data).data()); - rootElement.append_attribute("FailedBoard").set_value(static_cast(data.m_failedBoard)); - return Envelope_(rootElement); -} - -std::string Hermes::Serialize(const RevokeMachineReadyData& data) -{ - pugi::xml_document doc; - pugi::xml_node rootElement = doc.append_child(Tag_(data).data()); - return Envelope_(rootElement); -} - -std::string Hermes::Serialize(const StartTransportData& data) -{ - pugi::xml_document doc; - pugi::xml_node rootElement = doc.append_child(Tag_(data).data()); - rootElement.append_attribute("BoardId").set_value(data.m_boardId.c_str()); - if (auto attr = data.m_optionalConveyorSpeedInMMPerSecs) - rootElement.append_attribute("ConveyorSpeed").set_value(*attr); - return Envelope_(rootElement); -} - -std::string Hermes::Serialize(const TransportFinishedData& data) -{ - pugi::xml_document doc; - pugi::xml_node rootElement = doc.append_child(Tag_(data).data()); - rootElement.append_attribute("TransferState").set_value(static_cast(data.m_transferState)); - rootElement.append_attribute("BoardId").set_value(data.m_boardId.c_str()); - return Envelope_(rootElement); -} - -std::string Hermes::Serialize(const StopTransportData& data) -{ - pugi::xml_document doc; - pugi::xml_node rootElement = doc.append_child(Tag_(data).data()); - rootElement.append_attribute("TransferState").set_value(static_cast(data.m_transferState)); - rootElement.append_attribute("BoardId").set_value(data.m_boardId.c_str()); - - return Envelope_(rootElement); -} - -std::string Hermes::Serialize(const NotificationData& data) -{ - pugi::xml_document doc; - pugi::xml_node rootElement = doc.append_child(Tag_(data).data()); - rootElement.append_attribute("NotificationCode").set_value(static_cast(data.m_notificationCode)); - rootElement.append_attribute("Severity").set_value(static_cast(data.m_severity)); - rootElement.append_attribute("Description").set_value(data.m_description.c_str()); - return Envelope_(rootElement); -} - -std::string Hermes::Serialize(const CheckAliveData& data) -{ - pugi::xml_document doc; - pugi::xml_node rootElement = doc.append_child(Tag_(data).data()); - return Envelope_(rootElement); -} - -std::string Hermes::Serialize(const GetConfigurationData& data) -{ - pugi::xml_document doc; - pugi::xml_node rootElement = doc.append_child(Tag_(data).data()); - return Envelope_(rootElement); -} - -std::string Hermes::Serialize(const SetConfigurationData& data) -{ - pugi::xml_document doc; - pugi::xml_node rootElement = doc.append_child(Tag_(data).data()); - rootElement.append_attribute("MachineId").set_value(data.m_machineId.c_str()); - ToXml(data.m_upstreamConfigurations, rootElement); - ToXml(data.m_downstreamConfigurations, rootElement); - return Envelope_(rootElement); -} - -std::string Hermes::Serialize(const CurrentConfigurationData& data) -{ - pugi::xml_document doc; - pugi::xml_node rootElement = doc.append_child(Tag_(data).data()); - if (data.m_optionalMachineId) - { - rootElement.append_attribute("MachineId").set_value(data.m_optionalMachineId->c_str()); - } - ToXml(data.m_upstreamConfigurations, rootElement); - ToXml(data.m_downstreamConfigurations, rootElement); - return Envelope_(rootElement); -} - -namespace Hermes -{ - namespace - { - ServiceDescription ServiceDescriptionFromXml(pugi::xml_node xmlNode) - { - ServiceDescription data; - data.m_laneId = xmlNode.attribute("LaneId").as_uint(); - data.m_machineId = xmlNode.attribute("MachineId").as_string(); - data.m_version = xmlNode.attribute("Version").as_string(); - return data; - } - - BoardAvailableData BoardAvailableDataFromXml(pugi::xml_node xmlNode) - { - BoardAvailableData data; - //required attributes - data.m_boardId = xmlNode.attribute("BoardId").as_string(); - data.m_boardIdCreatedBy = xmlNode.attribute("BoardIdCreatedBy").as_string(); - data.m_failedBoard = static_cast(xmlNode.attribute("FailedBoard").as_int()); - - if (auto attr = xmlNode.attribute("ProductTypeId")) - { - data.m_optionalProductTypeId = attr.as_string(); - } - - data.m_flippedBoard = static_cast(xmlNode.attribute("FlippedBoard").as_int()); - if (auto attr = xmlNode.attribute("TopBarcode")) - { - data.m_optionalTopBarcode = attr.as_string(); - } - if (auto attr = xmlNode.attribute("BottomBarcode")) - { - data.m_optionalBottomBarcode = attr.as_string(); - } - if (auto attr = xmlNode.attribute("Length")) - { - data.m_optionalLengthInMM = attr.as_double(); - } - if (auto attr = xmlNode.attribute("Width")) - { - data.m_optionalWidthInMM = attr.as_double(); - } - if (auto attr = xmlNode.attribute("Thickness")) - { - data.m_optionalThicknessInMM = attr.as_double(); - } - if (auto attr = xmlNode.attribute("ConveyorSpeed")) - { - data.m_optionalConveyorSpeedInMMPerSecs = attr.as_double(); - } - if (auto attr = xmlNode.attribute("TopClearanceHeight")) - { - data.m_optionalTopClearanceHeightInMM = attr.as_double(); - } - if (auto attr = xmlNode.attribute("BottomClearanceHeight")) - { - data.m_optionalBottomClearanceHeightInMM = attr.as_double(); - } - return data; - } - - RevokeBoardAvailableData RevokeBoardAvailableDataFromXml(pugi::xml_node) - { - RevokeBoardAvailableData data; - return data; - } - - MachineReadyData MachineReadyDataFromXml(pugi::xml_node xmlNode) - { - MachineReadyData data; - data.m_failedBoard = static_cast(xmlNode.attribute("FailedBoard").as_int()); - return data; - } - - RevokeMachineReadyData RevokeMachineReadyDataFromXml(pugi::xml_node) - { - RevokeMachineReadyData data; - return data; - } - - StartTransportData StartTransportDataFromXml(pugi::xml_node xmlNode) - { - StartTransportData data; - data.m_boardId = xmlNode.attribute("BoardId").as_string(); - - if (auto attr = xmlNode.attribute("ConveyorSpeed")) - { - data.m_optionalConveyorSpeedInMMPerSecs = attr.as_double(); - } - return data; - } - - StopTransportData StopTransportDataFromXml(pugi::xml_node xmlNode) - { - StopTransportData data; - data.m_transferState = static_cast(xmlNode.attribute("TransferState").as_int()); - data.m_boardId = xmlNode.attribute("BoardId").as_string(); - return data; - } - - TransportFinishedData TransportFinishedDataFromXml(pugi::xml_node xmlNode) - { - TransportFinishedData data; - data.m_transferState = static_cast(xmlNode.attribute("TransferState").as_int()); - data.m_boardId = xmlNode.attribute("BoardId").as_string(); - return data; - } - - NotificationData NotificationDataFromXml(pugi::xml_node xmlNode) - { - NotificationData data; - data.m_notificationCode = static_cast(xmlNode.attribute("NotificationCode").as_int()); - data.m_severity = static_cast(xmlNode.attribute("Severity").as_int()); - data.m_description = xmlNode.attribute("Description").as_string(); - return data; - } - - CheckAliveData CheckAliveDataFromXml(pugi::xml_node) - { - CheckAliveData data; - return data; - } - - SetConfigurationData SetConfigurationDataFromXml(pugi::xml_node xmlNode) - { - SetConfigurationData data; - data.m_machineId = xmlNode.attribute("MachineId").as_string(); - FromXml(data.m_downstreamConfigurations, xmlNode); - FromXml(data.m_upstreamConfigurations, xmlNode); - return data; - } - - GetConfigurationData GetConfigurationDataFromXml(pugi::xml_node) - { - GetConfigurationData data; - return data; - } - - CurrentConfigurationData CurrentConfigurationDataFromXml(pugi::xml_node xmlNode) - { - CurrentConfigurationData data; - if (auto&& attr = xmlNode.attribute("MachineId")) - { - data.m_optionalMachineId = attr.as_string(); - } - FromXml(data.m_downstreamConfigurations, xmlNode); - FromXml(data.m_upstreamConfigurations, xmlNode); - - return data; - } - } -} - -Hermes::VariantData Hermes::Deserialize(StringView message) -{ - pugi::xml_document doc; - auto parseResult = doc.load_buffer(message.data(), message.size(), pugi::parse_default, pugi::encoding_utf8); - if (!parseResult) - { - return Error{EErrorCode::eCLIENT_ERROR, - std::string(parseResult.description()) + " at offset " + std::to_string(parseResult.offset)}; - } - pugi::xml_node envelopeNode = doc.first_child(); - pugi::xml_node rootNode = envelopeNode.first_child(); - if (!rootNode) - { - return Error{EErrorCode::eCLIENT_ERROR, std::string("Missing message type node")}; - } - - const std::string& rootName = rootNode.name(); - if (rootName == Tag_(Hermes::ServiceDescription())) - return Hermes::ServiceDescriptionFromXml(rootNode); - else if (rootName == Tag_(Hermes::BoardAvailableData())) - return Hermes::BoardAvailableDataFromXml(rootNode); - else if (rootName == Tag_(Hermes::RevokeBoardAvailableData())) - return Hermes::RevokeBoardAvailableDataFromXml(rootNode); - else if (rootName == Tag_(Hermes::MachineReadyData())) - return Hermes::MachineReadyDataFromXml(rootNode); - else if (rootName == Tag_(Hermes::RevokeMachineReadyData())) - return Hermes::RevokeMachineReadyDataFromXml(rootNode); - else if (rootName == Tag_(Hermes::StartTransportData())) - return Hermes::StartTransportDataFromXml(rootNode); - else if (rootName == Tag_(Hermes::StopTransportData())) - return Hermes::StopTransportDataFromXml(rootNode); - else if (rootName == Tag_(Hermes::TransportFinishedData())) - return Hermes::TransportFinishedDataFromXml(rootNode); - else if (rootName == Tag_(Hermes::NotificationData())) - return Hermes::NotificationDataFromXml(rootNode); - else if (rootName == Tag_(Hermes::CheckAliveData())) - return Hermes::CheckAliveDataFromXml(rootNode); - else if (rootName == Tag_(Hermes::SetConfigurationData())) - return Hermes::SetConfigurationDataFromXml(rootNode); - else if (rootName == Tag_(Hermes::GetConfigurationData())) - return Hermes::GetConfigurationDataFromXml(rootNode); - else if (rootName == Tag_(Hermes::CurrentConfigurationData())) - return Hermes::CurrentConfigurationDataFromXml(rootNode); - else - return boost::blank(); -} - - diff --git a/src/Hermes/Serializer.h b/src/Hermes/Serializer.h deleted file mode 100644 index b1a0a6e..0000000 --- a/src/Hermes/Serializer.h +++ /dev/null @@ -1,75 +0,0 @@ -/*********************************************************************** -Copyright 2018 ASM Assembly Systems GmbH & Co. KG - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -************************************************************************/ - -#pragma once - -#include - -#ifdef _WINDOWS - #include "pugixml/pugixml.hpp" -#else - #include "pugixml.hpp" -#endif - -#include - -#include - -#ifdef _WINDOWS -# pragma warning( push ) -# pragma warning( disable : 4251 ) -#endif - -namespace Hermes -{ - std::string Serialize(const ServiceDescription&); - std::string Serialize(const BoardAvailableData&); - std::string Serialize(const RevokeBoardAvailableData&); - std::string Serialize(const MachineReadyData&); - std::string Serialize(const RevokeMachineReadyData&); - std::string Serialize(const StartTransportData&); - std::string Serialize(const TransportFinishedData&); - std::string Serialize(const StopTransportData&); - std::string Serialize(const NotificationData&); - std::string Serialize(const CheckAliveData&); - std::string Serialize(const GetConfigurationData&); - std::string Serialize(const SetConfigurationData&); - std::string Serialize(const CurrentConfigurationData&); - - bool TakeMessage(std::string& out_message, std::string& inout_buffer); - - using VariantData = boost::variant; - - VariantData Deserialize(StringView message); - -} - -#ifdef _WINDOWS -# pragma warning( pop ) -#endif diff --git a/src/Hermes/StringSpan.h b/src/Hermes/StringSpan.h new file mode 100644 index 0000000..1628aab --- /dev/null +++ b/src/Hermes/StringSpan.h @@ -0,0 +1,50 @@ +// Copyright (c) ASM Assembly Systems GmbH & Co. KG +#pragma once + +#include +// while we have not got std::string_view at our disposal, we make our own: + +namespace Hermes +{ + class StringSpan + { + public: + constexpr StringSpan() = default; + constexpr StringSpan(char* pData, std::size_t size) : m_pData(pData), m_size(size) {} + StringSpan(std::string& rhs) : m_pData(const_cast(rhs.data())), m_size(rhs.size()) {} + + operator StringView() const { return{m_pData, m_size}; } + + constexpr char* data() const { return m_pData; } + constexpr std::size_t size() const { return m_size; } + constexpr std::size_t length() const { return m_size; } + constexpr bool empty() const { return m_size == 0U; } + constexpr StringSpan substr(std::size_t pos, std::size_t count = std::string::npos) const { return{m_pData + pos, std::min(count, m_size - pos)}; } + + std::size_t find(char c, std::size_t pos = 0U) const { return StringView(*this).find(c, pos); } + std::size_t find(StringView v) const { return StringView(*this).find(v); } + + int compare(StringView rhs) { return StringView(*this).compare(rhs); } + int compare(std::size_t pos, std::size_t count, StringView rhs) { return StringView(*this).compare(pos, count, rhs); } + + friend std::ostream& operator<<(std::ostream& os, StringSpan sv) + { + os.write(sv.m_pData, sv.m_size); + return os; + } + + private: + char* m_pData = nullptr; + std::size_t m_size = 0U; + }; + + inline bool operator==(StringSpan lhs, StringSpan rhs) + { + return lhs.compare(rhs) == 0; + } + + inline bool operator!=(StringSpan lhs, StringSpan rhs) + { + return !operator==(lhs, rhs); + } +} diff --git a/src/Hermes/Upstream.cpp b/src/Hermes/Upstream.cpp index 84be64c..3601255 100644 --- a/src/Hermes/Upstream.cpp +++ b/src/Hermes/Upstream.cpp @@ -18,6 +18,7 @@ limitations under the License. #include #include "ApiCallback.h" +#include "MessageDispatcher.h" #include "Service.h" #include "UpstreamSession.h" @@ -32,7 +33,7 @@ struct HermesUpstream : ISessionCallback unsigned m_laneId = 0U; Service m_service; asio::deadline_timer m_timer{m_service.GetUnderlyingService()}; - UpstreamSettings m_configuration; + UpstreamSettings m_settings; unsigned m_sessionId{0U}; unsigned m_connectedSessionId{0U}; @@ -42,7 +43,10 @@ struct HermesUpstream : ISessionCallback ApiCallback m_boardAvailableCallback; ApiCallback m_revokeBoardAvailableCallback; ApiCallback m_transportFinishedCallback; + ApiCallback m_boardForecastCallback; + ApiCallback m_sendBoardInfoCallback; ApiCallback m_notificationCallback; + ApiCallback m_commandCallback; ApiCallback m_checkAliveCallback; ApiCallback m_stateCallback; ApiCallback m_disconnectedCallback; @@ -59,7 +63,10 @@ struct HermesUpstream : ISessionCallback m_boardAvailableCallback(callbacks.m_boardAvailableCallback), m_revokeBoardAvailableCallback(callbacks.m_revokeBoardAvailableCallback), m_transportFinishedCallback(callbacks.m_transportFinishedCallback), + m_boardForecastCallback(callbacks.m_boardForecastCallback), + m_sendBoardInfoCallback(callbacks.m_sendBoardInfoCallback), m_notificationCallback(callbacks.m_notificationCallback), + m_commandCallback(callbacks.m_commandCallback), m_checkAliveCallback(callbacks.m_checkAliveCallback), m_stateCallback(callbacks.m_stateCallback), m_disconnectedCallback(callbacks.m_disconnectedCallback) @@ -72,18 +79,18 @@ struct HermesUpstream : ISessionCallback m_service.Inform(0U, "Deleted"); } - void Enable(const UpstreamSettings& configuration) + void Enable(const UpstreamSettings& settings) { - m_service.Log(0U, "Enable(", configuration, "); m_enabled=", m_enabled, ", m_configuration=", m_configuration); + m_service.Log(0U, "Enable(", settings, "); m_enabled=", m_enabled, ", m_settings=", m_settings); - if (m_enabled && configuration == m_configuration) + if (m_enabled && settings == m_settings) return; m_enabled = true; RemoveSession_(NotificationData(ENotificationCode::eCONNECTION_RESET_BECAUSE_OF_CHANGED_CONFIGURATION, ESeverity::eINFO, "ConfigurationChanged")); - m_configuration = configuration; + m_settings = settings; CreateNewSession_(); } @@ -99,23 +106,15 @@ struct HermesUpstream : ISessionCallback } template - void Signal(unsigned sessionId, const DataT& data) + void Signal(unsigned sessionId, const DataT& data, StringView rawXml) { - m_service.Log(sessionId, "Signal(", data, ')'); + m_service.Log(sessionId, "Signal(", data, ',', rawXml, ')'); - auto pSession = Session_(sessionId); + auto* pSession = Session_(sessionId); if (!pSession) return; - pSession->Signal(data); - } - - void Reset(const NotificationData& notificationData) - { - m_service.Log(0U, "Reset(", notificationData, ')'); - - RemoveSession_(notificationData); - CreateNewSession_(); + pSession->Signal(data, rawXml); } void Stop() @@ -128,104 +127,142 @@ struct HermesUpstream : ISessionCallback } //================= ISessionCallback ========================= - void OnSocketConnected(unsigned sessionId, EState state, const ConnectionInfo& connectionInfo) override + void OnSocketConnected(unsigned sessionId, EState state, const ConnectionInfo& in_data) override { - auto* pSession = Session_(sessionId); + const auto* pSession = Session_(sessionId); if (!pSession) return; m_connectedSessionId = pSession->Id(); - auto apiConnectionInfo = ToC(connectionInfo); - m_connectedCallback(pSession->Id(), ToC(state), &apiConnectionInfo); + const Converter2C converter(in_data); + m_connectedCallback(pSession->Id(), ToC(state), converter.CPointer()); } - void On(unsigned sessionId, EState state, const ServiceDescription& serviceDescription) override + void On(unsigned sessionId, EState state, const ServiceDescriptionData& in_data) override { - auto* pSession = Session_(sessionId); + const auto* pSession = Session_(sessionId); if (!pSession) return; - auto apiServiceDescription = ToC(serviceDescription); - m_serviceDescriptionCallback(pSession->Id(), ToC(state), &apiServiceDescription); + const Converter2C converter(in_data); + m_serviceDescriptionCallback(pSession->Id(), ToC(state), converter.CPointer()); } void On(unsigned sessionId, EState state, const BoardAvailableData& in_data) override { - auto* pSession = Session_(sessionId); + const auto* pSession = Session_(sessionId); if (!pSession) return; - auto apiData = ToC(in_data); - m_boardAvailableCallback(sessionId, ToC(state), &apiData); + const Converter2C converter(in_data); + m_boardAvailableCallback(sessionId, ToC(state), converter.CPointer()); } - void On(unsigned sessionId, EState state, const RevokeBoardAvailableData& data) override + void On(unsigned sessionId, EState state, const RevokeBoardAvailableData& in_data) override { - auto* pSession = Session_(sessionId); + const auto* pSession = Session_(sessionId); if (!pSession) return; - auto apiData = ToC(data); - m_revokeBoardAvailableCallback(sessionId, ToC(state), &apiData); + const Converter2C converter(in_data); + m_revokeBoardAvailableCallback(sessionId, ToC(state), converter.CPointer()); } - void On(unsigned sessionId, EState state, const TransportFinishedData& data) override + void On(unsigned sessionId, EState state, const TransportFinishedData& in_data) override { - auto* pSession = Session_(sessionId); + const auto* pSession = Session_(sessionId); if (!pSession) return; - auto apiData = ToC(data); - m_transportFinishedCallback(sessionId, ToC(state), &apiData); + const Converter2C converter(in_data); + m_transportFinishedCallback(sessionId, ToC(state), converter.CPointer()); } - void On(unsigned sessionId, EState, const NotificationData& data) override + void On(unsigned sessionId, EState state, const BoardForecastData& in_data) override { - auto* pSession = Session_(sessionId); + const auto* pSession = Session_(sessionId); if (!pSession) return; - auto apiData = ToC(data); - m_notificationCallback(sessionId, &apiData); + const Converter2C converter(in_data); + m_boardForecastCallback(sessionId, ToC(state), converter.CPointer()); } - void On(unsigned sessionId, EState, const CheckAliveData& data) override + void On(unsigned sessionId, EState, const SendBoardInfoData& in_data) override { - auto* pSession = Session_(sessionId); + const auto* pSession = Session_(sessionId); if (!pSession) return; - auto apiData = ToC(data); - m_checkAliveCallback(sessionId, &apiData); + const Converter2C converter(in_data); + m_sendBoardInfoCallback(sessionId, converter.CPointer()); + } + + void On(unsigned sessionId, EState, const NotificationData& in_data) override + { + const auto* pSession = Session_(sessionId); + if (!pSession) + return; + + const Converter2C converter(in_data); + m_notificationCallback(sessionId, converter.CPointer()); + } + + void On(unsigned sessionId, EState, const CommandData& in_data) override + { + const auto* pSession = Session_(sessionId); + if (!pSession) + return; + + const Converter2C converter(in_data); + m_commandCallback(sessionId, converter.CPointer()); + } + + void On(unsigned sessionId, EState, const CheckAliveData& in_data) override + { + const auto* pSession = Session_(sessionId); + if (!pSession) + return; + + if (in_data.m_optionalType + && *in_data.m_optionalType == ECheckAliveType::ePING + && m_settings.m_checkAliveResponseMode == ECheckAliveResponseMode::eAUTO) + { + CheckAliveData data{in_data}; + data.m_optionalType = ECheckAliveType::ePONG; + m_service.Post([this, sessionId, data = std::move(data)]() { Signal(sessionId, data, Serialize(data)); }); + } + const Converter2C converter(in_data); + m_checkAliveCallback(sessionId, converter.CPointer()); } void OnState(unsigned sessionId, EState state) override { - auto* pSession = Session_(sessionId); + const auto* pSession = Session_(sessionId); if (!pSession) return; m_stateCallback(sessionId, ToC(state)); } - void OnDisconnected(unsigned sessionId, EState state, const Error& error) override + void OnDisconnected(unsigned sessionId, EState state, const Error& in_data) override { - auto* pSession = Session_(sessionId); + const auto* pSession = Session_(sessionId); if (!pSession) return; - if (pSession->OptionalPeerServiceDescription()) + if (pSession->OptionalPeerServiceDescriptionData()) { - m_service.Post([this]() { CreateNewSession_(); }); + DelayCreateNewSession_(1.0); } else { - DelayCreateNewSession_(); + DelayCreateNewSession_(m_settings.m_reconnectWaitTimeInSeconds); } m_upSession.reset(); - auto apiError = ToC(error); - m_disconnectedCallback(sessionId, ToC(state), &apiError); + const Converter2C converter(in_data); + m_disconnectedCallback(sessionId, ToC(state), converter.CPointer()); } //============ internal impplementation ============== @@ -238,15 +275,15 @@ struct HermesUpstream : ISessionCallback return nullptr; } - void RemoveSession_(const NotificationData& notification) + void RemoveSession_() { if (!m_upSession) return; auto sessionId = m_upSession->Id(); - m_service.Log(sessionId, "Disconnect_(", notification, ')'); + m_service.Log(sessionId, "RemoveSession_()"); - m_upSession->Disconnect(notification); + m_upSession->Disconnect(); m_upSession.reset(); if (sessionId != m_connectedSessionId) @@ -254,9 +291,17 @@ struct HermesUpstream : ISessionCallback m_connectedSessionId = 0U; Error error; - auto apiError = ToC(error); - m_disconnectedCallback(sessionId, eHERMES_DISCONNECTED, &apiError); + const Converter2C converter(error); + m_disconnectedCallback(sessionId, eHERMES_STATE_DISCONNECTED, converter.CPointer()); + } + void RemoveSession_(const NotificationData& data) + { + if (!m_upSession) + return; + + m_upSession->Signal(data, Serialize(data)); + RemoveSession_(); } void CreateNewSession_() @@ -272,15 +317,15 @@ struct HermesUpstream : ISessionCallback if (!++m_sessionId) { ++m_sessionId; } // avoid zero sessionId - m_upSession = std::make_unique(m_sessionId, m_service, m_configuration); + m_upSession = std::make_unique(m_sessionId, m_service, m_settings); m_upSession->Connect(*this); } - void DelayCreateNewSession_() + void DelayCreateNewSession_(double delay) { m_service.Log(0U, "DelayCreateNewSession_"); - m_timer.expires_from_now(boost::posix_time::seconds(m_configuration.m_reconnectWaitTimeInSeconds)); + m_timer.expires_from_now(boost::posix_time::millisec(static_cast(1000.0 * delay))); m_timer.async_wait([this](const boost::system::error_code& ec) { if (ec) // timer cancelled or whatever @@ -329,12 +374,12 @@ void EnableHermesUpstream(HermesUpstream* pUpstream, const HermesUpstreamSetting }); } -void SignalHermesUpstreamServiceDescription(HermesUpstream* pUpstream, uint32_t sessionId, const HermesServiceDescription* pData) +void SignalHermesUpstreamServiceDescription(HermesUpstream* pUpstream, uint32_t sessionId, const HermesServiceDescriptionData* pData) { pUpstream->m_service.Log(sessionId, "SignalHermesUpstreamServiceDescription"); pUpstream->m_service.Post([pUpstream, sessionId, data = ToCpp(*pData)]() { - pUpstream->Signal(sessionId, data); + pUpstream->Signal(sessionId, data, Serialize(data)); }); } @@ -343,7 +388,7 @@ void SignalHermesMachineReady(HermesUpstream* pUpstream, uint32_t sessionId, con pUpstream->m_service.Log(sessionId, "SignalHermesMachineReady"); pUpstream->m_service.Post([pUpstream, sessionId, data = ToCpp(*pData)]() { - pUpstream->Signal(sessionId, data); + pUpstream->Signal(sessionId, data, Serialize(data)); }); } @@ -352,7 +397,7 @@ void SignalHermesRevokeMachineReady(HermesUpstream* pUpstream, uint32_t sessionI pUpstream->m_service.Log(sessionId, "SignalHermesRevokeMachineReady"); pUpstream->m_service.Post([pUpstream, sessionId, data = ToCpp(*pData)]() { - pUpstream->Signal(sessionId, data); + pUpstream->Signal(sessionId, data, Serialize(data)); }); } @@ -362,7 +407,17 @@ void SignalHermesStartTransport(HermesUpstream* pUpstream, uint32_t sessionId, c pUpstream->m_service.Post([pUpstream, sessionId, data = ToCpp(*pData)]() { - pUpstream->Signal(sessionId, data); + pUpstream->Signal(sessionId, data, Serialize(data)); + }); +} + +void SignalHermesQueryBoardInfo(HermesUpstream* pUpstream, uint32_t sessionId, const HermesQueryBoardInfoData* pData) +{ + pUpstream->m_service.Log(sessionId, "SignalHermesQueryBoardInfo"); + + pUpstream->m_service.Post([pUpstream, sessionId, data = ToCpp(*pData)]() + { + pUpstream->Signal(sessionId, data, Serialize(data)); }); } @@ -372,7 +427,7 @@ void SignalHermesStopTransport(HermesUpstream* pUpstream, uint32_t sessionId, co pUpstream->m_service.Post([pUpstream, sessionId, data = ToCpp(*pData)]() { - pUpstream->Signal(sessionId, data); + pUpstream->Signal(sessionId, data, Serialize(data)); }); } @@ -382,7 +437,17 @@ void SignalHermesUpstreamNotification(HermesUpstream* pUpstream, uint32_t sessio pUpstream->m_service.Post([pUpstream, sessionId, data = ToCpp(*pData)]() { - pUpstream->Signal(sessionId, data); + pUpstream->Signal(sessionId, data, Serialize(data)); + }); +} + +void SignalHermesUpstreamCommand(HermesUpstream* pUpstream, uint32_t sessionId, const HermesCommandData* pData) +{ + pUpstream->m_service.Log(0U, "SignalHermesUpstreamCommand"); + + pUpstream->m_service.Post([pUpstream, sessionId, data = ToCpp(*pData)]() + { + pUpstream->Signal(sessionId, data, Serialize(data)); }); } @@ -392,7 +457,7 @@ void SignalHermesUpstreamCheckAlive(HermesUpstream* pUpstream, uint32_t sessionI pUpstream->m_service.Post([pUpstream, sessionId, data = ToCpp(*pData)]() { - pUpstream->Signal(sessionId, data); + pUpstream->Signal(sessionId, data, Serialize(data)); }); } @@ -402,14 +467,54 @@ void ResetHermesUpstream(HermesUpstream* pUpstream, const HermesNotificationData pUpstream->m_service.Post([pUpstream, data = ToCpp(*pData)]() { - pUpstream->Reset(data); + pUpstream->RemoveSession_(data); + pUpstream->DelayCreateNewSession_(1.0); + }); +} + +void SignalHermesUpstreamRawXml(HermesUpstream* pUpstream, uint32_t sessionId, HermesStringView rawXml) +{ + pUpstream->m_service.Log(sessionId, "SignalHermesUpstreamRawXml"); + pUpstream->m_service.Post([pUpstream, sessionId, xmlData = std::string(rawXml.m_pData, rawXml.m_size)]() mutable + { + MessageDispatcher dispatcher{sessionId, pUpstream->m_service}; + auto parseData = xmlData; + + bool wasDispatched = false; + dispatcher.Add([&](const auto& data) { wasDispatched = true; pUpstream->Signal(sessionId, data, xmlData); }); + dispatcher.Add([&](const auto& data) { wasDispatched = true; pUpstream->Signal(sessionId, data, xmlData); }); + dispatcher.Add([&](const auto& data) { wasDispatched = true; pUpstream->Signal(sessionId, data, xmlData); }); + dispatcher.Add([&](const auto& data) { wasDispatched = true; pUpstream->Signal(sessionId, data, xmlData); }); + dispatcher.Add([&](const auto& data) { wasDispatched = true; pUpstream->Signal(sessionId, data, xmlData); }); + dispatcher.Add([&](const auto& data) { wasDispatched = true; pUpstream->Signal(sessionId, data, xmlData); }); + dispatcher.Add([&](const auto& data) { wasDispatched = true; pUpstream->Signal(sessionId, data, xmlData); }); + dispatcher.Add([&](const auto& data) { wasDispatched = true; pUpstream->Signal(sessionId, data, xmlData); }); + + dispatcher.Dispatch(parseData); + if (wasDispatched) + return; + + pUpstream->Signal(sessionId, NotificationData{}, xmlData); + }); +} + +void ResetHermesUpstreamRawXml(HermesUpstream* pUpstream, HermesStringView rawXml) +{ + pUpstream->m_service.Log(0U, "ResetHermesUpstreamRawXml"); + pUpstream->m_service.Post([pUpstream, data = std::string(rawXml.m_pData, rawXml.m_size)]() + { + if (!data.empty() && pUpstream->m_upSession) + { + pUpstream->m_upSession->Signal(NotificationData(), data); + } + pUpstream->RemoveSession_(); + pUpstream->DelayCreateNewSession_(1.0); }); } void DisableHermesUpstream(HermesUpstream* pUpstream, const HermesNotificationData* pData) { pUpstream->m_service.Log(0U, "DisableHermesUpstream"); - pUpstream->m_service.Post([pUpstream, data = ToCpp(*pData)]() { pUpstream->Disable(data); diff --git a/src/Hermes/UpstreamConnection.h b/src/Hermes/UpstreamConnection.h index c984d8c..3c82364 100644 --- a/src/Hermes/UpstreamConnection.h +++ b/src/Hermes/UpstreamConnection.h @@ -25,7 +25,7 @@ namespace Hermes public: UpstreamConnection(IAsioServiceSp, const UpstreamSettings&, const UpstreamConfiguration&); - SignalResult Connect(const ServiceDescription&); + SignalResult Connect(const ServiceDescriptionData&); SignalResult Signal(const MachineReadyData&); SignalResult Signal(const RevokeMachineReadyData&); SignalResult Signal(const StartTransportData&); @@ -37,7 +37,7 @@ namespace Hermes struct IUpstreamConnectionCallback { - virtual void OnConnected(UpstreamConnection&, EHermesState, const ServiceDescription&) = 0; + virtual void OnConnected(UpstreamConnection&, EHermesState, const ServiceDescriptionData&) = 0; virtual void OnBoardAvailable(UpstreamConnection&, EHermesState, const BoardAvailableData&) = 0; virtual void OnRevokeBoardAvailable(UpstreamConnection&, EHermesState, const RevokeBoardAvailableData&) = 0; virtual void OnTransportFinished(UpstreamConnection&, EHermesState, const TransportFinishedData&) = 0; diff --git a/src/Hermes/UpstreamSerializer.cpp b/src/Hermes/UpstreamSerializer.cpp index 17d3257..0aa8f8a 100644 --- a/src/Hermes/UpstreamSerializer.cpp +++ b/src/Hermes/UpstreamSerializer.cpp @@ -18,12 +18,12 @@ limitations under the License. #include "UpstreamSerializer.h" #include "Network.h" -#include #include "IService.h" -#include "Serializer.h" +#include "MessageDispatcher.h" namespace Hermes { + namespace Upstream { struct Serializer : Upstream::ISerializer, ISocketCallback @@ -32,13 +32,23 @@ namespace Hermes IAsioService& m_service; IClientSocket& m_socket; ISerializerCallback* m_pCallback = nullptr; - std::string m_receiveBuffer; + MessageDispatcher m_dispatcher{m_sessionId, m_service}; Serializer(unsigned sessionId, IAsioService& service, IClientSocket& socket) : m_sessionId(sessionId), m_service(service), m_socket(socket) - {} + { + m_dispatcher.Add([this](const auto& data) { m_pCallback->On(data); }); + m_dispatcher.Add([this](const auto& data) { m_pCallback->On(data); }); + m_dispatcher.Add([this](const auto& data) { m_pCallback->On(data); }); + m_dispatcher.Add([this](const auto& data) { m_pCallback->On(data); }); + m_dispatcher.Add([this](const auto& data) { m_pCallback->On(data); }); + m_dispatcher.Add([this](const auto& data) { m_pCallback->On(data); }); + m_dispatcher.Add([this](const auto& data) { m_pCallback->On(data); }); + m_dispatcher.Add([this](const auto& data) { m_pCallback->On(data); }); + m_dispatcher.Add([this](const auto& data) { m_pCallback->On(data); }); + } // ISocketCallback void OnConnected(const ConnectionInfo& connectionInfo) override @@ -46,73 +56,14 @@ namespace Hermes m_pCallback->OnSocketConnected(connectionInfo); } - void OnReceived(StringView dataView) override + void OnReceived(StringSpan xmlData) override { - m_receiveBuffer.append(dataView.data(), dataView.size()); - m_service.Log(m_sessionId, "m_receiveBuffer[", dataView.size(), "]=", m_receiveBuffer); - - std::string messageXml; - while (TakeMessage(messageXml, m_receiveBuffer)) - { - m_service.Log(m_sessionId, "messageXml[", messageXml.size(), "]=", messageXml, - "\nm_receiveBuffer[", m_receiveBuffer.size(), "]=", m_receiveBuffer); - - const auto& variant = Deserialize(messageXml); - - if (const auto* pData = boost::get(&variant)) - { - auto error = m_service.Alarm(m_sessionId, EErrorCode::ePEER_ERROR, pData->m_text); - Signal(NotificationData(ENotificationCode::ePROTOCOL_ERROR, ESeverity::eFATAL, error.m_text)); - m_socket.Close(); - m_pCallback->OnDisconnected(error); - return; - } - - if (const auto* pData = boost::get(&variant)) - { - m_service.Log(m_sessionId, "CheckAliveData=", *pData); - m_pCallback->On(*pData); - continue; - } - if (const auto* pData = boost::get(&variant)) - { - m_service.Log(m_sessionId, "ServiceDescription=", *pData); - m_pCallback->On(*pData); - continue; - } - if (const auto* pData = boost::get(&variant)) - { - m_service.Log(m_sessionId, "NotificationData=", *pData); - m_pCallback->On(*pData); - continue; - } - if (const auto* pData = boost::get(&variant)) - { - m_service.Log(m_sessionId, "BoardAvailableData=", *pData); - m_pCallback->On(*pData); - continue; - } - if (const auto* pData = boost::get(&variant)) - { - m_service.Log(m_sessionId, "RevokeBoardAvailableData=", *pData); - m_pCallback->On(*pData); - continue; - } - if (const auto* pData = boost::get(&variant)) - { - m_service.Log(m_sessionId, "TransportFinishedData=", *pData); - m_pCallback->On(*pData); - continue; - } - - m_service.Warn(m_sessionId, "Unexpected message"); - } - - if (m_receiveBuffer.size() <= cMAX_MESSAGE_SIZE) + auto error = m_dispatcher.Dispatch(xmlData); + if (!error) return; - auto error = m_service.Alarm(m_sessionId, EErrorCode::ePEER_ERROR, "Maximum message size exceeded"); - Signal(NotificationData(ENotificationCode::ePROTOCOL_ERROR, ESeverity::eFATAL, error.m_text)); + error = m_service.Alarm(m_sessionId, EErrorCode::ePEER_ERROR, error.m_text); + Signal(Serialize(NotificationData(ENotificationCode::ePROTOCOL_ERROR, ESeverity::eFATAL, error.m_text))); m_socket.Close(); m_pCallback->OnDisconnected(error); } @@ -130,57 +81,16 @@ namespace Hermes m_socket.Connect(std::move(wpOwner), *this); } - void Signal(const ServiceDescription& data) override - { - const auto& xmlString = Serialize(data); - Send_(xmlString); - } - - void Signal(const MachineReadyData& data) override - { - const auto& xmlString = Serialize(data); - Send_(xmlString); - } - - void Signal(const RevokeMachineReadyData& data) override - { - const auto& xmlString = Serialize(data); - Send_(xmlString); - } - - void Signal(const StartTransportData& data) override - { - const auto& xmlString = Serialize(data); - Send_(xmlString); - } - - void Signal(const StopTransportData& data) override + void Signal(StringView rawXml) { - const auto& xmlString = Serialize(data); - Send_(xmlString); + m_socket.Send(rawXml); } - void Signal(const NotificationData& data) override - { - const auto& xmlString = Serialize(data); - Send_(xmlString); - } - - void Signal(const CheckAliveData& data) override - { - const auto& xmlString = Serialize(data); - Send_(xmlString); - } - void Disconnect() override { m_socket.Close(); } - void Send_(StringView message) - { - m_socket.Send(message); - } }; } diff --git a/src/Hermes/UpstreamSerializer.h b/src/Hermes/UpstreamSerializer.h index 55eac7b..b73e24c 100644 --- a/src/Hermes/UpstreamSerializer.h +++ b/src/Hermes/UpstreamSerializer.h @@ -31,13 +31,7 @@ namespace Hermes struct ISerializer { virtual void Connect(std::weak_ptr wpOwner, ISerializerCallback&) = 0; - virtual void Signal(const ServiceDescription&) = 0; - virtual void Signal(const MachineReadyData&) = 0; - virtual void Signal(const RevokeMachineReadyData&) = 0; - virtual void Signal(const StartTransportData&) = 0; - virtual void Signal(const StopTransportData&) = 0; - virtual void Signal(const NotificationData&) = 0; - virtual void Signal(const CheckAliveData&) = 0; + virtual void Signal(StringView rawXml) = 0; virtual void Disconnect() = 0; virtual ~ISerializer() = default; @@ -46,11 +40,14 @@ namespace Hermes struct ISerializerCallback { virtual void OnSocketConnected(const ConnectionInfo&) = 0; - virtual void On(const ServiceDescription&) = 0; + virtual void On(const ServiceDescriptionData&) = 0; virtual void On(const BoardAvailableData&) = 0; virtual void On(const RevokeBoardAvailableData&) = 0; virtual void On(const TransportFinishedData&) = 0; + virtual void On(const BoardForecastData&) = 0; + virtual void On(const SendBoardInfoData&) = 0; virtual void On(const NotificationData&) = 0; + virtual void On(const CommandData&) = 0; virtual void On(const CheckAliveData&) = 0; virtual void OnDisconnected(const Error&) = 0; diff --git a/src/Hermes/UpstreamSession.cpp b/src/Hermes/UpstreamSession.cpp index e0a5a8b..106624e 100644 --- a/src/Hermes/UpstreamSession.cpp +++ b/src/Hermes/UpstreamSession.cpp @@ -40,7 +40,7 @@ namespace Hermes std::unique_ptr m_upSocket; std::unique_ptr m_upSerializer; std::unique_ptr m_upStateMachine; - Optional m_optionalPeerServiceDescription; + Optional m_optionalPeerServiceDescriptionData; ConnectionInfo m_peerConnectionInfo; ISessionCallback* m_pCallback{nullptr}; @@ -68,9 +68,9 @@ namespace Hermes m_pCallback->OnSocketConnected(m_id, state, connectionInfo); } - template void Signal_(const DataT& data) + template void Signal_(const DataT& data, StringView rawXml) { - m_upStateMachine->Signal(data); + m_upStateMachine->Signal(data, rawXml); } template void On_(EState state, const DataT& data) @@ -81,16 +81,19 @@ namespace Hermes m_pCallback->On(m_id, state, data); } - void On(EState state, const ServiceDescription& data) + void On(EState state, const ServiceDescriptionData& data) { - m_optionalPeerServiceDescription = data; + m_optionalPeerServiceDescriptionData = data; On_(state, data); } void On(EState state, const BoardAvailableData& data) override { On_(state, data); } void On(EState state, const RevokeBoardAvailableData& data) override { On_(state, data); } void On(EState state, const TransportFinishedData& data) override { On_(state, data); } + void On(EState state, const BoardForecastData& data) override { On_(state, data); } + void On(EState state, const SendBoardInfoData& data) override { On_(state, data); } void On(EState state, const NotificationData& data) override { On_(state, data); } + void On(EState state, const CommandData& data) override { On_(state, data); } void On(EState state, const CheckAliveData& data) override { On_(state, data); } void OnState(EState state) override @@ -135,7 +138,7 @@ namespace Hermes } unsigned Session::Id() const { return m_spImpl->m_id; } - const Optional& Session::OptionalPeerServiceDescription() const { return m_spImpl->m_optionalPeerServiceDescription; } + const Optional& Session::OptionalPeerServiceDescriptionData() const { return m_spImpl->m_optionalPeerServiceDescriptionData; } const ConnectionInfo& Session::PeerConnectionInfo() const { return m_spImpl->m_peerConnectionInfo; } void Session::Connect(ISessionCallback& callback) @@ -144,18 +147,20 @@ namespace Hermes m_spImpl->m_upStateMachine->Connect(m_spImpl, *m_spImpl); } - void Session::Signal(const ServiceDescription& data) { m_spImpl->Signal_(data); } - void Session::Signal(const MachineReadyData& data) { m_spImpl->Signal_(data); } - void Session::Signal(const RevokeMachineReadyData& data) { m_spImpl->Signal_(data); } - void Session::Signal(const StartTransportData& data) { m_spImpl->Signal_(data); } - void Session::Signal(const StopTransportData& data) { m_spImpl->Signal_(data); } - void Session::Signal(const NotificationData& data) { m_spImpl->Signal_(data); } - void Session::Signal(const CheckAliveData& data) { m_spImpl->Signal_(data); } - - void Session::Disconnect(const NotificationData& data) + void Session::Signal(const ServiceDescriptionData& data, StringView rawXml) { m_spImpl->Signal_(data, rawXml); } + void Session::Signal(const MachineReadyData& data, StringView rawXml) { m_spImpl->Signal_(data, rawXml); } + void Session::Signal(const RevokeMachineReadyData& data, StringView rawXml) { m_spImpl->Signal_(data, rawXml); } + void Session::Signal(const StartTransportData& data, StringView rawXml) { m_spImpl->Signal_(data, rawXml); } + void Session::Signal(const StopTransportData& data, StringView rawXml) { m_spImpl->Signal_(data, rawXml); } + void Session::Signal(const QueryBoardInfoData& data, StringView rawXml) { m_spImpl->Signal_(data, rawXml); } + void Session::Signal(const NotificationData& data, StringView rawXml) { m_spImpl->Signal_(data, rawXml); } + void Session::Signal(const CommandData& data, StringView rawXml) { m_spImpl->Signal_(data, rawXml); } + void Session::Signal(const CheckAliveData& data, StringView rawXml) { m_spImpl->Signal_(data, rawXml); } + + void Session::Disconnect() { m_spImpl->m_pCallback = nullptr; - m_spImpl->m_upStateMachine->Disconnect(data); + m_spImpl->m_upStateMachine->Disconnect(); } } -} +} \ No newline at end of file diff --git a/src/Hermes/UpstreamSession.h b/src/Hermes/UpstreamSession.h index bb624dd..ff408b4 100644 --- a/src/Hermes/UpstreamSession.h +++ b/src/Hermes/UpstreamSession.h @@ -39,18 +39,20 @@ namespace Hermes explicit operator bool() const { return bool(m_spImpl); } unsigned Id() const; - const Optional& OptionalPeerServiceDescription() const; + const Optional& OptionalPeerServiceDescriptionData() const; const ConnectionInfo& PeerConnectionInfo() const; void Connect(ISessionCallback&); - void Signal(const ServiceDescription&); - void Signal(const MachineReadyData&); - void Signal(const RevokeMachineReadyData&); - void Signal(const StartTransportData&); - void Signal(const StopTransportData&); - void Signal(const NotificationData&); - void Signal(const CheckAliveData&); - void Disconnect(const NotificationData&); + void Signal(const ServiceDescriptionData&, StringView rawXml); + void Signal(const MachineReadyData&, StringView rawXml); + void Signal(const RevokeMachineReadyData&, StringView rawXml); + void Signal(const StartTransportData&, StringView rawXml); + void Signal(const StopTransportData&, StringView rawXml); + void Signal(const QueryBoardInfoData&, StringView rawXml); + void Signal(const NotificationData&, StringView rawXml); + void Signal(const CommandData&, StringView rawXml); + void Signal(const CheckAliveData&, StringView rawXml); + void Disconnect(); private: struct Impl; @@ -61,11 +63,14 @@ namespace Hermes struct ISessionCallback { virtual void OnSocketConnected(unsigned id, EState, const ConnectionInfo&) = 0; - virtual void On(unsigned id, EState, const ServiceDescription&) = 0; + virtual void On(unsigned id, EState, const ServiceDescriptionData&) = 0; virtual void On(unsigned id, EState, const BoardAvailableData&) = 0; virtual void On(unsigned id, EState, const RevokeBoardAvailableData&) = 0; virtual void On(unsigned id, EState, const TransportFinishedData&) = 0; + virtual void On(unsigned id, EState, const BoardForecastData&) = 0; + virtual void On(unsigned id, EState, const SendBoardInfoData&) = 0; virtual void On(unsigned id, EState, const NotificationData&) = 0; + virtual void On(unsigned id, EState, const CommandData&) = 0; virtual void On(unsigned id, EState, const CheckAliveData&) = 0; virtual void OnState(unsigned id, EState) = 0; virtual void OnDisconnected(unsigned id, EState, const Error&) = 0; diff --git a/src/Hermes/UpstreamStateMachine.cpp b/src/Hermes/UpstreamStateMachine.cpp index 7276765..334acf8 100644 --- a/src/Hermes/UpstreamStateMachine.cpp +++ b/src/Hermes/UpstreamStateMachine.cpp @@ -16,6 +16,7 @@ limitations under the License. #include "stdafx.h" #include "UpstreamStateMachine.h" +#include "MessageSerialization.h" #include "UpstreamSerializer.h" #include "IService.h" @@ -61,7 +62,7 @@ namespace Hermes if (m_state != EState::eNOT_CONNECTED) { - m_forward.Signal(NotificationData(ENotificationCode::eUNSPECIFIC, ESeverity::eFATAL, "SoftwareError")); + m_forward.Signal(Serialize(NotificationData(ENotificationCode::eUNSPECIFIC, ESeverity::eFATAL, "SoftwareError"))); } m_state = EState::eDISCONNECTED; @@ -80,7 +81,7 @@ namespace Hermes m_state = EState::eDISCONNECTED; m_pCallback->OnDisconnected(m_state, error); - m_forward.Signal(NotificationData(ENotificationCode::ePROTOCOL_ERROR, ESeverity::eFATAL, error.m_text)); + m_forward.Signal(Serialize(NotificationData(ENotificationCode::ePROTOCOL_ERROR, ESeverity::eFATAL, error.m_text))); m_forward.Disconnect(); } @@ -93,118 +94,119 @@ namespace Hermes m_forward.Connect(std::move(wpOwner), *this); } - void Signal(const ServiceDescription& data) override + void Signal(const ServiceDescriptionData&, StringView rawXml) override { switch (m_state) { case EState::eSOCKET_CONNECTED: m_state = EState::eSERVICE_DESCRIPTION_DOWNSTREAM; m_pCallback->OnState(m_state); - m_forward.Signal(data); + m_forward.Signal(rawXml); return; default: if (DisconnectedDueToIllegalClientEvent_("ServiceDescription")) return; - m_forward.Signal(data); + m_forward.Signal(rawXml); } } - void Signal(const MachineReadyData& data) override + void Signal(const MachineReadyData&, StringView rawXml) override { switch (m_state) { case EState::eNOT_AVAILABLE_NOT_READY: m_state = EState::eMACHINE_READY; m_pCallback->OnState(m_state); - m_forward.Signal(data); + m_forward.Signal(rawXml); return; case EState::eBOARD_AVAILABLE: m_state = EState::eAVAILABLE_AND_READY; m_pCallback->OnState(m_state); - m_forward.Signal(data); + m_forward.Signal(rawXml); return; default: if (DisconnectedDueToIllegalClientEvent_("MachineReady")) return; - m_forward.Signal(data); + m_forward.Signal(rawXml); } } - void Signal(const RevokeMachineReadyData& data) override + void Signal(const RevokeMachineReadyData&, StringView rawXml) override { switch (m_state) { case EState::eMACHINE_READY: m_state = EState::eNOT_AVAILABLE_NOT_READY; m_pCallback->OnState(m_state); - m_forward.Signal(data); + m_forward.Signal(rawXml); return; case EState::eAVAILABLE_AND_READY: m_state = EState::eBOARD_AVAILABLE; m_pCallback->OnState(m_state); - m_forward.Signal(data); + m_forward.Signal(rawXml); return; default: if (DisconnectedDueToIllegalClientEvent_("RevokeMachineReady")) return; - m_forward.Signal(data); + m_forward.Signal(rawXml); } } - void Signal(const StartTransportData& data) override + void Signal(const StartTransportData& data, StringView rawXml) override { switch (m_state) { case EState::eAVAILABLE_AND_READY: m_state = EState::eTRANSPORTING; - m_startTransportBoardId = data.m_boardId; + m_startTransportBoardId = rawXml.empty() ? data.m_boardId : std::string(); m_pCallback->OnState(m_state); - m_forward.Signal(data); + m_forward.Signal(rawXml); return; case EState::eMACHINE_READY: m_state = EState::eTRANSPORTING; - m_startTransportBoardId = data.m_boardId; + m_startTransportBoardId = rawXml.empty() ? data.m_boardId : std::string(); m_pCallback->OnState(m_state); - m_forward.Signal(data); + m_forward.Signal(rawXml); return; default: if (DisconnectedDueToIllegalClientEvent_("StartTransport")) return; - m_forward.Signal(data); + m_startTransportBoardId.clear(); + m_forward.Signal(rawXml); } } - void Signal(const StopTransportData& data) override + void Signal(const StopTransportData&, StringView rawXml) override { switch (m_state) { case EState::eTRANSPORTING: m_state = EState::eTRANSPORT_STOPPED; m_pCallback->OnState(m_state); - m_forward.Signal(data); + m_forward.Signal(rawXml); return; case EState::eTRANSPORT_FINISHED: m_state = EState::eNOT_AVAILABLE_NOT_READY; m_pCallback->OnState(m_state); - m_forward.Signal(data); + m_forward.Signal(rawXml); return; default: if (DisconnectedDueToIllegalClientEvent_("StopTransport")) return; - m_forward.Signal(data); + m_forward.Signal(rawXml); } } - void Signal(const NotificationData& data) override + void Signal(const QueryBoardInfoData&, StringView rawXml) override { switch (m_state) { @@ -213,12 +215,12 @@ namespace Hermes return; default: - m_forward.Signal(data); + m_forward.Signal(rawXml); return; } } - void Signal(const CheckAliveData& data) override + void Signal(const NotificationData&, StringView rawXml) override { switch (m_state) { @@ -227,28 +229,49 @@ namespace Hermes return; default: - m_forward.Signal(data); + m_forward.Signal(rawXml); return; } } - void Disconnect(const NotificationData& data) override + void Signal(const CommandData&, StringView rawXml) override { switch (m_state) { + case EState::eNOT_CONNECTED: case EState::eDISCONNECTED: return; + default: + m_forward.Signal(rawXml); + return; + } + } + + void Signal(const CheckAliveData&, StringView rawXml) override + { + switch (m_state) + { case EState::eNOT_CONNECTED: - m_state = EState::eDISCONNECTED; - m_pCallback->OnState(m_state); - m_forward.Disconnect(); + case EState::eDISCONNECTED: + return; + + default: + m_forward.Signal(rawXml); + return; + } + } + + void Disconnect() override + { + switch (m_state) + { + case EState::eDISCONNECTED: return; default: m_state = EState::eDISCONNECTED; m_pCallback->OnState(m_state); - m_forward.Signal(data); m_forward.Disconnect(); } @@ -269,7 +292,7 @@ namespace Hermes } } - void On(const ServiceDescription& data) override + void On(const ServiceDescriptionData& data) override { switch (m_state) { @@ -347,7 +370,7 @@ namespace Hermes { case EState::eTRANSPORT_STOPPED: { - if (data.m_boardId != m_startTransportBoardId) + if (data.m_boardId != m_startTransportBoardId && !m_startTransportBoardId.empty()) return StartAndStopBoardIdDoNotMatch_(m_startTransportBoardId, data.m_boardId); m_state = EState::eNOT_AVAILABLE_NOT_READY; m_pCallback->On(m_state, data); @@ -355,7 +378,7 @@ namespace Hermes } case EState::eTRANSPORTING: { - if (data.m_boardId != m_startTransportBoardId) + if (data.m_boardId != m_startTransportBoardId && !m_startTransportBoardId.empty()) return StartAndStopBoardIdDoNotMatch_(m_startTransportBoardId, data.m_boardId); m_state = EState::eTRANSPORT_FINISHED; m_pCallback->On(m_state, data); @@ -366,6 +389,42 @@ namespace Hermes } } + void On(const BoardForecastData& data) override + { + switch (m_state) + { + case EState::eNOT_AVAILABLE_NOT_READY: + { + m_pCallback->On(m_state, data); + return; + } + case EState::eMACHINE_READY: + { + m_pCallback->On(m_state, data); + return; + } + case EState::eTRANSPORTING: + case EState::eTRANSPORT_STOPPED: + return; + + default: + return OnUnexpectedPeerEvent_("BoardForeast"); + } + } + + void On(const SendBoardInfoData& data) override + { + switch (m_state) + { + case EState::eNOT_CONNECTED: + case EState::eDISCONNECTED: + return; + + default: + m_pCallback->On(m_state, data); + } + } + void On(const NotificationData& data) override { switch (m_state) @@ -376,7 +435,19 @@ namespace Hermes default: m_pCallback->On(m_state, data); + } + } + + void On(const CommandData& data) override + { + switch (m_state) + { + case EState::eNOT_CONNECTED: + case EState::eDISCONNECTED: return; + + default: + m_pCallback->On(m_state, data); } } @@ -390,7 +461,6 @@ namespace Hermes default: m_pCallback->On(m_state, data); - return; } } diff --git a/src/Hermes/UpstreamStateMachine.h b/src/Hermes/UpstreamStateMachine.h index 29e4062..e1307e3 100644 --- a/src/Hermes/UpstreamStateMachine.h +++ b/src/Hermes/UpstreamStateMachine.h @@ -31,14 +31,16 @@ namespace Hermes struct IStateMachine { virtual void Connect(std::weak_ptr wpOwner, IStateMachineCallback&) = 0; - virtual void Signal(const ServiceDescription&) = 0; - virtual void Signal(const MachineReadyData&) = 0; - virtual void Signal(const RevokeMachineReadyData&) = 0; - virtual void Signal(const StartTransportData&) = 0; - virtual void Signal(const StopTransportData&) = 0; - virtual void Signal(const NotificationData&) = 0; - virtual void Signal(const CheckAliveData&) = 0; - virtual void Disconnect(const NotificationData&) = 0; + virtual void Signal(const ServiceDescriptionData&, StringView rawXml) = 0; + virtual void Signal(const MachineReadyData&, StringView rawXml) = 0; + virtual void Signal(const RevokeMachineReadyData&, StringView rawXml) = 0; + virtual void Signal(const StartTransportData&, StringView rawXml) = 0; + virtual void Signal(const StopTransportData&, StringView rawXml) = 0; + virtual void Signal(const QueryBoardInfoData&, StringView rawXml) = 0; + virtual void Signal(const NotificationData&, StringView rawXml) = 0; + virtual void Signal(const CommandData&, StringView rawXml) = 0; + virtual void Signal(const CheckAliveData&, StringView rawXml) = 0; + virtual void Disconnect() = 0; virtual ~IStateMachine() = default; }; @@ -46,11 +48,14 @@ namespace Hermes struct IStateMachineCallback { virtual void OnSocketConnected(EState, const ConnectionInfo&) = 0; - virtual void On(EState, const ServiceDescription&) = 0; + virtual void On(EState, const ServiceDescriptionData&) = 0; virtual void On(EState, const BoardAvailableData&) = 0; virtual void On(EState, const RevokeBoardAvailableData&) = 0; virtual void On(EState, const TransportFinishedData&) = 0; + virtual void On(EState, const BoardForecastData&) = 0; + virtual void On(EState, const SendBoardInfoData&) = 0; virtual void On(EState, const NotificationData&) = 0; + virtual void On(EState, const CommandData&) = 0; virtual void On(EState, const CheckAliveData&) = 0; virtual void OnState(EState) = 0; virtual void OnDisconnected(EState, const Error&) = 0; diff --git a/src/Hermes/VerticalClient.cpp b/src/Hermes/VerticalClient.cpp new file mode 100644 index 0000000..16228f5 --- /dev/null +++ b/src/Hermes/VerticalClient.cpp @@ -0,0 +1,508 @@ +/*********************************************************************** +Copyright 2018 ASM Assembly Systems GmbH & Co. KG + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#include "stdafx.h" + +#include +#include "ApiCallback.h" +#include "MessageDispatcher.h" +#include "Service.h" +#include "VerticalClientSession.h" + +#include +#include + +using namespace Hermes; +using namespace Hermes::VerticalClient; + +struct HermesVerticalClient : ISessionCallback +{ + Service m_service; + asio::deadline_timer m_timer{ m_service.GetUnderlyingService() }; + VerticalClientSettings m_settings; + + unsigned m_sessionId{ 0U }; + unsigned m_connectedSessionId{ 0U }; + + ApiCallback m_connectedCallback; + ApiCallback m_serviceDescriptionCallback; + ApiCallback m_boardArrivedCallback; + ApiCallback m_boardDepartedCallback; + ApiCallback m_queryWorkOrderInfoCallback; + ApiCallback m_replyWorkOrderInfoCallback; + ApiCallback m_currentConfigurationCallback; + ApiCallback m_sendHermesCapabilitiesCallback; + ApiCallback m_notificationCallback; + ApiCallback m_checkAliveCallback; + ApiCallback m_disconnectedCallback; + + std::unique_ptr m_upSession; + + bool m_enabled{ false }; + + HermesVerticalClient(const HermesVerticalClientCallbacks& callbacks) : + m_service(callbacks.m_traceCallback), + m_connectedCallback(callbacks.m_connectedCallback), + m_serviceDescriptionCallback(callbacks.m_serviceDescriptionCallback), + m_boardArrivedCallback(callbacks.m_boardArrivedCallback), + m_boardDepartedCallback(callbacks.m_boardDepartedCallback), + m_queryWorkOrderInfoCallback(callbacks.m_queryWorkOrderInfoCallback), + m_replyWorkOrderInfoCallback(callbacks.m_replyWorkOrderInfoCallback), + m_currentConfigurationCallback(callbacks.m_currentConfigurationCallback), + m_sendHermesCapabilitiesCallback(callbacks.m_sendHermesCapabilitiesCallback), + m_notificationCallback(callbacks.m_notificationCallback), + m_checkAliveCallback(callbacks.m_checkAliveCallback), + m_disconnectedCallback(callbacks.m_disconnectedCallback) + { + m_service.Inform(0U, "Created"); + } + + virtual ~HermesVerticalClient() + { + m_service.Inform(0U, "Deleted"); + } + + void Enable(const VerticalClientSettings& settings) + { + m_service.Log(0U, "Enable(", settings, "); m_enabled=", m_enabled, ", m_settings=", m_settings); + + if (m_enabled && settings == m_settings) + return; + + m_enabled = true; + RemoveSession_(NotificationData(ENotificationCode::eCONNECTION_RESET_BECAUSE_OF_CHANGED_CONFIGURATION, + ESeverity::eINFO, "ConfigurationChanged")); + + m_settings = settings; + CreateNewSession_(); + } + + void Disable(const NotificationData& notificationData) + { + m_service.Log(0U, "Disable(", notificationData, "); m_enabled=", m_enabled); + + if (!m_enabled) + return; + + m_enabled = false; + RemoveSession_(notificationData); + } + + template + void Signal(unsigned sessionId, const DataT& data, StringView rawXml) + { + m_service.Log(sessionId, "Signal(", data, ',', rawXml, ')'); + + auto* pSession = Session_(sessionId); + if (!pSession) + return; + + pSession->Signal(data, rawXml); + } + + void Stop() + { + m_service.Log(0U, "Stop()"); + + NotificationData notificationData(ENotificationCode::eMACHINE_SHUTDOWN, ESeverity::eINFO, "Vertial client stopped by application"); + RemoveSession_(notificationData); + m_service.Stop(); + } + + //================= ISessionCallback ========================= + void OnSocketConnected(unsigned sessionId, EVerticalState state, const ConnectionInfo& in_data) override + { + const auto* pSession = Session_(sessionId); + if (!pSession) + return; + + m_connectedSessionId = pSession->Id(); + const Converter2C converter(in_data); + m_connectedCallback(pSession->Id(), ToC(state), converter.CPointer()); + } + + void On(unsigned sessionId, EVerticalState state, const SupervisoryServiceDescriptionData& in_data) override + { + const auto* pSession = Session_(sessionId); + if (!pSession) + return; + + const Converter2C converter(in_data); + m_serviceDescriptionCallback(pSession->Id(), ToC(state), converter.CPointer()); + } + + void On(unsigned sessionId, EVerticalState, const BoardArrivedData& in_data) override + { + const auto* pSession = Session_(sessionId); + if (!pSession) + return; + + const Converter2C converter(in_data); + m_boardArrivedCallback(sessionId, converter.CPointer()); + } + + void On(unsigned sessionId, EVerticalState, const BoardDepartedData& in_data) override + { + const auto* pSession = Session_(sessionId); + if (!pSession) + return; + + const Converter2C converter(in_data); + m_boardDepartedCallback(sessionId, converter.CPointer()); + } + + void On(unsigned sessionId, EVerticalState, const QueryWorkOrderInfoData& in_data) override + { + const auto* pSession = Session_(sessionId); + if (!pSession) + return; + + const Converter2C converter(in_data); + m_queryWorkOrderInfoCallback(sessionId, converter.CPointer()); + } + + void On(unsigned sessionId, EVerticalState, const ReplyWorkOrderInfoData& in_data) override + { + const auto* pSession = Session_(sessionId); + if (!pSession) + return; + + const Converter2C converter(in_data); + m_replyWorkOrderInfoCallback(sessionId, converter.CPointer()); + } + + void On(unsigned sessionId, EVerticalState, const CurrentConfigurationData& in_data) override + { + const auto* pSession = Session_(sessionId); + if (!pSession) + return; + + const Converter2C converter(in_data); + m_currentConfigurationCallback(sessionId, converter.CPointer()); + } + + void On(unsigned sessionId, EVerticalState, const SendHermesCapabilitiesData& in_data) override + { + const auto* pSession = Session_(sessionId); + if (!pSession) + return; + + const Converter2C converter(in_data); + + m_sendHermesCapabilitiesCallback(sessionId, converter.CPointer()); + } + + void On(unsigned sessionId, EVerticalState, const NotificationData& in_data) override + { + const auto* pSession = Session_(sessionId); + if (!pSession) + return; + + const Converter2C converter(in_data); + m_notificationCallback(sessionId, converter.CPointer()); + } + + void On(unsigned sessionId, EVerticalState, const CheckAliveData& in_data) override + { + const auto* pSession = Session_(sessionId); + if (!pSession) + return; + + if (in_data.m_optionalType + && *in_data.m_optionalType == ECheckAliveType::ePING + && m_settings.m_checkAliveResponseMode == ECheckAliveResponseMode::eAUTO) + { + CheckAliveData data{ in_data }; + data.m_optionalType = ECheckAliveType::ePONG; + m_service.Post([this, sessionId, data = std::move(data)]() { Signal(sessionId, data, Serialize(data)); }); + } + const Converter2C converter(in_data); + m_checkAliveCallback(sessionId, converter.CPointer()); + } + + void OnDisconnected(unsigned sessionId, EVerticalState state, const Error& error) override + { + const auto* pSession = Session_(sessionId); + if (!pSession) + return; + + if (pSession->OptionalPeerServiceDescriptionData()) + { + DelayCreateNewSession_(1.0); + } + else + { + DelayCreateNewSession_(m_settings.m_reconnectWaitTimeInSeconds); + } + + m_upSession.reset(); + const Converter2C converter(error); + m_disconnectedCallback(sessionId, ToC(state), converter.CPointer()); + } + + //============ internal impplementation ============== + Session* Session_(unsigned id) + { + if (m_upSession && m_upSession->Id() == id) + return m_upSession.get(); + + m_service.Warn(id, "Session ID no longer valid; current session ID=", m_upSession ? m_upSession->Id() : 0U); + return nullptr; + } + + void RemoveSession_() + { + if (!m_upSession) + return; + + auto sessionId = m_upSession->Id(); + m_service.Log(sessionId, "RemoveSession_()"); + + m_upSession->Disconnect(); + m_upSession.reset(); + + if (sessionId != m_connectedSessionId) + return; + + m_connectedSessionId = 0U; + Error error; + const Converter2C converter(error); + m_disconnectedCallback(sessionId, eHERMES_VERTICAL_STATE_DISCONNECTED, converter.CPointer()); + } + + void RemoveSession_(const NotificationData& data) + { + if (!m_upSession) + return; + + m_upSession->Signal(data, Serialize(data)); + RemoveSession_(); + } + + void CreateNewSession_() + { + if (m_upSession) + return; + + if (!m_enabled) + { + m_service.Log(0U, "CreateNewSession_, but disabled"); + return; + } + + if (!++m_sessionId) { ++m_sessionId; } // avoid zero sessionId + + m_upSession = std::make_unique(m_sessionId, m_service, m_settings); + m_upSession->Connect(*this); + } + + void DelayCreateNewSession_(double delay) + { + m_service.Log(0U, "DelayCreateNewSession_"); + + m_timer.expires_from_now(boost::posix_time::millisec(static_cast(1000.0 * delay))); + m_timer.async_wait([this](const boost::system::error_code& ec) + { + if (ec) // timer cancelled or whatever + return; + CreateNewSession_(); + }); + } +}; + +//===================== implementation of public C functions ===================== + +HermesVerticalClient* CreateHermesVerticalClient(const HermesVerticalClientCallbacks* pCallbacks) +{ + return new HermesVerticalClient(*pCallbacks); +} + +void RunHermesVerticalClient(HermesVerticalClient* pVerticalClient) +{ + pVerticalClient->m_service.Log(0U, "RunHermesVerticalClient"); + + pVerticalClient->m_service.Run(); +} + +void PostHermesVerticalClient(HermesVerticalClient* pVerticalClient, HermesVoidCallback voidCallback) +{ + pVerticalClient->m_service.Log(0U, "PostHermesVerticalClient"); + + pVerticalClient->m_service.Post([voidCallback] + { + voidCallback.m_pCall(voidCallback.m_pData); + }); +} + +void EnableHermesVerticalClient(HermesVerticalClient* pVerticalClient, const HermesVerticalClientSettings* pSettings) +{ + pVerticalClient->m_service.Log(0U, "EnableHermesVerticalClient"); + auto settings = ToCpp(*pSettings); + if (!settings.m_port) + { + settings.m_port = static_cast(cBASE_PORT); + } + + pVerticalClient->m_service.Post([pVerticalClient, settings = std::move(settings)]() + { + pVerticalClient->Enable(settings); + }); +} + +void SignalHermesVerticalClientDescription(HermesVerticalClient* pVerticalClient, uint32_t sessionId, const HermesSupervisoryServiceDescriptionData* pData) +{ + pVerticalClient->m_service.Log(sessionId, "SignalHermesVerticalClientDescription"); + pVerticalClient->m_service.Post([pVerticalClient, sessionId, data = ToCpp(*pData)]() + { + pVerticalClient->Signal(sessionId, data, Serialize(data)); + }); +} + +void SignalHermesSendWorkOrderInfo(HermesVerticalClient* pVerticalClient, uint32_t sessionId, const HermesSendWorkOrderInfoData* pData) +{ + pVerticalClient->m_service.Log(sessionId, "SignalHermesSendWorkOrderInfo"); + pVerticalClient->m_service.Post([pVerticalClient, sessionId, data = ToCpp(*pData)]() + { + pVerticalClient->Signal(sessionId, data, Serialize(data)); + }); +} + +void SignalHermesVerticalGetConfiguration(HermesVerticalClient* pVerticalClient, uint32_t sessionId, const HermesGetConfigurationData* pData) +{ + pVerticalClient->m_service.Log(sessionId, "SignalHermesVerticalGetConfiguration"); + pVerticalClient->m_service.Post([pVerticalClient, sessionId, data = ToCpp(*pData)]() + { + pVerticalClient->Signal(sessionId, data, Serialize(data)); + }); +} + +void SignalHermesVerticalSetConfiguration(HermesVerticalClient* pVerticalClient, uint32_t sessionId, const HermesSetConfigurationData* pData) +{ + pVerticalClient->m_service.Log(sessionId, "SignalHermesVerticalSetConfiguration"); + pVerticalClient->m_service.Post([pVerticalClient, sessionId, data = ToCpp(*pData)]() + { + pVerticalClient->Signal(sessionId, data, Serialize(data)); + }); +} + +void SignalHermesVerticalQueryHermesCapabilities(HermesVerticalClient* pVerticalClient, uint32_t sessionId, const HermesQueryHermesCapabilitiesData* pData) +{ + pVerticalClient->m_service.Log(sessionId, "SignalHermesQueryHermesCapabilities"); + pVerticalClient->m_service.Post([pVerticalClient, sessionId, data = ToCpp(*pData)]() + { + pVerticalClient->Signal(sessionId, data, Serialize(data)); + }); +} + +void SignalHermesVerticalClientNotification(HermesVerticalClient* pVerticalClient, uint32_t sessionId, const HermesNotificationData* pData) +{ + pVerticalClient->m_service.Log(0U, "SignalHermesVerticalClientNotification"); + + pVerticalClient->m_service.Post([pVerticalClient, sessionId, data = ToCpp(*pData)]() + { + pVerticalClient->Signal(sessionId, data, Serialize(data)); + }); +} + +void SignalHermesVerticalClientCheckAlive(HermesVerticalClient* pVerticalClient, uint32_t sessionId, const HermesCheckAliveData* pData) +{ + pVerticalClient->m_service.Log(0U, "SignalHermesVerticalClientCheckAlive"); + + pVerticalClient->m_service.Post([pVerticalClient, sessionId, data = ToCpp(*pData)]() + { + pVerticalClient->Signal(sessionId, data, Serialize(data)); + }); +} + +void ResetHermesVerticalClient(HermesVerticalClient* pVerticalClient, const HermesNotificationData* pData) +{ + pVerticalClient->m_service.Log(0U, "ResetHermesVerticalClient"); + + pVerticalClient->m_service.Post([pVerticalClient, data = ToCpp(*pData)]() + { + pVerticalClient->RemoveSession_(data); + pVerticalClient->DelayCreateNewSession_(1.0); + }); +} + + +void DisableHermesVerticalClient(HermesVerticalClient* pVerticalClient, const HermesNotificationData* pData) +{ + pVerticalClient->m_service.Log(0U, "DisableHermesVerticalClient"); + pVerticalClient->m_service.Post([pVerticalClient, data = ToCpp(*pData)]() + { + pVerticalClient->Disable(data); + }); +} + +void StopHermesVerticalClient(HermesVerticalClient* pVerticalClient) +{ + pVerticalClient->m_service.Log(0U, "StopHermesVerticalClient"); + + pVerticalClient->m_service.Post([pVerticalClient]() + { + pVerticalClient->Stop(); + }); +} + +void DeleteHermesVerticalClient(HermesVerticalClient* pVerticalClient) +{ + if (!pVerticalClient) + return; + + pVerticalClient->m_service.Log(0U, "DeleteHermesVerticalClient"); + + pVerticalClient->m_service.Stop(); + delete pVerticalClient; +} + +void SignalHermesVerticalClientRawXml(HermesVerticalClient* pVerticalClient, uint32_t sessionId, HermesStringView rawXml) +{ + pVerticalClient->m_service.Log(sessionId, "SignalHermesVerticalClientRawXml"); + pVerticalClient->m_service.Post([pVerticalClient, sessionId, xmlData = std::string(rawXml.m_pData, rawXml.m_size)]() mutable + { + MessageDispatcher dispatcher{ sessionId, pVerticalClient->m_service }; + auto parseData = xmlData; + + bool wasDispatched = false; + dispatcher.Add([&](const auto& data) { wasDispatched = true; pVerticalClient->Signal(sessionId, data, xmlData); }); + dispatcher.Add([&](const auto& data) { wasDispatched = true; pVerticalClient->Signal(sessionId, data, xmlData); }); + dispatcher.Add([&](const auto& data) { wasDispatched = true; pVerticalClient->Signal(sessionId, data, xmlData); }); + dispatcher.Add([&](const auto& data) { wasDispatched = true; pVerticalClient->Signal(sessionId, data, xmlData); }); + dispatcher.Add([&](const auto& data) { wasDispatched = true; pVerticalClient->Signal(sessionId, data, xmlData); }); + dispatcher.Add([&](const auto& data) { wasDispatched = true; pVerticalClient->Signal(sessionId, data, xmlData); }); + + dispatcher.Dispatch(parseData); + if (wasDispatched) + return; + + pVerticalClient->Signal(sessionId, NotificationData{}, xmlData); + }); +} + +void ResetHermesVerticalClientRawXml(HermesVerticalClient* pVerticalClient, HermesStringView rawXml) +{ + pVerticalClient->m_service.Log(0U, "ResetHermesVerticalClientRawXml"); + pVerticalClient->m_service.Post([pVerticalClient, data = std::string(rawXml.m_pData, rawXml.m_size)]() + { + if (!data.empty() && pVerticalClient->m_upSession) + { + pVerticalClient->m_upSession->Signal(NotificationData(), data); + } + pVerticalClient->RemoveSession_(); + pVerticalClient->DelayCreateNewSession_(1.0); + }); +} diff --git a/src/Hermes/VerticalClientSerializer.cpp b/src/Hermes/VerticalClientSerializer.cpp new file mode 100644 index 0000000..1a85773 --- /dev/null +++ b/src/Hermes/VerticalClientSerializer.cpp @@ -0,0 +1,101 @@ +/*********************************************************************** +Copyright 2018 ASM Assembly Systems GmbH & Co. KG + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#include "stdafx.h" +#include "VerticalClientSerializer.h" + +#include "Network.h" +#include "IService.h" +#include "MessageDispatcher.h" + +namespace Hermes +{ + namespace VerticalClient + { + struct Serializer : ISerializer, ISocketCallback + { + unsigned m_sessionId; + IAsioService& m_service; + IClientSocket& m_socket; + ISerializerCallback* m_pCallback = nullptr; + MessageDispatcher m_dispatcher{ m_sessionId, m_service }; + + Serializer(unsigned sessionId, IAsioService& service, IClientSocket& socket) : + m_sessionId(sessionId), + m_service(service), + m_socket(socket) + { + m_dispatcher.Add([this](const auto& data) { m_pCallback->On(data); }); + m_dispatcher.Add([this](const auto& data) { m_pCallback->On(data); }); + m_dispatcher.Add([this](const auto& data) { m_pCallback->On(data); }); + m_dispatcher.Add([this](const auto& data) { m_pCallback->On(data); }); + m_dispatcher.Add([this](const auto& data) { m_pCallback->On(data); }); + m_dispatcher.Add([this](const auto& data) { m_pCallback->On(data); }); + m_dispatcher.Add([this](const auto& data) { m_pCallback->On(data); }); + m_dispatcher.Add([this](const auto& data) { m_pCallback->On(data); }); + m_dispatcher.Add([this](const auto& data) { m_pCallback->On(data); }); + } + + // ISocketCallback + void OnConnected(const ConnectionInfo& connectionInfo) override + { + m_pCallback->OnSocketConnected(connectionInfo); + } + + void OnReceived(StringSpan xmlData) override + { + auto error = m_dispatcher.Dispatch(xmlData); + if (!error) + return; + + error = m_service.Alarm(m_sessionId, EErrorCode::ePEER_ERROR, error.m_text); + Signal(Serialize(NotificationData(ENotificationCode::ePROTOCOL_ERROR, ESeverity::eFATAL, error.m_text))); + m_socket.Close(); + m_pCallback->OnDisconnected(error); + } + + void OnDisconnected(const Error& error) override + { + m_pCallback->OnDisconnected(error); + } + + + //============== VerticalService::ISerializer ================================ + void Connect(std::weak_ptr wpOwner, ISerializerCallback& callback) override + { + assert(!m_pCallback); + m_pCallback = &callback; + m_socket.Connect(wpOwner, *this); + } + + void Signal(StringView rawXml) + { + m_socket.Send(rawXml); + } + + void Disconnect() override + { + m_socket.Close(); + } + }; + } + + std::unique_ptr VerticalClient::CreateSerializer(unsigned sessionId, IAsioService& service, + IClientSocket& socket) + { + return std::make_unique(sessionId, service, socket); + } +} diff --git a/src/Hermes/VerticalClientSerializer.h b/src/Hermes/VerticalClientSerializer.h new file mode 100644 index 0000000..70ade84 --- /dev/null +++ b/src/Hermes/VerticalClientSerializer.h @@ -0,0 +1,64 @@ +/*********************************************************************** +Copyright 2018 ASM Assembly Systems GmbH & Co. KG + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +// Copyright (c) ASM Assembly Systems GmbH & Co. KG +#pragma once + + +#include +#include + +namespace Hermes +{ + struct IAsioService; + struct IClientSocket; + + namespace VerticalClient + { + struct ISerializerCallback; + + struct ISerializer + { + virtual void Connect(std::weak_ptr wpOwner, ISerializerCallback&) = 0; + virtual void Signal(StringView rawXml) = 0; + virtual void Disconnect() = 0; + + virtual ~ISerializer() = default; + }; + + struct ISerializerCallback + { + virtual void OnSocketConnected(const ConnectionInfo&) = 0; + virtual void On(const SupervisoryServiceDescriptionData&) = 0; + virtual void On(const BoardArrivedData&) = 0; + virtual void On(const BoardDepartedData&) = 0; + virtual void On(const CurrentConfigurationData&) = 0; + virtual void On(const QueryWorkOrderInfoData&) = 0; + virtual void On(const ReplyWorkOrderInfoData&) = 0; + virtual void On(const NotificationData&) = 0; + virtual void On(const CheckAliveData&) = 0; + virtual void On(const SendHermesCapabilitiesData&) = 0; + virtual void OnDisconnected(const Error&) = 0; + + protected: + ~ISerializerCallback() = default; + }; + + std::unique_ptr CreateSerializer(unsigned sessionId, + IAsioService&, IClientSocket&); + } + +} diff --git a/src/Hermes/VerticalClientSession.cpp b/src/Hermes/VerticalClientSession.cpp new file mode 100644 index 0000000..83eb73b --- /dev/null +++ b/src/Hermes/VerticalClientSession.cpp @@ -0,0 +1,258 @@ +/*********************************************************************** +Copyright 2018 ASM Assembly Systems GmbH & Co. KG + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#include "stdafx.h" + +#include "VerticalClientSession.h" + +#include "Network.h" +#include "VerticalClientSerializer.h" +#include "IService.h" +#include "MessageSerialization.h" +#include "StringBuilder.h" + +#include "Network.h" + +#include + +namespace Hermes +{ + namespace asio = boost::asio; + + namespace VerticalClient + { + struct Session::Impl : ISerializerCallback + { + unsigned m_id; + EVerticalState m_state{ EVerticalState::eNOT_CONNECTED }; + IAsioService& m_service; + VerticalClientSettings m_configuration; + + std::unique_ptr m_upSocket; + std::unique_ptr m_upSerializer; + Optional m_optionalPeerServiceDescriptionData; + ConnectionInfo m_peerConnectionInfo; + + ISessionCallback* m_pCallback{ nullptr }; + + Impl(unsigned id, IAsioService& service, const VerticalClientSettings& configuration) : + m_id(id), + m_service(service), + m_configuration(configuration) + { + m_service.Log(m_id, "VerticalClientSession()"); + } + + ~Impl() + { + m_service.Log(m_id, "~VerticalClientSession()"); + } + + bool DisconnectedDueToIllegalClientEvent_(StringView event) + { + auto error = m_service.Alarm(m_id, EErrorCode::eCLIENT_ERROR, + "Unexpected client event in state ", m_state, ": ", event); + + if (!m_pCallback) + return true; + + if (m_state == EVerticalState::eDISCONNECTED) + return true; + + if (m_state != EVerticalState::eNOT_CONNECTED) + { + m_upSerializer->Signal(Serialize(NotificationData(ENotificationCode::eUNSPECIFIC, ESeverity::eFATAL, "SoftwareError"))); + } + + m_state = EVerticalState::eDISCONNECTED; + m_pCallback->OnDisconnected(m_id, m_state, error); + m_upSerializer->Disconnect(); + return true; + } + + void OnUnexpectedPeerEvent_(StringView event) + { + auto error = m_service.Alarm(m_id, EErrorCode::ePEER_ERROR, + "Unexpected peer event in state ", m_state, ": ", event); + + if (m_state == EVerticalState::eDISCONNECTED) + return; + + m_state = EVerticalState::eDISCONNECTED; + m_pCallback->OnDisconnected(m_id, m_state, error); + m_upSerializer->Signal(Serialize(NotificationData(ENotificationCode::ePROTOCOL_ERROR, ESeverity::eFATAL, error.m_text))); + m_upSerializer->Disconnect(); + } + + + //============= implementation of ISerializerCallback ============ + void OnSocketConnected(const ConnectionInfo& connectionInfo) override + { + switch (m_state) + { + case EVerticalState::eNOT_CONNECTED: + m_state = EVerticalState::eSOCKET_CONNECTED; + m_peerConnectionInfo = connectionInfo; + m_pCallback->OnSocketConnected(m_id, m_state, connectionInfo); + return; + + default: + return OnUnexpectedPeerEvent_("Connected"); + } + } + + void On(const SupervisoryServiceDescriptionData& data) override + { + switch (m_state) + { + case EVerticalState::eSUPERVISORY_SERVICE_DESCRIPTION: + m_state = EVerticalState::eCONNECTED; + m_optionalPeerServiceDescriptionData = data; + m_pCallback->On(m_id, m_state, data); + return; + + default: + return OnUnexpectedPeerEvent_("ServiceDescription"); + } + } + + template + void On_(const DataT& data, const char* name) + { + switch (m_state) + { + case EVerticalState::eNOT_CONNECTED: + case EVerticalState::eDISCONNECTED: + return OnUnexpectedPeerEvent_(name); + + default: + m_pCallback->On(m_id, m_state, data); + return; + } + } + + void On(const CurrentConfigurationData& data) override { On_(data, "CurrentConfiguration"); } + void On(const BoardArrivedData& data) override { On_(data, "BoardArrived"); } + void On(const BoardDepartedData& data) override { On_(data, "BoardDeparted"); } + void On(const QueryWorkOrderInfoData& data) override { On_(data, "QueryWorkOrderInfo"); } + void On(const ReplyWorkOrderInfoData& data) override { On_(data, "QueryWorkOrderInfo"); } + void On(const NotificationData& data) override { On_(data, "Notification"); } + void On(const CheckAliveData& data) override { On_(data, "CheckAlive"); } + void On(const SendHermesCapabilitiesData& data) override { On_(data, "SendHermesCapabilities"); } + + void Signal_(StringView rawXml) + { + switch (m_state) + { + case EVerticalState::eNOT_CONNECTED: + case EVerticalState::eDISCONNECTED: + return; + + default: + m_upSerializer->Signal(rawXml); + return; + } + } + + void OnDisconnected(const Error& error) override + { + switch (m_state) + { + case EVerticalState::eDISCONNECTED: + return; + + default: + m_state = EVerticalState::eDISCONNECTED; + m_pCallback->OnDisconnected(m_id, m_state, error); + } + } + }; + + + Session::Session(unsigned id, IAsioService& service, + const VerticalClientSettings& configuration) + { + m_spImpl = std::make_shared(id, service, configuration); + + NetworkConfiguration socketConfig; + socketConfig.m_hostName = configuration.m_hostAddress; + socketConfig.m_port = configuration.m_port; + socketConfig.m_retryDelayInSeconds = configuration.m_reconnectWaitTimeInSeconds; + socketConfig.m_checkAlivePeriodInSeconds = configuration.m_checkAlivePeriodInSeconds; + + m_spImpl->m_upSocket = CreateClientSocket(id, socketConfig, service); + m_spImpl->m_upSerializer = CreateSerializer(id, service, *m_spImpl->m_upSocket); + } + + Session::~Session() + { + if (!m_spImpl) + return; + + m_spImpl->m_pCallback = nullptr; + } + + unsigned Session::Id() const { return m_spImpl->m_id; } + const Optional& Session::OptionalPeerServiceDescriptionData() const + { + return m_spImpl->m_optionalPeerServiceDescriptionData; + } + + const ConnectionInfo& Session::PeerConnectionInfo() const { return m_spImpl->m_peerConnectionInfo; } + + void Session::Connect(ISessionCallback& callback) + { + m_spImpl->m_pCallback = &callback; + m_spImpl->m_upSerializer->Connect(m_spImpl, *m_spImpl); + } + + void Session::Signal(const SupervisoryServiceDescriptionData&, StringView rawXml) + { + switch (m_spImpl->m_state) + { + case EVerticalState::eSOCKET_CONNECTED: + m_spImpl->m_state = EVerticalState::eSUPERVISORY_SERVICE_DESCRIPTION; + m_spImpl->m_upSerializer->Signal(rawXml); + return; + + default: + if (m_spImpl->DisconnectedDueToIllegalClientEvent_("ServiceDescription")) + return; + m_spImpl->m_upSerializer->Signal(rawXml); + } + } + + void Session::Signal(const SendWorkOrderInfoData&, StringView rawXml) { m_spImpl->Signal_(rawXml); } + void Session::Signal(const SetConfigurationData&, StringView rawXml) { m_spImpl->Signal_(rawXml); } + void Session::Signal(const GetConfigurationData&, StringView rawXml) { m_spImpl->Signal_(rawXml); } + void Session::Signal(const NotificationData&, StringView rawXml) { m_spImpl->Signal_(rawXml); } + void Session::Signal(const CheckAliveData&, StringView rawXml) { m_spImpl->Signal_(rawXml); } + void Session::Signal(const QueryHermesCapabilitiesData&, StringView rawXml) { m_spImpl->Signal_(rawXml); } + + void Session::Disconnect() + { + switch (m_spImpl->m_state) + { + case EVerticalState::eDISCONNECTED: + return; + + default: + m_spImpl->m_state = EVerticalState::eDISCONNECTED; + m_spImpl->m_upSerializer->Disconnect(); + } + } + } +} \ No newline at end of file diff --git a/src/Hermes/VerticalClientSession.h b/src/Hermes/VerticalClientSession.h new file mode 100644 index 0000000..03395b5 --- /dev/null +++ b/src/Hermes/VerticalClientSession.h @@ -0,0 +1,78 @@ +/*********************************************************************** +Copyright 2018 ASM Assembly Systems GmbH & Co. KG + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#pragma once + +#include + +#include + +namespace Hermes +{ + struct IAsioService; + struct IClientSocket; + + namespace VerticalClient + { + struct ISessionCallback; + + class Session + { + public: + Session(unsigned id, IAsioService&, const VerticalClientSettings&); + Session(const Session&) = default; + Session& operator=(const Session&) = default; + Session(Session&&) = default; + Session& operator=(Session&&) = default; + ~Session(); + + explicit operator bool() const { return bool(m_spImpl); } + unsigned Id() const; + const Optional& OptionalPeerServiceDescriptionData() const; + const ConnectionInfo& PeerConnectionInfo() const; + + void Connect(ISessionCallback&); + void Signal(const SupervisoryServiceDescriptionData&, StringView rawXml); + void Signal(const SendWorkOrderInfoData&, StringView rawXml); + void Signal(const GetConfigurationData&, StringView rawXml); + void Signal(const SetConfigurationData&, StringView rawXml); + void Signal(const NotificationData&, StringView rawXml); + void Signal(const CheckAliveData&, StringView rawXml); + void Signal(const QueryHermesCapabilitiesData&, StringView rawXml); + void Disconnect(); + + private: + struct Impl; + std::shared_ptr m_spImpl; + + }; + + struct ISessionCallback + { + virtual void OnSocketConnected(unsigned id, EVerticalState, const ConnectionInfo&) = 0; + virtual void On(unsigned id, EVerticalState, const SupervisoryServiceDescriptionData&) = 0; + virtual void On(unsigned id, EVerticalState, const CurrentConfigurationData&) = 0; + virtual void On(unsigned id, EVerticalState, const BoardArrivedData&) = 0; + virtual void On(unsigned id, EVerticalState, const BoardDepartedData&) = 0; + virtual void On(unsigned id, EVerticalState, const QueryWorkOrderInfoData&) = 0; + virtual void On(unsigned id, EVerticalState, const ReplyWorkOrderInfoData&) = 0; + virtual void On(unsigned id, EVerticalState, const SendHermesCapabilitiesData&) = 0; + virtual void On(unsigned id, EVerticalState, const NotificationData&) = 0; + virtual void On(unsigned id, EVerticalState, const CheckAliveData&) = 0; + virtual void OnDisconnected(unsigned id, EVerticalState, const Error&) = 0; + }; + } +} diff --git a/src/Hermes/VerticalService.cpp b/src/Hermes/VerticalService.cpp new file mode 100644 index 0000000..d689a5a --- /dev/null +++ b/src/Hermes/VerticalService.cpp @@ -0,0 +1,504 @@ +/*********************************************************************** +Copyright 2018 ASM Assembly Systems GmbH & Co. KG + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +// Copyright (c) ASM Assembly Systems GmbH & Co. KG +#include "stdafx.h" +#include + +#include "ApiCallback.h" +#include "VerticalServiceSession.h" +#include "Network.h" +#include "Service.h" + +#include +#include +#include +#include +#include + +using namespace Hermes; +using namespace Hermes::VerticalService; + +struct HermesVerticalService : IAcceptorCallback, ISessionCallback +{ + Service m_service; + VerticalServiceSettings m_settings;; + + // we only hold on to the accepting session + std::unique_ptr m_upAcceptor{ CreateAcceptor(m_service, *this) }; + std::map m_sessionMap; + + ApiCallback m_connectedCallback; + ApiCallback m_serviceDescriptionCallback; + ApiCallback m_sendWorkOrderInfoCallback; + ApiCallback m_notificationCallback; + ApiCallback m_checkAliveCallback; + ApiCallback m_setConfigurationCallback; + ApiCallback m_getConfigurationCallback; + ApiCallback m_disconnectedCallback; + ApiCallback m_queryHermesCapabilitiesCallback; + + bool m_enabled{ false }; + + HermesVerticalService(const HermesVerticalServiceCallbacks& callbacks) : + m_service(callbacks.m_traceCallback), + m_connectedCallback(callbacks.m_connectedCallback), + m_serviceDescriptionCallback(callbacks.m_serviceDescriptionCallback), + m_sendWorkOrderInfoCallback(callbacks.m_sendWorkOrderInfoCallback), + m_notificationCallback(callbacks.m_notificationCallback), + m_checkAliveCallback(callbacks.m_checkAliveCallback), + m_setConfigurationCallback(callbacks.m_setConfigurationCallback), + m_getConfigurationCallback(callbacks.m_getConfigurationCallback), + m_disconnectedCallback(callbacks.m_disconnectedCallback), + m_queryHermesCapabilitiesCallback(callbacks.m_queryHermesCapabilitiesCallback) + { + m_service.Inform(0U, "Created"); + } + + virtual ~HermesVerticalService() + { + m_service.Inform(0U, "Deleted"); + } + + //================= forwarding calls ========================= + void Enable(const VerticalServiceSettings& settings) + { + m_service.Log(0U, "Enable(", settings, "); m_enabled=", m_enabled, ", m_settings=", m_settings); + + if (m_enabled && m_settings == settings) + return; + + RemoveSessions_(NotificationData(ENotificationCode::eCONNECTION_RESET_BECAUSE_OF_CHANGED_CONFIGURATION, + ESeverity::eINFO, "ConfigurationChanged")); + + m_enabled = true; + m_settings = settings; + + NetworkConfiguration networkConfiguration; + networkConfiguration.m_port = settings.m_port ? settings.m_port : cCONFIG_PORT; + networkConfiguration.m_retryDelayInSeconds = settings.m_reconnectWaitTimeInSeconds; + networkConfiguration.m_checkAlivePeriodInSeconds = settings.m_checkAlivePeriodInSeconds; + + m_upAcceptor->StartListening(networkConfiguration); + } + + void Disable(const NotificationData& data) + { + m_service.Log(0U, "Disable(", data, "); m_enabled=", m_enabled); + + if (!m_enabled) + return; + + m_enabled = false; + m_upAcceptor->StopListening(); + RemoveSessions_(data); + } + + void Stop() + { + m_service.Log(0U, "Stop(), sessionCount=", m_sessionMap.size()); + + const NotificationData notificationData(ENotificationCode::eMACHINE_SHUTDOWN, ESeverity::eINFO, "Vertical service stopped by application"); + RemoveSessions_(notificationData); + m_service.Stop(); + } + + void RemoveSessions_(const NotificationData& data) + { + auto sessionMap = std::move(m_sessionMap); + m_sessionMap.clear(); + + const Error error{}; + const Converter2C converter(error); + for (auto& entry : sessionMap) + { + entry.second.Signal(data); + entry.second.Disconnect(); + m_disconnectedCallback(entry.second.Id(), eHERMES_VERTICAL_STATE_DISCONNECTED, converter.CPointer()); + } + } + + void RemoveSession_(unsigned sessionId, const NotificationData& data) + { + auto itFound = m_sessionMap.find(sessionId); + if (itFound == m_sessionMap.end()) + return; + + auto session = std::move(itFound->second); + m_sessionMap.erase(itFound); + + session.Signal(data); + session.Disconnect(); + const Error error{}; + const Converter2C converter(error); + m_disconnectedCallback(session.Id(), eHERMES_VERTICAL_STATE_DISCONNECTED, converter.CPointer()); + } + + Session* Session_(unsigned id) + { + auto itFound = m_sessionMap.find(id); + if (itFound == m_sessionMap.end()) + { + m_service.Warn(id, "Session ID no longer valid"); + return nullptr; + } + + return &itFound->second; + } + + template + void Signal_(unsigned sessionId, const DataT& data) + { + m_service.Log(sessionId, "Signal(", data, ')'); + + auto* pSession = Session_(sessionId); + if (!pSession) + return m_service.Log(sessionId, "No matching session to signal to"); + + pSession->Signal(data); + } + + template + void SignalTrackingData_(const DataT& data) + { + m_service.Log(0U, "Signal(", data, ')'); + + for (auto& entry : m_sessionMap) + { + auto& session = entry.second; + if (!session.OptionalPeerServiceDescriptionData() || + !session.OptionalPeerServiceDescriptionData()->m_supportedFeatures.m_optionalFeatureBoardTracking) + continue; + session.Signal(data); + } + } + + //================= IAcceptorCallback ========================= + void OnAccepted(std::unique_ptr&& upSocket) override + { + auto sessionId = upSocket->SessionId(); + m_service.Inform(sessionId, "OnAccepted: ", upSocket->GetConnectionInfo()); +#ifdef _WINDOWS + auto result = m_sessionMap.try_emplace(sessionId, std::move(upSocket), m_service, m_settings); +#else + auto result = m_sessionMap.emplace(sessionId, VerticalService::Session(std::move(upSocket), m_service, m_settings)); +#endif + if (!result.second) + { + // should not really happen, unless someone launches a Denial of Service attack + m_service.Warn(sessionId, "Duplicate session ID"); + return; + } + result.first->second.Connect(*this); + } + + //================= VerticalService::ISessionCallback ========================= + void OnSocketConnected(unsigned sessionId, EVerticalState state, const ConnectionInfo& in_data) override + { + const auto* pSession = Session_(sessionId); + if (!pSession) + return; + + const Converter2C converter(in_data); + m_connectedCallback(sessionId, ToC(state), converter.CPointer()); + } + + void On(unsigned sessionId, EVerticalState state, const SupervisoryServiceDescriptionData& in_data) override + { + const auto* pSession = Session_(sessionId); + if (!pSession) + return; + + const Converter2C converter(in_data); + m_serviceDescriptionCallback(sessionId, ToC(state), converter.CPointer()); + } + + void On(unsigned sessionId, EVerticalState, const GetConfigurationData& in_data) override + { + const auto* pSession = Session_(sessionId); + if (!pSession) + return; + + const Converter2C configurationConverter(in_data); + const Converter2C connectionConverter(pSession->PeerConnectionInfo()); + m_getConfigurationCallback(sessionId, configurationConverter.CPointer(), connectionConverter.CPointer()); + } + + void On(unsigned sessionId, EVerticalState, const SetConfigurationData& in_data) override + { + const auto* pSession = Session_(sessionId); + if (!pSession) + return; + + const Converter2C configurationConverter(in_data); + const Converter2C connectionConverter(pSession->PeerConnectionInfo()); + m_setConfigurationCallback(sessionId, configurationConverter.CPointer(), connectionConverter.CPointer()); + } + + void On(unsigned sessionId, EVerticalState, const SendWorkOrderInfoData& in_data) override + { + const auto* pSession = Session_(sessionId); + if (!pSession) + return; + + const Converter2C converter(in_data); + m_sendWorkOrderInfoCallback(sessionId, converter.CPointer()); + } + + void On(unsigned sessionId, EVerticalState, const QueryHermesCapabilitiesData& in_data) override + { + const auto* pSession = Session_(sessionId); + if (!pSession) + return; + + const Converter2C converter(in_data); + m_queryHermesCapabilitiesCallback(sessionId, converter.CPointer()); + } + + void On(unsigned sessionId, EVerticalState, const NotificationData& in_data) override + { + const auto* pSession = Session_(sessionId); + if (!pSession) + return; + + const Converter2C converter(in_data); + m_notificationCallback(sessionId, converter.CPointer()); + } + + void On(unsigned sessionId, EVerticalState, const CheckAliveData& in_data) override + { + const auto* pSession = Session_(sessionId); + if (!pSession) + return; + + if (in_data.m_optionalType + && *in_data.m_optionalType == ECheckAliveType::ePING + && m_settings.m_checkAliveResponseMode == ECheckAliveResponseMode::eAUTO) + { + CheckAliveData data{ in_data }; + data.m_optionalType = ECheckAliveType::ePONG; + m_service.Post([this, sessionId, data = std::move(data)]() { Signal_(sessionId, data); }); + } + const Converter2C converter(in_data); + m_checkAliveCallback(sessionId, converter.CPointer()); + } + + void OnDisconnected(unsigned sessionId, EVerticalState state, const Error& error) override + { + // only notify if this was signalled as connected: + if (!m_sessionMap.erase(sessionId)) + return; + + const Converter2C converter(error); + m_disconnectedCallback(sessionId, ToC(state), converter.CPointer()); + } +}; + +HermesVerticalService* CreateHermesVerticalService(const HermesVerticalServiceCallbacks* pCallbacks) +{ + return new HermesVerticalService(*pCallbacks); +} + +void RunHermesVerticalService(HermesVerticalService* pVerticalService) +{ + pVerticalService->m_service.Log(0U, "RunHermesVerticalService"); + + pVerticalService->m_service.Run(); +} + +void PostHermesVerticalService(HermesVerticalService* pVerticalService, HermesVoidCallback voidCallback) +{ + pVerticalService->m_service.Log(0U, "EnableHermesDownstream"); + + pVerticalService->m_service.Post([voidCallback] + { + voidCallback.m_pCall(voidCallback.m_pData); + }); +} + +void EnableHermesVerticalService(HermesVerticalService* pVerticalService, + const HermesVerticalServiceSettings* pSettings) +{ + pVerticalService->m_service.Log(0U, "EnableHermesVerticalService"); + + pVerticalService->m_service.Post([pVerticalService, + settings = ToCpp(*pSettings)]() + { + pVerticalService->Enable(settings); + }); +} + +void SignalHermesVerticalServiceDescription(HermesVerticalService* pVerticalService, uint32_t sessionId, + const HermesSupervisoryServiceDescriptionData* pData) +{ + pVerticalService->m_service.Log(sessionId, "SignalHermesVerticalServiceDescription"); + pVerticalService->m_service.Post([pVerticalService, sessionId, data = ToCpp(*pData)]() + { + pVerticalService->Signal_(sessionId, data); + }); +} + +void SignalHermesBoardArrived(HermesVerticalService* pVerticalService, uint32_t sessionId, + const HermesBoardArrivedData* pData) +{ + pVerticalService->m_service.Log(sessionId, "SignalHermesBoardArrived"); + pVerticalService->m_service.Post([pVerticalService, sessionId, data = ToCpp(*pData)]() + { + if (sessionId == 0U) + { + pVerticalService->SignalTrackingData_(data); + } + else + { + pVerticalService->Signal_(sessionId, data); + } + }); +} + +void SignalHermesBoardDeparted(HermesVerticalService* pVerticalService, uint32_t sessionId, + const HermesBoardDepartedData* pData) +{ + pVerticalService->m_service.Log(sessionId, "SignalHermesBoardDeparted"); + pVerticalService->m_service.Post([pVerticalService, sessionId, data = ToCpp(*pData)]() + { + if (sessionId == 0U) + { + pVerticalService->SignalTrackingData_(data); + } + else + { + pVerticalService->Signal_(sessionId, data); + } + }); +} + +void SignalHermesSendHermesCapabilities(HermesVerticalService* pVerticalService, uint32_t sessionId, + const HermesSendHermesCapabilitiesData* pData) +{ + pVerticalService->m_service.Log(sessionId, "SignalHermesSendHermesCapabilities"); + pVerticalService->m_service.Post([pVerticalService, sessionId, data = ToCpp(*pData)]() + { + pVerticalService->Signal_(sessionId, data); + }); +} + +void ResetHermesVerticalServiceSession(HermesVerticalService* pVerticalService, uint32_t sessionId, + const HermesNotificationData* pData) +{ + pVerticalService->m_service.Log(sessionId, "ResetHermesVerticalServiceSession"); + pVerticalService->m_service.Post([pVerticalService, sessionId, data = ToCpp(*pData)]() + { + pVerticalService->RemoveSession_(sessionId, data); + }); +} + +void SignalHermesQueryWorkOrderInfo(HermesVerticalService* pVerticalService, uint32_t sessionId, + const HermesQueryWorkOrderInfoData* pData) +{ + pVerticalService->m_service.Log(sessionId, "SignalHermesQueryWorkOrderInfo"); + pVerticalService->m_service.Post([pVerticalService, sessionId, data = ToCpp(*pData)]() + { + pVerticalService->Signal_(sessionId, data); + }); +} + +void SignalHermesReplyWorkOrderInfo(HermesVerticalService* pVerticalService, uint32_t sessionId, + const HermesReplyWorkOrderInfoData* pData) +{ + pVerticalService->m_service.Log(sessionId, "SignalHermesReplyWorkOrderInfo"); + pVerticalService->m_service.Post([pVerticalService, sessionId, data = ToCpp(*pData)]() + { + pVerticalService->Signal_(sessionId, data); + }); +} + +void SignalSendHermesCapabilitiesData(HermesVerticalService* pVerticalService, uint32_t sessionId, + const HermesSendHermesCapabilitiesData* pData) +{ + pVerticalService->m_service.Log(sessionId, "SignalSendHermesCapabilitiesData"); + pVerticalService->m_service.Post([pVerticalService, sessionId, data = ToCpp(*pData)]() + { + pVerticalService->Signal_(sessionId, data); + }); +} + +void SignalHermesSendWorkOrderInfo(HermesVerticalService* pVerticalService, uint32_t sessionId, + const HermesReplyWorkOrderInfoData* pData) +{ + pVerticalService->m_service.Log(sessionId, "SignalHermesSendWorkOrderInfo"); + pVerticalService->m_service.Post([pVerticalService, sessionId, data = ToCpp(*pData)]() + { + pVerticalService->Signal_(sessionId, data); + }); +} + +void SignalHermesVerticalServiceNotification(HermesVerticalService* pVerticalService, uint32_t sessionId, + const HermesNotificationData* pData) +{ + pVerticalService->m_service.Log(sessionId, "SignalHermesVerticalServiceNotification"); + pVerticalService->m_service.Post([pVerticalService, sessionId, data = ToCpp(*pData)]() + { + pVerticalService->Signal_(sessionId, data); + }); +} + +void SignalHermesVerticalServiceCheckAlive(HermesVerticalService* pVerticalService, uint32_t sessionId, + const HermesCheckAliveData* pData) +{ + pVerticalService->m_service.Log(sessionId, "SignalHermesVerticalCheckAlive"); + pVerticalService->m_service.Post([pVerticalService, sessionId, data = ToCpp(*pData)]() + { + pVerticalService->Signal_(sessionId, data); + }); +} + +void SignalHermesVerticalCurrentConfiguration(HermesVerticalService* pVerticalService, uint32_t sessionId, + const HermesCurrentConfigurationData* pData) +{ + pVerticalService->m_service.Log(sessionId, "SignalVerticalCurrentConfiguration"); + pVerticalService->m_service.Post([pVerticalService, sessionId, data = ToCpp(*pData)]() + { + pVerticalService->Signal_(sessionId, data); + }); +} + +void DisableHermesVerticalService(HermesVerticalService* pVerticalService, const HermesNotificationData* pData) +{ + pVerticalService->m_service.Log(0U, "DisableHermesVerticalService"); + + pVerticalService->m_service.Post([pVerticalService, data = ToCpp(*pData)]() + { + pVerticalService->Disable(data); + }); +} + +void StopHermesVerticalService(HermesVerticalService* pVerticalService) +{ + pVerticalService->m_service.Log(0U, "StopHermesVerticalService"); + + pVerticalService->m_service.Post([pVerticalService]() + { + pVerticalService->Stop(); + }); +} + +void DeleteHermesVerticalService(HermesVerticalService* pVerticalService) +{ + pVerticalService->m_service.Log(0U, "DeleteHermesVerticalService"); + + pVerticalService->m_service.Stop(); + delete pVerticalService; +} diff --git a/src/Hermes/VerticalServiceSerializer.cpp b/src/Hermes/VerticalServiceSerializer.cpp new file mode 100644 index 0000000..a73e1a8 --- /dev/null +++ b/src/Hermes/VerticalServiceSerializer.cpp @@ -0,0 +1,99 @@ +/*********************************************************************** +Copyright 2018 ASM Assembly Systems GmbH & Co. KG + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#include "stdafx.h" +#include "VerticalServiceSerializer.h" + +#include "Network.h" +#include "IService.h" +#include "MessageDispatcher.h" + +namespace Hermes +{ + namespace VerticalService + { + struct Serializer : ISerializer, ISocketCallback + { + unsigned m_sessionId; + IAsioService& m_service; + IServerSocket& m_socket; + ISerializerCallback* m_pCallback = nullptr; + MessageDispatcher m_dispatcher{ m_sessionId, m_service }; + + Serializer(unsigned sessionId, IAsioService& service, IServerSocket& socket) : + m_sessionId(sessionId), + m_service(service), + m_socket(socket) + { + m_dispatcher.Add([this](const auto& data) { m_pCallback->On(data); }); + m_dispatcher.Add([this](const auto& data) { m_pCallback->On(data); }); + m_dispatcher.Add([this](const auto& data) { m_pCallback->On(data); }); + m_dispatcher.Add([this](const auto& data) { m_pCallback->On(data); }); + m_dispatcher.Add([this](const auto& data) { m_pCallback->On(data); }); + m_dispatcher.Add([this](const auto& data) { m_pCallback->On(data); }); + m_dispatcher.Add([this](const auto& data) { m_pCallback->On(data); }); + } + + // ISocketCallback + void OnConnected(const ConnectionInfo& connectionInfo) override + { + m_pCallback->OnSocketConnected(connectionInfo); + } + + void OnReceived(StringSpan xmlData) override + { + auto error = m_dispatcher.Dispatch(xmlData); + if (!error) + return; + + error = m_service.Alarm(m_sessionId, EErrorCode::ePEER_ERROR, error.m_text); + Signal(Serialize(NotificationData(ENotificationCode::ePROTOCOL_ERROR, ESeverity::eFATAL, error.m_text))); + m_socket.Close(); + m_pCallback->OnDisconnected(error); + } + + void OnDisconnected(const Error& error) override + { + m_pCallback->OnDisconnected(error); + } + + + //============== VerticalService::ISerializer ================================ + void Connect(std::weak_ptr wpOwner, ISerializerCallback& callback) override + { + assert(!m_pCallback); + m_pCallback = &callback; + m_socket.Connect(wpOwner, *this); + } + + void Signal(StringView rawXml) + { + m_socket.Send(rawXml); + } + + void Disconnect() override + { + m_socket.Close(); + } + }; + } + + std::unique_ptr VerticalService::CreateSerializer(unsigned sessionId, IAsioService& service, + IServerSocket& socket) + { + return std::make_unique(sessionId, service, socket); + } +} diff --git a/src/Hermes/VerticalServiceSerializer.h b/src/Hermes/VerticalServiceSerializer.h new file mode 100644 index 0000000..8fa01a3 --- /dev/null +++ b/src/Hermes/VerticalServiceSerializer.h @@ -0,0 +1,62 @@ +/*********************************************************************** +Copyright 2018 ASM Assembly Systems GmbH & Co. KG + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +// Copyright (c) ASM Assembly Systems GmbH & Co. KG +#pragma once + + +#include +#include + +namespace Hermes +{ + struct IAsioService; + struct IServerSocket; + + namespace VerticalService + { + struct ISerializerCallback; + + struct ISerializer + { + virtual void Connect(std::weak_ptr wpOwner, ISerializerCallback&) = 0; + virtual void Signal(StringView rawXml) = 0; + virtual void Disconnect() = 0; + + virtual ~ISerializer() = default; + }; + + struct ISerializerCallback + { + virtual void OnSocketConnected(const ConnectionInfo&) = 0; + virtual void On(const SupervisoryServiceDescriptionData&) = 0; + virtual void On(const GetConfigurationData&) = 0; + virtual void On(const SetConfigurationData&) = 0; + virtual void On(const SendWorkOrderInfoData&) = 0; + virtual void On(const NotificationData&) = 0; + virtual void On(const CheckAliveData&) = 0; + virtual void On(const QueryHermesCapabilitiesData&) = 0; + virtual void OnDisconnected(const Error&) = 0; + + protected: + ~ISerializerCallback() = default; + }; + + std::unique_ptr CreateSerializer(unsigned sessionId, + IAsioService&, IServerSocket&); + } + +} diff --git a/src/Hermes/VerticalServiceSession.cpp b/src/Hermes/VerticalServiceSession.cpp new file mode 100644 index 0000000..1cb6a67 --- /dev/null +++ b/src/Hermes/VerticalServiceSession.cpp @@ -0,0 +1,251 @@ +/*********************************************************************** +Copyright 2018 ASM Assembly Systems GmbH & Co. KG + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#include "stdafx.h" + +#include "VerticalServiceSession.h" + +#include "Network.h" +#include "VerticalServiceSerializer.h" +#include "IService.h" +#include "MessageSerialization.h" +#include "StringBuilder.h" + +#include "Network.h" + +#include + +namespace Hermes +{ + namespace asio = boost::asio; + + namespace VerticalService + { + struct Session::Impl : ISerializerCallback + { + unsigned m_id; + EVerticalState m_state{ EVerticalState::eNOT_CONNECTED }; + IAsioService& m_service; + VerticalServiceSettings m_configuration; + + std::unique_ptr m_upSocket; + std::unique_ptr m_upSerializer; + Optional m_optionalPeerServiceDescriptionData; + ConnectionInfo m_peerConnectionInfo; + + ISessionCallback* m_pCallback{ nullptr }; + + Impl(std::unique_ptr&& upSocket, IAsioService& service, const VerticalServiceSettings& configuration) : + m_id(upSocket->SessionId()), + m_service(service), + m_configuration(configuration), + m_upSocket(std::move(upSocket)) + { + m_service.Log(m_id, "VerticalServiceSession()"); + } + + ~Impl() + { + m_service.Log(m_id, "~VerticalServiceSession()"); + } + + bool DisconnectedDueToIllegalClientEvent_(StringView event) + { + auto error = m_service.Alarm(m_id, EErrorCode::eCLIENT_ERROR, + "Unexpected client event in state ", m_state, ": ", event); + + if (!m_pCallback) + return true; + + if (m_state == EVerticalState::eDISCONNECTED) + return true; + + if (m_state != EVerticalState::eNOT_CONNECTED) + { + m_upSerializer->Signal(Serialize(NotificationData(ENotificationCode::eUNSPECIFIC, ESeverity::eFATAL, "SoftwareError"))); + } + + m_state = EVerticalState::eDISCONNECTED; + m_pCallback->OnDisconnected(m_id, m_state, error); + m_upSerializer->Disconnect(); + return true; + } + + void OnUnexpectedPeerEvent_(StringView event) + { + auto error = m_service.Alarm(m_id, EErrorCode::ePEER_ERROR, + "Unexpected peer event in state ", m_state, ": ", event); + + if (m_state == EVerticalState::eDISCONNECTED) + return; + + m_state = EVerticalState::eDISCONNECTED; + m_pCallback->OnDisconnected(m_id, m_state, error); + m_upSerializer->Signal(Serialize(NotificationData(ENotificationCode::ePROTOCOL_ERROR, ESeverity::eFATAL, error.m_text))); + m_upSerializer->Disconnect(); + } + + //============= implementation of ISerializerCallback ============ + void OnSocketConnected(const ConnectionInfo& connectionInfo) override + { + switch (m_state) + { + case EVerticalState::eNOT_CONNECTED: + m_state = EVerticalState::eSOCKET_CONNECTED; + m_peerConnectionInfo = connectionInfo; + m_pCallback->OnSocketConnected(m_id, m_state, connectionInfo); + return; + + default: + return OnUnexpectedPeerEvent_("Connected"); + } + } + + void On(const SupervisoryServiceDescriptionData& data) override + { + switch (m_state) + { + case EVerticalState::eSOCKET_CONNECTED: + m_state = EVerticalState::eSUPERVISORY_SERVICE_DESCRIPTION; + m_optionalPeerServiceDescriptionData = data; + m_pCallback->On(m_id, m_state, data); + return; + + default: + return OnUnexpectedPeerEvent_("ServiceDescription"); + } + } + + template + void On_(const DataT& data, const char* name) + { + switch (m_state) + { + case EVerticalState::eNOT_CONNECTED: + case EVerticalState::eDISCONNECTED: + return OnUnexpectedPeerEvent_(name); + + default: + m_pCallback->On(m_id, m_state, data); + return; + } + } + + void On(const GetConfigurationData& data) override { On_(data, "GetConfiguration"); } + void On(const SetConfigurationData& data) override { On_(data, "SetConfiguration"); } + void On(const SendWorkOrderInfoData& data) override { On_(data, "SendWorkOrderInfo"); } + void On(const NotificationData& data) override { On_(data, "Notification"); } + void On(const CheckAliveData& data) override { On_(data, "CheckAlive"); } + void On(const QueryHermesCapabilitiesData& data) override { On_(data, "QueryHermesCapabilities"); } + + void Signal_(StringView rawXml) + { + switch (m_state) + { + case EVerticalState::eNOT_CONNECTED: + case EVerticalState::eDISCONNECTED: + return; + + default: + m_upSerializer->Signal(rawXml); + return; + } + } + + void OnDisconnected(const Error& error) override + { + switch (m_state) + { + case EVerticalState::eDISCONNECTED: + return; + + default: + m_state = EVerticalState::eDISCONNECTED; + m_pCallback->OnDisconnected(m_id, m_state, error); + } + } + }; + + + Session::Session(std::unique_ptr&& upSocket, IAsioService& service, + const VerticalServiceSettings& configuration) + { + auto sessionId = upSocket->SessionId(); + m_spImpl = std::make_shared(std::move(upSocket), service, configuration); + m_spImpl->m_upSerializer = CreateSerializer(sessionId, service, *m_spImpl->m_upSocket); + } + + Session::~Session() + { + if (!m_spImpl) + return; + + m_spImpl->m_pCallback = nullptr; + } + + unsigned Session::Id() const { return m_spImpl->m_id; } + const Optional& Session::OptionalPeerServiceDescriptionData() const + { + return m_spImpl->m_optionalPeerServiceDescriptionData; + } + + const ConnectionInfo& Session::PeerConnectionInfo() const { return m_spImpl->m_peerConnectionInfo; } + + void Session::Connect(ISessionCallback& callback) + { + m_spImpl->m_pCallback = &callback; + m_spImpl->m_upSerializer->Connect(m_spImpl, *m_spImpl); + } + + void Session::Signal(const SupervisoryServiceDescriptionData& data) + { + switch (m_spImpl->m_state) + { + case EVerticalState::eSUPERVISORY_SERVICE_DESCRIPTION: + m_spImpl->m_state = EVerticalState::eCONNECTED; + m_spImpl->m_upSerializer->Signal(Serialize(data)); + return; + + default: + if (m_spImpl->DisconnectedDueToIllegalClientEvent_("ServiceDescription")) + return; + m_spImpl->m_upSerializer->Signal(Serialize(data)); + } + } + + void Session::Signal(const BoardArrivedData& data) { m_spImpl->Signal_(Serialize(data)); } + void Session::Signal(const BoardDepartedData& data) { m_spImpl->Signal_(Serialize(data)); } + void Session::Signal(const QueryWorkOrderInfoData& data) { m_spImpl->Signal_(Serialize(data)); } + void Session::Signal(const ReplyWorkOrderInfoData& data) { m_spImpl->Signal_(Serialize(data)); } + void Session::Signal(const CurrentConfigurationData& data) { m_spImpl->Signal_(Serialize(data)); } + void Session::Signal(const NotificationData& data) { m_spImpl->Signal_(Serialize(data)); } + void Session::Signal(const CheckAliveData& data) { m_spImpl->Signal_(Serialize(data)); } + void Session::Signal(const SendHermesCapabilitiesData& data) { m_spImpl->Signal_(Serialize(data)); } + + void Session::Disconnect() + { + switch (m_spImpl->m_state) + { + case EVerticalState::eDISCONNECTED: + return; + + default: + m_spImpl->m_state = EVerticalState::eDISCONNECTED; + m_spImpl->m_upSerializer->Disconnect(); + } + } + } +} \ No newline at end of file diff --git a/src/Hermes/VerticalServiceSession.h b/src/Hermes/VerticalServiceSession.h new file mode 100644 index 0000000..8c17551 --- /dev/null +++ b/src/Hermes/VerticalServiceSession.h @@ -0,0 +1,80 @@ +/*********************************************************************** +Copyright 2018 ASM Assembly Systems GmbH & Co. KG + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#pragma once + +#include + +#include + +namespace Hermes +{ + struct IAsioService; + struct IServerSocket; + + namespace VerticalService + { + struct ISessionCallback; + + class Session + { + public: + Session(std::unique_ptr&&, IAsioService&, const VerticalServiceSettings&); + Session(const Session&) = default; + Session& operator=(const Session&) = default; + Session(Session&&) = default; + Session& operator=(Session&&) = default; + ~Session(); + + explicit operator bool() const { return bool(m_spImpl); } + unsigned Id() const; + const Optional& OptionalPeerServiceDescriptionData() const; + const ConnectionInfo& PeerConnectionInfo() const; + + void Connect(ISessionCallback&); + void Signal(const SupervisoryServiceDescriptionData&); + void Signal(const BoardArrivedData&); + void Signal(const BoardDepartedData&); + void Signal(const QueryWorkOrderInfoData&); + void Signal(const ReplyWorkOrderInfoData&); + void Signal(const CurrentConfigurationData&); + void Signal(const NotificationData&); + void Signal(const CheckAliveData&); + void Signal(const SendHermesCapabilitiesData&); + void Disconnect(); + + private: + struct Impl; + std::shared_ptr m_spImpl; + + }; + + struct ISessionCallback + { + virtual void OnSocketConnected(unsigned id, EVerticalState, const ConnectionInfo&) = 0; + virtual void On(unsigned id, EVerticalState, const SupervisoryServiceDescriptionData&) = 0; + virtual void On(unsigned id, EVerticalState, const GetConfigurationData&) = 0; + virtual void On(unsigned id, EVerticalState, const SetConfigurationData&) = 0; + virtual void On(unsigned id, EVerticalState, const SendWorkOrderInfoData&) = 0; + virtual void On(unsigned id, EVerticalState, const QueryHermesCapabilitiesData&) = 0; + virtual void On(unsigned id, EVerticalState, const NotificationData&) = 0; + virtual void On(unsigned id, EVerticalState, const CheckAliveData&) = 0; + virtual void OnDisconnected(unsigned id, EVerticalState, const Error&) = 0; + }; + + + } +} diff --git a/src/include/Hermes.h b/src/include/Hermes.h index b6631ee..10ea635 100644 --- a/src/include/Hermes.h +++ b/src/include/Hermes.h @@ -33,7 +33,7 @@ limitations under the License. #define HERMES_VERSION "1.0" -#include +#include "HermesData.h" #ifdef __cplusplus extern "C" { @@ -44,195 +44,16 @@ extern "C" { // It maintains the order and the naming as far // as the C syntax and the coding guidelines allow it. - // Not part of The Hermes Standard, but used extensively: a non-owning string type, in the spirit of std::string_view. - // This relieves us from the need to terminate all strings with \0. - // Note that all the C interface structures are non-owning and need to be backed up by actual storage. - struct HermesStringView - { - const char* m_pData; // if nullptr then we have no string at all - not even an empty string - uint32_t m_size; - }; - // base port number, The Hermes Standard 2.1 static const uint16_t cHERMES_BASE_PORT = 50100U; // configuration port number, The Hermes Standard 2.2 static const uint16_t cHERMES_CONFIG_PORT = 1248U; - // protocol states, The Hermes Standard 2.6 - enum EHermesState - { - eHERMES_NOT_CONNECTED, - eHERMES_SOCKET_CONNECTED, // not part of The Hermes Standard statechart, but helpful to differentiate an intermediate step - eHERMES_SERVICE_DESCRIPTION_DOWNSTREAM, - eHERMES_NOT_AVAILABLE_NOT_READY, - eHERMES_BOARD_AVAILABLE, - eHERMES_MACHINE_READY, - eHERMES_AVAILABLE_AND_READY, - eHERMES_TRANSPORTING, - eHERMES_TRANSPORT_STOPPED, - eHERMES_TRANSPORT_FINISHED, - eHERMES_DISCONNECTED, // not part of the The Hermes Standard, but implicitly present as the terminal state - eHERMES_STATE_ENUM_SIZE // not part of The Hermes Standard; only for programming convenience - }; - // maximum message size, The Hermes Standard 3.1 static const unsigned cHERMES_MAX_MESSAGE_SIZE = 65536U; - // CheckAlive, The Hermes Standard 3.3 - struct HermesCheckAliveData - {}; - - // ServiceDescription, The Hermes Standard 3.4 - struct HermesServiceDescription - { - HermesStringView m_machineId; - uint32_t m_laneId; - HermesStringView m_version; - // SupportedFeatures is omitted because V1.0 does not specify any - }; - - // Notification, The Hermes Standard 3.5 - enum EHermesNotificationCode - { - eHERMES_UNSPECIFIC_NOTIFICATION = 0, - eHERMES_PROTOCOL_ERROR = 1, - eHERMES_CONNECTION_REFUSED_BECAUSE_OF_ESTABLISHED_CONNECTION = 2, - eHERMES_CONNECTION_RESET_BECAUSE_OF_CHANGED_CONFIGURATION = 3, - eHERMES_CONFIGURATION_ERROR = 4, - eHERMES_MACHINE_SHUTDOWN = 5, - eHERMES_NOTIFICATION_CODE_ENUM_SIZE // not part of The Hermes Standard; only for programming convenience - }; - - enum EHermesSeverity - { - eHERMES_UNKNOWN_SEVERITY = 0, - eHERMES_FATAL = 1, - eHERMES_ERROR = 2, - eHERMES_eWARNING = 3, - eHERMES_INFO = 4, - eHERMES_SEVERITY_ENUM_SIZE // not part of The Hermes Standard; only for programming convenience - }; - - struct HermesNotificationData - { - int32_t m_notificationCode; // must be in the range of EHermesNotificationCode - int32_t m_severity; // must be in the range of EHermesSeverity - HermesStringView m_description; - }; - - // BoardAvailable, The Hermes Standard 3.6 - enum EHermesBoardQuality - { - eHERMES_ANY_BOARD_QUALITY = 0, - eHERMES_GOOD_BOARD_QUALITY = 1, - eHERMES_FAILED_BOARD_QUALITY = 2, - eHERMES_BOARD_QUALITY_ENUM_SIZE // not part of The Hermes Standard; only for programming convenience - }; - - enum EHermesFlippedBoard - { - eHERMES_SIDE_UP_IS_UNKNOWN, - eHERMES_BOARD_TOP_SIDE_IS_UP = 1, - eHERMES_BOARD_BOTTOM_SIDE_IS_UP = 2, - eHERMES_FLIPPED_BOARD_ENUM_SIZE // not part of The Hermes Standard; only for programming convenience - }; - - struct HermesBoardAvailableData - { - HermesStringView m_boardId; - HermesStringView m_boardIdCreatedBy; - EHermesBoardQuality m_failedBoard; - HermesStringView m_optionalProductTypeId; - EHermesFlippedBoard m_flippedBoard; - HermesStringView m_optionalTopBarcode; - HermesStringView m_optionalBottomBarcode; - const double* m_pOptionalLengthInMM; // possibly nullptr since optional - const double* m_pOptionalWidthInMM; // possibly nullptr since optional - const double* m_pOptionalThicknessInMM; // possibly nullptr since optional - const double* m_pOptionalConveyorSpeedInMMPerSecs; // possibly nullptr since optional - const double* m_pOptionalTopClearanceHeightInMM; // possibly nullptr since optional - const double* m_pOptionalBottomClearanceHeightInMM; // possibly nullptr since optional - }; - - // RevokeBoardAvailable, The Hermes Standard 3.7 - struct HermesRevokeBoardAvailableData - {}; - - // MachineReady, The Hermes Standard 3.8 - struct HermesMachineReadyData - { - EHermesBoardQuality m_failedBoard; - }; - - // RevokeMachineReady, The Hermes Standard 3.9 - struct HermesRevokeMachineReadyData - {}; - - // StartTransport, The Hermes Standard 3.10 - struct HermesStartTransportData - { - HermesStringView m_boardId; - const double* m_pOptionalConveyorSpeedInMMPerSecs; // possibly nullptr since optional - }; - - // StopTransport, The Hermes Standard 3.11 - enum EHermesTransferState - { - eHERMES_TRANSFER_NOT_STARTED = 1, - eHERMES_TRANSFER_INCOMPLETE = 2, - eHERMES_TRANSFER_COMPLETE = 3, - eHERMES_TRANSFER_STATE_ENUM_SIZE // not part of The Hermes Standard; only for programming convenience - }; - - struct HermesStopTransportData - { - EHermesTransferState m_transferState; // must be in the range of EHermesTransferState - HermesStringView m_boardId; - }; - - // TransportFinished, The Hermes Standard 3.12 - struct HermesTransportFinishedData - { - EHermesTransferState m_transferState; // must be in the range of EHermesTransferState - HermesStringView m_boardId; - }; - - // SetConfiguration, The Hermes Standard 3.13 - struct HermesUpstreamConfiguration - { - uint32_t m_upstreamLaneId; - HermesStringView m_hostAddress; - uint16_t m_port; // if 0 then HermesProtocol will use the default port number for this lane - }; - - struct HermesDownstreamConfiguration - { - uint32_t m_downstreamLaneId; - HermesStringView m_optionalClientAddress; // if 0 then requests from any client will be accepted - uint16_t m_port; // if 0, then HermesProcol will use the default port for this lane - }; - - struct HermesSetConfigurationData - { - HermesStringView m_machineId; - const HermesUpstreamConfiguration** m_upstreamConfigurations; //pointer to first element of array - uint32_t m_upstreamConfigurationCount; //count of array elements - const HermesDownstreamConfiguration** m_downstreamConfigurations; //pointer to first element of array - uint32_t m_downstreamConfigurationCount; //count of array elements - }; - - struct HermesGetConfigurationData - {}; - - struct HermesCurrentConfigurationData - { - HermesStringView m_optionalMachineId; - const HermesUpstreamConfiguration** m_upstreamConfigurations; //pointer to first element of array - uint32_t m_upstreamConfigurationCount; //count of array elements - const HermesDownstreamConfiguration** m_downstreamConfigurations; //pointer to first element of array - uint32_t m_downstreamConfigurationCount; //count of array elements - }; + // other data is specified in HermesData.h, which is separate since it is generated // What follows are the callbacks containing the various messages listed above. // This is more about API design and has no direct correspondence in The Hermes Standard. @@ -247,14 +68,6 @@ extern "C" { void* m_pData; }; - // For an established connection, an info about the connected foreign host and the foreign port is provided: - struct HermesConnectionInfo - { - HermesStringView m_address; - uint16_t m_port; - HermesStringView m_hostName; - }; - // The remote host has connected struct HermesConnectedCallback { @@ -269,10 +82,17 @@ extern "C" { void* m_pData; }; + // Command received: + struct HermesCommandCallback + { + void(*m_pCall)(void* /*m_pData*/, uint32_t /*sessionId*/, const HermesCommandData*); + void* m_pData; + }; + // The remote host has sent its service description struct HermesServiceDescriptionCallback { - void(*m_pCall)(void* /*m_pData*/, uint32_t /*sessionId*/, EHermesState, const HermesServiceDescription*); + void(*m_pCall)(void* /*m_pData*/, uint32_t /*sessionId*/, EHermesState, const HermesServiceDescriptionData*); void* m_pData; }; @@ -318,21 +138,22 @@ extern "C" { void* m_pData; }; - // Disconnections might well be due to an error condition. - enum EHermesErrorCode + struct HermesBoardForecastCallback { - eHERMES_SUCCESS, - eHERMES_IMPLEMENTATION_ERROR, // error inside the Hermes DLL - eHERMES_PEER_ERROR, // the remote host has misbehaved - eHERMES_CLIENT_ERROR, // the client code making the API calls has misbehaved - eHERMES_NETWORK_ERROR, // something is wrong with the network or its configuration - eHERMES_TIMEOUT, // a specified timeout has been reached - eHERMES_ERROR_CODE_ENUM_SIZE + void(*m_pCall)(void* /*m_pData*/, uint32_t /*sessionId*/, EHermesState, const HermesBoardForecastData*); + void* m_pData; }; - struct HermesError + + struct HermesQueryBoardInfoCallback { - EHermesErrorCode m_code; - HermesStringView m_text; + void(*m_pCall)(void* /*m_pData*/, uint32_t /*sessionId*/, const HermesQueryBoardInfoData*); + void* m_pData; + }; + + struct HermesSendBoardInfoCallback + { + void(*m_pCall)(void* /*m_pData*/, uint32_t /*sessionId*/, const HermesSendBoardInfoData*); + void* m_pData; }; struct HermesDisconnectedCallback @@ -352,40 +173,13 @@ extern "C" { }; // Trace data from the implementation. Note that handling of the traces must be thread-safe. - enum EHermesTraceType - { - eHERMES_TRACE_SENT, // raw message sent - eHERMES_TRACE_RECEIVED, // raw message received - eHERMES_TRACE_DEBUG, // debug trace from implementation internals - eHERMES_TRACE_INFO, - eHERMES_TRACE_WARNING, - eHERMES_TRACE_ERROR, - eHERMES_TRACE_TYPE_ENUM_SIZE - }; struct HermesTraceCallback { void(*m_pCall)(void* /*m_pData*/, unsigned /*sessionId*/, EHermesTraceType, HermesStringView /*trace*/); void *m_pData; }; - enum EHermesCheckState - { - eHERMES_CHECK_SEND_AND_RECEIVE, - eHERMES_CHECK_ONLY_RECEIVE, - eHERMES_CHECK_STATE_ENUM_SIZE - }; - // The interface for the connection to the downstream machine. - // Configuration settings for our connection: - struct HermesDownstreamSettings - { - HermesStringView m_machineId; // required for the service description - HermesStringView m_optionalClientAddress; // if empty then requests from any client will be accepted - uint16_t m_port; // if 0, then HermesProcol will use the default port for this lane - uint32_t m_checkAlivePeriodInSeconds; // if 0 then no check alive messages will be sent - uint32_t m_reconnectWaitTimeInSeconds; - EHermesCheckState m_checkState; - }; // These are the callbacks to deal with: struct HermesDownstreamCallbacks @@ -396,9 +190,11 @@ extern "C" { HermesRevokeMachineReadyCallback m_revokeMachineReadyCallback; HermesStartTransportCallback m_startTransportCallback; HermesStopTransportCallback m_stopTransportCallback; + HermesQueryBoardInfoCallback m_queryBoardInfoCallback; HermesNotificationCallback m_notificationCallback; HermesStateCallback m_stateCallback; HermesCheckAliveCallback m_checkAliveCallback; + HermesCommandCallback m_commandCallback; HermesDisconnectedCallback m_disconnectedCallback; HermesTraceCallback m_traceCallback; }; @@ -417,29 +213,26 @@ extern "C" { HERMESPROTOCOL_API void PostHermesDownstream(HermesDownstream*, HermesVoidCallback); HERMESPROTOCOL_API void EnableHermesDownstream(HermesDownstream*, const HermesDownstreamSettings*); - HERMESPROTOCOL_API void SignalHermesDownstreamServiceDescription(HermesDownstream*, uint32_t sessionId, const HermesServiceDescription*); + HERMESPROTOCOL_API void SignalHermesDownstreamServiceDescription(HermesDownstream*, uint32_t sessionId, const HermesServiceDescriptionData*); HERMESPROTOCOL_API void SignalHermesBoardAvailable(HermesDownstream*, uint32_t sessionId, const HermesBoardAvailableData*); HERMESPROTOCOL_API void SignalHermesRevokeBoardAvailable(HermesDownstream*, uint32_t sessionId, const HermesRevokeBoardAvailableData*); HERMESPROTOCOL_API void SignalHermesTransportFinished(HermesDownstream*, uint32_t sessionId, const HermesTransportFinishedData*); + HERMESPROTOCOL_API void SignalHermesBoardForecast(HermesDownstream*, uint32_t sessionId, const HermesBoardForecastData*); + HERMESPROTOCOL_API void SignalHermesSendBoardInfo(HermesDownstream*, uint32_t sessionId, const HermesSendBoardInfoData*); HERMESPROTOCOL_API void SignalHermesDownstreamNotification(HermesDownstream*, uint32_t sessionId, const HermesNotificationData*); HERMESPROTOCOL_API void SignalHermesDownstreamCheckAlive(HermesDownstream*, uint32_t sessionId, const HermesCheckAliveData*); + HERMESPROTOCOL_API void SignalHermesDownstreamCommand(HermesDownstream*, uint32_t sessionId, const HermesCommandData*); HERMESPROTOCOL_API void ResetHermesDownstream(HermesDownstream*, const HermesNotificationData*); HERMESPROTOCOL_API void DisableHermesDownstream(HermesDownstream*, const HermesNotificationData*); HERMESPROTOCOL_API void StopHermesDownstream(HermesDownstream*); HERMESPROTOCOL_API void DeleteHermesDownstream(HermesDownstream*); - // The interface for the connection to the upstream machine. - // Configuration settings for our connection: - struct HermesUpstreamSettings - { - HermesStringView m_machineId; // required for the service description - HermesStringView m_hostAddress; - uint16_t m_port; // if 0 then HermesProtocol will use the default port number for this lane - uint32_t m_checkAlivePeriodInSeconds; - uint32_t m_reconnectWaitTimeInSeconds; - EHermesCheckState m_checkState; - }; + // interface for testing with raw or no xml: + HERMESPROTOCOL_API void SignalHermesDownstreamRawXml(HermesDownstream*, uint32_t sessionId, HermesStringView); + HERMESPROTOCOL_API void ResetHermesDownstreamRawXml(HermesDownstream*, HermesStringView); + + // The interface for the connection to the downstream machine. // These are the callbacks to deal with: struct HermesUpstreamCallbacks @@ -449,9 +242,12 @@ extern "C" { HermesBoardAvailableCallback m_boardAvailableCallback; HermesRevokeBoardAvailableCallback m_revokeBoardAvailableCallback; HermesTransportFinishedCallback m_transportFinishedCallback; + HermesBoardForecastCallback m_boardForecastCallback; + HermesSendBoardInfoCallback m_sendBoardInfoCallback; HermesNotificationCallback m_notificationCallback; HermesStateCallback m_stateCallback; HermesCheckAliveCallback m_checkAliveCallback; + HermesCommandCallback m_commandCallback; HermesDisconnectedCallback m_disconnectedCallback; HermesTraceCallback m_traceCallback; }; @@ -463,19 +259,25 @@ extern "C" { HERMESPROTOCOL_API void PostHermesUpstream(HermesUpstream*, HermesVoidCallback); HERMESPROTOCOL_API void EnableHermesUpstream(HermesUpstream*, const HermesUpstreamSettings*); - HERMESPROTOCOL_API void SignalHermesUpstreamServiceDescription(HermesUpstream*, uint32_t sessionId, const HermesServiceDescription*); + HERMESPROTOCOL_API void SignalHermesUpstreamServiceDescription(HermesUpstream*, uint32_t sessionId, const HermesServiceDescriptionData*); HERMESPROTOCOL_API void SignalHermesMachineReady(HermesUpstream*, uint32_t sessionId, const HermesMachineReadyData*); HERMESPROTOCOL_API void SignalHermesRevokeMachineReady(HermesUpstream*, uint32_t sessionId, const HermesRevokeMachineReadyData*); HERMESPROTOCOL_API void SignalHermesStartTransport(HermesUpstream*, uint32_t sessionId, const HermesStartTransportData*); HERMESPROTOCOL_API void SignalHermesStopTransport(HermesUpstream*, uint32_t sessionId, const HermesStopTransportData*); + HERMESPROTOCOL_API void SignalHermesQueryBoardInfo(HermesUpstream*, uint32_t sessionId, const HermesQueryBoardInfoData*); HERMESPROTOCOL_API void SignalHermesUpstreamNotification(HermesUpstream*, uint32_t sessionId, const HermesNotificationData*); HERMESPROTOCOL_API void SignalHermesUpstreamCheckAlive(HermesUpstream*, uint32_t sessionId, const HermesCheckAliveData*); + HERMESPROTOCOL_API void SignalHermesUpstreamCommand(HermesUpstream*, uint32_t sessionId, const HermesCommandData*); HERMESPROTOCOL_API void ResetHermesUpstream(HermesUpstream*, const HermesNotificationData*); HERMESPROTOCOL_API void DisableHermesUpstream(HermesUpstream*, const HermesNotificationData*); HERMESPROTOCOL_API void StopHermesUpstream(HermesUpstream*); HERMESPROTOCOL_API void DeleteHermesUpstream(HermesUpstream*); + // interface for testing with raw xml: + HERMESPROTOCOL_API void SignalHermesUpstreamRawXml(HermesUpstream*, uint32_t sessionId, HermesStringView); + HERMESPROTOCOL_API void ResetHermesUpstreamRawXml(HermesUpstream*, HermesStringView); + // For the remote connection configuration, another set of callbacks is required. // The following are the callbacks for the configuring client: struct HermesCurrentConfigurationCallback @@ -492,13 +294,13 @@ extern "C" { struct HermesSetConfigurationCallback { - void(*m_pCall)(void* /*m_pData*/, uint32_t /*sessionId*/, const HermesConnectionInfo*, const HermesSetConfigurationData*); + void(*m_pCall)(void* /*m_pData*/, uint32_t /*sessionId*/, const HermesSetConfigurationData*, const HermesConnectionInfo*); void* m_pData; }; struct HermesGetConfigurationCallback { - void(*m_pCall)(void* /*m_pData*/, uint32_t/*sessionId*/, const HermesConnectionInfo*, const HermesGetConfigurationData*); + void(*m_pCall)(void* /*m_pData*/, uint32_t/*sessionId*/, const HermesGetConfigurationData*, const HermesConnectionInfo*); void* m_pData; }; @@ -527,12 +329,6 @@ extern "C" { unsigned timeoutInSeconds, const HermesGetConfigurationCallbacks*); // The API to interface with The Hermes Standard service running on the equipment: - struct HermesConfigurationServiceSettings - { - uint16_t m_port; // if 0 then use default - uint32_t m_reconnectWaitTimeInSeconds; - }; - struct HermesConfigurationServiceCallbacks { HermesConnectedCallback m_connectedCallback; @@ -556,6 +352,152 @@ extern "C" { HERMESPROTOCOL_API void StopHermesConfigurationService(HermesConfigurationService*); HERMESPROTOCOL_API void DeleteHermesConfigurationService(HermesConfigurationService*); + // vertical channel: + struct HermesVerticalConnectedCallback + { + void(*m_pCall)(void* /*m_pData*/, uint32_t /*sessionId*/, EHermesVerticalState, const HermesConnectionInfo*); + void* m_pData; + }; + + struct HermesSupervisoryServiceDescriptionCallback + { + void(*m_pCall)(void* /*m_pData*/, uint32_t /*sessionId*/, EHermesVerticalState, const HermesSupervisoryServiceDescriptionData*); + void* m_pData; + }; + + struct HermesSendWorkOrderInfoCallback + { + void(*m_pCall)(void* /*m_pData*/, uint32_t /*sessionId*/, const HermesSendWorkOrderInfoData*); + void* m_pData; + }; + + struct HermesQueryHermesCapabilitiesCallback + { + void(*m_pCall)(void* /*m_pData*/, uint32_t /*sessionId*/, const HermesQueryHermesCapabilitiesData*); + void* m_pData; + }; + + struct HermesVerticalDisconnectedCallback + { + void(*m_pCall)(void* /*m_pData*/, uint32_t /*sessionId*/, EHermesVerticalState, const HermesError*); + void* m_pData; + }; + + struct HermesVerticalServiceCallbacks + { + HermesVerticalConnectedCallback m_connectedCallback; + HermesSupervisoryServiceDescriptionCallback m_serviceDescriptionCallback; + HermesSendWorkOrderInfoCallback m_sendWorkOrderInfoCallback; + HermesNotificationCallback m_notificationCallback; + HermesCheckAliveCallback m_checkAliveCallback; + HermesGetConfigurationCallback m_getConfigurationCallback; + HermesSetConfigurationCallback m_setConfigurationCallback; + HermesQueryHermesCapabilitiesCallback m_queryHermesCapabilitiesCallback; + HermesVerticalDisconnectedCallback m_disconnectedCallback; + HermesTraceCallback m_traceCallback; + }; + + // The calling API + struct HermesVerticalService; // the opaque handle to the supervisor service + HERMESPROTOCOL_API HermesVerticalService* CreateHermesVerticalService(const HermesVerticalServiceCallbacks*); + HERMESPROTOCOL_API void RunHermesVerticalService(HermesVerticalService*); // blocks until ::StopHermesDownstream is called + HERMESPROTOCOL_API void PostHermesVerticalService(HermesVerticalService*, HermesVoidCallback); + HERMESPROTOCOL_API void EnableHermesVerticalService(HermesVerticalService*, const HermesVerticalServiceSettings*); + + HERMESPROTOCOL_API void SignalHermesVerticalServiceDescription(HermesVerticalService*, uint32_t sessionId, const HermesSupervisoryServiceDescriptionData*); + HERMESPROTOCOL_API void SignalHermesQueryWorkOrderInfo(HermesVerticalService*, uint32_t sessionId, const HermesQueryWorkOrderInfoData*); + HERMESPROTOCOL_API void SignalHermesReplyWorkOrderInfo(HermesVerticalService*, uint32_t sessionId, const HermesReplyWorkOrderInfoData*); + HERMESPROTOCOL_API void SignalHermesVerticalServiceNotification(HermesVerticalService*, uint32_t sessionId, const HermesNotificationData*); + HERMESPROTOCOL_API void SignalHermesVerticalServiceCheckAlive(HermesVerticalService*, uint32_t sessionId, const HermesCheckAliveData*); + HERMESPROTOCOL_API void SignalHermesVerticalCurrentConfiguration(HermesVerticalService*, uint32_t sessionId, const HermesCurrentConfigurationData*); + HERMESPROTOCOL_API void SignalHermesSendHermesCapabilities(HermesVerticalService*, uint32_t sessionId, const HermesSendHermesCapabilitiesData*); + + // if sessionId == 0, then the following two are propagated to all clients that have specified FeatureBoardTracking + HERMESPROTOCOL_API void SignalHermesBoardArrived(HermesVerticalService*, uint32_t sessionId, const HermesBoardArrivedData*); + HERMESPROTOCOL_API void SignalHermesBoardDeparted(HermesVerticalService*, uint32_t sessionId, const HermesBoardDepartedData*); + + HERMESPROTOCOL_API void ResetHermesVerticalServiceSession(HermesVerticalService*, uint32_t sessionId, const HermesNotificationData*); + + HERMESPROTOCOL_API void DisableHermesVerticalService(HermesVerticalService*, const HermesNotificationData*); + HERMESPROTOCOL_API void StopHermesVerticalService(HermesVerticalService*); + HERMESPROTOCOL_API void DeleteHermesVerticalService(HermesVerticalService*); + + struct HermesQueryWorkOrderInfoCallback + { + void(*m_pCall)(void* /*m_pData*/, uint32_t /*sessionId*/, const HermesQueryWorkOrderInfoData*); + void* m_pData; + }; + + struct HermesReplyWorkOrderInfoCallback + { + void(*m_pCall)(void* /*m_pData*/, uint32_t /*sessionId*/, const HermesReplyWorkOrderInfoData*); + void* m_pData; + }; + + struct HermesBoardArrivedCallback + { + void(*m_pCall)(void* /*m_pData*/, uint32_t /*sessionId*/, const HermesBoardArrivedData*); + void* m_pData; + }; + + struct HermesBoardDepartedCallback + { + void(*m_pCall)(void* /*m_pData*/, uint32_t /*sessionId*/, const HermesBoardDepartedData*); + void* m_pData; + }; + + struct HermesSendHermesCapabilitiesCallback + { + void(*m_pCall)(void* /*m_pData*/, uint32_t /*sessionId*/, const HermesSendHermesCapabilitiesData*); + void* m_pData; + }; + + struct HermesVerticalClientCallbacks + { + HermesVerticalConnectedCallback m_connectedCallback; + HermesSupervisoryServiceDescriptionCallback m_serviceDescriptionCallback; + HermesBoardArrivedCallback m_boardArrivedCallback; + HermesBoardDepartedCallback m_boardDepartedCallback; + HermesSendHermesCapabilitiesCallback m_sendHermesCapabilitiesCallback; + HermesQueryWorkOrderInfoCallback m_queryWorkOrderInfoCallback; + HermesReplyWorkOrderInfoCallback m_replyWorkOrderInfoCallback; + HermesNotificationCallback m_notificationCallback; + HermesCurrentConfigurationCallback m_currentConfigurationCallback; + HermesCheckAliveCallback m_checkAliveCallback; + HermesVerticalDisconnectedCallback m_disconnectedCallback; + HermesTraceCallback m_traceCallback; + }; + + + // The calling API + struct HermesVerticalClient; // the opaque handle to the supervisor service + HERMESPROTOCOL_API HermesVerticalClient* CreateHermesVerticalClient(const HermesVerticalClientCallbacks*); + HERMESPROTOCOL_API void RunHermesVerticalClient(HermesVerticalClient*); // blocks until ::StopHermesDownstream is called + HERMESPROTOCOL_API void PostHermesVerticalClient(HermesVerticalClient*, HermesVoidCallback); + HERMESPROTOCOL_API void EnableHermesVerticalClient(HermesVerticalClient*, const HermesVerticalClientSettings*); + + HERMESPROTOCOL_API void SignalHermesVerticalClientDescription(HermesVerticalClient*, uint32_t sessionId, const HermesSupervisoryServiceDescriptionData*); + HERMESPROTOCOL_API void SignalHermesSendWorkOrderInfo(HermesVerticalClient*, uint32_t sessionId, const HermesSendWorkOrderInfoData*); + HERMESPROTOCOL_API void SignalHermesVerticalGetConfiguration(HermesVerticalClient*, uint32_t sessionId, const HermesGetConfigurationData*); + HERMESPROTOCOL_API void SignalHermesVerticalSetConfiguration(HermesVerticalClient*, uint32_t sessionId, const HermesSetConfigurationData*); + HERMESPROTOCOL_API void SignalHermesVerticalQueryHermesCapabilities(HermesVerticalClient*, uint32_t sessionId, const HermesQueryHermesCapabilitiesData*); + + HERMESPROTOCOL_API void SignalHermesVerticalClientNotification(HermesVerticalClient*, uint32_t sessionId, const HermesNotificationData*); + HERMESPROTOCOL_API void SignalHermesVerticalClientCheckAlive(HermesVerticalClient*, uint32_t sessionId, const HermesCheckAliveData*); + + HERMESPROTOCOL_API void ResetHermesVerticalClient(HermesVerticalClient*, const HermesNotificationData*); + + // interface for testing with raw xml: + HERMESPROTOCOL_API void SignalHermesVerticalClientRawXml(HermesVerticalClient*, uint32_t sessionId, HermesStringView); + HERMESPROTOCOL_API void ResetHermesVerticalClientRawXml(HermesVerticalClient*, HermesStringView); + + HERMESPROTOCOL_API void DisableHermesVerticalClient(HermesVerticalClient*, const HermesNotificationData*); + HERMESPROTOCOL_API void StopHermesVerticalClient(HermesVerticalClient*); + HERMESPROTOCOL_API void DeleteHermesVerticalClient(HermesVerticalClient*); + + + + #ifdef __cplusplus } diff --git a/src/include/Hermes.hpp b/src/include/Hermes.hpp index e371600..60078da 100644 --- a/src/include/Hermes.hpp +++ b/src/include/Hermes.hpp @@ -26,6 +26,8 @@ limitations under the License. // These are lightweight C++ wrappers around the Hermes C Api: namespace Hermes { + enum class EState; + //======================= Downstream interface ===================================== struct IDownstreamCallback; class Downstream @@ -40,14 +42,21 @@ namespace Hermes template void Post(F&&); void Enable(const DownstreamSettings&); - void Signal(unsigned sessionId, const ServiceDescription&); + void Signal(unsigned sessionId, const ServiceDescriptionData&); void Signal(unsigned sessionId, const BoardAvailableData&); void Signal(unsigned sessionId, const RevokeBoardAvailableData&); void Signal(unsigned sessionId, const TransportFinishedData&); + void Signal(unsigned sessionId, const BoardForecastData&); + void Signal(unsigned sessionId, const SendBoardInfoData&); void Signal(unsigned sessionId, const NotificationData&); void Signal(unsigned sessionId, const CheckAliveData&); - + void Signal(unsigned sessionId, const CommandData&); void Reset(const NotificationData&); + + // raw XML for testing + void Signal(unsigned sessionId, StringView rawXml); + void Reset(StringView rawXml); + void Disable(const NotificationData&); void Stop(); @@ -66,14 +75,16 @@ namespace Hermes virtual void OnConnected(unsigned sessionId, EState, const ConnectionInfo&) = 0; virtual void On(unsigned sessionId, const NotificationData&) = 0; virtual void On(unsigned /*sessionId*/, const CheckAliveData&) {} // not necessarily interesting, hence not abstract + virtual void On(unsigned sessionId, const CommandData&) = 0; virtual void OnState(unsigned sessionId, EState) = 0; virtual void OnDisconnected(unsigned sessionId, EState, const Error&) = 0; - virtual void On(unsigned sessionId, EState, const ServiceDescription&) = 0; + virtual void On(unsigned sessionId, EState, const ServiceDescriptionData&) = 0; virtual void On(unsigned sessionId, EState, const MachineReadyData&) = 0; virtual void On(unsigned sessionId, EState, const RevokeMachineReadyData&) = 0; virtual void On(unsigned sessionId, EState, const StartTransportData&) = 0; virtual void On(unsigned sessionId, EState, const StopTransportData&) = 0; + virtual void On(unsigned /*sessionId*/, const QueryBoardInfoData&) {} // not necessarily interesting, hence not abstract virtual void OnTrace(unsigned sessionId, ETraceType, StringView trace) = 0; @@ -95,15 +106,21 @@ namespace Hermes template void Post(F&&); void Enable(const UpstreamSettings&); - void Signal(unsigned sessionId, const ServiceDescription&); + void Signal(unsigned sessionId, const ServiceDescriptionData&); void Signal(unsigned sessionId, const MachineReadyData&); void Signal(unsigned sessionId, const RevokeMachineReadyData&); void Signal(unsigned sessionId, const StartTransportData&); void Signal(unsigned sessionId, const StopTransportData&); + void Signal(unsigned sessionId, const QueryBoardInfoData&); void Signal(unsigned sessionId, const NotificationData&); void Signal(unsigned sessionId, const CheckAliveData&); - + void Signal(unsigned sessionId, const CommandData&); void Reset(const NotificationData&); + + // raw XML for testing + void Signal(unsigned sessionId, StringView rawXml); + void Reset(StringView rawXml); + void Disable(const NotificationData&); void Stop(); @@ -122,13 +139,16 @@ namespace Hermes virtual void OnConnected(unsigned sessionId, EState, const ConnectionInfo&) = 0; virtual void On(unsigned sessionId, const NotificationData&) = 0; virtual void On(unsigned /*sessionId*/, const CheckAliveData&) {} // not necessarily interesting, hence not abstract + virtual void On(unsigned sessionId, const CommandData&) = 0; virtual void OnState(unsigned sessionId, EState) = 0; virtual void OnDisconnected(unsigned sessionId, EState, const Error&) = 0; - virtual void On(unsigned sessionId, EState, const ServiceDescription&) = 0; + virtual void On(unsigned sessionId, EState, const ServiceDescriptionData&) = 0; virtual void On(unsigned sessionId, EState, const BoardAvailableData&) = 0; virtual void On(unsigned sessionId, EState, const RevokeBoardAvailableData&) = 0; virtual void On(unsigned sessionId, EState, const TransportFinishedData&) = 0; + virtual void On(unsigned /*sessionId*/, EState, const BoardForecastData&) {} // not necessarily interesting, hence not abstract + virtual void On(unsigned /*sessionId*/, const SendBoardInfoData&) {} // not necessarily interesting, hence not abstract virtual void OnTrace(unsigned sessionId, ETraceType, StringView trace) = 0; @@ -198,30 +218,151 @@ namespace Hermes ITraceCallback* // optional ); + //======================= VerticalService interface ===================================== + struct IVerticalServiceCallback; + class VerticalService + { + public: + explicit VerticalService(IVerticalServiceCallback&); + VerticalService(const VerticalService&) = delete; + VerticalService& operator=(const VerticalService&) = delete; + ~VerticalService() { ::DeleteHermesVerticalService(m_pImpl); } + + void Run(); + template void Post(F&&); + void Enable(const VerticalServiceSettings&); + + void Signal(unsigned sessionId, const SupervisoryServiceDescriptionData&); + void Signal(unsigned sessionId, const BoardArrivedData&); // only to a specific client + void Signal(const BoardArrivedData&); // to all clients that have specified FeatureBoardTracking + void Signal(unsigned sessionId, const BoardDepartedData&); // only to a specific client + void Signal(const BoardDepartedData&); // to all clients that have specified FeatureBoardTracking + void Signal(unsigned sessionId, const QueryWorkOrderInfoData&); + void Signal(unsigned sessionId, const ReplyWorkOrderInfoData&); + void Signal(unsigned sessionId, const SendHermesCapabilitiesData&); + void Signal(unsigned sessionId, const CurrentConfigurationData&); + void Signal(unsigned sessionId, const NotificationData&); + void Signal(unsigned sessionId, const CheckAliveData&); + void Signal(unsigned sessionId, const CommandData&); + void ResetSession(unsigned sessionId, const NotificationData&); + + void Disable(const NotificationData&); + void Stop(); + + private: + HermesVerticalService* m_pImpl = nullptr; + }; + + struct IVerticalServiceCallback + { + IVerticalServiceCallback() = default; + + // callbacks must not be moved or copied! + IVerticalServiceCallback(const IVerticalServiceCallback&) = delete; + IVerticalServiceCallback& operator=(const IVerticalServiceCallback&) = delete; + + virtual void OnConnected(unsigned sessionId, EVerticalState, const ConnectionInfo&) = 0; + virtual void On(unsigned sessionId, EVerticalState, const SupervisoryServiceDescriptionData&) = 0; + virtual void On(unsigned sessionId, const GetConfigurationData&, const ConnectionInfo&) = 0; + virtual void On(unsigned sessionId, const SetConfigurationData&, const ConnectionInfo&) = 0; + virtual void On(unsigned /*sessionId*/, const SendWorkOrderInfoData&) {}; // not necessarily interesting, hence not abstract + virtual void On(unsigned sessionId, const NotificationData&) = 0; + virtual void On(unsigned sessionId, const QueryHermesCapabilitiesData&) = 0; + virtual void On(unsigned /*sessionId*/, const CheckAliveData&) {} // not necessarily interesting, hence not abstract + virtual void OnDisconnected(unsigned sessionId, EVerticalState, const Error&) = 0; + + virtual void OnTrace(unsigned sessionId, ETraceType, StringView trace) = 0; + + protected: + virtual ~IVerticalServiceCallback() = default; + }; + + //======================= VerticalClient interface ===================================== + struct IVerticalClientCallback; + class VerticalClient + { + public: + explicit VerticalClient(IVerticalClientCallback&); + VerticalClient(const VerticalClient&) = delete; + VerticalClient& operator=(const VerticalClient&) = delete; + ~VerticalClient() { ::DeleteHermesVerticalClient(m_pImpl); } + + void Run(); + template void Post(F&&); + void Enable(const VerticalClientSettings&); + + void Signal(unsigned sessionId, const SupervisoryServiceDescriptionData&); + void Signal(unsigned sessionId, const GetConfigurationData&); + void Signal(unsigned sessionId, const SetConfigurationData&); + void Signal(unsigned sessionId, const QueryHermesCapabilitiesData&); + void Signal(unsigned sessionId, const SendWorkOrderInfoData&); + void Signal(unsigned sessionId, const NotificationData&); + void Signal(unsigned sessionId, const CheckAliveData&); + void Reset(const NotificationData&); + + // raw XML for testing + void Signal(unsigned sessionId, StringView rawXml); + void Reset(StringView rawXml); + + void Disable(const NotificationData&); + void Stop(); + + private: + HermesVerticalClient* m_pImpl = nullptr; + }; + + struct IVerticalClientCallback + { + IVerticalClientCallback() = default; + + // callbacks must not be moved or copied! + IVerticalClientCallback(const IVerticalClientCallback&) = delete; + IVerticalClientCallback& operator=(const IVerticalClientCallback&) = delete; + + virtual void OnConnected(unsigned sessionId, EVerticalState, const ConnectionInfo&) = 0; + virtual void On(unsigned sessionId, EVerticalState, const SupervisoryServiceDescriptionData&) = 0; + virtual void On(unsigned /*sessionId*/, const BoardArrivedData&) {}; // not necessarily interesting, hence not abstract + virtual void On(unsigned /*sessionId*/, const BoardDepartedData&) {} // not necessarily interesting, hence not abstract + virtual void On(unsigned sessionId, const QueryWorkOrderInfoData&) = 0; + virtual void On(unsigned sessionId, const ReplyWorkOrderInfoData&) = 0; + virtual void On(unsigned /*sessionId*/, const CurrentConfigurationData&) {} // not necessarily interesting, hence not abstract + virtual void On(unsigned /*sessionId*/, const SendHermesCapabilitiesData&) {} // not necessarily interesting, hence not abstract + virtual void On(unsigned sessionId, const NotificationData&) = 0; + virtual void On(unsigned /*sessionId*/, const CheckAliveData&) {} // not necessarily interesting, hence not abstract + virtual void OnDisconnected(unsigned sessionId, EVerticalState, const Error&) = 0; + + virtual void OnTrace(unsigned sessionId, ETraceType, StringView trace) = 0; + + protected: + virtual ~IVerticalClientCallback() = default; + }; + // Convenience interface for situations in which the same class implements IUpstreamCallback and IDownstreamCallback. // Because some function names clash, this adds a level of indirection to different function names, eg. - // On(unsigned, const ServiceDescription&) + // On(unsigned, const ServiceDescriptionData&) // becomes: - // OnUpstream(unsigned, const ServiceDescription&) + // OnUpstream(unsigned, const ServiceDescriptionData&) // and - // OnDownstream(unsigned, const ServiceDescription&) + // OnDownstream(unsigned, const ServiceDescriptionData&) // // Deriving from UpstreamCallbackHelper and DownstreamCallbackHelper gives unique names for all callback methods. // Unambiguous methods, eg. On(unsigned, EState, const BoardAvailableData&) remain unchanged! struct UpstreamCallbackHelper : IUpstreamCallback { virtual void OnUpstreamConnected(unsigned sessionId, EState, const ConnectionInfo&) = 0; - virtual void OnUpstream(unsigned sessionId, EState, const ServiceDescription&) = 0; + virtual void OnUpstream(unsigned sessionId, EState, const ServiceDescriptionData&) = 0; virtual void OnUpstream(unsigned sessionId, const NotificationData& data) = 0; virtual void OnUpstream(unsigned sessionId, const CheckAliveData& data) = 0; + virtual void OnUpstream(unsigned sessionId, const CommandData& data) = 0; virtual void OnUpstreamState(unsigned sessionId, EState) = 0; virtual void OnUpstreamDisconnected(unsigned sessionId, EState, const Error&) = 0; virtual void OnUpstreamTrace(unsigned sessionId, ETraceType, StringView trace) = 0; void OnConnected(unsigned sessionId, EState state, const ConnectionInfo& data) override { OnUpstreamConnected(sessionId, state, data); } - void On(unsigned sessionId, EState state, const ServiceDescription& data) override { OnUpstream(sessionId, state, data); } + void On(unsigned sessionId, EState state, const ServiceDescriptionData& data) override { OnUpstream(sessionId, state, data); } void On(unsigned sessionId, const NotificationData& data) override { OnUpstream(sessionId, data); } void On(unsigned sessionId, const CheckAliveData& data) override { OnUpstream(sessionId, data); } + void On(unsigned sessionId, const CommandData& data) override { OnUpstream(sessionId, data); } void OnState(unsigned sessionId, EState state) override { OnUpstreamState(sessionId, state); } void OnDisconnected(unsigned sessionId, EState state, const Error& data) override { OnUpstreamDisconnected(sessionId, state, data); } void OnTrace(unsigned sessionId, ETraceType type, StringView data) override { OnUpstreamTrace(sessionId, type, data); } @@ -230,23 +371,24 @@ namespace Hermes struct DownstreamCallbackHelper : IDownstreamCallback { virtual void OnDownstreamConnected(unsigned sessionId, EState, const ConnectionInfo&) = 0; - virtual void OnDownstream(unsigned sessionId, EState, const ServiceDescription&) = 0; + virtual void OnDownstream(unsigned sessionId, EState, const ServiceDescriptionData&) = 0; virtual void OnDownstream(unsigned sessionId, const NotificationData& data) = 0; virtual void OnDownstream(unsigned sessionId, const CheckAliveData& data) = 0; + virtual void OnDownstream(unsigned sessionId, const CommandData& data) = 0; virtual void OnDownstreamState(unsigned sessionId, EState) = 0; virtual void OnDownstreamDisconnected(unsigned sessionId, EState, const Error&) = 0; virtual void OnDownstreamTrace(unsigned sessionId, ETraceType, StringView trace) = 0; void OnConnected(unsigned sessionId, EState state, const ConnectionInfo& data) override { OnDownstreamConnected(sessionId, state, data); } - void On(unsigned sessionId, EState state, const ServiceDescription& data) override { OnDownstream(sessionId, state, data); } + void On(unsigned sessionId, EState state, const ServiceDescriptionData& data) override { OnDownstream(sessionId, state, data); } void On(unsigned sessionId, const NotificationData& data) override { OnDownstream(sessionId, data); } void On(unsigned sessionId, const CheckAliveData& data) override { OnDownstream(sessionId, data); } + void On(unsigned sessionId, const CommandData& data) override { OnDownstream(sessionId, data); } void OnState(unsigned sessionId, EState state) override { OnDownstreamState(sessionId, state); } void OnDisconnected(unsigned sessionId, EState state, const Error& data) override { OnDownstreamDisconnected(sessionId, state, data); } void OnTrace(unsigned sessionId, ETraceType type, StringView data) override { OnDownstreamTrace(sessionId, type, data); } }; - //======================== Downstream implementation ================================= inline Downstream::Downstream(unsigned laneId, IDownstreamCallback& callback) { @@ -262,9 +404,9 @@ namespace Hermes callbacks.m_serviceDescriptionCallback.m_pData = &callback; callbacks.m_serviceDescriptionCallback.m_pCall = [](void* pCallback, uint32_t sessionId, EHermesState state, - const HermesServiceDescription* pServiceDescription) + const HermesServiceDescriptionData* pServiceDescriptionData) { - static_cast(pCallback)->On(sessionId, ToCpp(state), ToCpp(*pServiceDescription)); + static_cast(pCallback)->On(sessionId, ToCpp(state), ToCpp(*pServiceDescriptionData)); }; callbacks.m_machineReadyCallback.m_pData = &callback; @@ -295,6 +437,13 @@ namespace Hermes static_cast(pCallback)->On(sessionId, ToCpp(state), ToCpp(*pData)); }; + callbacks.m_queryBoardInfoCallback.m_pData = &callback; + callbacks.m_queryBoardInfoCallback.m_pCall = [](void* pCallback, uint32_t sessionId, + const HermesQueryBoardInfoData* pData) + { + static_cast(pCallback)->On(sessionId, ToCpp(*pData)); + }; + callbacks.m_notificationCallback.m_pData = &callback; callbacks.m_notificationCallback.m_pCall = [](void* pCallback, uint32_t sessionId, const HermesNotificationData* pData) @@ -309,6 +458,13 @@ namespace Hermes static_cast(pCallback)->On(sessionId, ToCpp(*pData)); }; + callbacks.m_commandCallback.m_pData = &callback; + callbacks.m_commandCallback.m_pCall = [](void* pCallback, uint32_t sessionId, + const HermesCommandData* pData) + { + static_cast(pCallback)->On(sessionId, ToCpp(*pData)); + }; + callbacks.m_stateCallback.m_pData = &callback; callbacks.m_stateCallback.m_pCall = [](void* pCallback, uint32_t sessionId, EHermesState state) { @@ -351,56 +507,84 @@ namespace Hermes inline void Downstream::Enable(const DownstreamSettings& data) { - auto apiData = ToC(data); - ::EnableHermesDownstream(m_pImpl, &apiData); + const Converter2C converter(data); + ::EnableHermesDownstream(m_pImpl, converter.CPointer()); } - inline void Downstream::Signal(unsigned sessionId, const ServiceDescription& data) + inline void Downstream::Signal(unsigned sessionId, const ServiceDescriptionData& data) { - auto apiData = ToC(data); - ::SignalHermesDownstreamServiceDescription(m_pImpl, sessionId, &apiData); + const Converter2C converter(data); + ::SignalHermesDownstreamServiceDescription(m_pImpl, sessionId, converter.CPointer()); } inline void Downstream::Signal(unsigned sessionId, const BoardAvailableData& data) { - auto apiData = ToC(data); - ::SignalHermesBoardAvailable(m_pImpl, sessionId, &apiData); + const Converter2C converter(data); + ::SignalHermesBoardAvailable(m_pImpl, sessionId, converter.CPointer()); } inline void Downstream::Signal(unsigned sessionId, const RevokeBoardAvailableData& data) { - auto apiData = ToC(data); - ::SignalHermesRevokeBoardAvailable(m_pImpl, sessionId, &apiData); + const Converter2C converter(data); + ::SignalHermesRevokeBoardAvailable(m_pImpl, sessionId, converter.CPointer()); } inline void Downstream::Signal(unsigned sessionId, const TransportFinishedData& data) { - auto apiData = ToC(data); - ::SignalHermesTransportFinished(m_pImpl, sessionId, &apiData); + const Converter2C converter(data); + ::SignalHermesTransportFinished(m_pImpl, sessionId, converter.CPointer()); + } + + inline void Downstream::Signal(unsigned sessionId, const BoardForecastData& data) + { + const Converter2C converter(data); + ::SignalHermesBoardForecast(m_pImpl, sessionId, converter.CPointer()); + } + + inline void Downstream::Signal(unsigned sessionId, const SendBoardInfoData& data) + { + const Converter2C converter(data); + ::SignalHermesSendBoardInfo(m_pImpl, sessionId, converter.CPointer()); } inline void Downstream::Signal(unsigned sessionId, const NotificationData& data) { - auto apiData = ToC(data); - ::SignalHermesDownstreamNotification(m_pImpl, sessionId, &apiData); + const Converter2C converter(data); + ::SignalHermesDownstreamNotification(m_pImpl, sessionId, converter.CPointer()); } inline void Downstream::Signal(unsigned sessionId, const CheckAliveData& data) { - auto apiData = ToC(data); - ::SignalHermesDownstreamCheckAlive(m_pImpl, sessionId, &apiData); + const Converter2C converter(data); + ::SignalHermesDownstreamCheckAlive(m_pImpl, sessionId, converter.CPointer()); + } + + inline void Downstream::Signal(unsigned sessionId, const CommandData& data) + { + const Converter2C converter(data); + ::SignalHermesDownstreamCommand(m_pImpl, sessionId, converter.CPointer()); } inline void Downstream::Reset(const NotificationData& data) { - auto apiData = ToC(data); - ::ResetHermesDownstream(m_pImpl, &apiData); + const Converter2C converter(data); + ::ResetHermesDownstream(m_pImpl, converter.CPointer()); + } + + inline void Downstream::Signal(unsigned sessionId, StringView rawXml) + { + ::SignalHermesDownstreamRawXml(m_pImpl, sessionId, ToC(rawXml)); + } + + inline void Downstream::Reset(StringView rawXml) + { + ::ResetHermesDownstreamRawXml(m_pImpl, ToC(rawXml)); } inline void Downstream::Disable(const NotificationData& data) { - auto apiData = ToC(data); - ::DisableHermesDownstream(m_pImpl, &apiData); + const Converter2C converter(data); + ::DisableHermesDownstream(m_pImpl, converter.CPointer()); } inline void Downstream::Stop() @@ -423,9 +607,9 @@ namespace Hermes callbacks.m_serviceDescriptionCallback.m_pData = &callback; callbacks.m_serviceDescriptionCallback.m_pCall = [](void* pCallback, uint32_t sessionId, EHermesState state, - const HermesServiceDescription* pServiceDescription) + const HermesServiceDescriptionData* pServiceDescriptionData) { - static_cast(pCallback)->On(sessionId, ToCpp(state), ToCpp(*pServiceDescription)); + static_cast(pCallback)->On(sessionId, ToCpp(state), ToCpp(*pServiceDescriptionData)); }; callbacks.m_boardAvailableCallback.m_pData = &callback; @@ -449,6 +633,20 @@ namespace Hermes static_cast(pCallback)->On(sessionId, ToCpp(state), ToCpp(*pData)); }; + callbacks.m_boardForecastCallback.m_pData = &callback; + callbacks.m_boardForecastCallback.m_pCall = [](void* pCallback, uint32_t sessionId, EHermesState state, + const HermesBoardForecastData* pData) + { + static_cast(pCallback)->On(sessionId, ToCpp(state), ToCpp(*pData)); + }; + + callbacks.m_sendBoardInfoCallback.m_pData = &callback; + callbacks.m_sendBoardInfoCallback.m_pCall = [](void* pCallback, uint32_t sessionId, + const HermesSendBoardInfoData* pData) + { + static_cast(pCallback)->On(sessionId, ToCpp(*pData)); + }; + callbacks.m_notificationCallback.m_pData = &callback; callbacks.m_notificationCallback.m_pCall = [](void* pCallback, uint32_t sessionId, const HermesNotificationData* pData) @@ -463,6 +661,13 @@ namespace Hermes static_cast(pCallback)->On(sessionId, ToCpp(*pData)); }; + callbacks.m_commandCallback.m_pData = &callback; + callbacks.m_commandCallback.m_pCall = [](void* pCallback, uint32_t sessionId, + const HermesCommandData* pData) + { + static_cast(pCallback)->On(sessionId, ToCpp(*pData)); + }; + callbacks.m_stateCallback.m_pData = &callback; callbacks.m_stateCallback.m_pCall = [](void* pCallback, uint32_t sessionId, EHermesState state) { @@ -493,8 +698,8 @@ namespace Hermes inline void Upstream::Enable(const UpstreamSettings& data) { - auto apiData = ToC(data); - ::EnableHermesUpstream(m_pImpl, &apiData); + const Converter2C converter(data); + ::EnableHermesUpstream(m_pImpl, converter.CPointer()); } template void Upstream::Post(F&& f) @@ -509,58 +714,80 @@ namespace Hermes ::PostHermesUpstream(m_pImpl, callback); } - inline void Upstream::Signal(unsigned sessionId, const ServiceDescription& data) + inline void Upstream::Signal(unsigned sessionId, const ServiceDescriptionData& data) { - auto apiData = ToC(data); - ::SignalHermesUpstreamServiceDescription(m_pImpl, sessionId, &apiData); + const Converter2C converter(data); + ::SignalHermesUpstreamServiceDescription(m_pImpl, sessionId, converter.CPointer()); } inline void Upstream::Signal(unsigned sessionId, const MachineReadyData& data) { - auto apiData = ToC(data); - ::SignalHermesMachineReady(m_pImpl, sessionId, &apiData); + const Converter2C converter(data); + ::SignalHermesMachineReady(m_pImpl, sessionId, converter.CPointer()); } inline void Upstream::Signal(unsigned sessionId, const RevokeMachineReadyData& data) { - auto apiData = ToC(data); - ::SignalHermesRevokeMachineReady(m_pImpl, sessionId, &apiData); + const Converter2C converter(data); + ::SignalHermesRevokeMachineReady(m_pImpl, sessionId, converter.CPointer()); } inline void Upstream::Signal(unsigned sessionId, const StartTransportData& data) { - auto apiData = ToC(data); - ::SignalHermesStartTransport(m_pImpl, sessionId, &apiData); + const Converter2C converter(data); + ::SignalHermesStartTransport(m_pImpl, sessionId, converter.CPointer()); } inline void Upstream::Signal(unsigned sessionId, const StopTransportData& data) { - auto apiData = ToC(data); - ::SignalHermesStopTransport(m_pImpl, sessionId, &apiData); + const Converter2C converter(data); + ::SignalHermesStopTransport(m_pImpl, sessionId, converter.CPointer()); + } + + inline void Upstream::Signal(unsigned sessionId, const QueryBoardInfoData& data) + { + const Converter2C converter(data); + ::SignalHermesQueryBoardInfo(m_pImpl, sessionId, converter.CPointer()); } inline void Upstream::Signal(unsigned sessionId, const NotificationData& data) { - auto apiData = ToC(data); - ::SignalHermesUpstreamNotification(m_pImpl, sessionId, &apiData); + const Converter2C converter(data); + ::SignalHermesUpstreamNotification(m_pImpl, sessionId, converter.CPointer()); } inline void Upstream::Reset(const NotificationData& data) { - auto apiData = ToC(data); - ::ResetHermesUpstream(m_pImpl, &apiData); + const Converter2C converter(data); + ::ResetHermesUpstream(m_pImpl, converter.CPointer()); } inline void Upstream::Signal(unsigned sessionId, const CheckAliveData& data) { - auto apiData = ToC(data); - ::SignalHermesUpstreamCheckAlive(m_pImpl, sessionId, &apiData); + const Converter2C converter(data); + ::SignalHermesUpstreamCheckAlive(m_pImpl, sessionId, converter.CPointer()); + } + + inline void Upstream::Signal(unsigned sessionId, const CommandData& data) + { + const Converter2C converter(data); + ::SignalHermesUpstreamCommand(m_pImpl, sessionId, converter.CPointer()); + } + + inline void Upstream::Signal(unsigned sessionId, StringView rawXml) + { + ::SignalHermesUpstreamRawXml(m_pImpl, sessionId, ToC(rawXml)); + } + + inline void Upstream::Reset(StringView rawXml) + { + ::ResetHermesUpstreamRawXml(m_pImpl, ToC(rawXml)); } inline void Upstream::Disable(const NotificationData& data) { - auto apiData = ToC(data); - ::DisableHermesUpstream(m_pImpl, &apiData); + const Converter2C converter(data); + ::DisableHermesUpstream(m_pImpl, converter.CPointer()); } inline void Upstream::Stop() @@ -572,7 +799,7 @@ namespace Hermes inline ConfigurationService::ConfigurationService(IConfigurationServiceCallback& callback): m_callback(callback) { - HermesConfigurationServiceCallbacks callbacks; + HermesConfigurationServiceCallbacks callbacks{}; callbacks.m_connectedCallback.m_pData = this; callbacks.m_connectedCallback.m_pCall = [](void* pVoid, uint32_t sessionId, EHermesState, const HermesConnectionInfo* pInfo) { @@ -581,17 +808,17 @@ namespace Hermes callbacks.m_getConfigurationCallback.m_pData = this; callbacks.m_getConfigurationCallback.m_pCall = [](void* pVoid, uint32_t sessionId, - const HermesConnectionInfo* pConnectionInfo, const HermesGetConfigurationData*) + const HermesGetConfigurationData*, const HermesConnectionInfo* pConnectionInfo) { auto pThis = static_cast(pVoid); auto configuration = pThis->m_callback.OnGetConfiguration(sessionId, ToCpp(*pConnectionInfo)); - auto apiConfiguration = ToC(configuration); - ::SignalHermesCurrentConfiguration(pThis->m_pImpl, sessionId, &apiConfiguration); + const Converter2C converter(configuration); + ::SignalHermesCurrentConfiguration(pThis->m_pImpl, sessionId, converter.CPointer()); }; callbacks.m_setConfigurationCallback.m_pData = this; callbacks.m_setConfigurationCallback.m_pCall = [](void* pVoid, uint32_t sessionId, - const HermesConnectionInfo* pConnectionInfo, const HermesSetConfigurationData* pConfiguration) + const HermesSetConfigurationData* pConfiguration, const HermesConnectionInfo* pConnectionInfo) { auto pThis = static_cast(pVoid); auto error = pThis->m_callback.OnSetConfiguration(sessionId, ToCpp(*pConnectionInfo), ToCpp(*pConfiguration)); @@ -599,8 +826,8 @@ namespace Hermes return; NotificationData notification(ENotificationCode::eCONFIGURATION_ERROR, ESeverity::eERROR, error.m_text); - auto apiNotification = ToC(notification); - ::SignalHermesConfigurationNotification(pThis->m_pImpl, sessionId, &apiNotification); + const Converter2C converter(notification); + ::SignalHermesConfigurationNotification(pThis->m_pImpl, sessionId, converter.CPointer()); }; callbacks.m_disconnectedCallback.m_pData = this; @@ -638,14 +865,14 @@ namespace Hermes inline void ConfigurationService::Enable(const ConfigurationServiceSettings& data) { - auto apiData = ToC(data); - ::EnableHermesConfigurationService(m_pImpl, &apiData); + const Converter2C converter(data); + ::EnableHermesConfigurationService(m_pImpl, converter.CPointer()); } inline void ConfigurationService::Disable(const NotificationData& data) { - auto apiData = ToC(data); - ::DisableHermesConfigurationService(m_pImpl, &apiData); + const Converter2C converter(data); + ::DisableHermesConfigurationService(m_pImpl, converter.CPointer()); } inline void ConfigurationService::Stop() @@ -689,7 +916,7 @@ namespace Hermes return{configuration, error}; } - inline Error SetConfiguration(StringView hostName, const SetConfigurationData& configuration, + inline Error Hermes::SetConfiguration(StringView hostName, const SetConfigurationData& configuration, unsigned timeoutInSeconds, Hermes::CurrentConfigurationData* out_pConfiguration, // resulting configuration std::vector* out_pNotifications, // out: notification data @@ -740,11 +967,382 @@ namespace Hermes *static_cast(pData) = ToCpp(*pConfiguration); }; - auto apiConfiguration = ToC(configuration); - ::SetHermesConfiguration(ToC(hostName), &apiConfiguration, timeoutInSeconds, &callbacks); + Converter2C converter(configuration); + ::SetHermesConfiguration(ToC(hostName), converter.CPointer(), timeoutInSeconds, &callbacks); return error; } + inline VerticalService::VerticalService(IVerticalServiceCallback& callback) + { + HermesVerticalServiceCallbacks callbacks{}; + + callbacks.m_connectedCallback.m_pData = &callback; + callbacks.m_connectedCallback.m_pCall = [](void* pCallback, uint32_t sessionId, EHermesVerticalState state, + const HermesConnectionInfo* pConnectionInfo) + { + static_cast(pCallback)->OnConnected(sessionId, ToCpp(state), + ToCpp(*pConnectionInfo)); + }; + + callbacks.m_serviceDescriptionCallback.m_pData = &callback; + callbacks.m_serviceDescriptionCallback.m_pCall = [](void* pCallback, uint32_t sessionId, EHermesVerticalState state, + const HermesSupervisoryServiceDescriptionData* pServiceDescriptionData) + { + static_cast(pCallback)->On(sessionId, ToCpp(state), ToCpp(*pServiceDescriptionData)); + }; + + callbacks.m_getConfigurationCallback.m_pData = &callback; + callbacks.m_getConfigurationCallback.m_pCall = [](void* pCallback, uint32_t sessionId, const HermesGetConfigurationData* pData, + const HermesConnectionInfo* pInfo) + { + static_cast(pCallback)->On(sessionId, ToCpp(*pData), ToCpp(*pInfo)); + }; + + callbacks.m_setConfigurationCallback.m_pData = &callback; + callbacks.m_setConfigurationCallback.m_pCall = [](void* pCallback, uint32_t sessionId, const HermesSetConfigurationData* pData, + const HermesConnectionInfo* pInfo) + { + static_cast(pCallback)->On(sessionId, ToCpp(*pData), ToCpp(*pInfo)); + }; + + callbacks.m_sendWorkOrderInfoCallback.m_pData = &callback; + callbacks.m_sendWorkOrderInfoCallback.m_pCall = [](void* pCallback, uint32_t sessionId, + const HermesSendWorkOrderInfoData* pData) + { + static_cast(pCallback)->On(sessionId, ToCpp(*pData)); + }; + + callbacks.m_queryHermesCapabilitiesCallback.m_pData = &callback; + callbacks.m_queryHermesCapabilitiesCallback.m_pCall = [](void* pCallback, uint32_t sessionId, + const HermesQueryHermesCapabilitiesData* pData) + { + static_cast(pCallback)->On(sessionId, ToCpp(*pData)); + }; + + callbacks.m_notificationCallback.m_pData = &callback; + callbacks.m_notificationCallback.m_pCall = [](void* pCallback, uint32_t sessionId, + const HermesNotificationData* pData) + { + static_cast(pCallback)->On(sessionId, ToCpp(*pData)); + }; + + callbacks.m_checkAliveCallback.m_pData = &callback; + callbacks.m_checkAliveCallback.m_pCall = [](void* pCallback, uint32_t sessionId, + const HermesCheckAliveData* pData) + { + static_cast(pCallback)->On(sessionId, ToCpp(*pData)); + }; + + callbacks.m_disconnectedCallback.m_pData = &callback; + callbacks.m_disconnectedCallback.m_pCall = [](void* pCallback, uint32_t sessionId, EHermesVerticalState state, + const HermesError* pError) + { + static_cast(pCallback)->OnDisconnected(sessionId, ToCpp(state), ToCpp(*pError)); + }; + + callbacks.m_traceCallback.m_pData = &callback; + callbacks.m_traceCallback.m_pCall = [](void* pCallback, unsigned sessionId, EHermesTraceType type, + HermesStringView trace) + { + static_cast(pCallback)->OnTrace(sessionId, ToCpp(type), ToCpp(trace)); + }; + + m_pImpl = ::CreateHermesVerticalService(&callbacks); + } + + inline void VerticalService::Run() + { + ::RunHermesVerticalService(m_pImpl); + } + + template void VerticalService::Post(F&& f) + { + HermesVoidCallback callback; + callback.m_pData = std::make_unique(std::forward(f)).release(); + callback.m_pCall = [](void* pData) + { + auto upF = std::unique_ptr(static_cast(pData)); + (*upF)(); + }; + ::PostHermesVerticalService(m_pImpl, callback); + } + + inline void VerticalService::Enable(const VerticalServiceSettings& data) + { + const Converter2C converter(data); + ::EnableHermesVerticalService(m_pImpl, converter.CPointer()); + } + + inline void VerticalService::Signal(unsigned sessionId, const SupervisoryServiceDescriptionData& data) + { + const Converter2C converter(data); + ::SignalHermesVerticalServiceDescription(m_pImpl, sessionId, converter.CPointer()); + } + + inline void VerticalService::Signal(unsigned sessionId, const BoardArrivedData& data) + { + const Converter2C converter(data); + ::SignalHermesBoardArrived(m_pImpl, sessionId, converter.CPointer()); + } + + inline void VerticalService::Signal(const BoardArrivedData& data) + { + const Converter2C converter(data); + ::SignalHermesBoardArrived(m_pImpl, 0U, converter.CPointer()); + } + + inline void VerticalService::Signal(unsigned sessionId, const BoardDepartedData& data) + { + const Converter2C converter(data); + ::SignalHermesBoardDeparted(m_pImpl, sessionId, converter.CPointer()); + } + + inline void VerticalService::Signal(const BoardDepartedData& data) + { + const Converter2C converter(data); + ::SignalHermesBoardDeparted(m_pImpl, 0U, converter.CPointer()); + } + + inline void VerticalService::Signal(unsigned sessionId, const QueryWorkOrderInfoData& data) + { + const Converter2C converter(data); + ::SignalHermesQueryWorkOrderInfo(m_pImpl, sessionId, converter.CPointer()); + } + + inline void VerticalService::Signal(unsigned sessionId, const ReplyWorkOrderInfoData& data) + { + const Converter2C converter(data); + ::SignalHermesReplyWorkOrderInfo(m_pImpl, sessionId, converter.CPointer()); + } + + inline void VerticalService::Signal(unsigned sessionId, const SendHermesCapabilitiesData& data) + { + const Converter2C converter(data); + ::SignalHermesSendHermesCapabilities(m_pImpl, sessionId, converter.CPointer()); + } + + inline void VerticalService::Signal(unsigned sessionId, const CurrentConfigurationData& data) + { + const Converter2C converter(data); + ::SignalHermesVerticalCurrentConfiguration(m_pImpl, sessionId, converter.CPointer()); + } + + + inline void VerticalService::Signal(unsigned sessionId, const NotificationData& data) + { + const Converter2C converter(data); + ::SignalHermesVerticalServiceNotification(m_pImpl, sessionId, converter.CPointer()); + } + + inline void VerticalService::Signal(unsigned sessionId, const CheckAliveData& data) + { + const Converter2C converter(data); + ::SignalHermesVerticalServiceCheckAlive(m_pImpl, sessionId, converter.CPointer()); + } + + inline void VerticalService::ResetSession(unsigned sessionId, const NotificationData& data) + { + const Converter2C converter(data); + ::ResetHermesVerticalServiceSession(m_pImpl, sessionId, converter.CPointer()); + } + + + inline void VerticalService::Disable(const NotificationData& data) + { + const Converter2C converter(data); + ::DisableHermesVerticalService(m_pImpl, converter.CPointer()); + } + + inline void VerticalService::Stop() + { + ::StopHermesVerticalService(m_pImpl); + } + + //======================== VerticalClient implementation ================================= + inline VerticalClient::VerticalClient(IVerticalClientCallback& callback) + { + HermesVerticalClientCallbacks callbacks{}; + + callbacks.m_connectedCallback.m_pData = &callback; + callbacks.m_connectedCallback.m_pCall = [](void* pCallback, uint32_t sessionId, EHermesVerticalState state, + const HermesConnectionInfo* pConnectionInfo) + { + static_cast(pCallback)->OnConnected(sessionId, ToCpp(state), + ToCpp(*pConnectionInfo)); + }; + + callbacks.m_serviceDescriptionCallback.m_pData = &callback; + callbacks.m_serviceDescriptionCallback.m_pCall = [](void* pCallback, uint32_t sessionId, EHermesVerticalState state, + const HermesSupervisoryServiceDescriptionData* pServiceDescriptionData) + { + static_cast(pCallback)->On(sessionId, ToCpp(state), ToCpp(*pServiceDescriptionData)); + }; + + callbacks.m_boardArrivedCallback.m_pData = &callback; + callbacks.m_boardArrivedCallback.m_pCall = [](void* pCallback, uint32_t sessionId, + const HermesBoardArrivedData* pData) + { + static_cast(pCallback)->On(sessionId, ToCpp(*pData)); + }; + + callbacks.m_boardDepartedCallback.m_pData = &callback; + callbacks.m_boardDepartedCallback.m_pCall = [](void* pCallback, uint32_t sessionId, + const HermesBoardDepartedData* pData) + { + static_cast(pCallback)->On(sessionId, ToCpp(*pData)); + }; + + callbacks.m_queryWorkOrderInfoCallback.m_pData = &callback; + callbacks.m_queryWorkOrderInfoCallback.m_pCall = [](void* pCallback, uint32_t sessionId, + const HermesQueryWorkOrderInfoData* pData) + { + static_cast(pCallback)->On(sessionId, ToCpp(*pData)); + }; + + callbacks.m_replyWorkOrderInfoCallback.m_pData = &callback; + callbacks.m_replyWorkOrderInfoCallback.m_pCall = [](void* pCallback, uint32_t sessionId, + const HermesReplyWorkOrderInfoData* pData) + { + static_cast(pCallback)->On(sessionId, ToCpp(*pData)); + }; + + callbacks.m_currentConfigurationCallback.m_pData = &callback; + callbacks.m_currentConfigurationCallback.m_pCall = [](void* pCallback, uint32_t sessionId, + const HermesCurrentConfigurationData* pData) + { + static_cast(pCallback)->On(sessionId, ToCpp(*pData)); + }; + + callbacks.m_notificationCallback.m_pData = &callback; + callbacks.m_notificationCallback.m_pCall = [](void* pCallback, uint32_t sessionId, + const HermesNotificationData* pData) + { + static_cast(pCallback)->On(sessionId, ToCpp(*pData)); + }; + + callbacks.m_checkAliveCallback.m_pData = &callback; + callbacks.m_checkAliveCallback.m_pCall = [](void* pCallback, uint32_t sessionId, + const HermesCheckAliveData* pData) + { + static_cast(pCallback)->On(sessionId, ToCpp(*pData)); + }; + + callbacks.m_disconnectedCallback.m_pData = &callback; + callbacks.m_disconnectedCallback.m_pCall = [](void* pCallback, uint32_t sessionId, EHermesVerticalState state, + const HermesError* pError) + { + static_cast(pCallback)->OnDisconnected(sessionId, ToCpp(state), ToCpp(*pError)); + }; + + callbacks.m_traceCallback.m_pData = &callback; + callbacks.m_traceCallback.m_pCall = [](void* pCallback, unsigned sessionId, EHermesTraceType type, + HermesStringView trace) + { + static_cast(pCallback)->OnTrace(sessionId, ToCpp(type), ToCpp(trace)); + }; + + callbacks.m_sendHermesCapabilitiesCallback.m_pData = &callback; + callbacks.m_sendHermesCapabilitiesCallback.m_pCall = [](void* pCallback, uint32_t sessionId, + const HermesSendHermesCapabilitiesData* pData) + { + static_cast(pCallback)->On(sessionId, ToCpp(*pData)); + }; + + m_pImpl = ::CreateHermesVerticalClient(&callbacks); + } + + inline void VerticalClient::Run() + { + ::RunHermesVerticalClient(m_pImpl); + } + + template void VerticalClient::Post(F&& f) + { + HermesVoidCallback callback; + callback.m_pData = std::make_unique(std::forward(f)).release(); + callback.m_pCall = [](void* pData) + { + auto upF = std::unique_ptr(static_cast(pData)); + (*upF)(); + }; + ::PostHermesVerticalClient(m_pImpl, callback); + } + + inline void VerticalClient::Enable(const VerticalClientSettings& data) + { + const Converter2C converter(data); + ::EnableHermesVerticalClient(m_pImpl, converter.CPointer()); + } + + inline void VerticalClient::Signal(unsigned sessionId, const SupervisoryServiceDescriptionData& data) + { + const Converter2C converter(data); + ::SignalHermesVerticalClientDescription(m_pImpl, sessionId, converter.CPointer()); + } + + inline void VerticalClient::Signal(unsigned sessionId, const SendWorkOrderInfoData& data) + { + const Converter2C converter(data); + ::SignalHermesSendWorkOrderInfo(m_pImpl, sessionId, converter.CPointer()); + } + + inline void VerticalClient::Signal(unsigned sessionId, const GetConfigurationData& data) + { + const Converter2C converter(data); + ::SignalHermesVerticalGetConfiguration(m_pImpl, sessionId, converter.CPointer()); + } + + inline void VerticalClient::Signal(unsigned sessionId, const SetConfigurationData& data) + { + const Converter2C converter(data); + ::SignalHermesVerticalSetConfiguration(m_pImpl, sessionId, converter.CPointer()); + } + + inline void VerticalClient::Signal(unsigned sessionId, const QueryHermesCapabilitiesData& data) + { + const Converter2C converter(data); + ::SignalHermesVerticalQueryHermesCapabilities(m_pImpl, sessionId, converter.CPointer()); + } + + inline void VerticalClient::Signal(unsigned sessionId, const NotificationData& data) + { + const Converter2C converter(data); + ::SignalHermesVerticalClientNotification(m_pImpl, sessionId, converter.CPointer()); + } + + inline void VerticalClient::Signal(unsigned sessionId, const CheckAliveData& data) + { + const Converter2C converter(data); + ::SignalHermesVerticalClientCheckAlive(m_pImpl, sessionId, converter.CPointer()); + } + + inline void VerticalClient::Reset(const NotificationData& data) + { + const Converter2C converter(data); + ::ResetHermesVerticalClient(m_pImpl, converter.CPointer()); + } + + inline void VerticalClient::Signal(unsigned sessionId, StringView rawXml) + { + ::SignalHermesVerticalClientRawXml(m_pImpl, sessionId, ToC(rawXml)); + } + + inline void VerticalClient::Reset(StringView rawXml) + { + ::ResetHermesVerticalClientRawXml(m_pImpl, ToC(rawXml)); + } + + inline void VerticalClient::Disable(const NotificationData& data) + { + const Converter2C converter(data); + ::DisableHermesVerticalClient(m_pImpl, converter.CPointer()); + } + + inline void VerticalClient::Stop() + { + ::StopHermesVerticalClient(m_pImpl); + } + } diff --git a/src/include/HermesData.h b/src/include/HermesData.h new file mode 100644 index 0000000..6bb29ef --- /dev/null +++ b/src/include/HermesData.h @@ -0,0 +1,782 @@ +// Copyright (c) ASM Assembly Systems GmbH & Co. KG +// +// C interface for an implementation of The Hermes Standard +// +#ifndef HERMESDATA_H +#define HERMESDATA_H + +#include "HermesStringView.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define HERMES_MAX_MESSAGE_SIZE 65536U /* The Hermes Standard 3.1 */ +#define HERMES_BASE_PORT 50100U /* The Hermes Standard 2.3.1 */ +#define HERMES_CONFIG_PORT 1248U /* The Hermes Standard 2.4.1 */ +#define HERMES_ROUTE_RETURN_BOARD 900U /* The Hermes Standard 3.6 */ +#define HERMES_ROUTE_UNDEFINED 999U /* The Hermes Standard 3.6 */ +#define HERMES_ROUTE_MANUALLY_REMOVE_BOARD 999U /* The Hermes Standard 3.6 */ +#define HERMES_ACTION_UNDEFINED 1U /* The Hermes Standard 3.6 */ +#define HERMES_ACTION_PROCESS_BOARD 1U /* The Hermes Standard 3.6 */ +#define HERMES_ACTION_PASS_THROUGH_BOARD 2U /* The Hermes Standard 3.6 */ + + +/* The Hermes Standard 3.3 */ +enum EHermesCheckAliveType +{ + eHERMES_CHECK_ALIVE_TYPE_UNKNOWN, + eHERMES_CHECK_ALIVE_TYPE_PING, + eHERMES_CHECK_ALIVE_TYPE_PONG, + cHERMES_CHECK_ALIVE_TYPE_ENUM_SIZE = 3 +}; + +/* The Hermes Standard 3.5 */ +enum EHermesNotificationCode +{ + eHERMES_NOTIFICATION_CODE_UNSPECIFIC, + eHERMES_NOTIFICATION_CODE_PROTOCOL_ERROR, + eHERMES_NOTIFICATION_CODE_CONNECTION_REFUSED_BECAUSE_OF_ESTABLISHED_CONNECTION, + eHERMES_NOTIFICATION_CODE_CONNECTION_RESET_BECAUSE_OF_CHANGED_CONFIGURATION, + eHERMES_NOTIFICATION_CODE_CONFIGURATION_ERROR, + eHERMES_NOTIFICATION_CODE_MACHINE_SHUTDOWN, + eHERMES_NOTIFICATION_CODE_BOARD_FORECAST_ERROR, + cHERMES_NOTIFICATION_CODE_ENUM_SIZE = 7 +}; + +/* The Hermes Standard 3.5 */ +enum EHermesSeverity +{ + eHERMES_SEVERITY_UNKNOWN, + eHERMES_SEVERITY_FATAL, + eHERMES_SEVERITY_ERROR, + eHERMES_SEVERITY_WARNING, + eHERMES_SEVERITY_INFO, + cHERMES_SEVERITY_ENUM_SIZE = 5 +}; + +/* The Hermes Standard 3.6 */ +enum EHermesBoardQuality +{ + eHERMES_BOARD_QUALITY_ANY, + eHERMES_BOARD_QUALITY_GOOD, + eHERMES_BOARD_QUALITY_BAD, + cHERMES_BOARD_QUALITY_ENUM_SIZE = 3 +}; + +/* The Hermes Standard 3.6 */ +enum EHermesFlippedBoard +{ + eHERMES_FLIPPED_BOARD_SIDE_UP_IS_UNKNOWN, + eHERMES_FLIPPED_BOARD_TOP_SIDE_IS_UP, + eHERMES_FLIPPED_BOARD_BOTTOM_SIDE_IS_UP, + cHERMES_FLIPPED_BOARD_ENUM_SIZE = 3 +}; + +/* The Hermes Standard 3.6 */ +enum EHermesSubBoardState +{ + eHERMES_SUB_BOARD_STATE_UNKNOWN, + eHERMES_SUB_BOARD_STATE_GOOD, + eHERMES_SUB_BOARD_STATE_FAILED, + eHERMES_SUB_BOARD_STATE_MISSING, + eHERMES_SUB_BOARD_STATE_SKIP, + cHERMES_SUB_BOARD_STATE_ENUM_SIZE = 5 +}; + +/* The Hermes Standard 3.11 */ +enum EHermesTransferState +{ + eHERMES_TRANSFER_STATE_UNKNOWN, + eHERMES_TRANSFER_STATE_NOT_STARTED, + eHERMES_TRANSFER_STATE_INCOMPLETE, + eHERMES_TRANSFER_STATE_COMPLETE, + cHERMES_TRANSFER_STATE_ENUM_SIZE = 4 +}; + +/* The Hermes Standard 3.23 */ +enum EHermesBoardArrivedTransfer +{ + eHERMES_BOARD_ARRIVED_TRANSFER_UNKNOWN, + eHERMES_BOARD_ARRIVED_TRANSFER_TRANSFERRED, + eHERMES_BOARD_ARRIVED_TRANSFER_LOADED, + eHERMES_BOARD_ARRIVED_TRANSFER_INSERTED, + cHERMES_BOARD_ARRIVED_TRANSFER_ENUM_SIZE = 4 +}; + +/* The Hermes Standard 3.24 */ +enum EHermesBoardDepartedTransfer +{ + eHERMES_BOARD_DEPARTED_TRANSFER_UNKNOWN, + eHERMES_BOARD_DEPARTED_TRANSFER_TRANSFERRED, + eHERMES_BOARD_DEPARTED_TRANSFER_UNLOADED, + eHERMES_BOARD_DEPARTED_TRANSFER_REMOVED, + cHERMES_BOARD_DEPARTED_TRANSFER_ENUM_SIZE = 4 +}; + +/* The Hermes Standard 3.27 */ +enum EHermesReplyWorkOrderInfoStatus +{ + eHERMES_REPLY_WORK_ORDER_INFO_STATUS_REJECTED, + eHERMES_REPLY_WORK_ORDER_INFO_STATUS_ACCEPTED_AND_READY, + eHERMES_REPLY_WORK_ORDER_INFO_STATUS_ACCEPTED_AND_QUEUED, + cHERMES_REPLY_WORK_ORDER_INFO_STATUS_ENUM_SIZE = 3 +}; + +/* The Hermes Standard chapter 2.6 */ +enum EHermesState +{ + eHERMES_STATE_NOT_CONNECTED, + eHERMES_STATE_SOCKET_CONNECTED, + eHERMES_STATE_SERVICE_DESCRIPTION_DOWNSTREAM, + eHERMES_STATE_NOT_AVAILABLE_NOT_READY, + eHERMES_STATE_BOARD_AVAILABLE, + eHERMES_STATE_MACHINE_READY, + eHERMES_STATE_AVAILABLE_AND_READY, + eHERMES_STATE_TRANSPORTING, + eHERMES_STATE_TRANSPORT_STOPPED, + eHERMES_STATE_TRANSPORT_FINISHED, + eHERMES_STATE_DISCONNECTED, + cHERMES_STATE_ENUM_SIZE = 11 +}; + +/* Trace levels of the implementation (not part of The Hermes Standard) */ +enum EHermesTraceType +{ + eHERMES_TRACE_TYPE_SENT, + eHERMES_TRACE_TYPE_RECEIVED, + eHERMES_TRACE_TYPE_DEBUG, + eHERMES_TRACE_TYPE_INFO, + eHERMES_TRACE_TYPE_WARNING, + eHERMES_TRACE_TYPE_ERROR, + cHERMES_TRACE_TYPE_ENUM_SIZE = 6 +}; + +/* Internal state check modes of the implementation (not part of The Hermes Standard) */ +enum EHermesCheckState +{ + eHERMES_CHECK_STATE_SEND_AND_RECEIVE, + eHERMES_CHECK_STATE_ONLY_RECEIVE, + cHERMES_CHECK_STATE_ENUM_SIZE = 2 +}; + +/* How to respond to a check alive ping) */ +enum EHermesCheckAliveResponseMode +{ + eHERMES_CHECK_ALIVE_RESPONSE_MODE_AUTO, + eHERMES_CHECK_ALIVE_RESPONSE_MODE_APPLICATION, + cHERMES_CHECK_ALIVE_RESPONSE_MODE_ENUM_SIZE = 2 +}; + +/* Error codes (not part of The Hermes Standard) */ +enum EHermesErrorCode +{ + eHERMES_ERROR_CODE_SUCCESS, + eHERMES_ERROR_CODE_IMPLEMENTATION_ERROR, + eHERMES_ERROR_CODE_PEER_ERROR, + eHERMES_ERROR_CODE_CLIENT_ERROR, + eHERMES_ERROR_CODE_NETWORK_ERROR, + eHERMES_ERROR_CODE_TIMEOUT, + cHERMES_ERROR_CODE_ENUM_SIZE = 6 +}; + +/* The Hermes Standard chapter 2.5.3 */ +enum EHermesVerticalState +{ + eHERMES_VERTICAL_STATE_NOT_CONNECTED, + eHERMES_VERTICAL_STATE_SOCKET_CONNECTED, + eHERMES_VERTICAL_STATE_SUPERVISORY_SERVICE_DESCRIPTION, + eHERMES_VERTICAL_STATE_CONNECTED, + eHERMES_VERTICAL_STATE_DISCONNECTED, + cHERMES_VERTICAL_STATE_ENUM_SIZE = 5 +}; + +/* CheckAlive, The Hermes Standard 3.3 */ +struct HermesCheckAliveData +{ + const EHermesCheckAliveType* m_pOptionalType; + HermesStringView m_optionalId; +}; + +/* FeatureBoardForecast, The Hermes Standard 3.4 */ +struct HermesFeatureBoardForecast +{ +}; + +/* FeatureCheckAliveResponse, The Hermes Standard 3.4 */ +struct HermesFeatureCheckAliveResponse +{ +}; + +/* FeatureQueryBoardInfo, The Hermes Standard 3.4 */ +struct HermesFeatureQueryBoardInfo +{ +}; + +/* FeatureSendBoardInfo, The Hermes Standard 3.4 */ +struct HermesFeatureSendBoardInfo +{ +}; + +/* FeatureCommand, The Hermes Standard 3.4 */ +struct HermesFeatureCommand +{ +}; + +/* SupportedFeatures, The Hermes Standard 3.4 */ +struct HermesSupportedFeatures +{ + const HermesFeatureBoardForecast* m_pOptionalFeatureBoardForecast; + const HermesFeatureCheckAliveResponse* m_pOptionalFeatureCheckAliveResponse; + const HermesFeatureQueryBoardInfo* m_pOptionalFeatureQueryBoardInfo; + const HermesFeatureSendBoardInfo* m_pOptionalFeatureSendBoardInfo; + const HermesFeatureCommand* m_pOptionalFeatureCommand; +}; + +/* ServiceDescription, The Hermes Standard 3.4 */ +struct HermesServiceDescriptionData +{ + HermesStringView m_machineId; + uint32_t m_laneId; + HermesStringView m_optionalInterfaceId; + HermesStringView m_version; + const HermesSupportedFeatures* m_pSupportedFeatures; +}; + +/* Notification, The Hermes Standard 3.5 */ +struct HermesNotificationData +{ + EHermesNotificationCode m_notificationCode; + EHermesSeverity m_severity; + HermesStringView m_description; +}; + +/* SubBoard, The Hermes Standard 3.6 */ +struct HermesSubBoard +{ + uint16_t m_pos; + HermesStringView m_optionalBc; + EHermesSubBoardState m_st; +}; + +/* The Hermes Standard 3.6 */ +struct HermesSubBoards +{ + const HermesSubBoard** m_pData; // pointer to first element + size_t m_size; // number of elements +}; + +/* BoardAvailable, The Hermes Standard 3.6 */ +struct HermesBoardAvailableData +{ + HermesStringView m_boardId; + HermesStringView m_boardIdCreatedBy; + EHermesBoardQuality m_failedBoard; + HermesStringView m_optionalProductTypeId; + EHermesFlippedBoard m_flippedBoard; + HermesStringView m_optionalTopBarcode; + HermesStringView m_optionalBottomBarcode; + const double* m_pOptionalLengthInMM; + const double* m_pOptionalWidthInMM; + const double* m_pOptionalThicknessInMM; + const double* m_pOptionalConveyorSpeedInMMPerSecs; + const double* m_pOptionalTopClearanceHeightInMM; + const double* m_pOptionalBottomClearanceHeightInMM; + const double* m_pOptionalWeightInGrams; + HermesStringView m_optionalWorkOrderId; + HermesStringView m_optionalBatchId; + const uint16_t* m_pOptionalRoute; + const uint16_t* m_pOptionalAction; + HermesSubBoards m_optionalSubBoards; +}; + +/* RevokeBoardAvailable, The Hermes Standard 3.7 */ +struct HermesRevokeBoardAvailableData +{ +}; + +/* MachineReady, The Hermes Standard 3.8 */ +struct HermesMachineReadyData +{ + EHermesBoardQuality m_failedBoard; + HermesStringView m_optionalForecastId; + HermesStringView m_optionalBoardId; + HermesStringView m_optionalProductTypeId; + const EHermesFlippedBoard* m_pOptionalFlippedBoard; + HermesStringView m_optionalTopBarcode; + HermesStringView m_optionalBottomBarcode; + const double* m_pOptionalLengthInMM; + const double* m_pOptionalWidthInMM; + const double* m_pOptionalThicknessInMM; + const double* m_pOptionalConveyorSpeedInMMPerSecs; + const double* m_pOptionalTopClearanceHeightInMM; + const double* m_pOptionalBottomClearanceHeightInMM; + const double* m_pOptionalWeightInGrams; + HermesStringView m_optionalWorkOrderId; + HermesStringView m_optionalBatchId; +}; + +/* RevokeMachineReady, The Hermes Standard 3.9 */ +struct HermesRevokeMachineReadyData +{ +}; + +/* StartTransport, The Hermes Standard 3.10 */ +struct HermesStartTransportData +{ + HermesStringView m_boardId; + const double* m_pOptionalConveyorSpeedInMMPerSecs; +}; + +/* StopTransport, The Hermes Standard 3.11 */ +struct HermesStopTransportData +{ + EHermesTransferState m_transferState; + HermesStringView m_boardId; +}; + +/* TransportFinished, The Hermes Standard 3.12 */ +struct HermesTransportFinishedData +{ + EHermesTransferState m_transferState; + HermesStringView m_boardId; +}; + +/* UpstreamConfiguration, The Hermes Standard 3.13 */ +struct HermesUpstreamConfiguration +{ + uint32_t m_upstreamLaneId; + HermesStringView m_optionalUpstreamInterfaceId; + HermesStringView m_hostAddress; + uint16_t m_port; +}; + +/* The Hermes Standard 3.13 */ +struct HermesUpstreamConfigurations +{ + const HermesUpstreamConfiguration** m_pData; // pointer to first element + size_t m_size; // number of elements +}; + +/* DownstreamConfiguration, The Hermes Standard 3.13 */ +struct HermesDownstreamConfiguration +{ + uint32_t m_downstreamLaneId; + HermesStringView m_optionalDownstreamInterfaceId; + HermesStringView m_optionalClientAddress; + uint16_t m_port; +}; + +/* The Hermes Standard 3.13 */ +struct HermesDownstreamConfigurations +{ + const HermesDownstreamConfiguration** m_pData; // pointer to first element + size_t m_size; // number of elements +}; + +/* SetConfiguration, The Hermes Standard 3.13 */ +struct HermesSetConfigurationData +{ + HermesStringView m_machineId; + const uint16_t* m_pOptionalSupervisorySystemPort; + HermesUpstreamConfigurations m_upstreamConfigurations; + HermesDownstreamConfigurations m_downstreamConfigurations; +}; + +/* GetConfiguration, The Hermes Standard 3.14 */ +struct HermesGetConfigurationData +{ +}; + +/* CurrentConfiguration, The Hermes Standard 3.15 */ +struct HermesCurrentConfigurationData +{ + HermesStringView m_optionalMachineId; + const uint16_t* m_pOptionalSupervisorySystemPort; + HermesUpstreamConfigurations m_upstreamConfigurations; + HermesDownstreamConfigurations m_downstreamConfigurations; +}; + +/* BoardForecast, The Hermes Standard 3.16 */ +struct HermesBoardForecastData +{ + HermesStringView m_optionalForecastId; + const double* m_pOptionalTimeUntilAvailableInSeconds; + HermesStringView m_optionalBoardId; + HermesStringView m_optionalBoardIdCreatedBy; + EHermesBoardQuality m_failedBoard; + HermesStringView m_optionalProductTypeId; + EHermesFlippedBoard m_flippedBoard; + HermesStringView m_optionalTopBarcode; + HermesStringView m_optionalBottomBarcode; + const double* m_pOptionalLengthInMM; + const double* m_pOptionalWidthInMM; + const double* m_pOptionalThicknessInMM; + const double* m_pOptionalConveyorSpeedInMMPerSecs; + const double* m_pOptionalTopClearanceHeightInMM; + const double* m_pOptionalBottomClearanceHeightInMM; + const double* m_pOptionalWeightInGrams; + HermesStringView m_optionalWorkOrderId; + HermesStringView m_optionalBatchId; +}; + +/* QueryBoardInfo, The Hermes Standard 3.17 */ +struct HermesQueryBoardInfoData +{ + HermesStringView m_optionalTopBarcode; + HermesStringView m_optionalBottomBarcode; +}; + +/* SendBoardInfo, The Hermes Standard 3.18 */ +struct HermesSendBoardInfoData +{ + HermesStringView m_optionalBoardId; + HermesStringView m_optionalBoardIdCreatedBy; + const EHermesBoardQuality* m_pOptionalFailedBoard; + HermesStringView m_optionalProductTypeId; + const EHermesFlippedBoard* m_pOptionalFlippedBoard; + HermesStringView m_optionalTopBarcode; + HermesStringView m_optionalBottomBarcode; + const double* m_pOptionalLengthInMM; + const double* m_pOptionalWidthInMM; + const double* m_pOptionalThicknessInMM; + const double* m_pOptionalConveyorSpeedInMMPerSecs; + const double* m_pOptionalTopClearanceHeightInMM; + const double* m_pOptionalBottomClearanceHeightInMM; + const double* m_pOptionalWeightInGrams; + HermesStringView m_optionalWorkOrderId; + HermesStringView m_optionalBatchId; + const uint16_t* m_pOptionalRoute; + const uint16_t* m_pOptionalAction; + HermesSubBoards m_optionalSubBoards; +}; + +/* FeatureConfiguration, The Hermes Standard 3.22 */ +struct HermesFeatureConfiguration +{ +}; + +/* FeatureBoardTracking, The Hermes Standard 3.22 */ +struct HermesFeatureBoardTracking +{ +}; + +/* FeatureQueryWorkOrderInfo, The Hermes Standard 3.22 */ +struct HermesFeatureQueryWorkOrderInfo +{ +}; + +/* FeatureSendWorkOrderInfo, The Hermes Standard 3.22 */ +struct HermesFeatureSendWorkOrderInfo +{ +}; + +/* FeatureReplyWorkOrderInfo, The Hermes Standard 3.22 */ +struct HermesFeatureReplyWorkOrderInfo +{ +}; + +/* FeatureQueryHermesCapabilities, The Hermes Standard 3.22 */ +struct HermesFeatureQueryHermesCapabilities +{ +}; + +/* FeatureSendHermesCapabilities, The Hermes Standard 3.22 */ +struct HermesFeatureSendHermesCapabilities +{ +}; + +/* SupervisoryFeatures, The Hermes Standard 6 */ +struct HermesSupervisoryFeatures +{ + const HermesFeatureConfiguration* m_pOptionalFeatureConfiguration; + const HermesFeatureCheckAliveResponse* m_pOptionalFeatureCheckAliveResponse; + const HermesFeatureBoardTracking* m_pOptionalFeatureBoardTracking; + const HermesFeatureQueryWorkOrderInfo* m_pOptionalFeatureQueryWorkOrderInfo; + const HermesFeatureSendWorkOrderInfo* m_pOptionalFeatureSendWorkOrderInfo; + const HermesFeatureReplyWorkOrderInfo* m_pOptionalFeatureReplyWorkOrderInfo; + const HermesFeatureQueryHermesCapabilities* m_pOptionalFeatureQueryHermesCapabilities; + const HermesFeatureSendHermesCapabilities* m_pOptionalFeatureSendHermesCapabilities; +}; + +/* SupervisoryServiceDescription, The Hermes Standard 3.22 */ +struct HermesSupervisoryServiceDescriptionData +{ + HermesStringView m_systemId; + HermesStringView m_version; + const HermesSupervisoryFeatures* m_pSupportedFeatures; +}; + +/* BoardArrived, The Hermes Standard 3.23 */ +struct HermesBoardArrivedData +{ + HermesStringView m_machineId; + uint32_t m_upstreamLaneId; + HermesStringView m_optionalUpstreamInterfaceId; + HermesStringView m_optionalMagazineId; + const uint32_t* m_pOptionalSlotId; + EHermesBoardArrivedTransfer m_boardTransfer; + HermesStringView m_boardId; + HermesStringView m_boardIdCreatedBy; + EHermesBoardQuality m_failedBoard; + HermesStringView m_optionalProductTypeId; + EHermesFlippedBoard m_flippedBoard; + HermesStringView m_optionalTopBarcode; + HermesStringView m_optionalBottomBarcode; + const double* m_pOptionalLengthInMM; + const double* m_pOptionalWidthInMM; + const double* m_pOptionalThicknessInMM; + const double* m_pOptionalConveyorSpeedInMMPerSecs; + const double* m_pOptionalTopClearanceHeightInMM; + const double* m_pOptionalBottomClearanceHeightInMM; + const double* m_pOptionalWeightInGrams; + HermesStringView m_optionalWorkOrderId; + HermesStringView m_optionalBatchId; + const uint16_t* m_pOptionalRoute; + const uint16_t* m_pOptionalAction; + HermesSubBoards m_optionalSubBoards; +}; + +/* BoardDeparted, The Hermes Standard 3.24 */ +struct HermesBoardDepartedData +{ + HermesStringView m_machineId; + uint32_t m_downstreamLaneId; + HermesStringView m_optionalDownstreamInterfaceId; + HermesStringView m_optionalMagazineId; + const uint32_t* m_pOptionalSlotId; + EHermesBoardDepartedTransfer m_boardTransfer; + HermesStringView m_boardId; + HermesStringView m_boardIdCreatedBy; + EHermesBoardQuality m_failedBoard; + HermesStringView m_optionalProductTypeId; + EHermesFlippedBoard m_flippedBoard; + HermesStringView m_optionalTopBarcode; + HermesStringView m_optionalBottomBarcode; + const double* m_pOptionalLengthInMM; + const double* m_pOptionalWidthInMM; + const double* m_pOptionalThicknessInMM; + const double* m_pOptionalConveyorSpeedInMMPerSecs; + const double* m_pOptionalTopClearanceHeightInMM; + const double* m_pOptionalBottomClearanceHeightInMM; + const double* m_pOptionalWeightInGrams; + HermesStringView m_optionalWorkOrderId; + HermesStringView m_optionalBatchId; + const uint16_t* m_pOptionalRoute; + const uint16_t* m_pOptionalAction; + HermesSubBoards m_optionalSubBoards; +}; + +/* QueryWorkOrderInfo, The Hermes Standard 3.25 */ +struct HermesQueryWorkOrderInfoData +{ + HermesStringView m_optionalQueryId; + HermesStringView m_machineId; + HermesStringView m_optionalMagazineId; + const uint32_t* m_pOptionalSlotId; + HermesStringView m_optionalBarcode; + HermesStringView m_optionalWorkOrderId; + HermesStringView m_optionalBatchId; +}; + +/* SendWorkOrderInfo, The Hermes Standard 3.26 */ +struct HermesSendWorkOrderInfoData +{ + HermesStringView m_optionalQueryId; + HermesStringView m_optionalWorkOrderId; + HermesStringView m_optionalBatchId; + HermesStringView m_optionalBoardId; + HermesStringView m_optionalBoardIdCreatedBy; + const EHermesBoardQuality* m_pOptionalFailedBoard; + HermesStringView m_optionalProductTypeId; + const EHermesFlippedBoard* m_pOptionalFlippedBoard; + HermesStringView m_optionalTopBarcode; + HermesStringView m_optionalBottomBarcode; + const double* m_pOptionalLengthInMM; + const double* m_pOptionalWidthInMM; + const double* m_pOptionalThicknessInMM; + const double* m_pOptionalConveyorSpeedInMMPerSecs; + const double* m_pOptionalTopClearanceHeightInMM; + const double* m_pOptionalBottomClearanceHeightInMM; + const double* m_pOptionalWeightInGrams; + const uint16_t* m_pOptionalRoute; + HermesSubBoards m_optionalSubBoards; +}; + +/* ReplyWorkOrderInfo, The Hermes Standard 3.27 */ +struct HermesReplyWorkOrderInfoData +{ + HermesStringView m_workOrderId; + HermesStringView m_optionalBatchId; + EHermesReplyWorkOrderInfoStatus m_status; +}; + +/* QueryHermesCapabilities, The Hermes Standard 6 */ +struct HermesQueryHermesCapabilitiesData +{ +}; + +/* MessageCheckAliveResponse, The Hermes Standard 6 */ +struct HermesMessageCheckAliveResponse +{ +}; + +/* MessageBoardForecast, The Hermes Standard 6 */ +struct HermesMessageBoardForecast +{ +}; + +/* MessageQueryBoardInfo, The Hermes Standard 6 */ +struct HermesMessageQueryBoardInfo +{ +}; + +/* MessageSendBoardInfo, The Hermes Standard 6 */ +struct HermesMessageSendBoardInfo +{ +}; + +/* MessageBoardArrived, The Hermes Standard 6 */ +struct HermesMessageBoardArrived +{ +}; + +/* MessageBoardDeparted, The Hermes Standard 6 */ +struct HermesMessageBoardDeparted +{ +}; + +/* MessageQueryWorkOrderInfo, The Hermes Standard 6 */ +struct HermesMessageQueryWorkOrderInfo +{ +}; + +/* MessageReplyWorkOrderInfo, The Hermes Standard 6 */ +struct HermesMessageReplyWorkOrderInfo +{ +}; + +/* MessageCommand, The Hermes Standard 6 */ +struct HermesMessageCommand +{ +}; + +/* OptionalMessages, The Hermes Standard 6 */ +struct HermesOptionalMessages +{ + const HermesMessageCheckAliveResponse* m_pOptionalMessageCheckAliveResponse; + const HermesMessageBoardForecast* m_pOptionalMessageBoardForecast; + const HermesMessageQueryBoardInfo* m_pOptionalMessageQueryBoardInfo; + const HermesMessageSendBoardInfo* m_pOptionalMessageSendBoardInfo; + const HermesMessageBoardArrived* m_pOptionalMessageBoardArrived; + const HermesMessageBoardDeparted* m_pOptionalMessageBoardDeparted; + const HermesMessageQueryWorkOrderInfo* m_pOptionalMessageQueryWorkOrderInfo; + const HermesMessageReplyWorkOrderInfo* m_pOptionalMessageReplyWorkOrderInfo; + const HermesMessageCommand* m_pOptionalMessageCommand; +}; + +/* Attributes, The Hermes Standard 6 */ +struct HermesAttributes +{ + uint16_t m_productTypeId; + uint16_t m_topBarcode; + uint16_t m_bottomBarcode; + uint16_t m_length; + uint16_t m_width; + uint16_t m_thickness; + uint16_t m_conveyorSpeed; + uint16_t m_topClearanceHeight; + uint16_t m_bottomClearanceHeight; + uint16_t m_weight; + uint16_t m_workOrderId; + uint16_t m_batchId; + uint16_t m_route; + uint16_t m_action; + uint16_t m_subBoards; +}; + +/* SendHermesCapabilities, The Hermes Standard 6 */ +struct HermesSendHermesCapabilitiesData +{ + const HermesOptionalMessages* m_pOptionalMessages; + const HermesAttributes* m_pAttributes; +}; + +/* Command, The Hermes Standard 3.28 */ +struct HermesCommandData +{ + uint16_t m_command; +}; + +/* UpstreamSettings, Configuration of upstream interface (not part of The Hermes Standard) */ +struct HermesUpstreamSettings +{ + HermesStringView m_machineId; + HermesStringView m_hostAddress; + uint16_t m_port; + double m_checkAlivePeriodInSeconds; + double m_reconnectWaitTimeInSeconds; + EHermesCheckAliveResponseMode m_checkAliveResponseMode; + EHermesCheckState m_checkState; +}; + +/* DownstreamSettings, Configuration of downstream interface (not part of The Hermes Standard) */ +struct HermesDownstreamSettings +{ + HermesStringView m_machineId; + HermesStringView m_optionalClientAddress; + uint16_t m_port; + double m_checkAlivePeriodInSeconds; + double m_reconnectWaitTimeInSeconds; + EHermesCheckAliveResponseMode m_checkAliveResponseMode; + EHermesCheckState m_checkState; +}; + +/* ConfigurationServiceSettings, Configuration of configuration service interface (not part of The Hermes Standard) */ +struct HermesConfigurationServiceSettings +{ + uint16_t m_port; + double m_reconnectWaitTimeInSeconds; +}; + +/* VerticalServiceSettings, Configuration of vertical service interface (not part of The Hermes Standard) */ +struct HermesVerticalServiceSettings +{ + HermesStringView m_systemId; + uint16_t m_port; + double m_reconnectWaitTimeInSeconds; + double m_checkAlivePeriodInSeconds; + EHermesCheckAliveResponseMode m_checkAliveResponseMode; +}; + +/* VerticalClientSettings, Configuration of vertical client interface (not part of The Hermes Standard) */ +struct HermesVerticalClientSettings +{ + HermesStringView m_systemId; + HermesStringView m_hostAddress; + uint16_t m_port; + double m_reconnectWaitTimeInSeconds; + double m_checkAlivePeriodInSeconds; + EHermesCheckAliveResponseMode m_checkAliveResponseMode; +}; + +/* Error, Error object (not part of The Hermes Standard) */ +struct HermesError +{ + EHermesErrorCode m_code; + HermesStringView m_text; +}; + +/* ConnectionInfo, Attributes for the established connection (not part of The Hermes Standard) */ +struct HermesConnectionInfo +{ + HermesStringView m_address; + uint16_t m_port; + HermesStringView m_hostName; +}; + +#ifdef __cplusplus +} +#endif + +#endif //#define HERMESDATA_H diff --git a/src/include/HermesData.hpp b/src/include/HermesData.hpp index 8a5c200..442bdba 100644 --- a/src/include/HermesData.hpp +++ b/src/include/HermesData.hpp @@ -1,815 +1,2254 @@ -/*********************************************************************** -Copyright 2018 ASM Assembly Systems GmbH & Co. KG - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -************************************************************************/ - -// Copyright (c) ASM Assembly Systems GmbH & Co. KG -#pragma once - -#include "HermesOptional.hpp" -#include "HermesStringView.hpp" - -#include -#include - -namespace Hermes -{ - static const uint16_t cCONFIG_PORT = 1248U; - static const uint16_t cBASE_PORT = 50100U; - static const std::size_t cMAX_MESSAGE_SIZE = 65536U; - - enum class EState - { - eNOT_CONNECTED, - eSOCKET_CONNECTED, - eSERVICE_DESCRIPTION_DOWNSTREAM, - eNOT_AVAILABLE_NOT_READY, - eBOARD_AVAILABLE, - eMACHINE_READY, - eAVAILABLE_AND_READY, - eTRANSPORTING, - eTRANSPORT_STOPPED, - eTRANSPORT_FINISHED, - eDISCONNECTED - }; - template - S& operator<<(S& s, EState e) - { - switch (e) - { - case EState::eNOT_CONNECTED: s << "eNOT_CONNECTED"; return s; - case EState::eSOCKET_CONNECTED: s << "eSOCKET_CONNECTED"; return s; - case EState::eSERVICE_DESCRIPTION_DOWNSTREAM: s << "eUPSTREAM_SERVICE_DESCRIPTION"; return s; - case EState::eNOT_AVAILABLE_NOT_READY: s << "eNOT_AVAILABLE_NOT_READY"; return s; - case EState::eBOARD_AVAILABLE: s << "eBOARD_AVAILABLE"; return s; - case EState::eMACHINE_READY: s << "eMACHINE_READY"; return s; - case EState::eAVAILABLE_AND_READY: s << "eAVAILABLE_AND_READY"; return s; - case EState::eTRANSPORTING: s << "eTRANSPORTING"; return s; - case EState::eTRANSPORT_STOPPED: s << "eTRANSPORT_STOPPED"; return s; - case EState::eTRANSPORT_FINISHED: s << "eTRANSPORT_FINISHED"; return s; - case EState::eDISCONNECTED: s << "eDISCONNECTED"; return s; - default: s << "INVALID_STATE:" << static_cast(e); return s; - } - } - inline constexpr std::size_t size(EState) { return static_cast(EState::eDISCONNECTED) + 1U; } - - enum class ETraceType - { - eSENT, // raw message sent - eRECEIVED, // raw message received - eDEBUG, // debug trace from implementation internals - eINFO, - eWARNING, - eERROR - }; - template - S& operator<<(S& s, ETraceType e) - { - switch (e) - { - case ETraceType::eSENT: s << "eSENT"; return s; - case ETraceType::eRECEIVED: s << "eRECEIVED"; return s; - case ETraceType::eDEBUG: s << "eDEBUG"; return s; - case ETraceType::eINFO: s << "eINFO"; return s; - case ETraceType::eWARNING: s << "eWARNING"; return s; - case ETraceType::eERROR: s << "eERROR"; return s; - default: s << "INVALID_TRACE_TYPE:" << static_cast(e); return s; - } - } - inline constexpr std::size_t size(ETraceType) { return static_cast(ETraceType::eERROR) + 1U; } - - enum class EBoardQuality - { - eANY, - eGOOD, - eFAILED - }; - template - S& operator<<(S& s, EBoardQuality e) - { - switch (e) - { - case EBoardQuality::eANY: s << "eANY"; return s; - case EBoardQuality::eGOOD: s << "eGOOD"; return s; - case EBoardQuality::eFAILED: s << "eFAILED"; return s; - default: s << "INVALID_BOARD_QUALITY:" << static_cast(e); return s; - } - } - inline constexpr std::size_t size(EBoardQuality) { return static_cast(EBoardQuality::eFAILED) + 1U; } - - enum class EFlippedBoard - { - eSIDE_UP_IS_UNKNOWN, - eTOP_SIDE_IS_UP, - eBOTTOM_SIDE_IS_UP - }; - template - S& operator<<(S& s, EFlippedBoard e) - { - switch (e) - { - case EFlippedBoard::eSIDE_UP_IS_UNKNOWN: s << "eSIDE_UP_IS_UNKNOWN"; return s; - case EFlippedBoard::eTOP_SIDE_IS_UP: s << "eTOP_SIDE_IS_UP"; return s; - case EFlippedBoard::eBOTTOM_SIDE_IS_UP: s << "eBOTTOM_SIDE_IS_UP"; return s; - default: s << "INVALID_FLIPPED_BOARD:" << static_cast(e); return s; - } - } - inline constexpr std::size_t size(EFlippedBoard) { return static_cast(EFlippedBoard::eBOTTOM_SIDE_IS_UP) + 1U; } - - enum class ETransferState - { - eNOT_STARTED = 1, - eINCOMPLETE = 2, - eCOMPLETE = 3 - }; - template - S& operator<<(S& s, ETransferState e) - { - switch (e) - { - case ETransferState::eNOT_STARTED: s << "eNOT_STARTED"; return s; - case ETransferState::eINCOMPLETE: s << "eINCOMPLETE"; return s; - case ETransferState::eCOMPLETE: s << "eCOMPLETE"; return s; - default: s << "INVALID_TRANSFER_STATE:" << static_cast(e); return s; - } - } - inline constexpr std::size_t size(ETransferState) { return static_cast(ETransferState::eCOMPLETE) + 1U; } - - enum class ENotificationCode - { - eUNSPECIFIC, - ePROTOCOL_ERROR, - eCONNECTION_REFUSED_BECAUSE_OF_ESTABLISHED_CONNECTION, - eCONNECTION_RESET_BECAUSE_OF_CHANGED_CONFIGURATION, - eCONFIGURATION_ERROR, - eMACHINE_SHUTDOWN - }; - template - S& operator<<(S& s, ENotificationCode e) - { - switch (e) - { - case ENotificationCode::eUNSPECIFIC: s << "eUNSPECIFIC"; return s; - case ENotificationCode::ePROTOCOL_ERROR: s << "ePROTOCOL_ERROR"; return s; - case ENotificationCode::eCONNECTION_REFUSED_BECAUSE_OF_ESTABLISHED_CONNECTION: s << "eCONNECTION_REFUSED_BECAUSE_OF_ESTABLISHED_CONNECTION"; return s; - case ENotificationCode::eCONNECTION_RESET_BECAUSE_OF_CHANGED_CONFIGURATION: s << "eCONNECTION_RESET_BECAUSE_OF_CHANGED_CONFIGURATION"; return s; - case ENotificationCode::eCONFIGURATION_ERROR: s << "eCONFIGURATION_ERROR"; return s; - case ENotificationCode::eMACHINE_SHUTDOWN: s << "eMACHINE_SHUTDOWN"; return s; - default: s << "UNKNOWN_NOTIFICATION_CODE:" << static_cast(e); return s; - } - } - inline constexpr std::size_t size(ENotificationCode) { return static_cast(ENotificationCode::eMACHINE_SHUTDOWN) + 1U; } - - enum class ESeverity - { - eUNKNOWN, - eFATAL, - eERROR, - eWARNING, - eINFO - }; - template - S& operator<<(S& s, ESeverity e) - { - switch (e) - { - case ESeverity::eUNKNOWN: s << "eUNKNOWN"; return s; - case ESeverity::eFATAL: s << "eFATAL"; return s; - case ESeverity::eERROR: s << "eERROR"; return s; - case ESeverity::eWARNING: s << "eWARNING"; return s; - case ESeverity::eINFO: s << "eINFO"; return s; - default: s << "INVALID_SEVERITY:" << static_cast(e); return s; - } - } - inline constexpr std::size_t size(ESeverity) { return static_cast(ESeverity::eINFO) + 1U; } - - enum class ECheckState - { - eSEND_AND_RECEIVE, - eONLY_RECEIVE - }; - template - S& operator<<(S& s, ECheckState e) - { - switch (e) - { - case ECheckState::eSEND_AND_RECEIVE: s << "eSEND_AND_RECEIVE"; return s; - case ECheckState::eONLY_RECEIVE: s << "eONLY_RECEIVE"; return s; - default: s << "INVALID_CHECK_STATE:" << static_cast(e); return s; - } - } - inline constexpr std::size_t size(ECheckState) { return static_cast(ECheckState::eONLY_RECEIVE) + 1U; } - - enum class EErrorCode - { - eSUCCESS, - eIMPLEMENTATION_ERROR, // error inside the Hermes DLL - ePEER_ERROR, // the remote host has misbehaved - eCLIENT_ERROR, // the client code making the API calls has misbehaved - eNETWORK_ERROR, // something is wrong with the network or its configuration - eTIMEOUT // a specified timeout has been reached - }; - template - S& operator<<(S& s, EErrorCode e) - { - switch (e) - { - case EErrorCode::eSUCCESS: s << "eSUCCESS"; return s; - case EErrorCode::eIMPLEMENTATION_ERROR: s << "eIMPLEMENTATION_ERROR"; return s; - case EErrorCode::ePEER_ERROR: s << "ePEER_ERROR"; return s; - case EErrorCode::eCLIENT_ERROR: s << "eCLIENT_ERROR"; return s; - case EErrorCode::eNETWORK_ERROR: s << "eNETWORK_ERROR"; return s; - case EErrorCode::eTIMEOUT: s << "eTIMEOUT"; return s; - default: s << "INVALID_ERROR_CODE:" << static_cast(e); return s; - } - } - inline constexpr std::size_t size(EErrorCode) { return static_cast(EErrorCode::eTIMEOUT) + 1U; } - - struct UpstreamConfiguration - { - unsigned m_upstreamLaneId = 0; - std::string m_hostAddress; - uint16_t m_port = 0; - - UpstreamConfiguration() = default; - UpstreamConfiguration(uint32_t upstreamLaneId, StringView hostName, uint16_t port = 0) : - m_upstreamLaneId(upstreamLaneId), - m_hostAddress(hostName), - m_port(port) - {} - - friend bool operator==(const UpstreamConfiguration& lhs, const UpstreamConfiguration& rhs) - { - return lhs.m_upstreamLaneId == rhs.m_upstreamLaneId - && lhs.m_hostAddress == rhs.m_hostAddress - && lhs.m_port == rhs.m_port; - } - friend bool operator!=(const UpstreamConfiguration& lhs, const UpstreamConfiguration& rhs) { return !operator==(lhs, rhs); } - - - template - friend S& operator<<(S& s, const UpstreamConfiguration& in_config) - { - s << "{m_upstreamLaneId=" << in_config.m_upstreamLaneId - << "\n,m_hostAddress=" << in_config.m_hostAddress - << "\n,m_port=" << in_config.m_port - << '}'; - return s; - } - }; - - struct DownstreamConfiguration - { - uint32_t m_downstreamLaneId = 0; - std::string m_optionalClientAddress; - uint16_t m_port = 0; - - DownstreamConfiguration() = default; - DownstreamConfiguration(int32_t downstreamLaneId, uint16_t port = 0) : - m_downstreamLaneId(downstreamLaneId), - m_port(port) - {} - DownstreamConfiguration(uint32_t downstreamLaneId, const std::string& clientName, uint16_t port = 0) : - m_downstreamLaneId(downstreamLaneId), - m_optionalClientAddress(clientName), - m_port(port) - {} - - friend bool operator==(const DownstreamConfiguration& lhs, const DownstreamConfiguration& rhs) - { - return lhs.m_downstreamLaneId == rhs.m_downstreamLaneId - && lhs.m_optionalClientAddress == rhs.m_optionalClientAddress - && lhs.m_port == rhs.m_port; - } - friend bool operator!=(const DownstreamConfiguration& lhs, const DownstreamConfiguration& rhs) { return !operator==(lhs, rhs); } - - template - friend S& operator<<(S& s, const DownstreamConfiguration& in_config) - { - s << "{ m_downstreamLaneId=" << in_config.m_downstreamLaneId - << "\n,m_optionalClientAddress=" << in_config.m_optionalClientAddress - << "\n,m_port=" << in_config.m_port << '}'; - return s; - } - }; - - struct SetConfigurationData - { - std::string m_machineId; - std::vector m_upstreamConfigurations; - std::vector m_downstreamConfigurations; - - friend bool operator==(const SetConfigurationData& lhs, const SetConfigurationData& rhs) - { - return lhs.m_machineId == rhs.m_machineId - && lhs.m_downstreamConfigurations == rhs.m_downstreamConfigurations - && lhs.m_upstreamConfigurations == rhs.m_upstreamConfigurations; - } - friend bool operator!=(const SetConfigurationData& lhs, const SetConfigurationData& rhs) { return !operator==(lhs, rhs); } - - - template - friend S& operator<<(S& s, const SetConfigurationData& in_data) - { - s << "{m_machineId=" << in_data.m_machineId; - for (const auto& config : in_data.m_upstreamConfigurations) - { - s << "\n,upstream=" << config; - } - for (const auto& config : in_data.m_downstreamConfigurations) - { - s << "\n,downstream=" << config; - } - s << '}'; - return s; - } - }; - - struct GetConfigurationData // for uniformity and future extensions - { - friend bool operator==(const GetConfigurationData&, const GetConfigurationData&) { return true; } - friend bool operator!=(const GetConfigurationData&, const GetConfigurationData&) { return false; } - template friend S& operator<<(S& s, const GetConfigurationData&) - { - s << "{}"; - return s; - } - }; - - struct CurrentConfigurationData - { - Optional m_optionalMachineId; - std::vector m_upstreamConfigurations; - std::vector m_downstreamConfigurations; - - CurrentConfigurationData() = default; - - friend bool operator==(const CurrentConfigurationData& lhs, const CurrentConfigurationData& rhs) - { - return lhs.m_optionalMachineId == rhs.m_optionalMachineId - && lhs.m_downstreamConfigurations == rhs.m_downstreamConfigurations - && lhs.m_upstreamConfigurations == rhs.m_upstreamConfigurations; - } - friend bool operator!=(const CurrentConfigurationData& lhs, const CurrentConfigurationData& rhs) { return !operator==(lhs, rhs); } - - template - friend S& operator<<(S& s, const CurrentConfigurationData& in_data) - { - s << "{m_optionalMachineId=" << in_data.m_optionalMachineId; - for (const auto& upstreamConfig : in_data.m_upstreamConfigurations) - { - s << "\n,upstream=" << upstreamConfig; - } - for (const auto& downstreamConfig : in_data.m_downstreamConfigurations) - { - s << "\n,downstream=" << downstreamConfig; - } - s << '}'; - return s; - } - }; - - struct ConnectionInfo - { - std::string m_address; - uint16_t m_port = 0U; - std::string m_hostName; - - ConnectionInfo() = default; - ConnectionInfo(StringView address, uint16_t port, StringView hostName) : - m_address(address), - m_port(port), - m_hostName(hostName) - {} - - friend bool operator==(const ConnectionInfo& lhs, const ConnectionInfo& rhs) - { - return lhs.m_address == rhs.m_address - && lhs.m_port == rhs.m_port - && lhs.m_hostName == rhs.m_hostName; - } - friend bool operator!=(const ConnectionInfo& lhs, const ConnectionInfo& rhs) { return !operator==(lhs, rhs); } - - template - friend S& operator<<(S& s, const ConnectionInfo& info) - { - s << "{m_address=" << info.m_address - << "\n,m_port=" << info.m_port - << "\n,m_hostName=" << info.m_hostName - << '}'; - return s; - } - }; - - struct ServiceDescription - { - std::string m_machineId; - uint32_t m_laneId = 1; - std::string m_version{"1.0"}; - - ServiceDescription() = default; - ServiceDescription(StringView machineId, uint32_t laneId) : - m_machineId(machineId), - m_laneId(laneId) - {} - - friend bool operator==(const ServiceDescription& lhs, const ServiceDescription& rhs) - { - return lhs.m_machineId == rhs.m_machineId - && lhs.m_laneId == rhs.m_laneId - && lhs.m_version == rhs.m_version; - } - friend bool operator!=(const ServiceDescription& lhs, const ServiceDescription& rhs) { return !operator==(lhs, rhs); } - - template - friend S& operator<<(S& s, const ServiceDescription& in_data) - { - s << "{m_machineId=" << in_data.m_machineId - << "\n,m_laneId=" << in_data.m_laneId - << "\n,m_version=" << in_data.m_version - << '}'; - return s; - } - }; - - struct MachineReadyData - { - EBoardQuality m_failedBoard = EBoardQuality::eANY; - - MachineReadyData() = default; - explicit MachineReadyData(EBoardQuality quality) : m_failedBoard(quality) {} - - friend bool operator==(const MachineReadyData& lhs, const MachineReadyData& rhs) - { - return lhs.m_failedBoard == rhs.m_failedBoard; - } - friend bool operator!=(const MachineReadyData& lhs, const MachineReadyData& rhs) { return !operator==(lhs, rhs); } - - template - friend S& operator<<(S& s, const MachineReadyData& in_data) - { - s << "{m_failedBoard=" << in_data.m_failedBoard << '}'; - return s; - } - }; - - - struct RevokeMachineReadyData // for uniformity and future extensions - { - friend bool operator==(const RevokeMachineReadyData&, const RevokeMachineReadyData&) { return true; } - friend bool operator!=(const RevokeMachineReadyData&, const RevokeMachineReadyData&) { return false; } - template friend S& operator<<(S& s, const RevokeMachineReadyData&) - { - s << "{}"; - return s; - } - }; - - struct BoardAvailableData - { - std::string m_boardId; - std::string m_boardIdCreatedBy; - EBoardQuality m_failedBoard = EBoardQuality::eANY; - Optional m_optionalProductTypeId; - EFlippedBoard m_flippedBoard = EFlippedBoard::eSIDE_UP_IS_UNKNOWN; - Optional m_optionalTopBarcode; - Optional m_optionalBottomBarcode; - Optional m_optionalLengthInMM; - Optional m_optionalWidthInMM; - Optional m_optionalThicknessInMM; - Optional m_optionalConveyorSpeedInMMPerSecs; - Optional m_optionalTopClearanceHeightInMM; - Optional m_optionalBottomClearanceHeightInMM; - - BoardAvailableData() = default; - BoardAvailableData(StringView boardId, StringView boardIdCreatedBy, - EBoardQuality failedBoard = EBoardQuality::eANY, - EFlippedBoard flippedBoard = EFlippedBoard::eSIDE_UP_IS_UNKNOWN) : - m_boardId(boardId), - m_boardIdCreatedBy(boardIdCreatedBy), - m_failedBoard(failedBoard), - m_flippedBoard(flippedBoard) - {} - - friend bool operator==(const BoardAvailableData& lhs, const BoardAvailableData& rhs) - { - return lhs.m_boardId == rhs.m_boardId - && lhs.m_boardIdCreatedBy == rhs.m_boardIdCreatedBy - && lhs.m_failedBoard == rhs.m_failedBoard - && lhs.m_optionalProductTypeId == rhs.m_optionalProductTypeId - && lhs.m_flippedBoard == rhs.m_flippedBoard - && lhs.m_optionalTopBarcode == rhs.m_optionalTopBarcode - && lhs.m_optionalBottomBarcode == rhs.m_optionalBottomBarcode - && lhs.m_optionalLengthInMM == rhs.m_optionalLengthInMM - && lhs.m_optionalWidthInMM == rhs.m_optionalWidthInMM - && lhs.m_optionalThicknessInMM == rhs.m_optionalThicknessInMM - && lhs.m_optionalConveyorSpeedInMMPerSecs == rhs.m_optionalConveyorSpeedInMMPerSecs - && lhs.m_optionalTopClearanceHeightInMM == rhs.m_optionalTopClearanceHeightInMM - && lhs.m_optionalBottomClearanceHeightInMM == rhs.m_optionalBottomClearanceHeightInMM; - } - friend bool operator!=(const BoardAvailableData& lhs, const BoardAvailableData& rhs) { return !operator==(lhs, rhs); } - - template - friend S& operator<<(S& s, const BoardAvailableData& in_data) - { - s << "{m_boardId=" << in_data.m_boardId - << "\n,m_boardIdCreatedBy=" << in_data.m_boardIdCreatedBy - << "\n,m_failedBoard=" << in_data.m_failedBoard - << "\n,m_optionalProductTypeId=" << in_data.m_optionalProductTypeId - << "\n,m_flippedBoard=" << in_data.m_flippedBoard - << "\n,m_optionalTopBarcode=" << in_data.m_optionalTopBarcode - << "\n,m_optionalBottomBarcode=" << in_data.m_optionalBottomBarcode - << "\n,m_optionalLengthInMM=" << in_data.m_optionalLengthInMM - << "\n,m_optionalWidthInMM=" << in_data.m_optionalWidthInMM - << "\n,m_optionalThicknessInMM=" << in_data.m_optionalThicknessInMM - << "\n,m_optionalConveyorSpeedInMMPerSecs=" << in_data.m_optionalConveyorSpeedInMMPerSecs - << "\n,m_optionalTopClearanceHeightInMM=" << in_data.m_optionalTopClearanceHeightInMM - << "\n,m_optionalBottomClearanceHeightInMM=" << in_data.m_optionalBottomClearanceHeightInMM - << '}'; - return s; - } - }; - - struct RevokeBoardAvailableData // for uniformity and future extensions - { - friend bool operator==(const RevokeBoardAvailableData&, const RevokeBoardAvailableData&) { return true; } - friend bool operator!=(const RevokeBoardAvailableData&, const RevokeBoardAvailableData&) { return false; } - template friend S& operator<<(S& s, const RevokeBoardAvailableData&) - { - s << "{}"; - return s; - } - }; - - struct StartTransportData - { - std::string m_boardId; - Optional m_optionalConveyorSpeedInMMPerSecs; - - StartTransportData() = default; - explicit StartTransportData(StringView boardId) : - m_boardId(boardId) - {} - - friend bool operator==(const StartTransportData& lhs, const StartTransportData& rhs) - { - return lhs.m_boardId == rhs.m_boardId - && lhs.m_optionalConveyorSpeedInMMPerSecs == rhs.m_optionalConveyorSpeedInMMPerSecs; - } - friend bool operator!=(const StartTransportData& lhs, const StartTransportData& rhs) { return !operator==(lhs, rhs); } - - template - friend S& operator<<(S& s, const StartTransportData& in_data) - { - s << "{m_boardId=" << in_data.m_boardId - << "\n,m_optionalConveyorSpeedInMMPerSecs=" << in_data.m_optionalConveyorSpeedInMMPerSecs - << '}'; - return s; - } - }; - - struct StopTransportData - { - ETransferState m_transferState = ETransferState::eINCOMPLETE; - std::string m_boardId; - - StopTransportData() = default; - StopTransportData(ETransferState state, StringView boardId) : - m_transferState(state), - m_boardId(boardId) - {} - - friend bool operator==(const StopTransportData& lhs, const StopTransportData& rhs) - { - return lhs.m_boardId == rhs.m_boardId - && lhs.m_transferState == rhs.m_transferState; - } - friend bool operator!=(const StopTransportData& lhs, const StopTransportData& rhs) { return !operator==(lhs, rhs); } - - template - friend S& operator<<(S& s, const StopTransportData& in_data) - { - s << "{m_transferState=" << in_data.m_transferState - << "\n,m_boardId=" << in_data.m_boardId - << '}'; - return s; - } - }; - - struct TransportFinishedData - { - ETransferState m_transferState = ETransferState::eINCOMPLETE; - std::string m_boardId; - - TransportFinishedData() = default; - TransportFinishedData(ETransferState state, StringView boardId) : - m_transferState(state), - m_boardId(boardId) - {} - - friend bool operator==(const TransportFinishedData& lhs, const TransportFinishedData& rhs) - { - return lhs.m_boardId == rhs.m_boardId - && lhs.m_transferState == rhs.m_transferState; - } - friend bool operator!=(const TransportFinishedData& lhs, const TransportFinishedData& rhs) { return !operator==(lhs, rhs); } - - template - friend S& operator<<(S& s, const TransportFinishedData& in_data) - { - s << "{m_transferState=" << in_data.m_transferState - << "\n,m_boardId=" << in_data.m_boardId - << '}'; - return s; - } - }; - - struct NotificationData - { - ENotificationCode m_notificationCode = ENotificationCode::eUNSPECIFIC; - ESeverity m_severity{}; - std::string m_description; - - NotificationData() = default; - NotificationData(ENotificationCode code, ESeverity severity, StringView description) : - m_notificationCode(code), - m_severity(severity), - m_description(description) - {} - - friend bool operator==(const NotificationData& lhs, const NotificationData& rhs) - { - return lhs.m_notificationCode == rhs.m_notificationCode - && lhs.m_severity == rhs.m_severity - && lhs.m_description == rhs.m_description; - } - friend bool operator!=(const NotificationData& lhs, const NotificationData& rhs) { return !operator==(lhs, rhs); } - - template - friend S& operator<<(S& s, const NotificationData& in_data) - { - s << "{m_notificationCode=" << in_data.m_notificationCode - << "\n,m_severity=" << in_data.m_severity - << "\n,m_description=" << in_data.m_description - << '}'; - return s; - } - }; - - struct CheckAliveData // for uniformity and future extensions - { - friend bool operator==(const CheckAliveData&, const CheckAliveData&) { return true; } - friend bool operator!=(const CheckAliveData&, const CheckAliveData&) { return false; } - template friend S& operator<<(S& s, const CheckAliveData&) - { - s << "{}"; - return s; - } - }; - - struct UpstreamSettings - { - std::string m_machineId; - std::string m_hostAddress; - uint16_t m_port = 0U; // if 0, then HermesProcol will use the default port for this lane - uint32_t m_checkAlivePeriodInSeconds = 60U; - uint32_t m_reconnectWaitTimeInSeconds = 10U; - ECheckState m_checkState = ECheckState::eSEND_AND_RECEIVE; - - UpstreamSettings() = default; - UpstreamSettings(StringView machineId, StringView upstreamHostName, uint16_t upstreamPort) : - m_machineId(machineId), - m_hostAddress(upstreamHostName), - m_port(upstreamPort) - {} - - friend bool operator==(const UpstreamSettings& lhs, const UpstreamSettings& rhs) - { - return lhs.m_machineId == rhs.m_machineId - && lhs.m_hostAddress == rhs.m_hostAddress - && lhs.m_port == rhs.m_port - && lhs.m_checkAlivePeriodInSeconds == rhs.m_checkAlivePeriodInSeconds - && lhs.m_reconnectWaitTimeInSeconds == rhs.m_reconnectWaitTimeInSeconds - && lhs.m_checkState == rhs.m_checkState; - } - friend bool operator!=(const UpstreamSettings& lhs, const UpstreamSettings& rhs) { return !operator==(lhs, rhs); } - - template - friend S& operator<<(S& s, const UpstreamSettings& in_data) - { - s << "{m_machineId=" << in_data.m_machineId - << "\n,m_hostAddress=" << in_data.m_hostAddress - << "\n,m_port=" << in_data.m_port - << "\n,m_checkAlivePeriodInSeconds=" << in_data.m_checkAlivePeriodInSeconds - << "\n,m_reconnectWaitTimeInSeconds=" << in_data.m_reconnectWaitTimeInSeconds - << "\n,m_checkState=" << in_data.m_checkState - << '}'; - return s; - } - }; - - struct DownstreamSettings - { - std::string m_machineId; - std::string m_optionalClientAddress; // if empty then requests from any client will be accepted - uint16_t m_port = 0; // if 0, then HermesProcol will use the default port for this lane - uint32_t m_checkAlivePeriodInSeconds = 60U; - uint32_t m_reconnectWaitTimeInSeconds = 10U; - ECheckState m_checkState = ECheckState::eSEND_AND_RECEIVE; - - DownstreamSettings() = default; - explicit DownstreamSettings(StringView machineId, uint16_t myPort) : - m_machineId(machineId), - m_port(myPort) - {} - - friend bool operator==(const DownstreamSettings& lhs, const DownstreamSettings& rhs) - { - return lhs.m_machineId == rhs.m_machineId - && lhs.m_optionalClientAddress == rhs.m_optionalClientAddress - && lhs.m_port == rhs.m_port - && lhs.m_checkAlivePeriodInSeconds == rhs.m_checkAlivePeriodInSeconds - && lhs.m_reconnectWaitTimeInSeconds == rhs.m_reconnectWaitTimeInSeconds - && lhs.m_checkState == rhs.m_checkState; - } - friend bool operator!=(const DownstreamSettings& lhs, const DownstreamSettings& rhs) { return !operator==(lhs, rhs); } - - template - friend S& operator<<(S& s, const DownstreamSettings& in_data) - { - s << "{m_machineId=" << in_data.m_machineId - << "\n,m_optionalClientAddress=" << in_data.m_optionalClientAddress - << "\n,m_port=" << in_data.m_port - << "\n,m_checkAlivePeriodInSeconds=" << in_data.m_checkAlivePeriodInSeconds - << "\n,m_reconnectWaitTimeInSeconds=" << in_data.m_reconnectWaitTimeInSeconds - << "\n,m_checkState=" << in_data.m_checkState - << '}'; - return s; - } - }; - - struct ConfigurationServiceSettings - { - uint16_t m_port = 0; - uint32_t m_reconnectWaitTimeInSeconds = 10U; - - friend bool operator==(const ConfigurationServiceSettings& lhs, const ConfigurationServiceSettings& rhs) - { - return lhs.m_port == rhs.m_port - && lhs.m_reconnectWaitTimeInSeconds == rhs.m_reconnectWaitTimeInSeconds; - } - friend bool operator!=(const ConfigurationServiceSettings& lhs, const ConfigurationServiceSettings& rhs) { return !operator==(lhs, rhs); } - - template - friend S& operator<<(S& s, const ConfigurationServiceSettings& in_data) - { - s << "{m_port=" << in_data.m_port - << "\n,m_reconnectWaitTimeInSeconds=" << in_data.m_reconnectWaitTimeInSeconds - << '}'; - return s; - } - }; - - class Error - { - public: - EErrorCode m_code = EErrorCode::eSUCCESS; - std::string m_text; - - Error() {} - Error(EErrorCode code, StringView text) : - m_code(code), - m_text(text) - {} - - explicit operator bool() const { return m_code != EErrorCode::eSUCCESS; } - - friend bool operator==(const Error& lhs, const Error& rhs) - { - return lhs.m_code == rhs.m_code - && lhs.m_text == rhs.m_text; - } - friend bool operator!=(const Error& lhs, const Error& rhs) { return !operator==(lhs, rhs); } - - template - friend S& operator<<(S& s, const Error& error) - { - s << '{' << error.m_code; - if (!error.m_text.empty()) { s << "\n," << error.m_text; } - s << '}'; - return s; - } - - }; -} +// Copyright (c) ASM Assembly Systems GmbH & Co. KG +// +// C++ interface for an implementation of The Hermes Standard +// +#pragma once + +#include "HermesOptional.hpp" +#include "HermesStringView.hpp" + +#include +#include +#include + +namespace Hermes { + +static const uint32_t cMAX_MESSAGE_SIZE = 65536U; // The Hermes Standard 3.1 +static const uint16_t cBASE_PORT = 50100U; // The Hermes Standard 2.3.1 +static const uint16_t cCONFIG_PORT = 1248U; // The Hermes Standard 2.4.1 +static const uint16_t cROUTE_RETURN_BOARD = 900U; // The Hermes Standard 3.6 +static const uint16_t cROUTE_UNDEFINED = 999U; // The Hermes Standard 3.6 +static const uint16_t cROUTE_MANUALLY_REMOVE_BOARD = 999U; // The Hermes Standard 3.6 +static const uint16_t cACTION_UNDEFINED = 1U; // The Hermes Standard 3.6 +static const uint16_t cACTION_PROCESS_BOARD = 1U; // The Hermes Standard 3.6 +static const uint16_t cACTION_PASS_THROUGH_BOARD = 2U; // The Hermes Standard 3.6 + + +//========== The Hermes Standard 3.3 ========== +enum class ECheckAliveType +{ + eUNKNOWN, + ePING, + ePONG +}; +template +S& operator<<(S& s, ECheckAliveType e) +{ + switch(e) + { + case ECheckAliveType::eUNKNOWN: s << "eUNKNOWN"; return s; + case ECheckAliveType::ePING: s << "ePING"; return s; + case ECheckAliveType::ePONG: s << "ePONG"; return s; + default: s << "INVALID_CHECK_ALIVE_TYPE: " << static_cast(e); return s; + } +} +inline constexpr std::size_t size(ECheckAliveType) { return 3; } + +//========== The Hermes Standard 3.5 ========== +enum class ENotificationCode +{ + eUNSPECIFIC, + ePROTOCOL_ERROR, + eCONNECTION_REFUSED_BECAUSE_OF_ESTABLISHED_CONNECTION, + eCONNECTION_RESET_BECAUSE_OF_CHANGED_CONFIGURATION, + eCONFIGURATION_ERROR, + eMACHINE_SHUTDOWN, + eBOARD_FORECAST_ERROR +}; +template +S& operator<<(S& s, ENotificationCode e) +{ + switch(e) + { + case ENotificationCode::eUNSPECIFIC: s << "eUNSPECIFIC"; return s; + case ENotificationCode::ePROTOCOL_ERROR: s << "ePROTOCOL_ERROR"; return s; + case ENotificationCode::eCONNECTION_REFUSED_BECAUSE_OF_ESTABLISHED_CONNECTION: s << "eCONNECTION_REFUSED_BECAUSE_OF_ESTABLISHED_CONNECTION"; return s; + case ENotificationCode::eCONNECTION_RESET_BECAUSE_OF_CHANGED_CONFIGURATION: s << "eCONNECTION_RESET_BECAUSE_OF_CHANGED_CONFIGURATION"; return s; + case ENotificationCode::eCONFIGURATION_ERROR: s << "eCONFIGURATION_ERROR"; return s; + case ENotificationCode::eMACHINE_SHUTDOWN: s << "eMACHINE_SHUTDOWN"; return s; + case ENotificationCode::eBOARD_FORECAST_ERROR: s << "eBOARD_FORECAST_ERROR"; return s; + default: s << "INVALID_NOTIFICATION_CODE: " << static_cast(e); return s; + } +} +inline constexpr std::size_t size(ENotificationCode) { return 7; } + +//========== The Hermes Standard 3.5 ========== +enum class ESeverity +{ + eUNKNOWN, + eFATAL, + eERROR, + eWARNING, + eINFO +}; +template +S& operator<<(S& s, ESeverity e) +{ + switch(e) + { + case ESeverity::eUNKNOWN: s << "eUNKNOWN"; return s; + case ESeverity::eFATAL: s << "eFATAL"; return s; + case ESeverity::eERROR: s << "eERROR"; return s; + case ESeverity::eWARNING: s << "eWARNING"; return s; + case ESeverity::eINFO: s << "eINFO"; return s; + default: s << "INVALID_SEVERITY: " << static_cast(e); return s; + } +} +inline constexpr std::size_t size(ESeverity) { return 5; } + +//========== The Hermes Standard 3.6 ========== +enum class EBoardQuality +{ + eANY, + eGOOD, + eBAD +}; +template +S& operator<<(S& s, EBoardQuality e) +{ + switch(e) + { + case EBoardQuality::eANY: s << "eANY"; return s; + case EBoardQuality::eGOOD: s << "eGOOD"; return s; + case EBoardQuality::eBAD: s << "eBAD"; return s; + default: s << "INVALID_BOARD_QUALITY: " << static_cast(e); return s; + } +} +inline constexpr std::size_t size(EBoardQuality) { return 3; } + +//========== The Hermes Standard 3.6 ========== +enum class EFlippedBoard +{ + eSIDE_UP_IS_UNKNOWN, + eTOP_SIDE_IS_UP, + eBOTTOM_SIDE_IS_UP +}; +template +S& operator<<(S& s, EFlippedBoard e) +{ + switch(e) + { + case EFlippedBoard::eSIDE_UP_IS_UNKNOWN: s << "eSIDE_UP_IS_UNKNOWN"; return s; + case EFlippedBoard::eTOP_SIDE_IS_UP: s << "eTOP_SIDE_IS_UP"; return s; + case EFlippedBoard::eBOTTOM_SIDE_IS_UP: s << "eBOTTOM_SIDE_IS_UP"; return s; + default: s << "INVALID_FLIPPED_BOARD: " << static_cast(e); return s; + } +} +inline constexpr std::size_t size(EFlippedBoard) { return 3; } + +//========== The Hermes Standard 3.6 ========== +enum class ESubBoardState +{ + eUNKNOWN, + eGOOD, + eFAILED, + eMISSING, + eSKIP +}; +template +S& operator<<(S& s, ESubBoardState e) +{ + switch(e) + { + case ESubBoardState::eUNKNOWN: s << "eUNKNOWN"; return s; + case ESubBoardState::eGOOD: s << "eGOOD"; return s; + case ESubBoardState::eFAILED: s << "eFAILED"; return s; + case ESubBoardState::eMISSING: s << "eMISSING"; return s; + case ESubBoardState::eSKIP: s << "eSKIP"; return s; + default: s << "INVALID_SUB_BOARD_STATE: " << static_cast(e); return s; + } +} +inline constexpr std::size_t size(ESubBoardState) { return 5; } + +//========== The Hermes Standard 3.11 ========== +enum class ETransferState +{ + eUNKNOWN, + eNOT_STARTED, + eINCOMPLETE, + eCOMPLETE +}; +template +S& operator<<(S& s, ETransferState e) +{ + switch(e) + { + case ETransferState::eUNKNOWN: s << "eUNKNOWN"; return s; + case ETransferState::eNOT_STARTED: s << "eNOT_STARTED"; return s; + case ETransferState::eINCOMPLETE: s << "eINCOMPLETE"; return s; + case ETransferState::eCOMPLETE: s << "eCOMPLETE"; return s; + default: s << "INVALID_TRANSFER_STATE: " << static_cast(e); return s; + } +} +inline constexpr std::size_t size(ETransferState) { return 4; } + +//========== The Hermes Standard 3.23 ========== +enum class EBoardArrivedTransfer +{ + eUNKNOWN, + eTRANSFERRED, + eLOADED, + eINSERTED +}; +template +S& operator<<(S& s, EBoardArrivedTransfer e) +{ + switch(e) + { + case EBoardArrivedTransfer::eUNKNOWN: s << "eUNKNOWN"; return s; + case EBoardArrivedTransfer::eTRANSFERRED: s << "eTRANSFERRED"; return s; + case EBoardArrivedTransfer::eLOADED: s << "eLOADED"; return s; + case EBoardArrivedTransfer::eINSERTED: s << "eINSERTED"; return s; + default: s << "INVALID_BOARD_ARRIVED_TRANSFER: " << static_cast(e); return s; + } +} +inline constexpr std::size_t size(EBoardArrivedTransfer) { return 4; } + +//========== The Hermes Standard 3.24 ========== +enum class EBoardDepartedTransfer +{ + eUNKNOWN, + eTRANSFERRED, + eUNLOADED, + eREMOVED +}; +template +S& operator<<(S& s, EBoardDepartedTransfer e) +{ + switch(e) + { + case EBoardDepartedTransfer::eUNKNOWN: s << "eUNKNOWN"; return s; + case EBoardDepartedTransfer::eTRANSFERRED: s << "eTRANSFERRED"; return s; + case EBoardDepartedTransfer::eUNLOADED: s << "eUNLOADED"; return s; + case EBoardDepartedTransfer::eREMOVED: s << "eREMOVED"; return s; + default: s << "INVALID_BOARD_DEPARTED_TRANSFER: " << static_cast(e); return s; + } +} +inline constexpr std::size_t size(EBoardDepartedTransfer) { return 4; } + +//========== The Hermes Standard 3.27 ========== +enum class EReplyWorkOrderInfoStatus +{ + eREJECTED, + eACCEPTED_AND_READY, + eACCEPTED_AND_QUEUED +}; +template +S& operator<<(S& s, EReplyWorkOrderInfoStatus e) +{ + switch(e) + { + case EReplyWorkOrderInfoStatus::eREJECTED: s << "eREJECTED"; return s; + case EReplyWorkOrderInfoStatus::eACCEPTED_AND_READY: s << "eACCEPTED_AND_READY"; return s; + case EReplyWorkOrderInfoStatus::eACCEPTED_AND_QUEUED: s << "eACCEPTED_AND_QUEUED"; return s; + default: s << "INVALID_REPLY_WORK_ORDER_INFO_STATUS: " << static_cast(e); return s; + } +} +inline constexpr std::size_t size(EReplyWorkOrderInfoStatus) { return 3; } + +//========== The Hermes Standard chapter 2.6 ========== +enum class EState +{ + eNOT_CONNECTED, + eSOCKET_CONNECTED, + eSERVICE_DESCRIPTION_DOWNSTREAM, + eNOT_AVAILABLE_NOT_READY, + eBOARD_AVAILABLE, + eMACHINE_READY, + eAVAILABLE_AND_READY, + eTRANSPORTING, + eTRANSPORT_STOPPED, + eTRANSPORT_FINISHED, + eDISCONNECTED +}; +template +S& operator<<(S& s, EState e) +{ + switch(e) + { + case EState::eNOT_CONNECTED: s << "eNOT_CONNECTED"; return s; + case EState::eSOCKET_CONNECTED: s << "eSOCKET_CONNECTED"; return s; + case EState::eSERVICE_DESCRIPTION_DOWNSTREAM: s << "eSERVICE_DESCRIPTION_DOWNSTREAM"; return s; + case EState::eNOT_AVAILABLE_NOT_READY: s << "eNOT_AVAILABLE_NOT_READY"; return s; + case EState::eBOARD_AVAILABLE: s << "eBOARD_AVAILABLE"; return s; + case EState::eMACHINE_READY: s << "eMACHINE_READY"; return s; + case EState::eAVAILABLE_AND_READY: s << "eAVAILABLE_AND_READY"; return s; + case EState::eTRANSPORTING: s << "eTRANSPORTING"; return s; + case EState::eTRANSPORT_STOPPED: s << "eTRANSPORT_STOPPED"; return s; + case EState::eTRANSPORT_FINISHED: s << "eTRANSPORT_FINISHED"; return s; + case EState::eDISCONNECTED: s << "eDISCONNECTED"; return s; + default: s << "INVALID_STATE: " << static_cast(e); return s; + } +} +inline constexpr std::size_t size(EState) { return 11; } + +//========== Trace levels of the implementation (not part of The Hermes Standard) ========== +enum class ETraceType +{ + eSENT, // raw message sent + eRECEIVED, // raw message received + eDEBUG, + eINFO, + eWARNING, + eERROR +}; +template +S& operator<<(S& s, ETraceType e) +{ + switch(e) + { + case ETraceType::eSENT: s << "eSENT"; return s; + case ETraceType::eRECEIVED: s << "eRECEIVED"; return s; + case ETraceType::eDEBUG: s << "eDEBUG"; return s; + case ETraceType::eINFO: s << "eINFO"; return s; + case ETraceType::eWARNING: s << "eWARNING"; return s; + case ETraceType::eERROR: s << "eERROR"; return s; + default: s << "INVALID_TRACE_TYPE: " << static_cast(e); return s; + } +} +inline constexpr std::size_t size(ETraceType) { return 6; } + +//========== Internal state check modes of the implementation (not part of The Hermes Standard) ========== +enum class ECheckState +{ + eSEND_AND_RECEIVE, // check sent and received messages for conformance with state machine + eONLY_RECEIVE // check only received message for conformance with state machine +}; +template +S& operator<<(S& s, ECheckState e) +{ + switch(e) + { + case ECheckState::eSEND_AND_RECEIVE: s << "eSEND_AND_RECEIVE"; return s; + case ECheckState::eONLY_RECEIVE: s << "eONLY_RECEIVE"; return s; + default: s << "INVALID_CHECK_STATE: " << static_cast(e); return s; + } +} +inline constexpr std::size_t size(ECheckState) { return 2; } + +//========== How to respond to a check alive ping) ========== +enum class ECheckAliveResponseMode +{ + eAUTO, // automatically respond to a check alive ping with a pong + eAPPLICATION // let the application respond with a pong +}; +template +S& operator<<(S& s, ECheckAliveResponseMode e) +{ + switch(e) + { + case ECheckAliveResponseMode::eAUTO: s << "eAUTO"; return s; + case ECheckAliveResponseMode::eAPPLICATION: s << "eAPPLICATION"; return s; + default: s << "INVALID_CHECK_ALIVE_RESPONSE_MODE: " << static_cast(e); return s; + } +} +inline constexpr std::size_t size(ECheckAliveResponseMode) { return 2; } + +//========== Error codes (not part of The Hermes Standard) ========== +enum class EErrorCode +{ + eSUCCESS, + eIMPLEMENTATION_ERROR, // error inside the Hermes DLL + ePEER_ERROR, // the remote peer has misbehaved + eCLIENT_ERROR, // the client code making the API calls has misbehaved + eNETWORK_ERROR, // something is wrong with the network or its configuration + eTIMEOUT // the specified timeout has been exceeded +}; +template +S& operator<<(S& s, EErrorCode e) +{ + switch(e) + { + case EErrorCode::eSUCCESS: s << "eSUCCESS"; return s; + case EErrorCode::eIMPLEMENTATION_ERROR: s << "eIMPLEMENTATION_ERROR"; return s; + case EErrorCode::ePEER_ERROR: s << "ePEER_ERROR"; return s; + case EErrorCode::eCLIENT_ERROR: s << "eCLIENT_ERROR"; return s; + case EErrorCode::eNETWORK_ERROR: s << "eNETWORK_ERROR"; return s; + case EErrorCode::eTIMEOUT: s << "eTIMEOUT"; return s; + default: s << "INVALID_ERROR_CODE: " << static_cast(e); return s; + } +} +inline constexpr std::size_t size(EErrorCode) { return 6; } + +//========== The Hermes Standard chapter 2.5.3 ========== +enum class EVerticalState +{ + eNOT_CONNECTED, + eSOCKET_CONNECTED, + eSUPERVISORY_SERVICE_DESCRIPTION, + eCONNECTED, + eDISCONNECTED +}; +template +S& operator<<(S& s, EVerticalState e) +{ + switch(e) + { + case EVerticalState::eNOT_CONNECTED: s << "eNOT_CONNECTED"; return s; + case EVerticalState::eSOCKET_CONNECTED: s << "eSOCKET_CONNECTED"; return s; + case EVerticalState::eSUPERVISORY_SERVICE_DESCRIPTION: s << "eSUPERVISORY_SERVICE_DESCRIPTION"; return s; + case EVerticalState::eCONNECTED: s << "eCONNECTED"; return s; + case EVerticalState::eDISCONNECTED: s << "eDISCONNECTED"; return s; + default: s << "INVALID_VERTICAL_STATE: " << static_cast(e); return s; + } +} +inline constexpr std::size_t size(EVerticalState) { return 5; } + +//========== The Hermes Standard 3.3 ========== +struct CheckAliveData +{ + Optional m_optionalType; + Optional m_optionalId; + + friend bool operator==(const CheckAliveData& lhs, const CheckAliveData& rhs) + { + return lhs.m_optionalType == rhs.m_optionalType + && lhs.m_optionalId == rhs.m_optionalId; + } + friend bool operator!=(const CheckAliveData& lhs, const CheckAliveData& rhs) { return !operator==(lhs, rhs); } + + template friend S& operator<<(S& s, const CheckAliveData& data) + { + s << '{'; + if (data.m_optionalType) { s << " Type=" << *data.m_optionalType; } + if (data.m_optionalId) { s << " Id=" << *data.m_optionalId; } + s << " }"; + return s; + } +}; + +//========== The Hermes Standard 3.4 ========== +struct FeatureBoardForecast +{ + friend bool operator==(const FeatureBoardForecast&, const FeatureBoardForecast&) { return true; } + friend bool operator!=(const FeatureBoardForecast&, const FeatureBoardForecast&) { return false; } + template friend S& operator<<(S& s, const FeatureBoardForecast&) { s << "{}"; return s; } +}; + +//========== The Hermes Standard 3.4 ========== +struct FeatureCheckAliveResponse +{ + friend bool operator==(const FeatureCheckAliveResponse&, const FeatureCheckAliveResponse&) { return true; } + friend bool operator!=(const FeatureCheckAliveResponse&, const FeatureCheckAliveResponse&) { return false; } + template friend S& operator<<(S& s, const FeatureCheckAliveResponse&) { s << "{}"; return s; } +}; + +//========== The Hermes Standard 3.4 ========== +struct FeatureQueryBoardInfo +{ + friend bool operator==(const FeatureQueryBoardInfo&, const FeatureQueryBoardInfo&) { return true; } + friend bool operator!=(const FeatureQueryBoardInfo&, const FeatureQueryBoardInfo&) { return false; } + template friend S& operator<<(S& s, const FeatureQueryBoardInfo&) { s << "{}"; return s; } +}; + +//========== The Hermes Standard 3.4 ========== +struct FeatureSendBoardInfo +{ + friend bool operator==(const FeatureSendBoardInfo&, const FeatureSendBoardInfo&) { return true; } + friend bool operator!=(const FeatureSendBoardInfo&, const FeatureSendBoardInfo&) { return false; } + template friend S& operator<<(S& s, const FeatureSendBoardInfo&) { s << "{}"; return s; } +}; + +//========== The Hermes Standard 3.4 ========== +struct FeatureCommand +{ + friend bool operator==(const FeatureCommand&, const FeatureCommand&) { return true; } + friend bool operator!=(const FeatureCommand&, const FeatureCommand&) { return false; } + template friend S& operator<<(S& s, const FeatureCommand&) { s << "{}"; return s; } +}; + +//========== The Hermes Standard 3.4 ========== +struct SupportedFeatures +{ + Optional m_optionalFeatureBoardForecast; + Optional m_optionalFeatureCheckAliveResponse; + Optional m_optionalFeatureQueryBoardInfo; + Optional m_optionalFeatureSendBoardInfo; + Optional m_optionalFeatureCommand; + + friend bool operator==(const SupportedFeatures& lhs, const SupportedFeatures& rhs) + { + return lhs.m_optionalFeatureBoardForecast == rhs.m_optionalFeatureBoardForecast + && lhs.m_optionalFeatureCheckAliveResponse == rhs.m_optionalFeatureCheckAliveResponse + && lhs.m_optionalFeatureQueryBoardInfo == rhs.m_optionalFeatureQueryBoardInfo + && lhs.m_optionalFeatureSendBoardInfo == rhs.m_optionalFeatureSendBoardInfo + && lhs.m_optionalFeatureCommand == rhs.m_optionalFeatureCommand; + } + friend bool operator!=(const SupportedFeatures& lhs, const SupportedFeatures& rhs) { return !operator==(lhs, rhs); } + + template friend S& operator<<(S& s, const SupportedFeatures& data) + { + s << '{'; + if (data.m_optionalFeatureBoardForecast) { s << " FeatureBoardForecast=" << *data.m_optionalFeatureBoardForecast; } + if (data.m_optionalFeatureCheckAliveResponse) { s << " FeatureCheckAliveResponse=" << *data.m_optionalFeatureCheckAliveResponse; } + if (data.m_optionalFeatureQueryBoardInfo) { s << " FeatureQueryBoardInfo=" << *data.m_optionalFeatureQueryBoardInfo; } + if (data.m_optionalFeatureSendBoardInfo) { s << " FeatureSendBoardInfo=" << *data.m_optionalFeatureSendBoardInfo; } + if (data.m_optionalFeatureCommand) { s << " FeatureCommand=" << *data.m_optionalFeatureCommand; } + s << " }"; + return s; + } +}; + +//========== The Hermes Standard 3.4 ========== +struct ServiceDescriptionData +{ + std::string m_machineId; + unsigned m_laneId{0}; + Optional m_optionalInterfaceId; + std::string m_version{"1.5"}; + SupportedFeatures m_supportedFeatures; + + ServiceDescriptionData() = default; + ServiceDescriptionData(StringView machineId, + unsigned laneId) : + m_machineId(machineId), + m_laneId(laneId) + {} + + friend bool operator==(const ServiceDescriptionData& lhs, const ServiceDescriptionData& rhs) + { + return lhs.m_machineId == rhs.m_machineId + && lhs.m_laneId == rhs.m_laneId + && lhs.m_optionalInterfaceId == rhs.m_optionalInterfaceId + && lhs.m_version == rhs.m_version + && lhs.m_supportedFeatures == rhs.m_supportedFeatures; + } + friend bool operator!=(const ServiceDescriptionData& lhs, const ServiceDescriptionData& rhs) { return !operator==(lhs, rhs); } + + template friend S& operator<<(S& s, const ServiceDescriptionData& data) + { + s << '{'; + s << " MachineId=" << data.m_machineId; + s << " LaneId=" << data.m_laneId; + if (data.m_optionalInterfaceId) { s << " InterfaceId=" << *data.m_optionalInterfaceId; } + s << " Version=" << data.m_version; + s << " SupportedFeatures=" << data.m_supportedFeatures; + s << " }"; + return s; + } +}; + +//========== The Hermes Standard 3.5 ========== +struct NotificationData +{ + ENotificationCode m_notificationCode{ENotificationCode::eUNSPECIFIC}; + ESeverity m_severity{ESeverity::eUNKNOWN}; + std::string m_description; + + NotificationData() = default; + NotificationData(ENotificationCode notificationCode, + ESeverity severity, + StringView description) : + m_notificationCode(notificationCode), + m_severity(severity), + m_description(description) + {} + + friend bool operator==(const NotificationData& lhs, const NotificationData& rhs) + { + return lhs.m_notificationCode == rhs.m_notificationCode + && lhs.m_severity == rhs.m_severity + && lhs.m_description == rhs.m_description; + } + friend bool operator!=(const NotificationData& lhs, const NotificationData& rhs) { return !operator==(lhs, rhs); } + + template friend S& operator<<(S& s, const NotificationData& data) + { + s << '{'; + s << " NotificationCode=" << data.m_notificationCode; + s << " Severity=" << data.m_severity; + s << " Description=" << data.m_description; + s << " }"; + return s; + } +}; + +//========== The Hermes Standard 3.6 ========== +struct SubBoard +{ + uint16_t m_pos{0}; + Optional m_optionalBc; + ESubBoardState m_st{ESubBoardState::eUNKNOWN}; + + SubBoard() = default; + SubBoard(uint16_t pos, + ESubBoardState st) : + m_pos(pos), + m_st(st) + {} + + friend bool operator==(const SubBoard& lhs, const SubBoard& rhs) + { + return lhs.m_pos == rhs.m_pos + && lhs.m_optionalBc == rhs.m_optionalBc + && lhs.m_st == rhs.m_st; + } + friend bool operator!=(const SubBoard& lhs, const SubBoard& rhs) { return !operator==(lhs, rhs); } + + template friend S& operator<<(S& s, const SubBoard& data) + { + s << '{'; + s << " Pos=" << data.m_pos; + if (data.m_optionalBc) { s << " Bc=" << *data.m_optionalBc; } + s << " St=" << data.m_st; + s << " }"; + return s; + } +}; + +/* The Hermes Standard 3.6 */ +using SubBoards = std::vector; +inline std::ostream& operator<<(std::ostream& s, const SubBoards& data) +{ + s << '['; + if (!data.empty()) { s << ' '; } + for (const auto& item : data) + { + s << item << ' '; + } + s << ']'; + return s; +} + +//========== The Hermes Standard 3.6 ========== +struct BoardAvailableData +{ + std::string m_boardId{"00000000-0000-0000-0000-000000000000"}; + std::string m_boardIdCreatedBy; + EBoardQuality m_failedBoard{EBoardQuality::eANY}; + Optional m_optionalProductTypeId; + EFlippedBoard m_flippedBoard{EFlippedBoard::eSIDE_UP_IS_UNKNOWN}; + Optional m_optionalTopBarcode; + Optional m_optionalBottomBarcode; + Optional m_optionalLengthInMM; + Optional m_optionalWidthInMM; + Optional m_optionalThicknessInMM; + Optional m_optionalConveyorSpeedInMMPerSecs; + Optional m_optionalTopClearanceHeightInMM; + Optional m_optionalBottomClearanceHeightInMM; + Optional m_optionalWeightInGrams; + Optional m_optionalWorkOrderId; + Optional m_optionalBatchId; + Optional m_optionalRoute; + Optional m_optionalAction; + SubBoards m_optionalSubBoards; + + BoardAvailableData() = default; + BoardAvailableData(StringView boardId, + StringView boardIdCreatedBy, + EBoardQuality failedBoard, + EFlippedBoard flippedBoard) : + m_boardId(boardId), + m_boardIdCreatedBy(boardIdCreatedBy), + m_failedBoard(failedBoard), + m_flippedBoard(flippedBoard) + {} + + friend bool operator==(const BoardAvailableData& lhs, const BoardAvailableData& rhs) + { + return lhs.m_boardId == rhs.m_boardId + && lhs.m_boardIdCreatedBy == rhs.m_boardIdCreatedBy + && lhs.m_failedBoard == rhs.m_failedBoard + && lhs.m_optionalProductTypeId == rhs.m_optionalProductTypeId + && lhs.m_flippedBoard == rhs.m_flippedBoard + && lhs.m_optionalTopBarcode == rhs.m_optionalTopBarcode + && lhs.m_optionalBottomBarcode == rhs.m_optionalBottomBarcode + && lhs.m_optionalLengthInMM == rhs.m_optionalLengthInMM + && lhs.m_optionalWidthInMM == rhs.m_optionalWidthInMM + && lhs.m_optionalThicknessInMM == rhs.m_optionalThicknessInMM + && lhs.m_optionalConveyorSpeedInMMPerSecs == rhs.m_optionalConveyorSpeedInMMPerSecs + && lhs.m_optionalTopClearanceHeightInMM == rhs.m_optionalTopClearanceHeightInMM + && lhs.m_optionalBottomClearanceHeightInMM == rhs.m_optionalBottomClearanceHeightInMM + && lhs.m_optionalWeightInGrams == rhs.m_optionalWeightInGrams + && lhs.m_optionalWorkOrderId == rhs.m_optionalWorkOrderId + && lhs.m_optionalBatchId == rhs.m_optionalBatchId + && lhs.m_optionalRoute == rhs.m_optionalRoute + && lhs.m_optionalAction == rhs.m_optionalAction + && lhs.m_optionalSubBoards == rhs.m_optionalSubBoards; + } + friend bool operator!=(const BoardAvailableData& lhs, const BoardAvailableData& rhs) { return !operator==(lhs, rhs); } + + template friend S& operator<<(S& s, const BoardAvailableData& data) + { + s << '{'; + s << " BoardId=" << data.m_boardId; + s << " BoardIdCreatedBy=" << data.m_boardIdCreatedBy; + s << " FailedBoard=" << data.m_failedBoard; + if (data.m_optionalProductTypeId) { s << " ProductTypeId=" << *data.m_optionalProductTypeId; } + s << " FlippedBoard=" << data.m_flippedBoard; + if (data.m_optionalTopBarcode) { s << " TopBarcode=" << *data.m_optionalTopBarcode; } + if (data.m_optionalBottomBarcode) { s << " BottomBarcode=" << *data.m_optionalBottomBarcode; } + if (data.m_optionalLengthInMM) { s << " Length=" << *data.m_optionalLengthInMM; } + if (data.m_optionalWidthInMM) { s << " Width=" << *data.m_optionalWidthInMM; } + if (data.m_optionalThicknessInMM) { s << " Thickness=" << *data.m_optionalThicknessInMM; } + if (data.m_optionalConveyorSpeedInMMPerSecs) { s << " ConveyorSpeed=" << *data.m_optionalConveyorSpeedInMMPerSecs; } + if (data.m_optionalTopClearanceHeightInMM) { s << " TopClearanceHeight=" << *data.m_optionalTopClearanceHeightInMM; } + if (data.m_optionalBottomClearanceHeightInMM) { s << " BottomClearanceHeight=" << *data.m_optionalBottomClearanceHeightInMM; } + if (data.m_optionalWeightInGrams) { s << " Weight=" << *data.m_optionalWeightInGrams; } + if (data.m_optionalWorkOrderId) { s << " WorkOrderId=" << *data.m_optionalWorkOrderId; } + if (data.m_optionalBatchId) { s << " BatchId=" << *data.m_optionalBatchId; } + if (data.m_optionalRoute) { s << " Route=" << *data.m_optionalRoute; } + if (data.m_optionalAction) { s << " Action=" << *data.m_optionalAction; } + if (!data.m_optionalSubBoards.empty()) { s << " SubBoards=" << data.m_optionalSubBoards; } + s << " }"; + return s; + } +}; + +//========== The Hermes Standard 3.7 ========== +struct RevokeBoardAvailableData +{ + friend bool operator==(const RevokeBoardAvailableData&, const RevokeBoardAvailableData&) { return true; } + friend bool operator!=(const RevokeBoardAvailableData&, const RevokeBoardAvailableData&) { return false; } + template friend S& operator<<(S& s, const RevokeBoardAvailableData&) { s << "{}"; return s; } +}; + +//========== The Hermes Standard 3.8 ========== +struct MachineReadyData +{ + EBoardQuality m_failedBoard{EBoardQuality::eANY}; + Optional m_optionalForecastId; + Optional m_optionalBoardId; + Optional m_optionalProductTypeId; + Optional m_optionalFlippedBoard; + Optional m_optionalTopBarcode; + Optional m_optionalBottomBarcode; + Optional m_optionalLengthInMM; + Optional m_optionalWidthInMM; + Optional m_optionalThicknessInMM; + Optional m_optionalConveyorSpeedInMMPerSecs; + Optional m_optionalTopClearanceHeightInMM; + Optional m_optionalBottomClearanceHeightInMM; + Optional m_optionalWeightInGrams; + Optional m_optionalWorkOrderId; + Optional m_optionalBatchId; + + MachineReadyData() = default; + explicit MachineReadyData(EBoardQuality failedBoard) : + m_failedBoard(failedBoard) + {} + + friend bool operator==(const MachineReadyData& lhs, const MachineReadyData& rhs) + { + return lhs.m_failedBoard == rhs.m_failedBoard + && lhs.m_optionalForecastId == rhs.m_optionalForecastId + && lhs.m_optionalBoardId == rhs.m_optionalBoardId + && lhs.m_optionalProductTypeId == rhs.m_optionalProductTypeId + && lhs.m_optionalFlippedBoard == rhs.m_optionalFlippedBoard + && lhs.m_optionalTopBarcode == rhs.m_optionalTopBarcode + && lhs.m_optionalBottomBarcode == rhs.m_optionalBottomBarcode + && lhs.m_optionalLengthInMM == rhs.m_optionalLengthInMM + && lhs.m_optionalWidthInMM == rhs.m_optionalWidthInMM + && lhs.m_optionalThicknessInMM == rhs.m_optionalThicknessInMM + && lhs.m_optionalConveyorSpeedInMMPerSecs == rhs.m_optionalConveyorSpeedInMMPerSecs + && lhs.m_optionalTopClearanceHeightInMM == rhs.m_optionalTopClearanceHeightInMM + && lhs.m_optionalBottomClearanceHeightInMM == rhs.m_optionalBottomClearanceHeightInMM + && lhs.m_optionalWeightInGrams == rhs.m_optionalWeightInGrams + && lhs.m_optionalWorkOrderId == rhs.m_optionalWorkOrderId + && lhs.m_optionalBatchId == rhs.m_optionalBatchId; + } + friend bool operator!=(const MachineReadyData& lhs, const MachineReadyData& rhs) { return !operator==(lhs, rhs); } + + template friend S& operator<<(S& s, const MachineReadyData& data) + { + s << '{'; + s << " FailedBoard=" << data.m_failedBoard; + if (data.m_optionalForecastId) { s << " ForecastId=" << *data.m_optionalForecastId; } + if (data.m_optionalBoardId) { s << " BoardId=" << *data.m_optionalBoardId; } + if (data.m_optionalProductTypeId) { s << " ProductTypeId=" << *data.m_optionalProductTypeId; } + if (data.m_optionalFlippedBoard) { s << " FlippedBoard=" << *data.m_optionalFlippedBoard; } + if (data.m_optionalTopBarcode) { s << " TopBarcode=" << *data.m_optionalTopBarcode; } + if (data.m_optionalBottomBarcode) { s << " BottomBarcode=" << *data.m_optionalBottomBarcode; } + if (data.m_optionalLengthInMM) { s << " Length=" << *data.m_optionalLengthInMM; } + if (data.m_optionalWidthInMM) { s << " Width=" << *data.m_optionalWidthInMM; } + if (data.m_optionalThicknessInMM) { s << " Thickness=" << *data.m_optionalThicknessInMM; } + if (data.m_optionalConveyorSpeedInMMPerSecs) { s << " ConveyorSpeed=" << *data.m_optionalConveyorSpeedInMMPerSecs; } + if (data.m_optionalTopClearanceHeightInMM) { s << " TopClearanceHeight=" << *data.m_optionalTopClearanceHeightInMM; } + if (data.m_optionalBottomClearanceHeightInMM) { s << " BottomClearanceHeight=" << *data.m_optionalBottomClearanceHeightInMM; } + if (data.m_optionalWeightInGrams) { s << " Weight=" << *data.m_optionalWeightInGrams; } + if (data.m_optionalWorkOrderId) { s << " WorkOrderId=" << *data.m_optionalWorkOrderId; } + if (data.m_optionalBatchId) { s << " BatchId=" << *data.m_optionalBatchId; } + s << " }"; + return s; + } +}; + +//========== The Hermes Standard 3.9 ========== +struct RevokeMachineReadyData +{ + friend bool operator==(const RevokeMachineReadyData&, const RevokeMachineReadyData&) { return true; } + friend bool operator!=(const RevokeMachineReadyData&, const RevokeMachineReadyData&) { return false; } + template friend S& operator<<(S& s, const RevokeMachineReadyData&) { s << "{}"; return s; } +}; + +//========== The Hermes Standard 3.10 ========== +struct StartTransportData +{ + std::string m_boardId{"00000000-0000-0000-0000-000000000000"}; + Optional m_optionalConveyorSpeedInMMPerSecs; + + StartTransportData() = default; + explicit StartTransportData(StringView boardId) : + m_boardId(boardId) + {} + + friend bool operator==(const StartTransportData& lhs, const StartTransportData& rhs) + { + return lhs.m_boardId == rhs.m_boardId + && lhs.m_optionalConveyorSpeedInMMPerSecs == rhs.m_optionalConveyorSpeedInMMPerSecs; + } + friend bool operator!=(const StartTransportData& lhs, const StartTransportData& rhs) { return !operator==(lhs, rhs); } + + template friend S& operator<<(S& s, const StartTransportData& data) + { + s << '{'; + s << " BoardId=" << data.m_boardId; + if (data.m_optionalConveyorSpeedInMMPerSecs) { s << " ConveyorSpeed=" << *data.m_optionalConveyorSpeedInMMPerSecs; } + s << " }"; + return s; + } +}; + +//========== The Hermes Standard 3.11 ========== +struct StopTransportData +{ + ETransferState m_transferState{ETransferState::eUNKNOWN}; + std::string m_boardId{"00000000-0000-0000-0000-000000000000"}; + + StopTransportData() = default; + StopTransportData(ETransferState transferState, + StringView boardId) : + m_transferState(transferState), + m_boardId(boardId) + {} + + friend bool operator==(const StopTransportData& lhs, const StopTransportData& rhs) + { + return lhs.m_transferState == rhs.m_transferState + && lhs.m_boardId == rhs.m_boardId; + } + friend bool operator!=(const StopTransportData& lhs, const StopTransportData& rhs) { return !operator==(lhs, rhs); } + + template friend S& operator<<(S& s, const StopTransportData& data) + { + s << '{'; + s << " TransferState=" << data.m_transferState; + s << " BoardId=" << data.m_boardId; + s << " }"; + return s; + } +}; + +//========== The Hermes Standard 3.12 ========== +struct TransportFinishedData +{ + ETransferState m_transferState{ETransferState::eUNKNOWN}; + std::string m_boardId{"00000000-0000-0000-0000-000000000000"}; + + TransportFinishedData() = default; + TransportFinishedData(ETransferState transferState, + StringView boardId) : + m_transferState(transferState), + m_boardId(boardId) + {} + + friend bool operator==(const TransportFinishedData& lhs, const TransportFinishedData& rhs) + { + return lhs.m_transferState == rhs.m_transferState + && lhs.m_boardId == rhs.m_boardId; + } + friend bool operator!=(const TransportFinishedData& lhs, const TransportFinishedData& rhs) { return !operator==(lhs, rhs); } + + template friend S& operator<<(S& s, const TransportFinishedData& data) + { + s << '{'; + s << " TransferState=" << data.m_transferState; + s << " BoardId=" << data.m_boardId; + s << " }"; + return s; + } +}; + +//========== The Hermes Standard 3.13 ========== +struct UpstreamConfiguration +{ + unsigned m_upstreamLaneId{0}; + Optional m_optionalUpstreamInterfaceId; + std::string m_hostAddress; + uint16_t m_port{0}; + + UpstreamConfiguration() = default; + UpstreamConfiguration(unsigned upstreamLaneId, + StringView hostAddress, + uint16_t port) : + m_upstreamLaneId(upstreamLaneId), + m_hostAddress(hostAddress), + m_port(port) + {} + + friend bool operator==(const UpstreamConfiguration& lhs, const UpstreamConfiguration& rhs) + { + return lhs.m_upstreamLaneId == rhs.m_upstreamLaneId + && lhs.m_optionalUpstreamInterfaceId == rhs.m_optionalUpstreamInterfaceId + && lhs.m_hostAddress == rhs.m_hostAddress + && lhs.m_port == rhs.m_port; + } + friend bool operator!=(const UpstreamConfiguration& lhs, const UpstreamConfiguration& rhs) { return !operator==(lhs, rhs); } + + template friend S& operator<<(S& s, const UpstreamConfiguration& data) + { + s << '{'; + s << " UpstreamLaneId=" << data.m_upstreamLaneId; + if (data.m_optionalUpstreamInterfaceId) { s << " UpstreamInterfaceId=" << *data.m_optionalUpstreamInterfaceId; } + s << " HostAddress=" << data.m_hostAddress; + s << " Port=" << data.m_port; + s << " }"; + return s; + } +}; + +/* The Hermes Standard 3.13 */ +using UpstreamConfigurations = std::vector; +inline std::ostream& operator<<(std::ostream& s, const UpstreamConfigurations& data) +{ + s << '['; + if (!data.empty()) { s << ' '; } + for (const auto& item : data) + { + s << item << ' '; + } + s << ']'; + return s; +} + +//========== The Hermes Standard 3.13 ========== +struct DownstreamConfiguration +{ + unsigned m_downstreamLaneId{0}; + Optional m_optionalDownstreamInterfaceId; + Optional m_optionalClientAddress; + uint16_t m_port{0}; + + DownstreamConfiguration() = default; + DownstreamConfiguration(unsigned downstreamLaneId, + uint16_t port) : + m_downstreamLaneId(downstreamLaneId), + m_port(port) + {} + + friend bool operator==(const DownstreamConfiguration& lhs, const DownstreamConfiguration& rhs) + { + return lhs.m_downstreamLaneId == rhs.m_downstreamLaneId + && lhs.m_optionalDownstreamInterfaceId == rhs.m_optionalDownstreamInterfaceId + && lhs.m_optionalClientAddress == rhs.m_optionalClientAddress + && lhs.m_port == rhs.m_port; + } + friend bool operator!=(const DownstreamConfiguration& lhs, const DownstreamConfiguration& rhs) { return !operator==(lhs, rhs); } + + template friend S& operator<<(S& s, const DownstreamConfiguration& data) + { + s << '{'; + s << " DownstreamLaneId=" << data.m_downstreamLaneId; + if (data.m_optionalDownstreamInterfaceId) { s << " DownstreamInterfaceId=" << *data.m_optionalDownstreamInterfaceId; } + if (data.m_optionalClientAddress) { s << " ClientAddress=" << *data.m_optionalClientAddress; } + s << " Port=" << data.m_port; + s << " }"; + return s; + } +}; + +/* The Hermes Standard 3.13 */ +using DownstreamConfigurations = std::vector; +inline std::ostream& operator<<(std::ostream& s, const DownstreamConfigurations& data) +{ + s << '['; + if (!data.empty()) { s << ' '; } + for (const auto& item : data) + { + s << item << ' '; + } + s << ']'; + return s; +} + +//========== The Hermes Standard 3.13 ========== +struct SetConfigurationData +{ + std::string m_machineId; + Optional m_optionalSupervisorySystemPort; + UpstreamConfigurations m_upstreamConfigurations; + DownstreamConfigurations m_downstreamConfigurations; + + SetConfigurationData() = default; + explicit SetConfigurationData(StringView machineId) : + m_machineId(machineId) + {} + + friend bool operator==(const SetConfigurationData& lhs, const SetConfigurationData& rhs) + { + return lhs.m_machineId == rhs.m_machineId + && lhs.m_optionalSupervisorySystemPort == rhs.m_optionalSupervisorySystemPort + && lhs.m_upstreamConfigurations == rhs.m_upstreamConfigurations + && lhs.m_downstreamConfigurations == rhs.m_downstreamConfigurations; + } + friend bool operator!=(const SetConfigurationData& lhs, const SetConfigurationData& rhs) { return !operator==(lhs, rhs); } + + template friend S& operator<<(S& s, const SetConfigurationData& data) + { + s << '{'; + s << " MachineId=" << data.m_machineId; + if (data.m_optionalSupervisorySystemPort) { s << " SupervisorySystemPort=" << *data.m_optionalSupervisorySystemPort; } + s << " UpstreamConfigurations=" << data.m_upstreamConfigurations; + s << " DownstreamConfigurations=" << data.m_downstreamConfigurations; + s << " }"; + return s; + } +}; + +//========== The Hermes Standard 3.14 ========== +struct GetConfigurationData +{ + friend bool operator==(const GetConfigurationData&, const GetConfigurationData&) { return true; } + friend bool operator!=(const GetConfigurationData&, const GetConfigurationData&) { return false; } + template friend S& operator<<(S& s, const GetConfigurationData&) { s << "{}"; return s; } +}; + +//========== The Hermes Standard 3.15 ========== +struct CurrentConfigurationData +{ + Optional m_optionalMachineId; + Optional m_optionalSupervisorySystemPort; + UpstreamConfigurations m_upstreamConfigurations; + DownstreamConfigurations m_downstreamConfigurations; + + friend bool operator==(const CurrentConfigurationData& lhs, const CurrentConfigurationData& rhs) + { + return lhs.m_optionalMachineId == rhs.m_optionalMachineId + && lhs.m_optionalSupervisorySystemPort == rhs.m_optionalSupervisorySystemPort + && lhs.m_upstreamConfigurations == rhs.m_upstreamConfigurations + && lhs.m_downstreamConfigurations == rhs.m_downstreamConfigurations; + } + friend bool operator!=(const CurrentConfigurationData& lhs, const CurrentConfigurationData& rhs) { return !operator==(lhs, rhs); } + + template friend S& operator<<(S& s, const CurrentConfigurationData& data) + { + s << '{'; + if (data.m_optionalMachineId) { s << " MachineId=" << *data.m_optionalMachineId; } + if (data.m_optionalSupervisorySystemPort) { s << " SupervisorySystemPort=" << *data.m_optionalSupervisorySystemPort; } + s << " UpstreamConfigurations=" << data.m_upstreamConfigurations; + s << " DownstreamConfigurations=" << data.m_downstreamConfigurations; + s << " }"; + return s; + } +}; + +//========== The Hermes Standard 3.16 ========== +struct BoardForecastData +{ + Optional m_optionalForecastId; + Optional m_optionalTimeUntilAvailableInSeconds; + Optional m_optionalBoardId; + Optional m_optionalBoardIdCreatedBy; + EBoardQuality m_failedBoard{EBoardQuality::eANY}; + Optional m_optionalProductTypeId; + EFlippedBoard m_flippedBoard{EFlippedBoard::eSIDE_UP_IS_UNKNOWN}; + Optional m_optionalTopBarcode; + Optional m_optionalBottomBarcode; + Optional m_optionalLengthInMM; + Optional m_optionalWidthInMM; + Optional m_optionalThicknessInMM; + Optional m_optionalConveyorSpeedInMMPerSecs; + Optional m_optionalTopClearanceHeightInMM; + Optional m_optionalBottomClearanceHeightInMM; + Optional m_optionalWeightInGrams; + Optional m_optionalWorkOrderId; + Optional m_optionalBatchId; + + BoardForecastData() = default; + BoardForecastData(EBoardQuality failedBoard, + EFlippedBoard flippedBoard) : + m_failedBoard(failedBoard), + m_flippedBoard(flippedBoard) + {} + + friend bool operator==(const BoardForecastData& lhs, const BoardForecastData& rhs) + { + return lhs.m_optionalForecastId == rhs.m_optionalForecastId + && lhs.m_optionalTimeUntilAvailableInSeconds == rhs.m_optionalTimeUntilAvailableInSeconds + && lhs.m_optionalBoardId == rhs.m_optionalBoardId + && lhs.m_optionalBoardIdCreatedBy == rhs.m_optionalBoardIdCreatedBy + && lhs.m_failedBoard == rhs.m_failedBoard + && lhs.m_optionalProductTypeId == rhs.m_optionalProductTypeId + && lhs.m_flippedBoard == rhs.m_flippedBoard + && lhs.m_optionalTopBarcode == rhs.m_optionalTopBarcode + && lhs.m_optionalBottomBarcode == rhs.m_optionalBottomBarcode + && lhs.m_optionalLengthInMM == rhs.m_optionalLengthInMM + && lhs.m_optionalWidthInMM == rhs.m_optionalWidthInMM + && lhs.m_optionalThicknessInMM == rhs.m_optionalThicknessInMM + && lhs.m_optionalConveyorSpeedInMMPerSecs == rhs.m_optionalConveyorSpeedInMMPerSecs + && lhs.m_optionalTopClearanceHeightInMM == rhs.m_optionalTopClearanceHeightInMM + && lhs.m_optionalBottomClearanceHeightInMM == rhs.m_optionalBottomClearanceHeightInMM + && lhs.m_optionalWeightInGrams == rhs.m_optionalWeightInGrams + && lhs.m_optionalWorkOrderId == rhs.m_optionalWorkOrderId + && lhs.m_optionalBatchId == rhs.m_optionalBatchId; + } + friend bool operator!=(const BoardForecastData& lhs, const BoardForecastData& rhs) { return !operator==(lhs, rhs); } + + template friend S& operator<<(S& s, const BoardForecastData& data) + { + s << '{'; + if (data.m_optionalForecastId) { s << " ForecastId=" << *data.m_optionalForecastId; } + if (data.m_optionalTimeUntilAvailableInSeconds) { s << " TimeUntilAvailable=" << *data.m_optionalTimeUntilAvailableInSeconds; } + if (data.m_optionalBoardId) { s << " BoardId=" << *data.m_optionalBoardId; } + if (data.m_optionalBoardIdCreatedBy) { s << " BoardIdCreatedBy=" << *data.m_optionalBoardIdCreatedBy; } + s << " FailedBoard=" << data.m_failedBoard; + if (data.m_optionalProductTypeId) { s << " ProductTypeId=" << *data.m_optionalProductTypeId; } + s << " FlippedBoard=" << data.m_flippedBoard; + if (data.m_optionalTopBarcode) { s << " TopBarcode=" << *data.m_optionalTopBarcode; } + if (data.m_optionalBottomBarcode) { s << " BottomBarcode=" << *data.m_optionalBottomBarcode; } + if (data.m_optionalLengthInMM) { s << " Length=" << *data.m_optionalLengthInMM; } + if (data.m_optionalWidthInMM) { s << " Width=" << *data.m_optionalWidthInMM; } + if (data.m_optionalThicknessInMM) { s << " Thickness=" << *data.m_optionalThicknessInMM; } + if (data.m_optionalConveyorSpeedInMMPerSecs) { s << " ConveyorSpeed=" << *data.m_optionalConveyorSpeedInMMPerSecs; } + if (data.m_optionalTopClearanceHeightInMM) { s << " TopClearanceHeight=" << *data.m_optionalTopClearanceHeightInMM; } + if (data.m_optionalBottomClearanceHeightInMM) { s << " BottomClearanceHeight=" << *data.m_optionalBottomClearanceHeightInMM; } + if (data.m_optionalWeightInGrams) { s << " Weight=" << *data.m_optionalWeightInGrams; } + if (data.m_optionalWorkOrderId) { s << " WorkOrderId=" << *data.m_optionalWorkOrderId; } + if (data.m_optionalBatchId) { s << " BatchId=" << *data.m_optionalBatchId; } + s << " }"; + return s; + } +}; + +//========== The Hermes Standard 3.17 ========== +struct QueryBoardInfoData +{ + Optional m_optionalTopBarcode; + Optional m_optionalBottomBarcode; + + friend bool operator==(const QueryBoardInfoData& lhs, const QueryBoardInfoData& rhs) + { + return lhs.m_optionalTopBarcode == rhs.m_optionalTopBarcode + && lhs.m_optionalBottomBarcode == rhs.m_optionalBottomBarcode; + } + friend bool operator!=(const QueryBoardInfoData& lhs, const QueryBoardInfoData& rhs) { return !operator==(lhs, rhs); } + + template friend S& operator<<(S& s, const QueryBoardInfoData& data) + { + s << '{'; + if (data.m_optionalTopBarcode) { s << " TopBarcode=" << *data.m_optionalTopBarcode; } + if (data.m_optionalBottomBarcode) { s << " BottomBarcode=" << *data.m_optionalBottomBarcode; } + s << " }"; + return s; + } +}; + +//========== The Hermes Standard 3.18 ========== +struct SendBoardInfoData +{ + Optional m_optionalBoardId; + Optional m_optionalBoardIdCreatedBy; + Optional m_optionalFailedBoard; + Optional m_optionalProductTypeId; + Optional m_optionalFlippedBoard; + Optional m_optionalTopBarcode; + Optional m_optionalBottomBarcode; + Optional m_optionalLengthInMM; + Optional m_optionalWidthInMM; + Optional m_optionalThicknessInMM; + Optional m_optionalConveyorSpeedInMMPerSecs; + Optional m_optionalTopClearanceHeightInMM; + Optional m_optionalBottomClearanceHeightInMM; + Optional m_optionalWeightInGrams; + Optional m_optionalWorkOrderId; + Optional m_optionalBatchId; + Optional m_optionalRoute; + Optional m_optionalAction; + SubBoards m_optionalSubBoards; + + friend bool operator==(const SendBoardInfoData& lhs, const SendBoardInfoData& rhs) + { + return lhs.m_optionalBoardId == rhs.m_optionalBoardId + && lhs.m_optionalBoardIdCreatedBy == rhs.m_optionalBoardIdCreatedBy + && lhs.m_optionalFailedBoard == rhs.m_optionalFailedBoard + && lhs.m_optionalProductTypeId == rhs.m_optionalProductTypeId + && lhs.m_optionalFlippedBoard == rhs.m_optionalFlippedBoard + && lhs.m_optionalTopBarcode == rhs.m_optionalTopBarcode + && lhs.m_optionalBottomBarcode == rhs.m_optionalBottomBarcode + && lhs.m_optionalLengthInMM == rhs.m_optionalLengthInMM + && lhs.m_optionalWidthInMM == rhs.m_optionalWidthInMM + && lhs.m_optionalThicknessInMM == rhs.m_optionalThicknessInMM + && lhs.m_optionalConveyorSpeedInMMPerSecs == rhs.m_optionalConveyorSpeedInMMPerSecs + && lhs.m_optionalTopClearanceHeightInMM == rhs.m_optionalTopClearanceHeightInMM + && lhs.m_optionalBottomClearanceHeightInMM == rhs.m_optionalBottomClearanceHeightInMM + && lhs.m_optionalWeightInGrams == rhs.m_optionalWeightInGrams + && lhs.m_optionalWorkOrderId == rhs.m_optionalWorkOrderId + && lhs.m_optionalBatchId == rhs.m_optionalBatchId + && lhs.m_optionalRoute == rhs.m_optionalRoute + && lhs.m_optionalAction == rhs.m_optionalAction + && lhs.m_optionalSubBoards == rhs.m_optionalSubBoards; + } + friend bool operator!=(const SendBoardInfoData& lhs, const SendBoardInfoData& rhs) { return !operator==(lhs, rhs); } + + template friend S& operator<<(S& s, const SendBoardInfoData& data) + { + s << '{'; + if (data.m_optionalBoardId) { s << " BoardId=" << *data.m_optionalBoardId; } + if (data.m_optionalBoardIdCreatedBy) { s << " BoardIdCreatedBy=" << *data.m_optionalBoardIdCreatedBy; } + if (data.m_optionalFailedBoard) { s << " FailedBoard=" << *data.m_optionalFailedBoard; } + if (data.m_optionalProductTypeId) { s << " ProductTypeId=" << *data.m_optionalProductTypeId; } + if (data.m_optionalFlippedBoard) { s << " FlippedBoard=" << *data.m_optionalFlippedBoard; } + if (data.m_optionalTopBarcode) { s << " TopBarcode=" << *data.m_optionalTopBarcode; } + if (data.m_optionalBottomBarcode) { s << " BottomBarcode=" << *data.m_optionalBottomBarcode; } + if (data.m_optionalLengthInMM) { s << " Length=" << *data.m_optionalLengthInMM; } + if (data.m_optionalWidthInMM) { s << " Width=" << *data.m_optionalWidthInMM; } + if (data.m_optionalThicknessInMM) { s << " Thickness=" << *data.m_optionalThicknessInMM; } + if (data.m_optionalConveyorSpeedInMMPerSecs) { s << " ConveyorSpeed=" << *data.m_optionalConveyorSpeedInMMPerSecs; } + if (data.m_optionalTopClearanceHeightInMM) { s << " TopClearanceHeight=" << *data.m_optionalTopClearanceHeightInMM; } + if (data.m_optionalBottomClearanceHeightInMM) { s << " BottomClearanceHeight=" << *data.m_optionalBottomClearanceHeightInMM; } + if (data.m_optionalWeightInGrams) { s << " Weight=" << *data.m_optionalWeightInGrams; } + if (data.m_optionalWorkOrderId) { s << " WorkOrderId=" << *data.m_optionalWorkOrderId; } + if (data.m_optionalBatchId) { s << " BatchId=" << *data.m_optionalBatchId; } + if (data.m_optionalRoute) { s << " Route=" << *data.m_optionalRoute; } + if (data.m_optionalAction) { s << " Action=" << *data.m_optionalAction; } + if (!data.m_optionalSubBoards.empty()) { s << " SubBoards=" << data.m_optionalSubBoards; } + s << " }"; + return s; + } +}; + +//========== The Hermes Standard 3.22 ========== +struct FeatureConfiguration +{ + friend bool operator==(const FeatureConfiguration&, const FeatureConfiguration&) { return true; } + friend bool operator!=(const FeatureConfiguration&, const FeatureConfiguration&) { return false; } + template friend S& operator<<(S& s, const FeatureConfiguration&) { s << "{}"; return s; } +}; + +//========== The Hermes Standard 3.22 ========== +struct FeatureBoardTracking +{ + friend bool operator==(const FeatureBoardTracking&, const FeatureBoardTracking&) { return true; } + friend bool operator!=(const FeatureBoardTracking&, const FeatureBoardTracking&) { return false; } + template friend S& operator<<(S& s, const FeatureBoardTracking&) { s << "{}"; return s; } +}; + +//========== The Hermes Standard 3.22 ========== +struct FeatureQueryWorkOrderInfo +{ + friend bool operator==(const FeatureQueryWorkOrderInfo&, const FeatureQueryWorkOrderInfo&) { return true; } + friend bool operator!=(const FeatureQueryWorkOrderInfo&, const FeatureQueryWorkOrderInfo&) { return false; } + template friend S& operator<<(S& s, const FeatureQueryWorkOrderInfo&) { s << "{}"; return s; } +}; + +//========== The Hermes Standard 3.22 ========== +struct FeatureSendWorkOrderInfo +{ + friend bool operator==(const FeatureSendWorkOrderInfo&, const FeatureSendWorkOrderInfo&) { return true; } + friend bool operator!=(const FeatureSendWorkOrderInfo&, const FeatureSendWorkOrderInfo&) { return false; } + template friend S& operator<<(S& s, const FeatureSendWorkOrderInfo&) { s << "{}"; return s; } +}; + +//========== The Hermes Standard 3.22 ========== +struct FeatureReplyWorkOrderInfo +{ + friend bool operator==(const FeatureReplyWorkOrderInfo&, const FeatureReplyWorkOrderInfo&) { return true; } + friend bool operator!=(const FeatureReplyWorkOrderInfo&, const FeatureReplyWorkOrderInfo&) { return false; } + template friend S& operator<<(S& s, const FeatureReplyWorkOrderInfo&) { s << "{}"; return s; } +}; + +//========== The Hermes Standard 3.22 ========== +struct FeatureQueryHermesCapabilities +{ + friend bool operator==(const FeatureQueryHermesCapabilities&, const FeatureQueryHermesCapabilities&) { return true; } + friend bool operator!=(const FeatureQueryHermesCapabilities&, const FeatureQueryHermesCapabilities&) { return false; } + template friend S& operator<<(S& s, const FeatureQueryHermesCapabilities&) { s << "{}"; return s; } +}; + +//========== The Hermes Standard 3.22 ========== +struct FeatureSendHermesCapabilities +{ + friend bool operator==(const FeatureSendHermesCapabilities&, const FeatureSendHermesCapabilities&) { return true; } + friend bool operator!=(const FeatureSendHermesCapabilities&, const FeatureSendHermesCapabilities&) { return false; } + template friend S& operator<<(S& s, const FeatureSendHermesCapabilities&) { s << "{}"; return s; } +}; + +//========== The Hermes Standard 6 ========== +struct SupervisoryFeatures +{ + Optional m_optionalFeatureConfiguration; + Optional m_optionalFeatureCheckAliveResponse; + Optional m_optionalFeatureBoardTracking; + Optional m_optionalFeatureQueryWorkOrderInfo; + Optional m_optionalFeatureSendWorkOrderInfo; + Optional m_optionalFeatureReplyWorkOrderInfo; + Optional m_optionalFeatureQueryHermesCapabilities; + Optional m_optionalFeatureSendHermesCapabilities; + + friend bool operator==(const SupervisoryFeatures& lhs, const SupervisoryFeatures& rhs) + { + return lhs.m_optionalFeatureConfiguration == rhs.m_optionalFeatureConfiguration + && lhs.m_optionalFeatureCheckAliveResponse == rhs.m_optionalFeatureCheckAliveResponse + && lhs.m_optionalFeatureBoardTracking == rhs.m_optionalFeatureBoardTracking + && lhs.m_optionalFeatureQueryWorkOrderInfo == rhs.m_optionalFeatureQueryWorkOrderInfo + && lhs.m_optionalFeatureSendWorkOrderInfo == rhs.m_optionalFeatureSendWorkOrderInfo + && lhs.m_optionalFeatureReplyWorkOrderInfo == rhs.m_optionalFeatureReplyWorkOrderInfo + && lhs.m_optionalFeatureQueryHermesCapabilities == rhs.m_optionalFeatureQueryHermesCapabilities + && lhs.m_optionalFeatureSendHermesCapabilities == rhs.m_optionalFeatureSendHermesCapabilities; + } + friend bool operator!=(const SupervisoryFeatures& lhs, const SupervisoryFeatures& rhs) { return !operator==(lhs, rhs); } + + template friend S& operator<<(S& s, const SupervisoryFeatures& data) + { + s << '{'; + if (data.m_optionalFeatureConfiguration) { s << " FeatureConfiguration=" << *data.m_optionalFeatureConfiguration; } + if (data.m_optionalFeatureCheckAliveResponse) { s << " FeatureCheckAliveResponse=" << *data.m_optionalFeatureCheckAliveResponse; } + if (data.m_optionalFeatureBoardTracking) { s << " FeatureBoardTracking=" << *data.m_optionalFeatureBoardTracking; } + if (data.m_optionalFeatureQueryWorkOrderInfo) { s << " FeatureQueryWorkOrderInfo=" << *data.m_optionalFeatureQueryWorkOrderInfo; } + if (data.m_optionalFeatureSendWorkOrderInfo) { s << " FeatureSendWorkOrderInfo=" << *data.m_optionalFeatureSendWorkOrderInfo; } + if (data.m_optionalFeatureReplyWorkOrderInfo) { s << " FeatureReplyWorkOrderInfo=" << *data.m_optionalFeatureReplyWorkOrderInfo; } + if (data.m_optionalFeatureQueryHermesCapabilities) { s << " FeatureQueryHermesCapabilities=" << *data.m_optionalFeatureQueryHermesCapabilities; } + if (data.m_optionalFeatureSendHermesCapabilities) { s << " FeatureSendHermesCapabilities=" << *data.m_optionalFeatureSendHermesCapabilities; } + s << " }"; + return s; + } +}; + +//========== The Hermes Standard 3.22 ========== +struct SupervisoryServiceDescriptionData +{ + std::string m_systemId; + std::string m_version{"1.5"}; + SupervisoryFeatures m_supportedFeatures; + + SupervisoryServiceDescriptionData() = default; + explicit SupervisoryServiceDescriptionData(StringView systemId) : + m_systemId(systemId) + {} + + friend bool operator==(const SupervisoryServiceDescriptionData& lhs, const SupervisoryServiceDescriptionData& rhs) + { + return lhs.m_systemId == rhs.m_systemId + && lhs.m_version == rhs.m_version + && lhs.m_supportedFeatures == rhs.m_supportedFeatures; + } + friend bool operator!=(const SupervisoryServiceDescriptionData& lhs, const SupervisoryServiceDescriptionData& rhs) { return !operator==(lhs, rhs); } + + template friend S& operator<<(S& s, const SupervisoryServiceDescriptionData& data) + { + s << '{'; + s << " SystemId=" << data.m_systemId; + s << " Version=" << data.m_version; + s << " SupportedFeatures=" << data.m_supportedFeatures; + s << " }"; + return s; + } +}; + +//========== The Hermes Standard 3.23 ========== +struct BoardArrivedData +{ + std::string m_machineId; + unsigned m_upstreamLaneId{0}; + Optional m_optionalUpstreamInterfaceId; + Optional m_optionalMagazineId; + Optional m_optionalSlotId; + EBoardArrivedTransfer m_boardTransfer{EBoardArrivedTransfer::eUNKNOWN}; + std::string m_boardId{"00000000-0000-0000-0000-000000000000"}; + std::string m_boardIdCreatedBy; + EBoardQuality m_failedBoard{EBoardQuality::eANY}; + Optional m_optionalProductTypeId; + EFlippedBoard m_flippedBoard{EFlippedBoard::eSIDE_UP_IS_UNKNOWN}; + Optional m_optionalTopBarcode; + Optional m_optionalBottomBarcode; + Optional m_optionalLengthInMM; + Optional m_optionalWidthInMM; + Optional m_optionalThicknessInMM; + Optional m_optionalConveyorSpeedInMMPerSecs; + Optional m_optionalTopClearanceHeightInMM; + Optional m_optionalBottomClearanceHeightInMM; + Optional m_optionalWeightInGrams; + Optional m_optionalWorkOrderId; + Optional m_optionalBatchId; + Optional m_optionalRoute; + Optional m_optionalAction; + SubBoards m_optionalSubBoards; + + BoardArrivedData() = default; + BoardArrivedData(StringView machineId, + unsigned upstreamLaneId, + EBoardArrivedTransfer boardTransfer, + StringView boardId, + StringView boardIdCreatedBy, + EBoardQuality failedBoard, + EFlippedBoard flippedBoard) : + m_machineId(machineId), + m_upstreamLaneId(upstreamLaneId), + m_boardTransfer(boardTransfer), + m_boardId(boardId), + m_boardIdCreatedBy(boardIdCreatedBy), + m_failedBoard(failedBoard), + m_flippedBoard(flippedBoard) + {} + + friend bool operator==(const BoardArrivedData& lhs, const BoardArrivedData& rhs) + { + return lhs.m_machineId == rhs.m_machineId + && lhs.m_upstreamLaneId == rhs.m_upstreamLaneId + && lhs.m_optionalUpstreamInterfaceId == rhs.m_optionalUpstreamInterfaceId + && lhs.m_optionalMagazineId == rhs.m_optionalMagazineId + && lhs.m_optionalSlotId == rhs.m_optionalSlotId + && lhs.m_boardTransfer == rhs.m_boardTransfer + && lhs.m_boardId == rhs.m_boardId + && lhs.m_boardIdCreatedBy == rhs.m_boardIdCreatedBy + && lhs.m_failedBoard == rhs.m_failedBoard + && lhs.m_optionalProductTypeId == rhs.m_optionalProductTypeId + && lhs.m_flippedBoard == rhs.m_flippedBoard + && lhs.m_optionalTopBarcode == rhs.m_optionalTopBarcode + && lhs.m_optionalBottomBarcode == rhs.m_optionalBottomBarcode + && lhs.m_optionalLengthInMM == rhs.m_optionalLengthInMM + && lhs.m_optionalWidthInMM == rhs.m_optionalWidthInMM + && lhs.m_optionalThicknessInMM == rhs.m_optionalThicknessInMM + && lhs.m_optionalConveyorSpeedInMMPerSecs == rhs.m_optionalConveyorSpeedInMMPerSecs + && lhs.m_optionalTopClearanceHeightInMM == rhs.m_optionalTopClearanceHeightInMM + && lhs.m_optionalBottomClearanceHeightInMM == rhs.m_optionalBottomClearanceHeightInMM + && lhs.m_optionalWeightInGrams == rhs.m_optionalWeightInGrams + && lhs.m_optionalWorkOrderId == rhs.m_optionalWorkOrderId + && lhs.m_optionalBatchId == rhs.m_optionalBatchId + && lhs.m_optionalRoute == rhs.m_optionalRoute + && lhs.m_optionalAction == rhs.m_optionalAction + && lhs.m_optionalSubBoards == rhs.m_optionalSubBoards; + } + friend bool operator!=(const BoardArrivedData& lhs, const BoardArrivedData& rhs) { return !operator==(lhs, rhs); } + + template friend S& operator<<(S& s, const BoardArrivedData& data) + { + s << '{'; + s << " MachineId=" << data.m_machineId; + s << " UpstreamLaneId=" << data.m_upstreamLaneId; + if (data.m_optionalUpstreamInterfaceId) { s << " UpstreamInterfaceId=" << *data.m_optionalUpstreamInterfaceId; } + if (data.m_optionalMagazineId) { s << " MagazineId=" << *data.m_optionalMagazineId; } + if (data.m_optionalSlotId) { s << " SlotId=" << *data.m_optionalSlotId; } + s << " BoardTransfer=" << data.m_boardTransfer; + s << " BoardId=" << data.m_boardId; + s << " BoardIdCreatedBy=" << data.m_boardIdCreatedBy; + s << " FailedBoard=" << data.m_failedBoard; + if (data.m_optionalProductTypeId) { s << " ProductTypeId=" << *data.m_optionalProductTypeId; } + s << " FlippedBoard=" << data.m_flippedBoard; + if (data.m_optionalTopBarcode) { s << " TopBarcode=" << *data.m_optionalTopBarcode; } + if (data.m_optionalBottomBarcode) { s << " BottomBarcode=" << *data.m_optionalBottomBarcode; } + if (data.m_optionalLengthInMM) { s << " Length=" << *data.m_optionalLengthInMM; } + if (data.m_optionalWidthInMM) { s << " Width=" << *data.m_optionalWidthInMM; } + if (data.m_optionalThicknessInMM) { s << " Thickness=" << *data.m_optionalThicknessInMM; } + if (data.m_optionalConveyorSpeedInMMPerSecs) { s << " ConveyorSpeed=" << *data.m_optionalConveyorSpeedInMMPerSecs; } + if (data.m_optionalTopClearanceHeightInMM) { s << " TopClearanceHeight=" << *data.m_optionalTopClearanceHeightInMM; } + if (data.m_optionalBottomClearanceHeightInMM) { s << " BottomClearanceHeight=" << *data.m_optionalBottomClearanceHeightInMM; } + if (data.m_optionalWeightInGrams) { s << " Weight=" << *data.m_optionalWeightInGrams; } + if (data.m_optionalWorkOrderId) { s << " WorkOrderId=" << *data.m_optionalWorkOrderId; } + if (data.m_optionalBatchId) { s << " BatchId=" << *data.m_optionalBatchId; } + if (data.m_optionalRoute) { s << " Route=" << *data.m_optionalRoute; } + if (data.m_optionalAction) { s << " Action=" << *data.m_optionalAction; } + if (!data.m_optionalSubBoards.empty()) { s << " SubBoards=" << data.m_optionalSubBoards; } + s << " }"; + return s; + } +}; + +//========== The Hermes Standard 3.24 ========== +struct BoardDepartedData +{ + std::string m_machineId; + unsigned m_downstreamLaneId{0}; + Optional m_optionalDownstreamInterfaceId; + Optional m_optionalMagazineId; + Optional m_optionalSlotId; + EBoardDepartedTransfer m_boardTransfer{EBoardDepartedTransfer::eUNKNOWN}; + std::string m_boardId{"00000000-0000-0000-0000-000000000000"}; + std::string m_boardIdCreatedBy; + EBoardQuality m_failedBoard{EBoardQuality::eANY}; + Optional m_optionalProductTypeId; + EFlippedBoard m_flippedBoard{EFlippedBoard::eSIDE_UP_IS_UNKNOWN}; + Optional m_optionalTopBarcode; + Optional m_optionalBottomBarcode; + Optional m_optionalLengthInMM; + Optional m_optionalWidthInMM; + Optional m_optionalThicknessInMM; + Optional m_optionalConveyorSpeedInMMPerSecs; + Optional m_optionalTopClearanceHeightInMM; + Optional m_optionalBottomClearanceHeightInMM; + Optional m_optionalWeightInGrams; + Optional m_optionalWorkOrderId; + Optional m_optionalBatchId; + Optional m_optionalRoute; + Optional m_optionalAction; + SubBoards m_optionalSubBoards; + + BoardDepartedData() = default; + BoardDepartedData(StringView machineId, + unsigned downstreamLaneId, + EBoardDepartedTransfer boardTransfer, + StringView boardId, + StringView boardIdCreatedBy, + EBoardQuality failedBoard, + EFlippedBoard flippedBoard) : + m_machineId(machineId), + m_downstreamLaneId(downstreamLaneId), + m_boardTransfer(boardTransfer), + m_boardId(boardId), + m_boardIdCreatedBy(boardIdCreatedBy), + m_failedBoard(failedBoard), + m_flippedBoard(flippedBoard) + {} + + friend bool operator==(const BoardDepartedData& lhs, const BoardDepartedData& rhs) + { + return lhs.m_machineId == rhs.m_machineId + && lhs.m_downstreamLaneId == rhs.m_downstreamLaneId + && lhs.m_optionalDownstreamInterfaceId == rhs.m_optionalDownstreamInterfaceId + && lhs.m_optionalMagazineId == rhs.m_optionalMagazineId + && lhs.m_optionalSlotId == rhs.m_optionalSlotId + && lhs.m_boardTransfer == rhs.m_boardTransfer + && lhs.m_boardId == rhs.m_boardId + && lhs.m_boardIdCreatedBy == rhs.m_boardIdCreatedBy + && lhs.m_failedBoard == rhs.m_failedBoard + && lhs.m_optionalProductTypeId == rhs.m_optionalProductTypeId + && lhs.m_flippedBoard == rhs.m_flippedBoard + && lhs.m_optionalTopBarcode == rhs.m_optionalTopBarcode + && lhs.m_optionalBottomBarcode == rhs.m_optionalBottomBarcode + && lhs.m_optionalLengthInMM == rhs.m_optionalLengthInMM + && lhs.m_optionalWidthInMM == rhs.m_optionalWidthInMM + && lhs.m_optionalThicknessInMM == rhs.m_optionalThicknessInMM + && lhs.m_optionalConveyorSpeedInMMPerSecs == rhs.m_optionalConveyorSpeedInMMPerSecs + && lhs.m_optionalTopClearanceHeightInMM == rhs.m_optionalTopClearanceHeightInMM + && lhs.m_optionalBottomClearanceHeightInMM == rhs.m_optionalBottomClearanceHeightInMM + && lhs.m_optionalWeightInGrams == rhs.m_optionalWeightInGrams + && lhs.m_optionalWorkOrderId == rhs.m_optionalWorkOrderId + && lhs.m_optionalBatchId == rhs.m_optionalBatchId + && lhs.m_optionalRoute == rhs.m_optionalRoute + && lhs.m_optionalAction == rhs.m_optionalAction + && lhs.m_optionalSubBoards == rhs.m_optionalSubBoards; + } + friend bool operator!=(const BoardDepartedData& lhs, const BoardDepartedData& rhs) { return !operator==(lhs, rhs); } + + template friend S& operator<<(S& s, const BoardDepartedData& data) + { + s << '{'; + s << " MachineId=" << data.m_machineId; + s << " DownstreamLaneId=" << data.m_downstreamLaneId; + if (data.m_optionalDownstreamInterfaceId) { s << " DownstreamInterfaceId=" << *data.m_optionalDownstreamInterfaceId; } + if (data.m_optionalMagazineId) { s << " MagazineId=" << *data.m_optionalMagazineId; } + if (data.m_optionalSlotId) { s << " SlotId=" << *data.m_optionalSlotId; } + s << " BoardTransfer=" << data.m_boardTransfer; + s << " BoardId=" << data.m_boardId; + s << " BoardIdCreatedBy=" << data.m_boardIdCreatedBy; + s << " FailedBoard=" << data.m_failedBoard; + if (data.m_optionalProductTypeId) { s << " ProductTypeId=" << *data.m_optionalProductTypeId; } + s << " FlippedBoard=" << data.m_flippedBoard; + if (data.m_optionalTopBarcode) { s << " TopBarcode=" << *data.m_optionalTopBarcode; } + if (data.m_optionalBottomBarcode) { s << " BottomBarcode=" << *data.m_optionalBottomBarcode; } + if (data.m_optionalLengthInMM) { s << " Length=" << *data.m_optionalLengthInMM; } + if (data.m_optionalWidthInMM) { s << " Width=" << *data.m_optionalWidthInMM; } + if (data.m_optionalThicknessInMM) { s << " Thickness=" << *data.m_optionalThicknessInMM; } + if (data.m_optionalConveyorSpeedInMMPerSecs) { s << " ConveyorSpeed=" << *data.m_optionalConveyorSpeedInMMPerSecs; } + if (data.m_optionalTopClearanceHeightInMM) { s << " TopClearanceHeight=" << *data.m_optionalTopClearanceHeightInMM; } + if (data.m_optionalBottomClearanceHeightInMM) { s << " BottomClearanceHeight=" << *data.m_optionalBottomClearanceHeightInMM; } + if (data.m_optionalWeightInGrams) { s << " Weight=" << *data.m_optionalWeightInGrams; } + if (data.m_optionalWorkOrderId) { s << " WorkOrderId=" << *data.m_optionalWorkOrderId; } + if (data.m_optionalBatchId) { s << " BatchId=" << *data.m_optionalBatchId; } + if (data.m_optionalRoute) { s << " Route=" << *data.m_optionalRoute; } + if (data.m_optionalAction) { s << " Action=" << *data.m_optionalAction; } + if (!data.m_optionalSubBoards.empty()) { s << " SubBoards=" << data.m_optionalSubBoards; } + s << " }"; + return s; + } +}; + +//========== The Hermes Standard 3.25 ========== +struct QueryWorkOrderInfoData +{ + Optional m_optionalQueryId; + std::string m_machineId; + Optional m_optionalMagazineId; + Optional m_optionalSlotId; + Optional m_optionalBarcode; + Optional m_optionalWorkOrderId; + Optional m_optionalBatchId; + + QueryWorkOrderInfoData() = default; + explicit QueryWorkOrderInfoData(StringView machineId) : + m_machineId(machineId) + {} + + friend bool operator==(const QueryWorkOrderInfoData& lhs, const QueryWorkOrderInfoData& rhs) + { + return lhs.m_optionalQueryId == rhs.m_optionalQueryId + && lhs.m_machineId == rhs.m_machineId + && lhs.m_optionalMagazineId == rhs.m_optionalMagazineId + && lhs.m_optionalSlotId == rhs.m_optionalSlotId + && lhs.m_optionalBarcode == rhs.m_optionalBarcode + && lhs.m_optionalWorkOrderId == rhs.m_optionalWorkOrderId + && lhs.m_optionalBatchId == rhs.m_optionalBatchId; + } + friend bool operator!=(const QueryWorkOrderInfoData& lhs, const QueryWorkOrderInfoData& rhs) { return !operator==(lhs, rhs); } + + template friend S& operator<<(S& s, const QueryWorkOrderInfoData& data) + { + s << '{'; + if (data.m_optionalQueryId) { s << " QueryId=" << *data.m_optionalQueryId; } + s << " MachineId=" << data.m_machineId; + if (data.m_optionalMagazineId) { s << " MagazineId=" << *data.m_optionalMagazineId; } + if (data.m_optionalSlotId) { s << " SlotId=" << *data.m_optionalSlotId; } + if (data.m_optionalBarcode) { s << " Barcode=" << *data.m_optionalBarcode; } + if (data.m_optionalWorkOrderId) { s << " WorkOrderId=" << *data.m_optionalWorkOrderId; } + if (data.m_optionalBatchId) { s << " BatchId=" << *data.m_optionalBatchId; } + s << " }"; + return s; + } +}; + +//========== The Hermes Standard 3.26 ========== +struct SendWorkOrderInfoData +{ + Optional m_optionalQueryId; + Optional m_optionalWorkOrderId; + Optional m_optionalBatchId; + Optional m_optionalBoardId; + Optional m_optionalBoardIdCreatedBy; + Optional m_optionalFailedBoard; + Optional m_optionalProductTypeId; + Optional m_optionalFlippedBoard; + Optional m_optionalTopBarcode; + Optional m_optionalBottomBarcode; + Optional m_optionalLengthInMM; + Optional m_optionalWidthInMM; + Optional m_optionalThicknessInMM; + Optional m_optionalConveyorSpeedInMMPerSecs; + Optional m_optionalTopClearanceHeightInMM; + Optional m_optionalBottomClearanceHeightInMM; + Optional m_optionalWeightInGrams; + Optional m_optionalRoute; + SubBoards m_optionalSubBoards; + + friend bool operator==(const SendWorkOrderInfoData& lhs, const SendWorkOrderInfoData& rhs) + { + return lhs.m_optionalQueryId == rhs.m_optionalQueryId + && lhs.m_optionalWorkOrderId == rhs.m_optionalWorkOrderId + && lhs.m_optionalBatchId == rhs.m_optionalBatchId + && lhs.m_optionalBoardId == rhs.m_optionalBoardId + && lhs.m_optionalBoardIdCreatedBy == rhs.m_optionalBoardIdCreatedBy + && lhs.m_optionalFailedBoard == rhs.m_optionalFailedBoard + && lhs.m_optionalProductTypeId == rhs.m_optionalProductTypeId + && lhs.m_optionalFlippedBoard == rhs.m_optionalFlippedBoard + && lhs.m_optionalTopBarcode == rhs.m_optionalTopBarcode + && lhs.m_optionalBottomBarcode == rhs.m_optionalBottomBarcode + && lhs.m_optionalLengthInMM == rhs.m_optionalLengthInMM + && lhs.m_optionalWidthInMM == rhs.m_optionalWidthInMM + && lhs.m_optionalThicknessInMM == rhs.m_optionalThicknessInMM + && lhs.m_optionalConveyorSpeedInMMPerSecs == rhs.m_optionalConveyorSpeedInMMPerSecs + && lhs.m_optionalTopClearanceHeightInMM == rhs.m_optionalTopClearanceHeightInMM + && lhs.m_optionalBottomClearanceHeightInMM == rhs.m_optionalBottomClearanceHeightInMM + && lhs.m_optionalWeightInGrams == rhs.m_optionalWeightInGrams + && lhs.m_optionalRoute == rhs.m_optionalRoute + && lhs.m_optionalSubBoards == rhs.m_optionalSubBoards; + } + friend bool operator!=(const SendWorkOrderInfoData& lhs, const SendWorkOrderInfoData& rhs) { return !operator==(lhs, rhs); } + + template friend S& operator<<(S& s, const SendWorkOrderInfoData& data) + { + s << '{'; + if (data.m_optionalQueryId) { s << " QueryId=" << *data.m_optionalQueryId; } + if (data.m_optionalWorkOrderId) { s << " WorkOrderId=" << *data.m_optionalWorkOrderId; } + if (data.m_optionalBatchId) { s << " BatchId=" << *data.m_optionalBatchId; } + if (data.m_optionalBoardId) { s << " BoardId=" << *data.m_optionalBoardId; } + if (data.m_optionalBoardIdCreatedBy) { s << " BoardIdCreatedBy=" << *data.m_optionalBoardIdCreatedBy; } + if (data.m_optionalFailedBoard) { s << " FailedBoard=" << *data.m_optionalFailedBoard; } + if (data.m_optionalProductTypeId) { s << " ProductTypeId=" << *data.m_optionalProductTypeId; } + if (data.m_optionalFlippedBoard) { s << " FlippedBoard=" << *data.m_optionalFlippedBoard; } + if (data.m_optionalTopBarcode) { s << " TopBarcode=" << *data.m_optionalTopBarcode; } + if (data.m_optionalBottomBarcode) { s << " BottomBarcode=" << *data.m_optionalBottomBarcode; } + if (data.m_optionalLengthInMM) { s << " Length=" << *data.m_optionalLengthInMM; } + if (data.m_optionalWidthInMM) { s << " Width=" << *data.m_optionalWidthInMM; } + if (data.m_optionalThicknessInMM) { s << " Thickness=" << *data.m_optionalThicknessInMM; } + if (data.m_optionalConveyorSpeedInMMPerSecs) { s << " ConveyorSpeed=" << *data.m_optionalConveyorSpeedInMMPerSecs; } + if (data.m_optionalTopClearanceHeightInMM) { s << " TopClearanceHeight=" << *data.m_optionalTopClearanceHeightInMM; } + if (data.m_optionalBottomClearanceHeightInMM) { s << " BottomClearanceHeight=" << *data.m_optionalBottomClearanceHeightInMM; } + if (data.m_optionalWeightInGrams) { s << " Weight=" << *data.m_optionalWeightInGrams; } + if (data.m_optionalRoute) { s << " Route=" << *data.m_optionalRoute; } + if (!data.m_optionalSubBoards.empty()) { s << " SubBoards=" << data.m_optionalSubBoards; } + s << " }"; + return s; + } +}; + +//========== The Hermes Standard 3.27 ========== +struct ReplyWorkOrderInfoData +{ + std::string m_workOrderId; + Optional m_optionalBatchId; + EReplyWorkOrderInfoStatus m_status{EReplyWorkOrderInfoStatus::eREJECTED}; + + ReplyWorkOrderInfoData() = default; + ReplyWorkOrderInfoData(StringView workOrderId, + EReplyWorkOrderInfoStatus status) : + m_workOrderId(workOrderId), + m_status(status) + {} + + friend bool operator==(const ReplyWorkOrderInfoData& lhs, const ReplyWorkOrderInfoData& rhs) + { + return lhs.m_workOrderId == rhs.m_workOrderId + && lhs.m_optionalBatchId == rhs.m_optionalBatchId + && lhs.m_status == rhs.m_status; + } + friend bool operator!=(const ReplyWorkOrderInfoData& lhs, const ReplyWorkOrderInfoData& rhs) { return !operator==(lhs, rhs); } + + template friend S& operator<<(S& s, const ReplyWorkOrderInfoData& data) + { + s << '{'; + s << " WorkOrderId=" << data.m_workOrderId; + if (data.m_optionalBatchId) { s << " BatchId=" << *data.m_optionalBatchId; } + s << " Status=" << data.m_status; + s << " }"; + return s; + } +}; + +//========== The Hermes Standard 6 ========== +struct QueryHermesCapabilitiesData +{ + friend bool operator==(const QueryHermesCapabilitiesData&, const QueryHermesCapabilitiesData&) { return true; } + friend bool operator!=(const QueryHermesCapabilitiesData&, const QueryHermesCapabilitiesData&) { return false; } + template friend S& operator<<(S& s, const QueryHermesCapabilitiesData&) { s << "{}"; return s; } +}; + +//========== The Hermes Standard 6 ========== +struct MessageCheckAliveResponse +{ + friend bool operator==(const MessageCheckAliveResponse&, const MessageCheckAliveResponse&) { return true; } + friend bool operator!=(const MessageCheckAliveResponse&, const MessageCheckAliveResponse&) { return false; } + template friend S& operator<<(S& s, const MessageCheckAliveResponse&) { s << "{}"; return s; } +}; + +//========== The Hermes Standard 6 ========== +struct MessageBoardForecast +{ + friend bool operator==(const MessageBoardForecast&, const MessageBoardForecast&) { return true; } + friend bool operator!=(const MessageBoardForecast&, const MessageBoardForecast&) { return false; } + template friend S& operator<<(S& s, const MessageBoardForecast&) { s << "{}"; return s; } +}; + +//========== The Hermes Standard 6 ========== +struct MessageQueryBoardInfo +{ + friend bool operator==(const MessageQueryBoardInfo&, const MessageQueryBoardInfo&) { return true; } + friend bool operator!=(const MessageQueryBoardInfo&, const MessageQueryBoardInfo&) { return false; } + template friend S& operator<<(S& s, const MessageQueryBoardInfo&) { s << "{}"; return s; } +}; + +//========== The Hermes Standard 6 ========== +struct MessageSendBoardInfo +{ + friend bool operator==(const MessageSendBoardInfo&, const MessageSendBoardInfo&) { return true; } + friend bool operator!=(const MessageSendBoardInfo&, const MessageSendBoardInfo&) { return false; } + template friend S& operator<<(S& s, const MessageSendBoardInfo&) { s << "{}"; return s; } +}; + +//========== The Hermes Standard 6 ========== +struct MessageBoardArrived +{ + friend bool operator==(const MessageBoardArrived&, const MessageBoardArrived&) { return true; } + friend bool operator!=(const MessageBoardArrived&, const MessageBoardArrived&) { return false; } + template friend S& operator<<(S& s, const MessageBoardArrived&) { s << "{}"; return s; } +}; + +//========== The Hermes Standard 6 ========== +struct MessageBoardDeparted +{ + friend bool operator==(const MessageBoardDeparted&, const MessageBoardDeparted&) { return true; } + friend bool operator!=(const MessageBoardDeparted&, const MessageBoardDeparted&) { return false; } + template friend S& operator<<(S& s, const MessageBoardDeparted&) { s << "{}"; return s; } +}; + +//========== The Hermes Standard 6 ========== +struct MessageQueryWorkOrderInfo +{ + friend bool operator==(const MessageQueryWorkOrderInfo&, const MessageQueryWorkOrderInfo&) { return true; } + friend bool operator!=(const MessageQueryWorkOrderInfo&, const MessageQueryWorkOrderInfo&) { return false; } + template friend S& operator<<(S& s, const MessageQueryWorkOrderInfo&) { s << "{}"; return s; } +}; + +//========== The Hermes Standard 6 ========== +struct MessageReplyWorkOrderInfo +{ + friend bool operator==(const MessageReplyWorkOrderInfo&, const MessageReplyWorkOrderInfo&) { return true; } + friend bool operator!=(const MessageReplyWorkOrderInfo&, const MessageReplyWorkOrderInfo&) { return false; } + template friend S& operator<<(S& s, const MessageReplyWorkOrderInfo&) { s << "{}"; return s; } +}; + +//========== The Hermes Standard 6 ========== +struct MessageCommand +{ + friend bool operator==(const MessageCommand&, const MessageCommand&) { return true; } + friend bool operator!=(const MessageCommand&, const MessageCommand&) { return false; } + template friend S& operator<<(S& s, const MessageCommand&) { s << "{}"; return s; } +}; + +//========== The Hermes Standard 6 ========== +struct OptionalMessages +{ + Optional m_optionalMessageCheckAliveResponse; + Optional m_optionalMessageBoardForecast; + Optional m_optionalMessageQueryBoardInfo; + Optional m_optionalMessageSendBoardInfo; + Optional m_optionalMessageBoardArrived; + Optional m_optionalMessageBoardDeparted; + Optional m_optionalMessageQueryWorkOrderInfo; + Optional m_optionalMessageReplyWorkOrderInfo; + Optional m_optionalMessageCommand; + + friend bool operator==(const OptionalMessages& lhs, const OptionalMessages& rhs) + { + return lhs.m_optionalMessageCheckAliveResponse == rhs.m_optionalMessageCheckAliveResponse + && lhs.m_optionalMessageBoardForecast == rhs.m_optionalMessageBoardForecast + && lhs.m_optionalMessageQueryBoardInfo == rhs.m_optionalMessageQueryBoardInfo + && lhs.m_optionalMessageSendBoardInfo == rhs.m_optionalMessageSendBoardInfo + && lhs.m_optionalMessageBoardArrived == rhs.m_optionalMessageBoardArrived + && lhs.m_optionalMessageBoardDeparted == rhs.m_optionalMessageBoardDeparted + && lhs.m_optionalMessageQueryWorkOrderInfo == rhs.m_optionalMessageQueryWorkOrderInfo + && lhs.m_optionalMessageReplyWorkOrderInfo == rhs.m_optionalMessageReplyWorkOrderInfo + && lhs.m_optionalMessageCommand == rhs.m_optionalMessageCommand; + } + friend bool operator!=(const OptionalMessages& lhs, const OptionalMessages& rhs) { return !operator==(lhs, rhs); } + + template friend S& operator<<(S& s, const OptionalMessages& data) + { + s << '{'; + if (data.m_optionalMessageCheckAliveResponse) { s << " MessageCheckAliveResponse=" << *data.m_optionalMessageCheckAliveResponse; } + if (data.m_optionalMessageBoardForecast) { s << " MessageBoardForecast=" << *data.m_optionalMessageBoardForecast; } + if (data.m_optionalMessageQueryBoardInfo) { s << " MessageQueryBoardInfo=" << *data.m_optionalMessageQueryBoardInfo; } + if (data.m_optionalMessageSendBoardInfo) { s << " MessageSendBoardInfo=" << *data.m_optionalMessageSendBoardInfo; } + if (data.m_optionalMessageBoardArrived) { s << " MessageBoardArrived=" << *data.m_optionalMessageBoardArrived; } + if (data.m_optionalMessageBoardDeparted) { s << " MessageBoardDeparted=" << *data.m_optionalMessageBoardDeparted; } + if (data.m_optionalMessageQueryWorkOrderInfo) { s << " MessageQueryWorkOrderInfo=" << *data.m_optionalMessageQueryWorkOrderInfo; } + if (data.m_optionalMessageReplyWorkOrderInfo) { s << " MessageReplyWorkOrderInfo=" << *data.m_optionalMessageReplyWorkOrderInfo; } + if (data.m_optionalMessageCommand) { s << " MessageCommand=" << *data.m_optionalMessageCommand; } + s << " }"; + return s; + } +}; + +//========== The Hermes Standard 6 ========== +struct Attributes +{ + uint16_t m_productTypeId{0}; + uint16_t m_topBarcode{0}; + uint16_t m_bottomBarcode{0}; + uint16_t m_length{0}; + uint16_t m_width{0}; + uint16_t m_thickness{0}; + uint16_t m_conveyorSpeed{0}; + uint16_t m_topClearanceHeight{0}; + uint16_t m_bottomClearanceHeight{0}; + uint16_t m_weight{0}; + uint16_t m_workOrderId{0}; + uint16_t m_batchId{0}; + uint16_t m_route{0}; + uint16_t m_action{0}; + uint16_t m_subBoards{0}; + + Attributes() = default; + Attributes(uint16_t productTypeId, + uint16_t topBarcode, + uint16_t bottomBarcode, + uint16_t length, + uint16_t width, + uint16_t thickness, + uint16_t conveyorSpeed, + uint16_t topClearanceHeight, + uint16_t bottomClearanceHeight, + uint16_t weight, + uint16_t workOrderId, + uint16_t batchId, + uint16_t route, + uint16_t action, + uint16_t subBoards) : + m_productTypeId(productTypeId), + m_topBarcode(topBarcode), + m_bottomBarcode(bottomBarcode), + m_length(length), + m_width(width), + m_thickness(thickness), + m_conveyorSpeed(conveyorSpeed), + m_topClearanceHeight(topClearanceHeight), + m_bottomClearanceHeight(bottomClearanceHeight), + m_weight(weight), + m_workOrderId(workOrderId), + m_batchId(batchId), + m_route(route), + m_action(action), + m_subBoards(subBoards) + {} + + friend bool operator==(const Attributes& lhs, const Attributes& rhs) + { + return lhs.m_productTypeId == rhs.m_productTypeId + && lhs.m_topBarcode == rhs.m_topBarcode + && lhs.m_bottomBarcode == rhs.m_bottomBarcode + && lhs.m_length == rhs.m_length + && lhs.m_width == rhs.m_width + && lhs.m_thickness == rhs.m_thickness + && lhs.m_conveyorSpeed == rhs.m_conveyorSpeed + && lhs.m_topClearanceHeight == rhs.m_topClearanceHeight + && lhs.m_bottomClearanceHeight == rhs.m_bottomClearanceHeight + && lhs.m_weight == rhs.m_weight + && lhs.m_workOrderId == rhs.m_workOrderId + && lhs.m_batchId == rhs.m_batchId + && lhs.m_route == rhs.m_route + && lhs.m_action == rhs.m_action + && lhs.m_subBoards == rhs.m_subBoards; + } + friend bool operator!=(const Attributes& lhs, const Attributes& rhs) { return !operator==(lhs, rhs); } + + template friend S& operator<<(S& s, const Attributes& data) + { + s << '{'; + s << " ProductTypeId=" << data.m_productTypeId; + s << " TopBarcode=" << data.m_topBarcode; + s << " BottomBarcode=" << data.m_bottomBarcode; + s << " Length=" << data.m_length; + s << " Width=" << data.m_width; + s << " Thickness=" << data.m_thickness; + s << " ConveyorSpeed=" << data.m_conveyorSpeed; + s << " TopClearanceHeight=" << data.m_topClearanceHeight; + s << " BottomClearanceHeight=" << data.m_bottomClearanceHeight; + s << " Weight=" << data.m_weight; + s << " WorkOrderId=" << data.m_workOrderId; + s << " BatchId=" << data.m_batchId; + s << " Route=" << data.m_route; + s << " Action=" << data.m_action; + s << " SubBoards=" << data.m_subBoards; + s << " }"; + return s; + } +}; + +//========== The Hermes Standard 6 ========== +struct SendHermesCapabilitiesData +{ + OptionalMessages m_optionalMessages; + Attributes m_attributes; + + friend bool operator==(const SendHermesCapabilitiesData& lhs, const SendHermesCapabilitiesData& rhs) + { + return lhs.m_optionalMessages == rhs.m_optionalMessages + && lhs.m_attributes == rhs.m_attributes; + } + friend bool operator!=(const SendHermesCapabilitiesData& lhs, const SendHermesCapabilitiesData& rhs) { return !operator==(lhs, rhs); } + + template friend S& operator<<(S& s, const SendHermesCapabilitiesData& data) + { + s << '{'; + s << " OptionalMessages=" << data.m_optionalMessages; + s << " Attributes=" << data.m_attributes; + s << " }"; + return s; + } +}; + +//========== The Hermes Standard 3.28 ========== +struct CommandData +{ + uint16_t m_command{0}; + + CommandData() = default; + explicit CommandData(uint16_t command) : + m_command(command) + {} + + friend bool operator==(const CommandData& lhs, const CommandData& rhs) + { + return lhs.m_command == rhs.m_command; + } + friend bool operator!=(const CommandData& lhs, const CommandData& rhs) { return !operator==(lhs, rhs); } + + template friend S& operator<<(S& s, const CommandData& data) + { + s << '{'; + s << " Command=" << data.m_command; + s << " }"; + return s; + } +}; + +//========== Configuration of upstream interface (not part of The Hermes Standard) ========== +struct UpstreamSettings +{ + std::string m_machineId; + std::string m_hostAddress; + uint16_t m_port{0}; + double m_checkAlivePeriodInSeconds{60}; + double m_reconnectWaitTimeInSeconds{10}; + ECheckAliveResponseMode m_checkAliveResponseMode{ECheckAliveResponseMode::eAUTO}; + ECheckState m_checkState{ECheckState::eSEND_AND_RECEIVE}; + + UpstreamSettings() = default; + UpstreamSettings(StringView machineId, + StringView hostAddress, + uint16_t port) : + m_machineId(machineId), + m_hostAddress(hostAddress), + m_port(port) + {} + + friend bool operator==(const UpstreamSettings& lhs, const UpstreamSettings& rhs) + { + return lhs.m_machineId == rhs.m_machineId + && lhs.m_hostAddress == rhs.m_hostAddress + && lhs.m_port == rhs.m_port + && lhs.m_checkAlivePeriodInSeconds == rhs.m_checkAlivePeriodInSeconds + && lhs.m_reconnectWaitTimeInSeconds == rhs.m_reconnectWaitTimeInSeconds + && lhs.m_checkAliveResponseMode == rhs.m_checkAliveResponseMode + && lhs.m_checkState == rhs.m_checkState; + } + friend bool operator!=(const UpstreamSettings& lhs, const UpstreamSettings& rhs) { return !operator==(lhs, rhs); } + + template friend S& operator<<(S& s, const UpstreamSettings& data) + { + s << '{'; + s << " MachineId=" << data.m_machineId; + s << " HostAddress=" << data.m_hostAddress; + s << " Port=" << data.m_port; + s << " CheckAlivePeriod=" << data.m_checkAlivePeriodInSeconds; + s << " ReconnectWaitTime=" << data.m_reconnectWaitTimeInSeconds; + s << " CheckAliveResponseMode=" << data.m_checkAliveResponseMode; + s << " CheckState=" << data.m_checkState; + s << " }"; + return s; + } +}; + +//========== Configuration of downstream interface (not part of The Hermes Standard) ========== +struct DownstreamSettings +{ + std::string m_machineId; + Optional m_optionalClientAddress; + uint16_t m_port{0}; + double m_checkAlivePeriodInSeconds{60}; + double m_reconnectWaitTimeInSeconds{10}; + ECheckAliveResponseMode m_checkAliveResponseMode{ECheckAliveResponseMode::eAUTO}; + ECheckState m_checkState{ECheckState::eSEND_AND_RECEIVE}; + + DownstreamSettings() = default; + DownstreamSettings(StringView machineId, + uint16_t port) : + m_machineId(machineId), + m_port(port) + {} + + friend bool operator==(const DownstreamSettings& lhs, const DownstreamSettings& rhs) + { + return lhs.m_machineId == rhs.m_machineId + && lhs.m_optionalClientAddress == rhs.m_optionalClientAddress + && lhs.m_port == rhs.m_port + && lhs.m_checkAlivePeriodInSeconds == rhs.m_checkAlivePeriodInSeconds + && lhs.m_reconnectWaitTimeInSeconds == rhs.m_reconnectWaitTimeInSeconds + && lhs.m_checkAliveResponseMode == rhs.m_checkAliveResponseMode + && lhs.m_checkState == rhs.m_checkState; + } + friend bool operator!=(const DownstreamSettings& lhs, const DownstreamSettings& rhs) { return !operator==(lhs, rhs); } + + template friend S& operator<<(S& s, const DownstreamSettings& data) + { + s << '{'; + s << " MachineId=" << data.m_machineId; + if (data.m_optionalClientAddress) { s << " ClientAddress=" << *data.m_optionalClientAddress; } + s << " Port=" << data.m_port; + s << " CheckAlivePeriod=" << data.m_checkAlivePeriodInSeconds; + s << " ReconnectWaitTime=" << data.m_reconnectWaitTimeInSeconds; + s << " CheckAliveResponseMode=" << data.m_checkAliveResponseMode; + s << " CheckState=" << data.m_checkState; + s << " }"; + return s; + } +}; + +//========== Configuration of configuration service interface (not part of The Hermes Standard) ========== +struct ConfigurationServiceSettings +{ + uint16_t m_port{0}; + double m_reconnectWaitTimeInSeconds{10}; + + ConfigurationServiceSettings() = default; + explicit ConfigurationServiceSettings(uint16_t port) : + m_port(port) + {} + + friend bool operator==(const ConfigurationServiceSettings& lhs, const ConfigurationServiceSettings& rhs) + { + return lhs.m_port == rhs.m_port + && lhs.m_reconnectWaitTimeInSeconds == rhs.m_reconnectWaitTimeInSeconds; + } + friend bool operator!=(const ConfigurationServiceSettings& lhs, const ConfigurationServiceSettings& rhs) { return !operator==(lhs, rhs); } + + template friend S& operator<<(S& s, const ConfigurationServiceSettings& data) + { + s << '{'; + s << " Port=" << data.m_port; + s << " ReconnectWaitTime=" << data.m_reconnectWaitTimeInSeconds; + s << " }"; + return s; + } +}; + +//========== Configuration of vertical service interface (not part of The Hermes Standard) ========== +struct VerticalServiceSettings +{ + std::string m_systemId; + uint16_t m_port{0}; + double m_reconnectWaitTimeInSeconds{10}; + double m_checkAlivePeriodInSeconds{60}; + ECheckAliveResponseMode m_checkAliveResponseMode{ECheckAliveResponseMode::eAUTO}; + + VerticalServiceSettings() = default; + VerticalServiceSettings(StringView systemId, + uint16_t port) : + m_systemId(systemId), + m_port(port) + {} + + friend bool operator==(const VerticalServiceSettings& lhs, const VerticalServiceSettings& rhs) + { + return lhs.m_systemId == rhs.m_systemId + && lhs.m_port == rhs.m_port + && lhs.m_reconnectWaitTimeInSeconds == rhs.m_reconnectWaitTimeInSeconds + && lhs.m_checkAlivePeriodInSeconds == rhs.m_checkAlivePeriodInSeconds + && lhs.m_checkAliveResponseMode == rhs.m_checkAliveResponseMode; + } + friend bool operator!=(const VerticalServiceSettings& lhs, const VerticalServiceSettings& rhs) { return !operator==(lhs, rhs); } + + template friend S& operator<<(S& s, const VerticalServiceSettings& data) + { + s << '{'; + s << " SystemId=" << data.m_systemId; + s << " Port=" << data.m_port; + s << " ReconnectWaitTime=" << data.m_reconnectWaitTimeInSeconds; + s << " CheckAlivePeriod=" << data.m_checkAlivePeriodInSeconds; + s << " CheckAliveResponseMode=" << data.m_checkAliveResponseMode; + s << " }"; + return s; + } +}; + +//========== Configuration of vertical client interface (not part of The Hermes Standard) ========== +struct VerticalClientSettings +{ + std::string m_systemId; + std::string m_hostAddress; + uint16_t m_port{0}; + double m_reconnectWaitTimeInSeconds{10}; + double m_checkAlivePeriodInSeconds{60}; + ECheckAliveResponseMode m_checkAliveResponseMode{ECheckAliveResponseMode::eAUTO}; + + VerticalClientSettings() = default; + VerticalClientSettings(StringView systemId, + StringView hostAddress, + uint16_t port) : + m_systemId(systemId), + m_hostAddress(hostAddress), + m_port(port) + {} + + friend bool operator==(const VerticalClientSettings& lhs, const VerticalClientSettings& rhs) + { + return lhs.m_systemId == rhs.m_systemId + && lhs.m_hostAddress == rhs.m_hostAddress + && lhs.m_port == rhs.m_port + && lhs.m_reconnectWaitTimeInSeconds == rhs.m_reconnectWaitTimeInSeconds + && lhs.m_checkAlivePeriodInSeconds == rhs.m_checkAlivePeriodInSeconds + && lhs.m_checkAliveResponseMode == rhs.m_checkAliveResponseMode; + } + friend bool operator!=(const VerticalClientSettings& lhs, const VerticalClientSettings& rhs) { return !operator==(lhs, rhs); } + + template friend S& operator<<(S& s, const VerticalClientSettings& data) + { + s << '{'; + s << " SystemId=" << data.m_systemId; + s << " HostAddress=" << data.m_hostAddress; + s << " Port=" << data.m_port; + s << " ReconnectWaitTime=" << data.m_reconnectWaitTimeInSeconds; + s << " CheckAlivePeriod=" << data.m_checkAlivePeriodInSeconds; + s << " CheckAliveResponseMode=" << data.m_checkAliveResponseMode; + s << " }"; + return s; + } +}; + +//========== Error object (not part of The Hermes Standard) ========== +struct Error +{ + EErrorCode m_code{EErrorCode::eSUCCESS}; + std::string m_text; + + Error() = default; + Error(EErrorCode code, + StringView text) : + m_code(code), + m_text(text) + {} + + explicit operator bool() const { return m_code != EErrorCode::eSUCCESS; } + + friend bool operator==(const Error& lhs, const Error& rhs) + { + return lhs.m_code == rhs.m_code + && lhs.m_text == rhs.m_text; + } + friend bool operator!=(const Error& lhs, const Error& rhs) { return !operator==(lhs, rhs); } + + template friend S& operator<<(S& s, const Error& data) + { + s << '{'; + s << " Code=" << data.m_code; + s << " Text=" << data.m_text; + s << " }"; + return s; + } +}; + +//========== Attributes for the established connection (not part of The Hermes Standard) ========== +struct ConnectionInfo +{ + std::string m_address; + uint16_t m_port{0}; + std::string m_hostName; + + ConnectionInfo() = default; + ConnectionInfo(StringView address, + uint16_t port, + StringView hostName) : + m_address(address), + m_port(port), + m_hostName(hostName) + {} + + friend bool operator==(const ConnectionInfo& lhs, const ConnectionInfo& rhs) + { + return lhs.m_address == rhs.m_address + && lhs.m_port == rhs.m_port + && lhs.m_hostName == rhs.m_hostName; + } + friend bool operator!=(const ConnectionInfo& lhs, const ConnectionInfo& rhs) { return !operator==(lhs, rhs); } + + template friend S& operator<<(S& s, const ConnectionInfo& data) + { + s << '{'; + s << " Address=" << data.m_address; + s << " Port=" << data.m_port; + s << " HostName=" << data.m_hostName; + s << " }"; + return s; + } +}; + + +} // namespace Hermes diff --git a/src/include/HermesDataConversion.hpp b/src/include/HermesDataConversion.hpp index 11a3254..114a37c 100644 --- a/src/include/HermesDataConversion.hpp +++ b/src/include/HermesDataConversion.hpp @@ -13,10 +13,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ************************************************************************/ - - - -// Copyright (c) ASM Assembly Systems GmbH & Co. KG #pragma once #include "Hermes.h" @@ -31,377 +27,1355 @@ namespace Hermes static_assert(cBASE_PORT == cHERMES_BASE_PORT, ""); static_assert(cMAX_MESSAGE_SIZE == cHERMES_MAX_MESSAGE_SIZE, ""); - // convert std::StringView from/to HermesStringView - inline HermesStringView ToC(const std::string& str) { return{str.data(), static_cast(str.size())}; } - template - const T* ToC(const Optional& optional) { return optional ? &*optional : nullptr; } + inline void CppToC(const std::string& data, HermesStringView& result) { result = {data.data(), data.size()}; } + inline void CToCpp(HermesStringView data, std::string& result) { result.assign(data.m_pData, data.m_size); } + inline HermesStringView ToC(StringView data) { return{data.data(), data.size()}; } + inline StringView ToCpp(HermesStringView data) { return{data.m_pData, data.m_size}; } - inline HermesStringView ToC(const Optional& optional) + inline void CppToC(const Optional& data, HermesStringView& result) + { + result = data ? HermesStringView{data->data(), data->size()} : HermesStringView{}; + } + inline void CToCpp(HermesStringView data, Optional& result) { - return optional ? ToC(*optional) : HermesStringView{0, 0}; + result = data.m_pData ? Optional{data.m_pData, data.m_size} : Optional{}; + } + + inline void CppToC(double data, double& result) { result = data; } + inline void CToCpp(double data, double& result) { result = data; } + + inline void CppToC(unsigned data, unsigned& result) { result = data; } + inline void CToCpp(unsigned data, unsigned& result) { result = data; } + + inline void CppToC(uint16_t data, uint16_t& result) { result = data; } + inline void CToCpp(uint16_t data, uint16_t& result) { result = data; } + + template + void CToCpp(const CT* pData, CppT& result) + { + if (!pData) + return; + + CToCpp(*pData, result); } - inline HermesStringView ToC(StringView view) { return{view.data(), static_cast(view.size())}; } - inline StringView ToCpp(HermesStringView view) { return{view.m_pData, view.m_size}; } template - Optional ToOptional(const T* pValue) + void CppToC(const Optional& data, const T*& result) { - if (!pValue) - return{}; - return *pValue; + result = data ? &*data : nullptr; } - - inline Optional ToOptional(HermesStringView view) + + template + void CToCpp(const CT* pData, Optional& result) { - if (!view.m_pData) - return{}; - return ToCpp(view).cpp_str(); + if (!pData) + return; + + result.emplace(); + CToCpp(*pData, *result); + } + + template + void CppToC(const Optional& data, Optional& result) + { + if (!data) + return; + + result.emplace(CT{}); + CppToC(*data, *result); + } + + template + void CppToC(const Optional& data, CT& intermediate, const CT*& result) + { + if (!data) + return; + + CppToC(*data, intermediate); + result = &intermediate; + } + + // struct for converting vom cpp to c vector: + template + struct VectorHolder + { + std::vector m_values; + std::vector m_pointers; + }; + + template + void CppToC(const std::vector& data, VectorHolder& result) + { + auto size = data.size(); + result.m_values.resize(size, CT{}); + for (uint32_t i = 0; i < size; ++i) + { + CppToC(data[i], result.m_values[i]); + } + } + + template + void CppToC(const std::vector& data, VectorHolder& intermediate, CVector& result) + { + auto size = data.size(); + intermediate.m_values.resize(size, CT{}); + intermediate.m_pointers.resize(size); + for (uint32_t i = 0; i < size; ++i) + { + CppToC(data[i], intermediate.m_values[i]); + intermediate.m_pointers[i] = &intermediate.m_values[i]; + } + result.m_pData = size == 0 ? nullptr : intermediate.m_pointers.data(); + result.m_size = size; + } + + template + void CToCpp(const CVector& data, std::vector& result) + { + result.resize(data.m_size); + for (uint32_t i = 0; i < data.m_size; ++i) + { + CToCpp(*data.m_pData[i], result[i]); + } } // enums - static_assert(size(EState()) == eHERMES_STATE_ENUM_SIZE, "enum mismatch"); - inline constexpr EHermesState ToC(EState e) { return static_cast(e); } - inline constexpr EState ToCpp(EHermesState e) { return static_cast(e); } + static_assert(size(EState()) == cHERMES_STATE_ENUM_SIZE, "enum mismatch"); + inline EHermesState ToC(EState data) { return static_cast(data); } + inline EState ToCpp(EHermesState data) { return static_cast(data); } + + static_assert(size(ETraceType()) == cHERMES_TRACE_TYPE_ENUM_SIZE, "enum mismatch"); + inline EHermesTraceType ToC(ETraceType data) { return static_cast(data); } + inline ETraceType ToCpp(EHermesTraceType data) { return static_cast(data); } + + static_assert(size(ECheckAliveType()) == cHERMES_CHECK_ALIVE_TYPE_ENUM_SIZE, "enum mismatch"); + inline void CppToC(ECheckAliveType data, EHermesCheckAliveType& result) { result = static_cast(data); } + inline void CToCpp(EHermesCheckAliveType data, ECheckAliveType& result) { result = static_cast(data); } + + static_assert(size(EBoardQuality()) == cHERMES_BOARD_QUALITY_ENUM_SIZE, "enum mismatch"); + inline void CppToC(EBoardQuality data, EHermesBoardQuality& result) { result = static_cast(data); } + inline void CToCpp(EHermesBoardQuality data, EBoardQuality& result) { result = static_cast(data); } - static_assert(size(ETraceType()) == eHERMES_TRACE_TYPE_ENUM_SIZE, "enum mismatch"); - inline constexpr EHermesTraceType ToC(ETraceType e) { return static_cast(e); } - inline constexpr ETraceType ToCpp(EHermesTraceType e) { return static_cast(e); } + static_assert(size(EFlippedBoard()) == cHERMES_FLIPPED_BOARD_ENUM_SIZE, "enum mismatch"); + inline void CppToC(EFlippedBoard data, EHermesFlippedBoard& result) { result = static_cast(data); } + inline void CToCpp(EHermesFlippedBoard data, EFlippedBoard& result) { result = static_cast(data); } - static_assert(size(EBoardQuality()) == eHERMES_BOARD_QUALITY_ENUM_SIZE, "enum mismatch"); - inline constexpr EHermesBoardQuality ToC(EBoardQuality e) { return static_cast(e); } - inline constexpr EBoardQuality ToCpp(EHermesBoardQuality e) { return static_cast(e); } + static_assert(size(ESubBoardState()) == cHERMES_SUB_BOARD_STATE_ENUM_SIZE, "enum mismatch"); + inline void CppToC(ESubBoardState data, EHermesSubBoardState& result) { result = static_cast(data); } + inline void CToCpp(EHermesSubBoardState data, ESubBoardState& result) { result = static_cast(data); } - static_assert(size(EFlippedBoard()) == eHERMES_FLIPPED_BOARD_ENUM_SIZE, "enum mismatch"); - inline constexpr EHermesFlippedBoard ToC(EFlippedBoard e) { return static_cast(e); } - inline constexpr EFlippedBoard ToCpp(EHermesFlippedBoard e) { return static_cast(e); } + static_assert(size(ETransferState()) == cHERMES_TRANSFER_STATE_ENUM_SIZE, "enum mismatch"); + inline void CppToC(ETransferState data, EHermesTransferState& result) { result = static_cast(data); } + inline void CToCpp(EHermesTransferState data, ETransferState& result) { result = static_cast(data); } - static_assert(size(ETransferState()) == eHERMES_TRANSFER_STATE_ENUM_SIZE, "enum mismatch"); - inline constexpr EHermesTransferState ToC(ETransferState e) { return static_cast(e); } - inline constexpr ETransferState ToCpp(EHermesTransferState e) { return static_cast(e); } + static_assert(size(ENotificationCode()) == cHERMES_NOTIFICATION_CODE_ENUM_SIZE, "enum mismatch"); + inline void CppToC(ENotificationCode data, EHermesNotificationCode& result) { result = static_cast(data); } + inline void CToCpp(EHermesNotificationCode data, ENotificationCode& result) { result = static_cast(data); } - static_assert(size(ENotificationCode()) == eHERMES_NOTIFICATION_CODE_ENUM_SIZE, "enum mismatch"); - inline constexpr EHermesNotificationCode ToC(ENotificationCode e) { return static_cast(e); } - inline constexpr ENotificationCode ToCpp(EHermesNotificationCode e) { return static_cast(e); } + static_assert(size(ESeverity()) == cHERMES_SEVERITY_ENUM_SIZE, "enum mismatch"); + inline void CppToC(ESeverity data, EHermesSeverity& result) { result = static_cast(data); } + inline void CToCpp(EHermesSeverity data, ESeverity& result) { result = static_cast(data); } - static_assert(size(ESeverity()) == eHERMES_SEVERITY_ENUM_SIZE, "enum mismatch"); - inline constexpr EHermesSeverity ToC(ESeverity e) { return static_cast(e); } - inline constexpr ESeverity ToCpp(EHermesSeverity e) { return static_cast(e); } + static_assert(size(ECheckState()) == cHERMES_CHECK_STATE_ENUM_SIZE, "enum mismatch"); + inline void CppToC(ECheckState data, EHermesCheckState& result) { result = static_cast(data); } + inline void CToCpp(EHermesCheckState data, ECheckState& result) { result = static_cast(data); } - static_assert(size(ECheckState()) == eHERMES_CHECK_STATE_ENUM_SIZE, "enum mismatch"); - inline constexpr EHermesCheckState ToC(ECheckState e) { return static_cast(e); } - inline constexpr ECheckState ToCpp(EHermesCheckState e) { return static_cast(e); } + static_assert(size(EErrorCode()) == cHERMES_ERROR_CODE_ENUM_SIZE, "enum mismatch"); + inline void CppToC(EErrorCode data, EHermesErrorCode& result) { result = static_cast(data); } + inline void CToCpp(EHermesErrorCode data, EErrorCode& result) { result = static_cast(data); } + + static_assert(size(ECheckAliveResponseMode()) == cHERMES_CHECK_ALIVE_RESPONSE_MODE_ENUM_SIZE, "enum mismatch"); + inline void CppToC(ECheckAliveResponseMode data, EHermesCheckAliveResponseMode& result) { result = static_cast(data); } + inline void CToCpp(EHermesCheckAliveResponseMode data, ECheckAliveResponseMode& result) { result = static_cast(data); } + + static_assert(size(EBoardArrivedTransfer()) == cHERMES_BOARD_ARRIVED_TRANSFER_ENUM_SIZE, "enum mismatch"); + inline void CppToC(EBoardArrivedTransfer data, EHermesBoardArrivedTransfer& result) { result = static_cast(data); } + inline void CToCpp(EHermesBoardArrivedTransfer data, EBoardArrivedTransfer& result) { result = static_cast(data); } + + static_assert(size(EBoardDepartedTransfer()) == cHERMES_BOARD_DEPARTED_TRANSFER_ENUM_SIZE, "enum mismatch"); + inline void CppToC(EBoardDepartedTransfer data, EHermesBoardDepartedTransfer& result) { result = static_cast(data); } + inline void CToCpp(EHermesBoardDepartedTransfer data, EBoardDepartedTransfer& result) { result = static_cast(data); } + + static_assert(size(EReplyWorkOrderInfoStatus()) == cHERMES_REPLY_WORK_ORDER_INFO_STATUS_ENUM_SIZE, "enum mismatch"); + inline void CppToC(EReplyWorkOrderInfoStatus data, EHermesReplyWorkOrderInfoStatus& result) { result = static_cast(data); } + inline void CToCpp(EHermesReplyWorkOrderInfoStatus data, EReplyWorkOrderInfoStatus& result) { result = static_cast(data); } + + static_assert(size(EVerticalState()) == cHERMES_VERTICAL_STATE_ENUM_SIZE, "enum mismatch"); + inline EHermesVerticalState ToC(EVerticalState data) { return static_cast(data); } + inline EVerticalState ToCpp(EHermesVerticalState data) { return static_cast(data); } - static_assert(size(EErrorCode()) == eHERMES_ERROR_CODE_ENUM_SIZE, "enum mismatch"); - inline constexpr EHermesErrorCode ToC(EErrorCode e) { return static_cast(e); } - inline constexpr EErrorCode ToCpp(EHermesErrorCode e) { return static_cast(e); } // UpstreamConfiguration - inline HermesUpstreamConfiguration ToC(const UpstreamConfiguration& in_data) + inline void CppToC(const UpstreamConfiguration& data, HermesUpstreamConfiguration& result) { - return{in_data.m_upstreamLaneId, Hermes::ToC(in_data.m_hostAddress), in_data.m_port}; + CppToC(data.m_upstreamLaneId, result.m_upstreamLaneId); + CppToC(data.m_optionalUpstreamInterfaceId, result.m_optionalUpstreamInterfaceId); + CppToC(data.m_hostAddress, result.m_hostAddress); + CppToC(data.m_port, result.m_port); } - inline UpstreamConfiguration ToCpp(const HermesUpstreamConfiguration& in_data) + + inline void CToCpp(const HermesUpstreamConfiguration& data, UpstreamConfiguration& result) { - return UpstreamConfiguration(in_data.m_upstreamLaneId, ToCpp(in_data.m_hostAddress), in_data.m_port); + CToCpp(data.m_upstreamLaneId, result.m_upstreamLaneId); + CToCpp(data.m_optionalUpstreamInterfaceId, result.m_optionalUpstreamInterfaceId); + CToCpp(data.m_port, result.m_port); + CToCpp(data.m_hostAddress, result.m_hostAddress); } // DownstreamConfiguration - inline HermesDownstreamConfiguration ToC(const DownstreamConfiguration& in_data) + inline void CppToC(const DownstreamConfiguration& data, HermesDownstreamConfiguration& result) { - return{in_data.m_downstreamLaneId, Hermes::ToC(in_data.m_optionalClientAddress), in_data.m_port}; + CppToC(data.m_downstreamLaneId, result.m_downstreamLaneId); + CppToC(data.m_optionalDownstreamInterfaceId, result.m_optionalDownstreamInterfaceId); + CppToC(data.m_optionalClientAddress, result.m_optionalClientAddress); + CppToC(data.m_port, result.m_port); } - inline DownstreamConfiguration ToCpp(const HermesDownstreamConfiguration& in_data) + + inline void CToCpp(const HermesDownstreamConfiguration& data, DownstreamConfiguration& result) { - return DownstreamConfiguration(in_data.m_downstreamLaneId, ToCpp(in_data.m_optionalClientAddress), in_data.m_port); + CToCpp(data.m_downstreamLaneId, result.m_downstreamLaneId); + CToCpp(data.m_optionalDownstreamInterfaceId, result.m_optionalDownstreamInterfaceId); + CToCpp(data.m_optionalClientAddress, result.m_optionalClientAddress); + CToCpp(data.m_port, result.m_port); } + template + struct Converter2C; - // helper template for converting a vector of C++ types to C - template - struct VectorHolder + template + struct ConverterBase { - std::vector m_values; - std::vector m_pointers; + ConverterBase() = default; + ConverterBase(const ConverterBase&) = delete; + ConverterBase(ConverterBase&&) = delete; + ConverterBase& operator=(const ConverterBase&) = delete; + ConverterBase& operator=(ConverterBase&&) = delete; + + const T* CPointer() const { return &m_data; } + T m_data{}; + }; - template - VectorHolder(const std::vector& in_data) + template<> + struct Converter2C : ConverterBase + { + explicit Converter2C(const SetConfigurationData& data) { - m_values.reserve(in_data.size()); - for (const auto& data : in_data) - { - m_values.emplace_back(ToC(data)); - } + CppToC(data.m_machineId, m_data.m_machineId); + CppToC(data.m_optionalSupervisorySystemPort, m_data.m_pOptionalSupervisorySystemPort); + CppToC(data.m_upstreamConfigurations, m_upstreamConfigurations, m_data.m_upstreamConfigurations); + CppToC(data.m_downstreamConfigurations, m_downstreamConfigurations, m_data.m_downstreamConfigurations); } + + private: + VectorHolder m_upstreamConfigurations; + VectorHolder m_downstreamConfigurations; + }; + + inline SetConfigurationData ToCpp(const HermesSetConfigurationData& data) + { + SetConfigurationData result; + CToCpp(data.m_machineId, result.m_machineId); + CToCpp(data.m_pOptionalSupervisorySystemPort, result.m_optionalSupervisorySystemPort); + CToCpp(data.m_upstreamConfigurations, result.m_upstreamConfigurations); + CToCpp(data.m_downstreamConfigurations, result.m_downstreamConfigurations); + return result; + } + + // GetConfigurationData + template<> struct Converter2C : ConverterBase + { + explicit Converter2C(const GetConfigurationData&) {} }; + inline GetConfigurationData ToCpp(const HermesGetConfigurationData&) { return{}; } - template - const C** ToC(VectorHolder& holder, uint32_t* pSize) + // CurrentConfigurationData + template<> + struct Converter2C : ConverterBase { - uint32_t size = static_cast(holder.m_values.size()); - holder.m_pointers.resize(size); - for (uint32_t i = 0U; i < size; ++i) + explicit Converter2C(const CurrentConfigurationData& data) { - holder.m_pointers[i] = &(holder.m_values[i]); + CppToC(data.m_optionalMachineId, m_data.m_optionalMachineId); + CppToC(data.m_optionalSupervisorySystemPort, m_data.m_pOptionalSupervisorySystemPort); + CppToC(data.m_upstreamConfigurations, m_upstreamConfigurations, m_data.m_upstreamConfigurations); + CppToC(data.m_downstreamConfigurations, m_downstreamConfigurations, m_data.m_downstreamConfigurations); } - *pSize = size; - return holder.m_pointers.data(); + + private: + VectorHolder m_upstreamConfigurations; + VectorHolder m_downstreamConfigurations; + }; + + inline CurrentConfigurationData ToCpp(const HermesCurrentConfigurationData& data) + { + CurrentConfigurationData result; + CToCpp(data.m_optionalMachineId, result.m_optionalMachineId); + CToCpp(data.m_pOptionalSupervisorySystemPort, result.m_optionalSupervisorySystemPort); + CToCpp(data.m_upstreamConfigurations, result.m_upstreamConfigurations); + CToCpp(data.m_downstreamConfigurations, result.m_downstreamConfigurations); + return result; } - template - std::vector ToCpp(const C** ppData, uint32_t size) + // ConnectionInfo + template<> + struct Converter2C : ConverterBase { - std::vector data; - data.reserve(size); - for (uint32_t i = 0U; i < size; ++i) + Converter2C(const ConnectionInfo& data) { - data.emplace_back(ToCpp(*(ppData[i]))); + CppToC(data.m_address, m_data.m_address); + CppToC(data.m_port, m_data.m_port); + CppToC(data.m_hostName, m_data.m_hostName); } - return data; + }; + inline ConnectionInfo ToCpp(const HermesConnectionInfo& data) + { + ConnectionInfo result; + CToCpp(data.m_address, result.m_address); + CToCpp(data.m_port, result.m_port); + CToCpp(data.m_hostName, result.m_hostName); + return result; } - // SetConfigurationData - class SetConfigurationDataHolder + // Features + inline void CppToC(const FeatureBoardForecast&, HermesFeatureBoardForecast&) {} + inline void CppToC(const FeatureCheckAliveResponse&, HermesFeatureCheckAliveResponse&) {} + inline void CppToC(const FeatureQueryBoardInfo&, HermesFeatureQueryBoardInfo&) {} + inline void CppToC(const FeatureSendBoardInfo&, HermesFeatureSendBoardInfo&) {} + inline void CppToC(const FeatureCommand&, HermesFeatureCommand&) {} + + inline void CToCpp(const HermesFeatureBoardForecast&, FeatureBoardForecast&) {} + inline void CToCpp(const HermesFeatureCheckAliveResponse&, FeatureCheckAliveResponse&) {} + inline void CToCpp(const HermesFeatureQueryBoardInfo&, FeatureQueryBoardInfo&) {} + inline void CToCpp(const HermesFeatureSendBoardInfo&, FeatureSendBoardInfo&) {} + inline void CToCpp(const HermesFeatureCommand&, FeatureCommand&) {} + + // SupportedFeatures + struct SupportedFeaturesHolder : ConverterBase { - public: - explicit SetConfigurationDataHolder(const SetConfigurationData& in_data) : - m_upstreamConfigurations(in_data.m_upstreamConfigurations), - m_downstreamConfigurations(in_data.m_downstreamConfigurations) + HermesFeatureBoardForecast m_optionalFeatureBoardForecast; + HermesFeatureCheckAliveResponse m_optionalFeatureCheckAliveResponse; + HermesFeatureQueryBoardInfo m_optionalFeatureQueryBoardInfo; + HermesFeatureSendBoardInfo m_optionalFeatureSendBoardInfo; + HermesFeatureCommand m_optionalFeatureCommand; + }; + + inline void CppToC(const SupportedFeatures& data, SupportedFeaturesHolder& result) + { + auto& hermesData = result.m_data; + CppToC(data.m_optionalFeatureBoardForecast, result.m_optionalFeatureBoardForecast, hermesData.m_pOptionalFeatureBoardForecast); + CppToC(data.m_optionalFeatureCheckAliveResponse, result.m_optionalFeatureCheckAliveResponse, hermesData.m_pOptionalFeatureCheckAliveResponse); + CppToC(data.m_optionalFeatureQueryBoardInfo, result.m_optionalFeatureQueryBoardInfo, hermesData.m_pOptionalFeatureQueryBoardInfo); + CppToC(data.m_optionalFeatureSendBoardInfo, result.m_optionalFeatureSendBoardInfo, hermesData.m_pOptionalFeatureSendBoardInfo); + CppToC(data.m_optionalFeatureCommand, result.m_optionalFeatureCommand, hermesData.m_pOptionalFeatureCommand); + } + + inline void CToCpp(const HermesSupportedFeatures& data, SupportedFeatures& result) + { + CToCpp(data.m_pOptionalFeatureBoardForecast, result.m_optionalFeatureBoardForecast); + CToCpp(data.m_pOptionalFeatureCheckAliveResponse, result.m_optionalFeatureCheckAliveResponse); + CToCpp(data.m_pOptionalFeatureQueryBoardInfo, result.m_optionalFeatureQueryBoardInfo); + CToCpp(data.m_pOptionalFeatureSendBoardInfo, result.m_optionalFeatureSendBoardInfo); + CToCpp(data.m_pOptionalFeatureCommand, result.m_optionalFeatureCommand); + } + + // ServiceDescriptionData + template<> + struct Converter2C : ConverterBase + { + explicit Converter2C(const ServiceDescriptionData& data) { - m_data.m_machineId = ToC(in_data.m_machineId); + CppToC(data.m_machineId, m_data.m_machineId); + CppToC(data.m_laneId, m_data.m_laneId); + CppToC(data.m_optionalInterfaceId, m_data.m_optionalInterfaceId); + CppToC(data.m_version, m_data.m_version); + CppToC(data.m_supportedFeatures, m_supportedFeatures); + m_data.m_pSupportedFeatures = &m_supportedFeatures.m_data; } - const HermesSetConfigurationData* operator&() + private: + SupportedFeaturesHolder m_supportedFeatures; + }; + inline ServiceDescriptionData ToCpp(const HermesServiceDescriptionData& data) + { + ServiceDescriptionData result; + CToCpp(data.m_machineId, result.m_machineId); + CToCpp(data.m_laneId, result.m_laneId); + CToCpp(data.m_optionalInterfaceId, result.m_optionalInterfaceId); + CToCpp(data.m_version, result.m_version); + CToCpp(data.m_pSupportedFeatures, result.m_supportedFeatures); + return result; + } + + // MachineReadyData + template<> + struct Converter2C : ConverterBase + { + explicit Converter2C(const MachineReadyData& data) { - m_data.m_upstreamConfigurations = ToC(m_upstreamConfigurations, &m_data.m_upstreamConfigurationCount); - m_data.m_downstreamConfigurations = ToC(m_downstreamConfigurations, &m_data.m_downstreamConfigurationCount); - return &m_data; + CppToC(data.m_optionalFlippedBoard, m_flippedBoard, m_data.m_pOptionalFlippedBoard); + CppToC(data.m_failedBoard, m_data.m_failedBoard); + CppToC(data.m_optionalForecastId, m_data.m_optionalForecastId); + CppToC(data.m_optionalBoardId, m_data.m_optionalBoardId); + CppToC(data.m_optionalProductTypeId, m_data.m_optionalProductTypeId); + CppToC(data.m_optionalTopBarcode, m_data.m_optionalTopBarcode); + CppToC(data.m_optionalBottomBarcode, m_data.m_optionalBottomBarcode); + CppToC(data.m_optionalLengthInMM, m_data.m_pOptionalLengthInMM); + CppToC(data.m_optionalWidthInMM, m_data.m_pOptionalWidthInMM); + CppToC(data.m_optionalThicknessInMM, m_data.m_pOptionalThicknessInMM); + CppToC(data.m_optionalConveyorSpeedInMMPerSecs, m_data.m_pOptionalConveyorSpeedInMMPerSecs); + CppToC(data.m_optionalTopClearanceHeightInMM, m_data.m_pOptionalTopClearanceHeightInMM); + CppToC(data.m_optionalBottomClearanceHeightInMM, m_data.m_pOptionalBottomClearanceHeightInMM); + CppToC(data.m_optionalWeightInGrams, m_data.m_pOptionalWeightInGrams); + CppToC(data.m_optionalWorkOrderId, m_data.m_optionalWorkOrderId); + CppToC(data.m_optionalBatchId, m_data.m_optionalBatchId); } private: - VectorHolder m_upstreamConfigurations; - VectorHolder m_downstreamConfigurations; - mutable HermesSetConfigurationData m_data; + EHermesFlippedBoard m_flippedBoard; }; - inline SetConfigurationDataHolder ToC(const SetConfigurationData& in_data) { return SetConfigurationDataHolder(in_data); } - inline SetConfigurationData ToCpp(const HermesSetConfigurationData& in_data) + inline MachineReadyData ToCpp(const HermesMachineReadyData& data) { - SetConfigurationData data; - data.m_machineId = ToCpp(in_data.m_machineId); - data.m_upstreamConfigurations = ToCpp(in_data.m_upstreamConfigurations, in_data.m_upstreamConfigurationCount); - data.m_downstreamConfigurations = ToCpp(in_data.m_downstreamConfigurations, in_data.m_downstreamConfigurationCount); - return data; + MachineReadyData result; + CToCpp(data.m_failedBoard, result.m_failedBoard); + CToCpp(data.m_optionalForecastId, result.m_optionalForecastId); + CToCpp(data.m_optionalBoardId, result.m_optionalBoardId); + CToCpp(data.m_optionalProductTypeId, result.m_optionalProductTypeId); + CToCpp(data.m_pOptionalFlippedBoard, result.m_optionalFlippedBoard); + CToCpp(data.m_optionalTopBarcode, result.m_optionalTopBarcode); + CToCpp(data.m_optionalBottomBarcode, result.m_optionalBottomBarcode); + CToCpp(data.m_pOptionalLengthInMM, result.m_optionalLengthInMM); + CToCpp(data.m_pOptionalWidthInMM, result.m_optionalWidthInMM); + CToCpp(data.m_pOptionalThicknessInMM, result.m_optionalThicknessInMM); + CToCpp(data.m_pOptionalConveyorSpeedInMMPerSecs, result.m_optionalConveyorSpeedInMMPerSecs); + CToCpp(data.m_pOptionalTopClearanceHeightInMM, result.m_optionalTopClearanceHeightInMM); + CToCpp(data.m_pOptionalBottomClearanceHeightInMM, result.m_optionalBottomClearanceHeightInMM); + CToCpp(data.m_pOptionalWeightInGrams, result.m_optionalWeightInGrams); + CToCpp(data.m_optionalWorkOrderId, result.m_optionalWorkOrderId); + CToCpp(data.m_optionalBatchId, result.m_optionalBatchId); + return result; } - // GetConfigurationData - inline HermesGetConfigurationData ToC(const GetConfigurationData&) { return{}; } - inline GetConfigurationData ToCpp(const HermesGetConfigurationData&) { return{}; } + // RevokeMachineReadyData + template<> struct Converter2C : ConverterBase + { + explicit Converter2C(const RevokeMachineReadyData&) {} + }; + inline RevokeMachineReadyData ToCpp(const HermesRevokeMachineReadyData&) { return{}; } - // CurrentConfigurationData - class CurrentConfigurationDataHolder + // SubBoards + inline void CppToC(const SubBoard& data, HermesSubBoard& result) { - public: - explicit CurrentConfigurationDataHolder(const CurrentConfigurationData& in_data) : - m_upstreamConfigurations(in_data.m_upstreamConfigurations), - m_downstreamConfigurations(in_data.m_downstreamConfigurations) + CppToC(data.m_pos, result.m_pos); + CppToC(data.m_optionalBc, result.m_optionalBc); + CppToC(data.m_st, result.m_st); + } + + inline void CToCpp(const HermesSubBoard& data, SubBoard& result) + { + CToCpp(data.m_pos, result.m_pos); + CToCpp(data.m_optionalBc, result.m_optionalBc); + CToCpp(data.m_st, result.m_st); + } + + // BoardAvailableData + template<> + struct Converter2C : ConverterBase + { + Converter2C(const BoardAvailableData& data) { - m_data.m_optionalMachineId = ToC(in_data.m_optionalMachineId); + CppToC(data.m_boardId, m_data.m_boardId); + CppToC(data.m_boardIdCreatedBy, m_data.m_boardIdCreatedBy); + CppToC(data.m_failedBoard, m_data.m_failedBoard); + CppToC(data.m_optionalProductTypeId, m_data.m_optionalProductTypeId); + CppToC(data.m_flippedBoard, m_data.m_flippedBoard); + CppToC(data.m_optionalTopBarcode, m_data.m_optionalTopBarcode); + CppToC(data.m_optionalBottomBarcode, m_data.m_optionalBottomBarcode); + CppToC(data.m_optionalLengthInMM, m_data.m_pOptionalLengthInMM); + CppToC(data.m_optionalWidthInMM, m_data.m_pOptionalWidthInMM); + CppToC(data.m_optionalThicknessInMM, m_data.m_pOptionalThicknessInMM); + CppToC(data.m_optionalConveyorSpeedInMMPerSecs, m_data.m_pOptionalConveyorSpeedInMMPerSecs); + CppToC(data.m_optionalTopClearanceHeightInMM, m_data.m_pOptionalTopClearanceHeightInMM); + CppToC(data.m_optionalBottomClearanceHeightInMM, m_data.m_pOptionalBottomClearanceHeightInMM); + CppToC(data.m_optionalWeightInGrams, m_data.m_pOptionalWeightInGrams); + CppToC(data.m_optionalWorkOrderId, m_data.m_optionalWorkOrderId); + CppToC(data.m_optionalBatchId, m_data.m_optionalBatchId); + CppToC(data.m_optionalRoute, m_data.m_pOptionalRoute); + CppToC(data.m_optionalAction, m_data.m_pOptionalAction); + CppToC(data.m_optionalSubBoards, m_subBoards, m_data.m_optionalSubBoards); } - const HermesCurrentConfigurationData* operator&() + private: + VectorHolder m_subBoards; + }; + inline BoardAvailableData ToCpp(const HermesBoardAvailableData& data) + { + BoardAvailableData result; + CToCpp(data.m_boardId, result.m_boardId); + CToCpp(data.m_boardIdCreatedBy, result.m_boardIdCreatedBy); + CToCpp(data.m_failedBoard, result.m_failedBoard); + CToCpp(data.m_optionalProductTypeId, result.m_optionalProductTypeId); + CToCpp(data.m_flippedBoard, result.m_flippedBoard); + CToCpp(data.m_optionalTopBarcode, result.m_optionalTopBarcode); + CToCpp(data.m_optionalBottomBarcode, result.m_optionalBottomBarcode); + CToCpp(data.m_pOptionalLengthInMM, result.m_optionalLengthInMM); + CToCpp(data.m_pOptionalWidthInMM, result.m_optionalWidthInMM); + CToCpp(data.m_pOptionalThicknessInMM, result.m_optionalThicknessInMM); + CToCpp(data.m_pOptionalConveyorSpeedInMMPerSecs, result.m_optionalConveyorSpeedInMMPerSecs); + CToCpp(data.m_pOptionalTopClearanceHeightInMM, result.m_optionalTopClearanceHeightInMM); + CToCpp(data.m_pOptionalBottomClearanceHeightInMM, result.m_optionalBottomClearanceHeightInMM); + CToCpp(data.m_pOptionalWeightInGrams, result.m_optionalWeightInGrams); + CToCpp(data.m_optionalWorkOrderId, result.m_optionalWorkOrderId); + CToCpp(data.m_optionalBatchId, result.m_optionalBatchId); + CToCpp(data.m_pOptionalRoute, result.m_optionalRoute); + CToCpp(data.m_pOptionalAction, result.m_optionalAction); + CToCpp(data.m_optionalSubBoards, result.m_optionalSubBoards); + return result; + } + + // RevokeBoardAvailableData + template<> struct Converter2C : ConverterBase + { + explicit Converter2C(const RevokeBoardAvailableData&) {} + }; + inline RevokeBoardAvailableData ToCpp(const HermesRevokeBoardAvailableData&) { return{}; } + + // StartTransportData + template<> + struct Converter2C : ConverterBase + { + Converter2C(const StartTransportData& data) { - m_data.m_upstreamConfigurations = ToC(m_upstreamConfigurations, &m_data.m_upstreamConfigurationCount); - m_data.m_downstreamConfigurations = ToC(m_downstreamConfigurations, &m_data.m_downstreamConfigurationCount); - return &m_data; + CppToC(data.m_boardId, m_data.m_boardId); + CppToC(data.m_optionalConveyorSpeedInMMPerSecs, m_data.m_pOptionalConveyorSpeedInMMPerSecs); } + }; + inline StartTransportData ToCpp(const HermesStartTransportData& data) + { + StartTransportData result; + CToCpp(data.m_boardId, result.m_boardId); + CToCpp(data.m_pOptionalConveyorSpeedInMMPerSecs, result.m_optionalConveyorSpeedInMMPerSecs); + return result; + } - private: - VectorHolder m_upstreamConfigurations; - VectorHolder m_downstreamConfigurations; - mutable HermesCurrentConfigurationData m_data; + // StopTransportData + template<> + struct Converter2C : ConverterBase + { + Converter2C(const StopTransportData& data) + { + CppToC(data.m_transferState, m_data.m_transferState); + CppToC(data.m_boardId, m_data.m_boardId); + } }; + inline StopTransportData ToCpp(const HermesStopTransportData& data) + { + StopTransportData result; + CToCpp(data.m_transferState, result.m_transferState); + CToCpp(data.m_boardId, result.m_boardId); + return result; + } - inline CurrentConfigurationDataHolder ToC(const CurrentConfigurationData& in_data) { return CurrentConfigurationDataHolder(in_data); } - inline CurrentConfigurationData ToCpp(const HermesCurrentConfigurationData& in_data) + // TransportFinishedData + template<> + struct Converter2C : ConverterBase { - CurrentConfigurationData data; - if (in_data.m_optionalMachineId.m_pData) + Converter2C(const TransportFinishedData& data) { - data.m_optionalMachineId = ToCpp(in_data.m_optionalMachineId); + CppToC(data.m_transferState, m_data.m_transferState); + CppToC(data.m_boardId, m_data.m_boardId); } - data.m_upstreamConfigurations = ToCpp(in_data.m_upstreamConfigurations, in_data.m_upstreamConfigurationCount); - data.m_downstreamConfigurations = ToCpp(in_data.m_downstreamConfigurations, in_data.m_downstreamConfigurationCount); - return data; + }; + inline TransportFinishedData ToCpp(const HermesTransportFinishedData& data) + { + TransportFinishedData result; + CToCpp(data.m_transferState, result.m_transferState); + CToCpp(data.m_boardId, result.m_boardId); + return result; } - // ConnectionInfo - inline HermesConnectionInfo ToC(const ConnectionInfo& in_data) - { - return{ToC(in_data.m_address), in_data.m_port, ToC(in_data.m_hostName)}; + // NotificationData + template<> + struct Converter2C : ConverterBase + { + Converter2C(const NotificationData& data) + { + CppToC(data.m_notificationCode, m_data.m_notificationCode); + CppToC(data.m_severity, m_data.m_severity); + CppToC(data.m_description, m_data.m_description); + } + }; + inline NotificationData ToCpp(const HermesNotificationData& data) + { + NotificationData result; + CToCpp(data.m_notificationCode, result.m_notificationCode); + CToCpp(data.m_severity, result.m_severity); + CToCpp(data.m_description, result.m_description); + return result; } - inline ConnectionInfo ToCpp(const HermesConnectionInfo& in_data) + + // CheckAliveData + template<> + struct Converter2C : ConverterBase { - return{ToCpp(in_data.m_address), in_data.m_port, ToCpp(in_data.m_hostName)}; + Converter2C(const CheckAliveData& data) + { + CppToC(data.m_optionalType, m_optionalType, m_data.m_pOptionalType); + CppToC(data.m_optionalId, m_data.m_optionalId); + } + + private: + EHermesCheckAliveType m_optionalType; + }; + inline CheckAliveData ToCpp(const HermesCheckAliveData& data) + { + CheckAliveData result; + CToCpp(data.m_pOptionalType, result.m_optionalType); + CToCpp(data.m_optionalId, result.m_optionalId); + return result; } - // ServiceDescription - inline HermesServiceDescription ToC(const ServiceDescription& in_data) + // BoardForecastData + template<> + struct Converter2C : ConverterBase { - return{ToC(in_data.m_machineId), in_data.m_laneId, ToC(in_data.m_version)}; + Converter2C(const BoardForecastData& data) + { + CppToC(data.m_optionalForecastId, m_data.m_optionalForecastId); + CppToC(data.m_optionalTimeUntilAvailableInSeconds, m_data.m_pOptionalTimeUntilAvailableInSeconds); + CppToC(data.m_optionalBoardId, m_data.m_optionalBoardId); + CppToC(data.m_optionalBoardIdCreatedBy, m_data.m_optionalBoardIdCreatedBy); + CppToC(data.m_failedBoard, m_data.m_failedBoard); + CppToC(data.m_optionalProductTypeId, m_data.m_optionalProductTypeId); + CppToC(data.m_flippedBoard, m_data.m_flippedBoard); + CppToC(data.m_optionalTopBarcode, m_data.m_optionalTopBarcode); + CppToC(data.m_optionalBottomBarcode, m_data.m_optionalBottomBarcode); + CppToC(data.m_optionalLengthInMM, m_data.m_pOptionalLengthInMM); + CppToC(data.m_optionalWidthInMM, m_data.m_pOptionalWidthInMM); + CppToC(data.m_optionalThicknessInMM, m_data.m_pOptionalThicknessInMM); + CppToC(data.m_optionalConveyorSpeedInMMPerSecs, m_data.m_pOptionalConveyorSpeedInMMPerSecs); + CppToC(data.m_optionalTopClearanceHeightInMM, m_data.m_pOptionalTopClearanceHeightInMM); + CppToC(data.m_optionalBottomClearanceHeightInMM, m_data.m_pOptionalBottomClearanceHeightInMM); + CppToC(data.m_optionalWeightInGrams, m_data.m_pOptionalWeightInGrams); + CppToC(data.m_optionalWorkOrderId, m_data.m_optionalWorkOrderId); + CppToC(data.m_optionalBatchId, m_data.m_optionalBatchId); + } + }; + inline BoardForecastData ToCpp(const HermesBoardForecastData& data) + { + BoardForecastData result; + CToCpp(data.m_optionalForecastId, result.m_optionalForecastId); + CToCpp(data.m_pOptionalTimeUntilAvailableInSeconds, result.m_optionalTimeUntilAvailableInSeconds); + CToCpp(data.m_optionalBoardId, result.m_optionalBoardId); + CToCpp(data.m_optionalBoardIdCreatedBy, result.m_optionalBoardIdCreatedBy); + CToCpp(data.m_failedBoard, result.m_failedBoard); + CToCpp(data.m_optionalProductTypeId, result.m_optionalProductTypeId); + CToCpp(data.m_flippedBoard, result.m_flippedBoard); + CToCpp(data.m_optionalTopBarcode, result.m_optionalTopBarcode); + CToCpp(data.m_optionalBottomBarcode, result.m_optionalBottomBarcode); + CToCpp(data.m_pOptionalLengthInMM, result.m_optionalLengthInMM); + CToCpp(data.m_pOptionalWidthInMM, result.m_optionalWidthInMM); + CToCpp(data.m_pOptionalThicknessInMM, result.m_optionalThicknessInMM); + CToCpp(data.m_pOptionalConveyorSpeedInMMPerSecs, result.m_optionalConveyorSpeedInMMPerSecs); + CToCpp(data.m_pOptionalTopClearanceHeightInMM, result.m_optionalTopClearanceHeightInMM); + CToCpp(data.m_pOptionalBottomClearanceHeightInMM, result.m_optionalBottomClearanceHeightInMM); + CToCpp(data.m_pOptionalWeightInGrams, result.m_optionalWeightInGrams); + CToCpp(data.m_optionalWorkOrderId, result.m_optionalWorkOrderId); + CToCpp(data.m_optionalBatchId, result.m_optionalBatchId); + return result; } - inline ServiceDescription ToCpp(const HermesServiceDescription& in_data) + + // QueryBoardInfoData + template<> + struct Converter2C : ConverterBase { - ServiceDescription data(ToCpp(in_data.m_machineId), in_data.m_laneId); - data.m_version = ToCpp(in_data.m_version); - return data; + Converter2C(const QueryBoardInfoData& data) + { + CppToC(data.m_optionalTopBarcode, m_data.m_optionalTopBarcode); + CppToC(data.m_optionalBottomBarcode, m_data.m_optionalBottomBarcode); + } + }; + inline QueryBoardInfoData ToCpp(const HermesQueryBoardInfoData& data) + { + QueryBoardInfoData result; + CToCpp(data.m_optionalTopBarcode, result.m_optionalTopBarcode); + CToCpp(data.m_optionalBottomBarcode, result.m_optionalBottomBarcode); + return result; } - // MachineReadyData - inline HermesMachineReadyData ToC(const MachineReadyData& in_data) { return{ToC(in_data.m_failedBoard)}; } - inline MachineReadyData ToCpp(const HermesMachineReadyData& in_data) + // SendBoardInfoData + template<> + struct Converter2C : ConverterBase + { + Converter2C(const SendBoardInfoData& data) + { + CppToC(data.m_optionalFailedBoard, m_optionalFailedBoard, m_data.m_pOptionalFailedBoard); + CppToC(data.m_optionalFlippedBoard, m_optionalFlippedBoard, m_data.m_pOptionalFlippedBoard); + + CppToC(data.m_optionalBoardId, m_data.m_optionalBoardId); + CppToC(data.m_optionalBoardIdCreatedBy, m_data.m_optionalBoardIdCreatedBy); + CppToC(data.m_optionalProductTypeId, m_data.m_optionalProductTypeId); + CppToC(data.m_optionalTopBarcode, m_data.m_optionalTopBarcode); + CppToC(data.m_optionalBottomBarcode, m_data.m_optionalBottomBarcode); + CppToC(data.m_optionalLengthInMM, m_data.m_pOptionalLengthInMM); + CppToC(data.m_optionalWidthInMM, m_data.m_pOptionalWidthInMM); + CppToC(data.m_optionalThicknessInMM, m_data.m_pOptionalThicknessInMM); + CppToC(data.m_optionalConveyorSpeedInMMPerSecs, m_data.m_pOptionalConveyorSpeedInMMPerSecs); + CppToC(data.m_optionalTopClearanceHeightInMM, m_data.m_pOptionalTopClearanceHeightInMM); + CppToC(data.m_optionalBottomClearanceHeightInMM, m_data.m_pOptionalBottomClearanceHeightInMM); + CppToC(data.m_optionalWeightInGrams, m_data.m_pOptionalWeightInGrams); + CppToC(data.m_optionalWorkOrderId, m_data.m_optionalWorkOrderId); + CppToC(data.m_optionalBatchId, m_data.m_optionalBatchId); + CppToC(data.m_optionalRoute, m_data.m_pOptionalRoute); + CppToC(data.m_optionalAction, m_data.m_pOptionalAction); + CppToC(data.m_optionalSubBoards, m_subBoards, m_data.m_optionalSubBoards); + } + + private: + EHermesBoardQuality m_optionalFailedBoard; + EHermesFlippedBoard m_optionalFlippedBoard; + VectorHolder m_subBoards; + }; + + inline SendBoardInfoData ToCpp(const HermesSendBoardInfoData& data) { - return MachineReadyData(ToCpp(in_data.m_failedBoard)); + SendBoardInfoData result; + CToCpp(data.m_optionalBoardId, result.m_optionalBoardId); + CToCpp(data.m_optionalBoardIdCreatedBy, result.m_optionalBoardIdCreatedBy); + CToCpp(data.m_pOptionalFailedBoard, result.m_optionalFailedBoard); + CToCpp(data.m_optionalProductTypeId, result.m_optionalProductTypeId); + CToCpp(data.m_pOptionalFlippedBoard, result.m_optionalFlippedBoard); + CToCpp(data.m_optionalTopBarcode, result.m_optionalTopBarcode); + CToCpp(data.m_optionalBottomBarcode, result.m_optionalBottomBarcode); + CToCpp(data.m_pOptionalLengthInMM, result.m_optionalLengthInMM); + CToCpp(data.m_pOptionalWidthInMM, result.m_optionalWidthInMM); + CToCpp(data.m_pOptionalThicknessInMM, result.m_optionalThicknessInMM); + CToCpp(data.m_pOptionalConveyorSpeedInMMPerSecs, result.m_optionalConveyorSpeedInMMPerSecs); + CToCpp(data.m_pOptionalTopClearanceHeightInMM, result.m_optionalTopClearanceHeightInMM); + CToCpp(data.m_pOptionalBottomClearanceHeightInMM, result.m_optionalBottomClearanceHeightInMM); + CToCpp(data.m_pOptionalWeightInGrams, result.m_optionalWeightInGrams); + CToCpp(data.m_optionalWorkOrderId, result.m_optionalWorkOrderId); + CToCpp(data.m_optionalBatchId, result.m_optionalBatchId); + CToCpp(data.m_pOptionalRoute, result.m_optionalRoute); + CToCpp(data.m_pOptionalAction, result.m_optionalAction); + CToCpp(data.m_optionalSubBoards, result.m_optionalSubBoards); + return result; } - // RevokeMachineReadyData - inline HermesRevokeMachineReadyData ToC(const RevokeMachineReadyData&) { return{}; } - inline RevokeMachineReadyData ToCpp(const HermesRevokeMachineReadyData&) { return{}; } + // SupervisoryFeatures + inline void CppToC(const FeatureConfiguration&, HermesFeatureConfiguration&) {} + inline void CppToC(const FeatureBoardTracking&, HermesFeatureBoardTracking&) {} + inline void CppToC(const FeatureQueryWorkOrderInfo&, HermesFeatureQueryWorkOrderInfo&) {} + inline void CppToC(const FeatureSendWorkOrderInfo&, HermesFeatureSendWorkOrderInfo&) {} + inline void CppToC(const FeatureReplyWorkOrderInfo&, HermesFeatureReplyWorkOrderInfo&) {} + inline void CppToC(const FeatureQueryHermesCapabilities&, HermesFeatureQueryHermesCapabilities&) {} + inline void CppToC(const FeatureSendHermesCapabilities&, HermesFeatureSendHermesCapabilities&) {} - // BoardAvailableData - inline HermesBoardAvailableData ToC(const BoardAvailableData& in_data) + inline void CToCpp(const HermesFeatureConfiguration&, FeatureConfiguration&) {} + inline void CToCpp(const HermesFeatureBoardTracking&, FeatureBoardTracking&) {} + inline void CToCpp(const HermesFeatureQueryWorkOrderInfo&, FeatureQueryWorkOrderInfo&) {} + inline void CToCpp(const HermesFeatureSendWorkOrderInfo&, FeatureSendWorkOrderInfo&) {} + inline void CToCpp(const HermesFeatureReplyWorkOrderInfo&, FeatureReplyWorkOrderInfo&) {} + inline void CToCpp(const HermesFeatureQueryHermesCapabilities&, FeatureQueryHermesCapabilities&) {} + inline void CToCpp(const HermesFeatureSendHermesCapabilities&, FeatureSendHermesCapabilities&) {} + + // SupervisoryFeatures + struct SupervisoryFeaturesHolder : ConverterBase { - return{ToC(in_data.m_boardId), ToC(in_data.m_boardIdCreatedBy), ToC(in_data.m_failedBoard), - ToC(in_data.m_optionalProductTypeId), ToC(in_data.m_flippedBoard), - ToC(in_data.m_optionalTopBarcode), ToC(in_data.m_optionalBottomBarcode), - ToC(in_data.m_optionalLengthInMM), ToC(in_data.m_optionalWidthInMM), ToC(in_data.m_optionalThicknessInMM), - ToC(in_data.m_optionalConveyorSpeedInMMPerSecs), - ToC(in_data.m_optionalTopClearanceHeightInMM), ToC(in_data.m_optionalBottomClearanceHeightInMM)}; + HermesFeatureConfiguration m_optionalFeatureConfiguration; + HermesFeatureCheckAliveResponse m_optionalFeatureCheckAliveResponse; + HermesFeatureBoardTracking m_optionalFeatureBoardTracking; + HermesFeatureQueryWorkOrderInfo m_optionalFeatureQueryWorkOrderInfo; + HermesFeatureSendWorkOrderInfo m_optionalFeatureSendWorkOrderInfo; + HermesFeatureReplyWorkOrderInfo m_optionalFeatureReplyWorkOrderInfo; + HermesFeatureQueryHermesCapabilities m_optionalFeatureQueryHermesCapabilities; + HermesFeatureSendHermesCapabilities m_optionalFeatureSendHermesCapabilities; + }; + + inline void CppToC(const SupervisoryFeatures& data, SupervisoryFeaturesHolder& intermediate) + { + auto& hermesData = intermediate.m_data; + CppToC(data.m_optionalFeatureConfiguration, intermediate.m_optionalFeatureConfiguration, hermesData.m_pOptionalFeatureConfiguration); + CppToC(data.m_optionalFeatureCheckAliveResponse, intermediate.m_optionalFeatureCheckAliveResponse, hermesData.m_pOptionalFeatureCheckAliveResponse); + CppToC(data.m_optionalFeatureBoardTracking, intermediate.m_optionalFeatureBoardTracking, hermesData.m_pOptionalFeatureBoardTracking); + CppToC(data.m_optionalFeatureQueryWorkOrderInfo, intermediate.m_optionalFeatureQueryWorkOrderInfo, hermesData.m_pOptionalFeatureQueryWorkOrderInfo); + CppToC(data.m_optionalFeatureSendWorkOrderInfo, intermediate.m_optionalFeatureSendWorkOrderInfo, hermesData.m_pOptionalFeatureSendWorkOrderInfo); + CppToC(data.m_optionalFeatureReplyWorkOrderInfo, intermediate.m_optionalFeatureReplyWorkOrderInfo, hermesData.m_pOptionalFeatureReplyWorkOrderInfo); + CppToC(data.m_optionalFeatureQueryHermesCapabilities, intermediate.m_optionalFeatureQueryHermesCapabilities, hermesData.m_pOptionalFeatureQueryHermesCapabilities); + CppToC(data.m_optionalFeatureSendHermesCapabilities, intermediate.m_optionalFeatureSendHermesCapabilities, hermesData.m_pOptionalFeatureSendHermesCapabilities); } - inline BoardAvailableData ToCpp(const HermesBoardAvailableData& in_data) - { - BoardAvailableData data(ToCpp(in_data.m_boardId), ToCpp(in_data.m_boardIdCreatedBy), - ToCpp(in_data.m_failedBoard), - ToCpp(in_data.m_flippedBoard)); - data.m_optionalProductTypeId = ToOptional(in_data.m_optionalProductTypeId); - data.m_optionalTopBarcode = ToOptional(in_data.m_optionalTopBarcode); - data.m_optionalBottomBarcode = ToOptional(in_data.m_optionalBottomBarcode); - data.m_optionalLengthInMM = ToOptional(in_data.m_pOptionalLengthInMM); - data.m_optionalWidthInMM = ToOptional(in_data.m_pOptionalWidthInMM); - data.m_optionalThicknessInMM = ToOptional(in_data.m_pOptionalThicknessInMM); - data.m_optionalConveyorSpeedInMMPerSecs = ToOptional(in_data.m_pOptionalConveyorSpeedInMMPerSecs); - data.m_optionalTopClearanceHeightInMM = ToOptional(in_data.m_pOptionalTopClearanceHeightInMM); - data.m_optionalBottomClearanceHeightInMM = ToOptional(in_data.m_pOptionalBottomClearanceHeightInMM); - return data; + + inline void CToCpp(const HermesSupervisoryFeatures& data, SupervisoryFeatures& result) + { + CToCpp(data.m_pOptionalFeatureConfiguration, result.m_optionalFeatureConfiguration); + CToCpp(data.m_pOptionalFeatureCheckAliveResponse, result.m_optionalFeatureCheckAliveResponse); + CToCpp(data.m_pOptionalFeatureBoardTracking, result.m_optionalFeatureBoardTracking); + CToCpp(data.m_pOptionalFeatureQueryWorkOrderInfo, result.m_optionalFeatureQueryWorkOrderInfo); + CToCpp(data.m_pOptionalFeatureSendWorkOrderInfo, result.m_optionalFeatureSendWorkOrderInfo); + CToCpp(data.m_pOptionalFeatureReplyWorkOrderInfo, result.m_optionalFeatureReplyWorkOrderInfo); + CToCpp(data.m_pOptionalFeatureQueryHermesCapabilities, result.m_optionalFeatureQueryHermesCapabilities); + CToCpp(data.m_pOptionalFeatureSendHermesCapabilities, result.m_optionalFeatureSendHermesCapabilities); } - // RevokeBoardAvailableData - inline HermesRevokeBoardAvailableData ToC(const RevokeBoardAvailableData&) { return{}; } - inline RevokeBoardAvailableData ToCpp(const HermesRevokeBoardAvailableData&) { return{}; } - - // StartTransportData - inline HermesStartTransportData ToC(const StartTransportData& in_data) + // SupervisoryServiceDescriptionData + template<> + struct Converter2C : ConverterBase + { + Converter2C(const SupervisoryServiceDescriptionData& data) + { + CppToC(data.m_systemId, m_data.m_systemId); + CppToC(data.m_version, m_data.m_version); + CppToC(data.m_supportedFeatures, m_supervisoryFeatures); + m_data.m_pSupportedFeatures = &m_supervisoryFeatures.m_data; + } + private: + SupervisoryFeaturesHolder m_supervisoryFeatures; + }; + + // SupervisoryServiceDescriptionData + inline SupervisoryServiceDescriptionData ToCpp(const HermesSupervisoryServiceDescriptionData& data) { - return{ToC(in_data.m_boardId), ToC(in_data.m_optionalConveyorSpeedInMMPerSecs)}; + SupervisoryServiceDescriptionData result; + CToCpp(data.m_systemId, result.m_systemId); + CToCpp(data.m_version, result.m_version); + CToCpp(data.m_pSupportedFeatures, result.m_supportedFeatures); + return result; } - inline StartTransportData ToCpp(const HermesStartTransportData& in_data) + + // BoardArrivedData + template<> + struct Converter2C : ConverterBase + { + Converter2C(const BoardArrivedData& data) + { + CppToC(data.m_machineId, m_data.m_machineId); + CppToC(data.m_upstreamLaneId, m_data.m_upstreamLaneId); + CppToC(data.m_optionalUpstreamInterfaceId, m_data.m_optionalUpstreamInterfaceId); + CppToC(data.m_optionalMagazineId, m_data.m_optionalMagazineId); + CppToC(data.m_optionalSlotId, m_data.m_pOptionalSlotId); + CppToC(data.m_boardTransfer, m_data.m_boardTransfer); + CppToC(data.m_boardId, m_data.m_boardId); + CppToC(data.m_boardIdCreatedBy, m_data.m_boardIdCreatedBy); + CppToC(data.m_failedBoard, m_data.m_failedBoard); + CppToC(data.m_optionalProductTypeId, m_data.m_optionalProductTypeId); + CppToC(data.m_flippedBoard, m_data.m_flippedBoard); + CppToC(data.m_optionalTopBarcode, m_data.m_optionalTopBarcode); + CppToC(data.m_optionalBottomBarcode, m_data.m_optionalBottomBarcode); + CppToC(data.m_optionalLengthInMM, m_data.m_pOptionalLengthInMM); + CppToC(data.m_optionalWidthInMM, m_data.m_pOptionalWidthInMM); + CppToC(data.m_optionalThicknessInMM, m_data.m_pOptionalThicknessInMM); + CppToC(data.m_optionalConveyorSpeedInMMPerSecs, m_data.m_pOptionalConveyorSpeedInMMPerSecs); + CppToC(data.m_optionalTopClearanceHeightInMM, m_data.m_pOptionalTopClearanceHeightInMM); + CppToC(data.m_optionalBottomClearanceHeightInMM, m_data.m_pOptionalBottomClearanceHeightInMM); + CppToC(data.m_optionalWeightInGrams, m_data.m_pOptionalWeightInGrams); + CppToC(data.m_optionalWorkOrderId, m_data.m_optionalWorkOrderId); + CppToC(data.m_optionalBatchId, m_data.m_optionalBatchId); + CppToC(data.m_optionalRoute, m_data.m_pOptionalRoute); + CppToC(data.m_optionalAction, m_data.m_pOptionalAction); + CppToC(data.m_optionalSubBoards, m_subBoards, m_data.m_optionalSubBoards); + } + private: + VectorHolder m_subBoards; + }; + inline BoardArrivedData ToCpp(const HermesBoardArrivedData& data) { - StartTransportData data(ToCpp(in_data.m_boardId)); - data.m_optionalConveyorSpeedInMMPerSecs = ToOptional(in_data.m_pOptionalConveyorSpeedInMMPerSecs); - return data; + BoardArrivedData result; + CToCpp(data.m_machineId, result.m_machineId); + CToCpp(data.m_upstreamLaneId, result.m_upstreamLaneId); + CToCpp(data.m_optionalUpstreamInterfaceId, result.m_optionalUpstreamInterfaceId); + CToCpp(data.m_optionalMagazineId, result.m_optionalMagazineId); + CToCpp(data.m_pOptionalSlotId, result.m_optionalSlotId); + CToCpp(data.m_boardTransfer, result.m_boardTransfer); + CToCpp(data.m_boardId, result.m_boardId); + CToCpp(data.m_boardIdCreatedBy, result.m_boardIdCreatedBy); + CToCpp(data.m_failedBoard, result.m_failedBoard); + CToCpp(data.m_optionalProductTypeId, result.m_optionalProductTypeId); + CToCpp(data.m_flippedBoard, result.m_flippedBoard); + CToCpp(data.m_optionalTopBarcode, result.m_optionalTopBarcode); + CToCpp(data.m_optionalBottomBarcode, result.m_optionalBottomBarcode); + CToCpp(data.m_pOptionalLengthInMM, result.m_optionalLengthInMM); + CToCpp(data.m_pOptionalWidthInMM, result.m_optionalWidthInMM); + CToCpp(data.m_pOptionalThicknessInMM, result.m_optionalThicknessInMM); + CToCpp(data.m_pOptionalConveyorSpeedInMMPerSecs, result.m_optionalConveyorSpeedInMMPerSecs); + CToCpp(data.m_pOptionalTopClearanceHeightInMM, result.m_optionalTopClearanceHeightInMM); + CToCpp(data.m_pOptionalBottomClearanceHeightInMM, result.m_optionalBottomClearanceHeightInMM); + CToCpp(data.m_pOptionalWeightInGrams, result.m_optionalWeightInGrams); + CToCpp(data.m_optionalWorkOrderId, result.m_optionalWorkOrderId); + CToCpp(data.m_optionalBatchId, result.m_optionalBatchId); + CToCpp(data.m_pOptionalRoute, result.m_optionalRoute); + CToCpp(data.m_pOptionalAction, result.m_optionalAction); + CToCpp(data.m_optionalSubBoards, result.m_optionalSubBoards); + return result; } - // StopTransportData - inline HermesStopTransportData ToC(const StopTransportData& in_data) + // BoardDepartedData + template<> + struct Converter2C : ConverterBase + { + Converter2C(const BoardDepartedData& data) + { + CppToC(data.m_machineId, m_data.m_machineId); + CppToC(data.m_downstreamLaneId, m_data.m_downstreamLaneId); + CppToC(data.m_optionalDownstreamInterfaceId, m_data.m_optionalDownstreamInterfaceId); + CppToC(data.m_optionalMagazineId, m_data.m_optionalMagazineId); + CppToC(data.m_optionalSlotId, m_data.m_pOptionalSlotId); + CppToC(data.m_boardTransfer, m_data.m_boardTransfer); + CppToC(data.m_boardId, m_data.m_boardId); + CppToC(data.m_boardIdCreatedBy, m_data.m_boardIdCreatedBy); + CppToC(data.m_failedBoard, m_data.m_failedBoard); + CppToC(data.m_optionalProductTypeId, m_data.m_optionalProductTypeId); + CppToC(data.m_flippedBoard, m_data.m_flippedBoard); + CppToC(data.m_optionalTopBarcode, m_data.m_optionalTopBarcode); + CppToC(data.m_optionalBottomBarcode, m_data.m_optionalBottomBarcode); + CppToC(data.m_optionalLengthInMM, m_data.m_pOptionalLengthInMM); + CppToC(data.m_optionalWidthInMM, m_data.m_pOptionalWidthInMM); + CppToC(data.m_optionalThicknessInMM, m_data.m_pOptionalThicknessInMM); + CppToC(data.m_optionalConveyorSpeedInMMPerSecs, m_data.m_pOptionalConveyorSpeedInMMPerSecs); + CppToC(data.m_optionalTopClearanceHeightInMM, m_data.m_pOptionalTopClearanceHeightInMM); + CppToC(data.m_optionalBottomClearanceHeightInMM, m_data.m_pOptionalBottomClearanceHeightInMM); + CppToC(data.m_optionalWeightInGrams, m_data.m_pOptionalWeightInGrams); + CppToC(data.m_optionalWorkOrderId, m_data.m_optionalWorkOrderId); + CppToC(data.m_optionalBatchId, m_data.m_optionalBatchId); + CppToC(data.m_optionalRoute, m_data.m_pOptionalRoute); + CppToC(data.m_optionalAction, m_data.m_pOptionalAction); + CppToC(data.m_optionalSubBoards, m_subBoards, m_data.m_optionalSubBoards); + } + private: + VectorHolder m_subBoards; + }; + + inline BoardDepartedData ToCpp(const HermesBoardDepartedData& data) { - return{ToC(in_data.m_transferState), ToC(in_data.m_boardId)}; + BoardDepartedData result; + + CToCpp(data.m_machineId, result.m_machineId); + CToCpp(data.m_downstreamLaneId, result.m_downstreamLaneId); + CToCpp(data.m_optionalDownstreamInterfaceId, result.m_optionalDownstreamInterfaceId); + CToCpp(data.m_optionalMagazineId, result.m_optionalMagazineId); + CToCpp(data.m_pOptionalSlotId, result.m_optionalSlotId); + CToCpp(data.m_boardTransfer, result.m_boardTransfer); + CToCpp(data.m_boardId, result.m_boardId); + CToCpp(data.m_boardIdCreatedBy, result.m_boardIdCreatedBy); + CToCpp(data.m_failedBoard, result.m_failedBoard); + CToCpp(data.m_optionalProductTypeId, result.m_optionalProductTypeId); + CToCpp(data.m_flippedBoard, result.m_flippedBoard); + CToCpp(data.m_optionalTopBarcode, result.m_optionalTopBarcode); + CToCpp(data.m_optionalBottomBarcode, result.m_optionalBottomBarcode); + CToCpp(data.m_pOptionalLengthInMM, result.m_optionalLengthInMM); + CToCpp(data.m_pOptionalWidthInMM, result.m_optionalWidthInMM); + CToCpp(data.m_pOptionalThicknessInMM, result.m_optionalThicknessInMM); + CToCpp(data.m_pOptionalConveyorSpeedInMMPerSecs, result.m_optionalConveyorSpeedInMMPerSecs); + CToCpp(data.m_pOptionalTopClearanceHeightInMM, result.m_optionalTopClearanceHeightInMM); + CToCpp(data.m_pOptionalBottomClearanceHeightInMM, result.m_optionalBottomClearanceHeightInMM); + CToCpp(data.m_pOptionalWeightInGrams, result.m_optionalWeightInGrams); + CToCpp(data.m_optionalWorkOrderId, result.m_optionalWorkOrderId); + CToCpp(data.m_optionalBatchId, result.m_optionalBatchId); + CToCpp(data.m_pOptionalRoute, result.m_optionalRoute); + CToCpp(data.m_pOptionalAction, result.m_optionalAction); + CToCpp(data.m_optionalSubBoards, result.m_optionalSubBoards); + return result; } - inline StopTransportData ToCpp(const HermesStopTransportData& in_data) + + // QueryWorkOrderInfoData + template<> + struct Converter2C : ConverterBase { - return StopTransportData(ToCpp(in_data.m_transferState), - ToCpp(in_data.m_boardId)); + Converter2C(const QueryWorkOrderInfoData& data) + { + CppToC(data.m_optionalQueryId, m_data.m_optionalQueryId); + CppToC(data.m_machineId, m_data.m_machineId); + CppToC(data.m_optionalMagazineId, m_data.m_optionalMagazineId); + CppToC(data.m_optionalSlotId, m_data.m_pOptionalSlotId); + CppToC(data.m_optionalBarcode, m_data.m_optionalBarcode); + CppToC(data.m_optionalWorkOrderId, m_data.m_optionalWorkOrderId); + CppToC(data.m_optionalBatchId, m_data.m_optionalBatchId); + } + }; + inline QueryWorkOrderInfoData ToCpp(const HermesQueryWorkOrderInfoData& data) + { + QueryWorkOrderInfoData result; + CToCpp(data.m_optionalQueryId, result.m_optionalQueryId); + CToCpp(data.m_machineId, result.m_machineId); + CToCpp(data.m_optionalMagazineId, result.m_optionalMagazineId); + CToCpp(data.m_pOptionalSlotId, result.m_optionalSlotId); + CToCpp(data.m_optionalBarcode, result.m_optionalBarcode); + CToCpp(data.m_optionalWorkOrderId, result.m_optionalWorkOrderId); + CToCpp(data.m_optionalBatchId, result.m_optionalBatchId); + return result; } - // TransportFinishedData - inline HermesTransportFinishedData ToC(const TransportFinishedData& in_data) + // SendWorkOrderInfoData + template<> + struct Converter2C : ConverterBase + { + Converter2C(const SendWorkOrderInfoData& data) + { + CppToC(data.m_optionalQueryId, m_data.m_optionalQueryId); + CppToC(data.m_optionalWorkOrderId, m_data.m_optionalWorkOrderId); + CppToC(data.m_optionalBatchId, m_data.m_optionalBatchId); + CppToC(data.m_optionalBoardId, m_data.m_optionalBoardId); + CppToC(data.m_optionalBoardIdCreatedBy, m_data.m_optionalBoardIdCreatedBy); + CppToC(data.m_optionalFailedBoard, m_optionalFailedBoard, m_data.m_pOptionalFailedBoard); + CppToC(data.m_optionalProductTypeId, m_data.m_optionalProductTypeId); + CppToC(data.m_optionalFlippedBoard, m_optionalFlippedBoard, m_data.m_pOptionalFlippedBoard); + CppToC(data.m_optionalTopBarcode, m_data.m_optionalTopBarcode); + CppToC(data.m_optionalBottomBarcode, m_data.m_optionalBottomBarcode); + CppToC(data.m_optionalLengthInMM, m_data.m_pOptionalLengthInMM); + CppToC(data.m_optionalWidthInMM, m_data.m_pOptionalWidthInMM); + CppToC(data.m_optionalThicknessInMM, m_data.m_pOptionalThicknessInMM); + CppToC(data.m_optionalConveyorSpeedInMMPerSecs, m_data.m_pOptionalConveyorSpeedInMMPerSecs); + CppToC(data.m_optionalTopClearanceHeightInMM, m_data.m_pOptionalTopClearanceHeightInMM); + CppToC(data.m_optionalBottomClearanceHeightInMM, m_data.m_pOptionalBottomClearanceHeightInMM); + CppToC(data.m_optionalWeightInGrams, m_data.m_pOptionalWeightInGrams); + CppToC(data.m_optionalRoute, m_data.m_pOptionalRoute); + CppToC(data.m_optionalSubBoards, m_subBoards, m_data.m_optionalSubBoards); + } + private: + VectorHolder m_subBoards; + EHermesBoardQuality m_optionalFailedBoard; + EHermesFlippedBoard m_optionalFlippedBoard; + }; + inline SendWorkOrderInfoData ToCpp(const HermesSendWorkOrderInfoData& data) { - return{ToC(in_data.m_transferState), ToC(in_data.m_boardId)}; + SendWorkOrderInfoData result; + CToCpp(data.m_optionalQueryId, result.m_optionalQueryId); + CToCpp(data.m_optionalWorkOrderId, result.m_optionalWorkOrderId); + CToCpp(data.m_optionalBatchId, result.m_optionalBatchId); + CToCpp(data.m_optionalBoardId, result.m_optionalBoardId); + CToCpp(data.m_optionalBoardIdCreatedBy, result.m_optionalBoardIdCreatedBy); + CToCpp(data.m_pOptionalFailedBoard, result.m_optionalFailedBoard); + CToCpp(data.m_optionalProductTypeId, result.m_optionalProductTypeId); + CToCpp(data.m_pOptionalFlippedBoard, result.m_optionalFlippedBoard); + CToCpp(data.m_optionalTopBarcode, result.m_optionalTopBarcode); + CToCpp(data.m_optionalBottomBarcode, result.m_optionalBottomBarcode); + CToCpp(data.m_pOptionalLengthInMM, result.m_optionalLengthInMM); + CToCpp(data.m_pOptionalWidthInMM, result.m_optionalWidthInMM); + CToCpp(data.m_pOptionalThicknessInMM, result.m_optionalThicknessInMM); + CToCpp(data.m_pOptionalConveyorSpeedInMMPerSecs, result.m_optionalConveyorSpeedInMMPerSecs); + CToCpp(data.m_pOptionalTopClearanceHeightInMM, result.m_optionalTopClearanceHeightInMM); + CToCpp(data.m_pOptionalBottomClearanceHeightInMM, result.m_optionalBottomClearanceHeightInMM); + CToCpp(data.m_pOptionalWeightInGrams, result.m_optionalWeightInGrams); + CToCpp(data.m_pOptionalRoute, result.m_optionalRoute); + CToCpp(data.m_optionalSubBoards, result.m_optionalSubBoards); + return result; } - inline TransportFinishedData ToCpp(const HermesTransportFinishedData& in_data) + + // ReplyWorkOrderInfoData + template<> + struct Converter2C : ConverterBase + { + Converter2C(const ReplyWorkOrderInfoData& data) + { + CppToC(data.m_workOrderId, m_data.m_workOrderId); + CppToC(data.m_optionalBatchId, m_data.m_optionalBatchId); + CppToC(data.m_status, m_data.m_status); + } + }; + inline ReplyWorkOrderInfoData ToCpp(const HermesReplyWorkOrderInfoData& data) { - return TransportFinishedData(ToCpp(in_data.m_transferState), - ToCpp(in_data.m_boardId)); + ReplyWorkOrderInfoData result; + CToCpp(data.m_workOrderId, result.m_workOrderId); + CToCpp(data.m_optionalBatchId, result.m_optionalBatchId); + CToCpp(data.m_status, result.m_status); + return result; } - // NotificationData - inline HermesNotificationData ToC(const NotificationData& in_data) - { - return{ToC(in_data.m_notificationCode), ToC(in_data.m_severity), ToC(in_data.m_description)}; + // CommandData + template<> + struct Converter2C : ConverterBase + { + Converter2C(const CommandData& data) + { + CppToC(data.m_command, m_data.m_command); + } + }; + inline CommandData ToCpp(const HermesCommandData& data) + { + CommandData result; + CToCpp(data.m_command, result.m_command); + return result; } - inline NotificationData ToCpp(const HermesNotificationData& in_data) + + + // QueryHermesCapabilitiesData + template<> + struct Converter2C : ConverterBase { - return NotificationData(ToCpp(static_cast(in_data.m_notificationCode)), - ToCpp(static_cast(in_data.m_severity)), - ToCpp(in_data.m_description)); + Converter2C(const QueryHermesCapabilitiesData&) + { + } + }; + inline QueryHermesCapabilitiesData ToCpp(const HermesQueryHermesCapabilitiesData&) + { + QueryHermesCapabilitiesData result; + return result; } + + // OptionalMessages + inline void CppToC(const MessageCheckAliveResponse&, HermesMessageCheckAliveResponse&) {} + inline void CppToC(const MessageBoardForecast&, HermesMessageBoardForecast&) {} + inline void CppToC(const MessageQueryBoardInfo&, HermesMessageQueryBoardInfo&) {} + inline void CppToC(const MessageSendBoardInfo&, HermesMessageSendBoardInfo&) {} + inline void CppToC(const MessageBoardArrived&, HermesMessageBoardArrived&) {} + inline void CppToC(const MessageBoardDeparted&, HermesMessageBoardDeparted&) {} + inline void CppToC(const MessageQueryWorkOrderInfo&, HermesMessageQueryWorkOrderInfo&) {} + inline void CppToC(const MessageReplyWorkOrderInfo&, HermesMessageReplyWorkOrderInfo&) {} + inline void CppToC(const MessageCommand&, HermesMessageCommand&) {} - // CheckAliveData - inline HermesCheckAliveData ToC(const CheckAliveData&) { return{}; } - inline CheckAliveData ToCpp(const HermesCheckAliveData&) { return{}; } + inline void CToCpp(const HermesMessageCheckAliveResponse&, MessageCheckAliveResponse&) {} + inline void CToCpp(const HermesMessageBoardForecast&, MessageBoardForecast&) {} + inline void CToCpp(const HermesMessageQueryBoardInfo&, MessageQueryBoardInfo&) {} + inline void CToCpp(const HermesMessageSendBoardInfo&, MessageSendBoardInfo&) {} + inline void CToCpp(const HermesMessageBoardArrived&, MessageBoardArrived&) {} + inline void CToCpp(const HermesMessageBoardDeparted&, MessageBoardDeparted&) {} + inline void CToCpp(const HermesMessageQueryWorkOrderInfo&, MessageQueryWorkOrderInfo&) {} + inline void CToCpp(const HermesMessageReplyWorkOrderInfo&, MessageReplyWorkOrderInfo&) {} + inline void CToCpp(const HermesMessageCommand&, MessageCommand&) {} + + // OptionalMessages + struct OptionalMessagesHolder : ConverterBase + { + HermesMessageCheckAliveResponse m_optionalMessageCheckAliveResponse; + HermesMessageBoardForecast m_optionalMessageBoardForecast; + HermesMessageQueryBoardInfo m_optionalMessageQueryBoardInfo; + HermesMessageSendBoardInfo m_optionalMessageSendBoardInfo; + HermesMessageBoardArrived m_optionalMessageBoardArrived; + HermesMessageBoardDeparted m_optionalMessageBoardDeparted; + HermesMessageQueryWorkOrderInfo m_optionalMessageQueryWorkOrderInfo; + HermesMessageReplyWorkOrderInfo m_optionalMessageReplyWorkOrderInfo; + HermesMessageCommand m_optionalMessageCommand; + }; + + inline void CppToC(const OptionalMessages& data, OptionalMessagesHolder& result) + { + auto& hermesData = result.m_data; + CppToC(data.m_optionalMessageCheckAliveResponse, result.m_optionalMessageCheckAliveResponse, hermesData.m_pOptionalMessageCheckAliveResponse); + CppToC(data.m_optionalMessageBoardForecast, result.m_optionalMessageBoardForecast, hermesData.m_pOptionalMessageBoardForecast); + CppToC(data.m_optionalMessageQueryBoardInfo, result.m_optionalMessageQueryBoardInfo, hermesData.m_pOptionalMessageQueryBoardInfo); + CppToC(data.m_optionalMessageSendBoardInfo, result.m_optionalMessageSendBoardInfo, hermesData.m_pOptionalMessageSendBoardInfo); + CppToC(data.m_optionalMessageBoardArrived, result.m_optionalMessageBoardArrived, hermesData.m_pOptionalMessageBoardArrived); + CppToC(data.m_optionalMessageBoardDeparted, result.m_optionalMessageBoardDeparted, hermesData.m_pOptionalMessageBoardDeparted); + CppToC(data.m_optionalMessageQueryWorkOrderInfo, result.m_optionalMessageQueryWorkOrderInfo, hermesData.m_pOptionalMessageQueryWorkOrderInfo); + CppToC(data.m_optionalMessageReplyWorkOrderInfo, result.m_optionalMessageReplyWorkOrderInfo, hermesData.m_pOptionalMessageReplyWorkOrderInfo); + CppToC(data.m_optionalMessageCommand, result.m_optionalMessageCommand, hermesData.m_pOptionalMessageCommand); + } + + inline void CToCpp(const HermesOptionalMessages& data, OptionalMessages& result) + { + CToCpp(data.m_pOptionalMessageCheckAliveResponse, result.m_optionalMessageCheckAliveResponse); + CToCpp(data.m_pOptionalMessageBoardForecast, result.m_optionalMessageBoardForecast); + CToCpp(data.m_pOptionalMessageQueryBoardInfo, result.m_optionalMessageQueryBoardInfo); + CToCpp(data.m_pOptionalMessageSendBoardInfo, result.m_optionalMessageSendBoardInfo); + CToCpp(data.m_pOptionalMessageBoardArrived, result.m_optionalMessageBoardArrived); + CToCpp(data.m_pOptionalMessageBoardDeparted, result.m_optionalMessageBoardDeparted); + CToCpp(data.m_pOptionalMessageQueryWorkOrderInfo, result.m_optionalMessageQueryWorkOrderInfo); + CToCpp(data.m_pOptionalMessageReplyWorkOrderInfo, result.m_optionalMessageReplyWorkOrderInfo); + CToCpp(data.m_pOptionalMessageCommand, result.m_optionalMessageCommand); + } + + // Attributes + inline void CppToC(const Attributes& data, HermesAttributes& result) + { + CppToC(data.m_productTypeId, result.m_productTypeId); + CppToC(data.m_topBarcode, result.m_topBarcode); + CppToC(data.m_bottomBarcode, result.m_bottomBarcode); + CppToC(data.m_length, result.m_length); + CppToC(data.m_width, result.m_width); + CppToC(data.m_thickness, result.m_thickness); + CppToC(data.m_conveyorSpeed, result.m_conveyorSpeed); + CppToC(data.m_topClearanceHeight, result.m_topClearanceHeight); + CppToC(data.m_bottomClearanceHeight, result.m_bottomClearanceHeight); + CppToC(data.m_weight, result.m_weight); + CppToC(data.m_workOrderId, result.m_workOrderId); + CppToC(data.m_batchId, result.m_batchId); + CppToC(data.m_route, result.m_route); + CppToC(data.m_action, result.m_action); + CppToC(data.m_subBoards, result.m_subBoards); + } + + inline void CToCpp(const HermesAttributes& data, Attributes& result) + { + CToCpp(data.m_productTypeId, result.m_productTypeId); + CToCpp(data.m_topBarcode, result.m_topBarcode); + CToCpp(data.m_bottomBarcode, result.m_bottomBarcode); + CToCpp(data.m_length, result.m_length); + CToCpp(data.m_width, result.m_width); + CToCpp(data.m_thickness, result.m_thickness); + CToCpp(data.m_conveyorSpeed, result.m_conveyorSpeed); + CToCpp(data.m_topClearanceHeight, result.m_topClearanceHeight); + CToCpp(data.m_bottomClearanceHeight, result.m_bottomClearanceHeight); + CToCpp(data.m_weight, result.m_weight); + CToCpp(data.m_workOrderId, result.m_workOrderId); + CToCpp(data.m_batchId, result.m_batchId); + CToCpp(data.m_route, result.m_route); + CToCpp(data.m_action, result.m_action); + CToCpp(data.m_subBoards, result.m_subBoards); + } - // UpstreamSettings - inline HermesUpstreamSettings ToC(const UpstreamSettings& in_data) + // SendHermesCapabilitiesData + template<> + struct Converter2C : ConverterBase { - return{Hermes::ToC(in_data.m_machineId), Hermes::ToC(in_data.m_hostAddress), in_data.m_port, - in_data.m_checkAlivePeriodInSeconds, in_data.m_reconnectWaitTimeInSeconds, - ToC(in_data.m_checkState)}; + Converter2C(const SendHermesCapabilitiesData& data) + { + CppToC(data.m_optionalMessages, m_optionalMessages); + m_data.m_pOptionalMessages = &m_optionalMessages.m_data; + CppToC(data.m_attributes, m_hermesAttributes); + m_data.m_pAttributes = &m_hermesAttributes; + } + private: + OptionalMessagesHolder m_optionalMessages; + HermesAttributes m_hermesAttributes; + }; + + inline SendHermesCapabilitiesData ToCpp(const HermesSendHermesCapabilitiesData& data) + { + SendHermesCapabilitiesData result; + CToCpp(data.m_pOptionalMessages, result.m_optionalMessages); + CToCpp(data.m_pAttributes, result.m_attributes); + return result; } - inline UpstreamSettings ToCpp(const HermesUpstreamSettings& in_data) + + + // UpstreamSettings + template<> + struct Converter2C : ConverterBase + { + Converter2C(const UpstreamSettings& data) + { + CppToC(data.m_machineId, m_data.m_machineId); + CppToC(data.m_hostAddress, m_data.m_hostAddress); + CppToC(data.m_port, m_data.m_port); + CppToC(data.m_checkAlivePeriodInSeconds, m_data.m_checkAlivePeriodInSeconds); + CppToC(data.m_reconnectWaitTimeInSeconds, m_data.m_reconnectWaitTimeInSeconds); + CppToC(data.m_checkAliveResponseMode, m_data.m_checkAliveResponseMode); + CppToC(data.m_checkState, m_data.m_checkState); + } + }; + inline UpstreamSettings ToCpp(const HermesUpstreamSettings& data) { - UpstreamSettings data(ToCpp(in_data.m_machineId), ToCpp(in_data.m_hostAddress), in_data.m_port); - data.m_checkAlivePeriodInSeconds = in_data.m_checkAlivePeriodInSeconds; - data.m_reconnectWaitTimeInSeconds = in_data.m_reconnectWaitTimeInSeconds; - data.m_checkState = ToCpp(in_data.m_checkState); - return data; + UpstreamSettings result; + CToCpp(data.m_machineId, result.m_machineId); + CToCpp(data.m_hostAddress, result.m_hostAddress); + CToCpp(data.m_port, result.m_port); + CToCpp(data.m_checkAlivePeriodInSeconds, result.m_checkAlivePeriodInSeconds); + CToCpp(data.m_reconnectWaitTimeInSeconds, result.m_reconnectWaitTimeInSeconds); + CToCpp(data.m_checkAliveResponseMode, result.m_checkAliveResponseMode); + CToCpp(data.m_checkState, result.m_checkState); + return result; } // DownstreamSettings - inline HermesDownstreamSettings ToC(const DownstreamSettings& in_data) + template<> + struct Converter2C : ConverterBase { - return{Hermes::ToC(in_data.m_machineId), Hermes::ToC(in_data.m_optionalClientAddress), in_data.m_port, - in_data.m_checkAlivePeriodInSeconds, in_data.m_reconnectWaitTimeInSeconds, - ToC(in_data.m_checkState)}; - } - inline DownstreamSettings ToCpp(const HermesDownstreamSettings& in_data) + Converter2C(const DownstreamSettings& data) + { + CppToC(data.m_machineId, m_data.m_machineId); + CppToC(data.m_optionalClientAddress, m_data.m_optionalClientAddress); + CppToC(data.m_port, m_data.m_port); + CppToC(data.m_checkAlivePeriodInSeconds, m_data.m_checkAlivePeriodInSeconds); + CppToC(data.m_reconnectWaitTimeInSeconds, m_data.m_reconnectWaitTimeInSeconds); + CppToC(data.m_checkAliveResponseMode, m_data.m_checkAliveResponseMode); + CppToC(data.m_checkState, m_data.m_checkState); + } + }; + inline DownstreamSettings ToCpp(const HermesDownstreamSettings& data) { - DownstreamSettings data(ToCpp(in_data.m_machineId), in_data.m_port); - data.m_optionalClientAddress = ToCpp(in_data.m_optionalClientAddress); - data.m_checkAlivePeriodInSeconds = in_data.m_checkAlivePeriodInSeconds; - data.m_reconnectWaitTimeInSeconds = in_data.m_reconnectWaitTimeInSeconds; - data.m_checkState = ToCpp(in_data.m_checkState); - return data; + DownstreamSettings result; + CToCpp(data.m_machineId, result.m_machineId); + CToCpp(data.m_optionalClientAddress, result.m_optionalClientAddress); + CToCpp(data.m_port, result.m_port); + CToCpp(data.m_checkAlivePeriodInSeconds, result.m_checkAlivePeriodInSeconds); + CToCpp(data.m_reconnectWaitTimeInSeconds, result.m_reconnectWaitTimeInSeconds); + CToCpp(data.m_checkAliveResponseMode, result.m_checkAliveResponseMode); + CToCpp(data.m_checkState, result.m_checkState); + return result; } // ConfigurationServiceSettings - inline HermesConfigurationServiceSettings ToC(const ConfigurationServiceSettings& in_data) + template<> + struct Converter2C : ConverterBase + { + Converter2C(const ConfigurationServiceSettings& data) + { + CppToC(data.m_port, m_data.m_port); + CppToC(data.m_reconnectWaitTimeInSeconds, m_data.m_reconnectWaitTimeInSeconds); + } + }; + inline ConfigurationServiceSettings ToCpp(const HermesConfigurationServiceSettings& data) { - return{in_data.m_port, in_data.m_reconnectWaitTimeInSeconds}; + ConfigurationServiceSettings result; + CToCpp(data.m_port, result.m_port); + CToCpp(data.m_reconnectWaitTimeInSeconds, result.m_reconnectWaitTimeInSeconds); + return result; } - inline ConfigurationServiceSettings ToCpp(const HermesConfigurationServiceSettings& in_data) + + // VerticalServiceSettings + template<> + struct Converter2C : ConverterBase { - ConfigurationServiceSettings data; - data.m_port = in_data.m_port; - data.m_reconnectWaitTimeInSeconds = in_data.m_reconnectWaitTimeInSeconds; - return data; + Converter2C(const VerticalServiceSettings& data) + { + CppToC(data.m_systemId, m_data.m_systemId); + CppToC(data.m_port, m_data.m_port); + CppToC(data.m_reconnectWaitTimeInSeconds, m_data.m_reconnectWaitTimeInSeconds); + CppToC(data.m_checkAlivePeriodInSeconds, m_data.m_checkAlivePeriodInSeconds); + CppToC(data.m_checkAliveResponseMode, m_data.m_checkAliveResponseMode); + } + }; + inline VerticalServiceSettings ToCpp(const HermesVerticalServiceSettings& data) + { + VerticalServiceSettings result; + CToCpp(data.m_systemId, result.m_systemId); + CToCpp(data.m_port, result.m_port); + CToCpp(data.m_reconnectWaitTimeInSeconds, result.m_reconnectWaitTimeInSeconds); + CToCpp(data.m_checkAlivePeriodInSeconds, result.m_checkAlivePeriodInSeconds); + CToCpp(data.m_checkAliveResponseMode, result.m_checkAliveResponseMode); + return result; } - // HermesError - inline HermesError ToC(const Error& in_data) - { - return{ToC(in_data.m_code), ToC(in_data.m_text)}; + // VerticalClientSettings + template<> + struct Converter2C : ConverterBase + { + Converter2C(const VerticalClientSettings& data) + { + CppToC(data.m_systemId, m_data.m_systemId); + CppToC(data.m_hostAddress, m_data.m_hostAddress); + CppToC(data.m_port, m_data.m_port); + CppToC(data.m_reconnectWaitTimeInSeconds, m_data.m_reconnectWaitTimeInSeconds); + CppToC(data.m_checkAlivePeriodInSeconds, m_data.m_checkAlivePeriodInSeconds); + CppToC(data.m_checkAliveResponseMode, m_data.m_checkAliveResponseMode); + } + }; + inline VerticalClientSettings ToCpp(const HermesVerticalClientSettings& data) + { + VerticalClientSettings result; + CToCpp(data.m_systemId, result.m_systemId); + CToCpp(data.m_hostAddress, result.m_hostAddress); + CToCpp(data.m_port, result.m_port); + CToCpp(data.m_reconnectWaitTimeInSeconds, result.m_reconnectWaitTimeInSeconds); + CToCpp(data.m_checkAlivePeriodInSeconds, result.m_checkAlivePeriodInSeconds); + CToCpp(data.m_checkAliveResponseMode, result.m_checkAliveResponseMode); + return result; } - inline Error ToCpp(const HermesError& in_data) + + // Error + template<> + struct Converter2C : ConverterBase + { + Converter2C(const Error& data) + { + CppToC(data.m_code, m_data.m_code); + CppToC(data.m_text, m_data.m_text); + } + }; + inline Error ToCpp(const HermesError& data) { - return Error(ToCpp(in_data.m_code), ToCpp(in_data.m_text)); + Error result; + CToCpp(data.m_code, result.m_code); + CToCpp(data.m_text, result.m_text); + return result; } diff --git a/src/include/HermesOptional.hpp b/src/include/HermesOptional.hpp index 13bc917..17d1122 100644 --- a/src/include/HermesOptional.hpp +++ b/src/include/HermesOptional.hpp @@ -20,6 +20,7 @@ limitations under the License. #pragma once #include +#include namespace Hermes { @@ -30,6 +31,8 @@ namespace Hermes Optional() : m_hasValue(false) {} Optional(const T& value) : m_hasValue(true), m_value(value) {} + template + Optional(const U1& u1, const U2& u2) : m_hasValue(true), m_value(u1, u2) {} // for the time being, avoid C++11 and its variadic templates for better compatibility. Up to two params should do for Hermes ... Optional& emplace() { m_value = T(); m_hasValue = true; return *this; } @@ -62,7 +65,7 @@ namespace Hermes void swap(Optional& rhs) { using std::swap; - swap(m_hasValue, rhs.m_value); + swap(m_hasValue, rhs.m_hasValue); swap(m_value, rhs.m_value); } friend void swap(Optional& lhs, Optional& rhs) { lhs.swap(rhs); } diff --git a/src/include/HermesSerialization.h b/src/include/HermesSerialization.h index 2976fed..d295aee 100644 --- a/src/include/HermesSerialization.h +++ b/src/include/HermesSerialization.h @@ -27,44 +27,202 @@ limitations under the License. extern "C" { #endif - struct HermesStringHandle; - HERMESPROTOCOL_API HermesStringView HermesStringViewFromHandle(HermesStringHandle*); - - HERMESPROTOCOL_API HermesStringHandle* HermesXmlFromServiceDescription(const HermesServiceDescription*); - HERMESPROTOCOL_API HermesStringHandle* HermesXmlFromBoardAvailableData(const HermesBoardAvailableData*); - HERMESPROTOCOL_API HermesStringHandle* HermesXmlFromRevokeBoardAvailableData(const HermesRevokeBoardAvailableData*); - HERMESPROTOCOL_API HermesStringHandle* HermesXmlFromMachineReadyData(const HermesMachineReadyData*); - HERMESPROTOCOL_API HermesStringHandle* HermesXmlFromRevokeMachineReadyData(const HermesRevokeMachineReadyData*); - HERMESPROTOCOL_API HermesStringHandle* HermesXmlFromStartTransportData(const HermesStartTransportData*); - HERMESPROTOCOL_API HermesStringHandle* HermesXmlFromStopTransportData(const HermesStopTransportData*); - HERMESPROTOCOL_API HermesStringHandle* HermesXmlFromTransportFinishedData(const HermesTransportFinishedData*); - HERMESPROTOCOL_API HermesStringHandle* HermesXmlFromNotificationData(const HermesNotificationData*); - HERMESPROTOCOL_API HermesStringHandle* HermesXmlFromCheckAliveData(const HermesCheckAliveData*); - HERMESPROTOCOL_API HermesStringHandle* HermesXmlFromGetConfigurationData(const HermesGetConfigurationData*); - HERMESPROTOCOL_API HermesStringHandle* HermesXmlFromSetConfigurationData(const HermesSetConfigurationData*); - HERMESPROTOCOL_API HermesStringHandle* HermesXmlFromCurrentConfigurationData(const HermesCurrentConfigurationData*); - - HERMESPROTOCOL_API void FreeHermesString(HermesStringHandle*); - - struct HermesDataHandle; - HERMESPROTOCOL_API HermesDataHandle* HermesDataFromXml(HermesStringView); - - HERMESPROTOCOL_API const HermesError* HermesErrorFromHandle(HermesDataHandle*); - HERMESPROTOCOL_API const HermesServiceDescription* HermesServiceDescriptionFromHandle(HermesDataHandle*); - HERMESPROTOCOL_API const HermesBoardAvailableData* HermesBoardAvailableDataFromHandle(HermesDataHandle*); - HERMESPROTOCOL_API const HermesRevokeBoardAvailableData* HermesRevokeBoardAvailableDataFromHandle(HermesDataHandle*); - HERMESPROTOCOL_API const HermesMachineReadyData* HermesMachineReadyDataFromHandle(HermesDataHandle*); - HERMESPROTOCOL_API const HermesRevokeMachineReadyData* HermesRevokeMachineReadyDataFromHandle(HermesDataHandle*); - HERMESPROTOCOL_API const HermesStartTransportData* HermesStartTransportDataFromHandle(HermesDataHandle*); - HERMESPROTOCOL_API const HermesStopTransportData* HermesStopTransportDataFromHandle(HermesDataHandle*); - HERMESPROTOCOL_API const HermesTransportFinishedData* HermesTransportFinishedDataFromHandle(HermesDataHandle*); - HERMESPROTOCOL_API const HermesNotificationData* HermesNotificationDataFromHandle(HermesDataHandle*); - HERMESPROTOCOL_API const HermesCheckAliveData* HermesCheckAliveDataFromHandle(HermesDataHandle*); - HERMESPROTOCOL_API const HermesGetConfigurationData* HermesGetConfigurationDataFromHandle(HermesDataHandle*); - HERMESPROTOCOL_API const HermesSetConfigurationData* HermesSetConfigurationDataFromHandle(HermesDataHandle*); - HERMESPROTOCOL_API const HermesCurrentConfigurationData* HermesCurrentConfigurationDataFromHandle(HermesDataHandle*); - - HERMESPROTOCOL_API void FreeHermesData(HermesDataHandle*); + // Serialize (just for unit testing) + struct HermesSerializationCallback + { + void(*m_pCall)(void* /*m_pData*/, HermesStringView); + void* m_pData; + }; + HERMESPROTOCOL_API void HermesSerializeServiceDescription(const HermesServiceDescriptionData*, HermesSerializationCallback); + HERMESPROTOCOL_API void HermesSerializeBoardAvailable(const HermesBoardAvailableData*, HermesSerializationCallback); + HERMESPROTOCOL_API void HermesSerializeRevokeBoardAvailable(const HermesRevokeBoardAvailableData*, HermesSerializationCallback); + HERMESPROTOCOL_API void HermesSerializeMachineReady(const HermesMachineReadyData*, HermesSerializationCallback); + HERMESPROTOCOL_API void HermesSerializeRevokeMachineReady(const HermesRevokeMachineReadyData*, HermesSerializationCallback); + HERMESPROTOCOL_API void HermesSerializeStartTransport(const HermesStartTransportData*, HermesSerializationCallback); + HERMESPROTOCOL_API void HermesSerializeStopTransport(const HermesStopTransportData*, HermesSerializationCallback); + HERMESPROTOCOL_API void HermesSerializeTransportFinished(const HermesTransportFinishedData*, HermesSerializationCallback); + HERMESPROTOCOL_API void HermesSerializeBoardForecast(const HermesBoardForecastData*, HermesSerializationCallback); + HERMESPROTOCOL_API void HermesSerializeQueryBoardInfo(const HermesQueryBoardInfoData*, HermesSerializationCallback); + HERMESPROTOCOL_API void HermesSerializeSendBoardInfo(const HermesSendBoardInfoData*, HermesSerializationCallback); + HERMESPROTOCOL_API void HermesSerializeNotification(const HermesNotificationData*, HermesSerializationCallback); + HERMESPROTOCOL_API void HermesSerializeCheckAlive(const HermesCheckAliveData*, HermesSerializationCallback); + HERMESPROTOCOL_API void HermesSerializeGetConfiguration(const HermesGetConfigurationData*, HermesSerializationCallback); + HERMESPROTOCOL_API void HermesSerializeSetConfiguration(const HermesSetConfigurationData*, HermesSerializationCallback); + HERMESPROTOCOL_API void HermesSerializeCurrentConfiguration(const HermesCurrentConfigurationData*, HermesSerializationCallback); + HERMESPROTOCOL_API void HermesSerializeSupervisoryServiceDescription(const HermesSupervisoryServiceDescriptionData*, HermesSerializationCallback); + HERMESPROTOCOL_API void HermesSerializeBoardArrived(const HermesBoardArrivedData*, HermesSerializationCallback); + HERMESPROTOCOL_API void HermesSerializeBoardDeparted(const HermesBoardDepartedData*, HermesSerializationCallback); + HERMESPROTOCOL_API void HermesSerializeQueryWorkOrderInfo(const HermesQueryWorkOrderInfoData*, HermesSerializationCallback); + HERMESPROTOCOL_API void HermesSerializeSendWorkOrderInfo(const HermesSendWorkOrderInfoData*, HermesSerializationCallback); + HERMESPROTOCOL_API void HermesSerializeReplyWorkOrderInfo(const HermesReplyWorkOrderInfoData*, HermesSerializationCallback); + HERMESPROTOCOL_API void HermesSerializeCommand(const HermesCommandData*, HermesSerializationCallback); + HERMESPROTOCOL_API void HermesSerializeQueryHermesCapabilities(const HermesQueryHermesCapabilitiesData*, HermesSerializationCallback); + HERMESPROTOCOL_API void HermesSerializeSendHermesCapabilities(const HermesSendHermesCapabilitiesData*, HermesSerializationCallback); + + // Deserialize (just for unit testing) + struct HermesDeserializationErrorCallback + { + void(*m_pCall)(void*, const HermesError*); + void* m_pData; + }; + struct HermesDeserializedServiceDescriptionCallback + { + void(*m_pCall)(void*, const HermesServiceDescriptionData*); + void* m_pData; + }; + struct HermesDeserializedBoardAvailableCallback + { + void(*m_pCall)(void*, const HermesBoardAvailableData*); + void* m_pData; + }; + struct HermesDeserializedRevokeBoardAvailableCallback + { + void(*m_pCall)(void*, const HermesRevokeBoardAvailableData*); + void* m_pData; + }; + struct HermesDeserializedMachineReadyCallback + { + void(*m_pCall)(void*, const HermesMachineReadyData*); + void* m_pData; + }; + struct HermesDeserializedRevokeMachineReadyCallback + { + void(*m_pCall)(void*, const HermesRevokeMachineReadyData*); + void* m_pData; + }; + struct HermesDeserializedStartTransportCallback + { + void(*m_pCall)(void*, const HermesStartTransportData*); + void* m_pData; + }; + struct HermesDeserializedStopTransportCallback + { + void(*m_pCall)(void*, const HermesStopTransportData*); + void* m_pData; + }; + struct HermesDeserializedTransportFinishedCallback + { + void(*m_pCall)(void*, const HermesTransportFinishedData*); + void* m_pData; + }; + struct HermesDeserializedBoardForecastCallback + { + void(*m_pCall)(void*, const HermesBoardForecastData*); + void* m_pData; + }; + struct HermesDeserializedQueryBoardInfoCallback + { + void(*m_pCall)(void*, const HermesQueryBoardInfoData*); + void* m_pData; + }; + struct HermesDeserializedSendBoardInfoCallback + { + void(*m_pCall)(void*, const HermesSendBoardInfoData*); + void* m_pData; + }; + struct HermesDeserializedNotificationCallback + { + void(*m_pCall)(void*, const HermesNotificationData*); + void* m_pData; + }; + struct HermesDeserializedCheckAliveCallback + { + void(*m_pCall)(void*, const HermesCheckAliveData*); + void* m_pData; + }; + struct HermesDeserializedGetConfigurationCallback + { + void(*m_pCall)(void*, const HermesGetConfigurationData*); + void* m_pData; + }; + struct HermesDeserializedSetConfigurationCallback + { + void(*m_pCall)(void*, const HermesSetConfigurationData*); + void* m_pData; + }; + struct HermesDeserializedCurrentConfigurationCallback + { + void(*m_pCall)(void*, const HermesCurrentConfigurationData*); + void* m_pData; + }; + struct HermesDeserializedSupervisoryServiceDescriptionCallback + { + void(*m_pCall)(void*, const HermesSupervisoryServiceDescriptionData*); + void* m_pData; + }; + struct HermesDeserializedBoardArrivedCallback + { + void(*m_pCall)(void*, const HermesBoardArrivedData*); + void* m_pData; + }; + struct HermesDeserializedBoardDepartedCallback + { + void(*m_pCall)(void*, const HermesBoardDepartedData*); + void* m_pData; + }; + struct HermesDeserializedQueryWorkOrderInfoCallback + { + void(*m_pCall)(void*, const HermesQueryWorkOrderInfoData*); + void* m_pData; + }; + struct HermesDeserializedSendWorkOrderInfoCallback + { + void(*m_pCall)(void*, const HermesSendWorkOrderInfoData*); + void* m_pData; + }; + struct HermesDeserializedReplyWorkOrderInfoCallback + { + void(*m_pCall)(void*, const HermesReplyWorkOrderInfoData*); + void* m_pData; + }; + struct HermesDeserializedCommandCallback + { + void(*m_pCall)(void*, const HermesCommandData*); + void* m_pData; + }; + + struct HermesDeserializedQueryHermesCapabilitiesCallback + { + void(*m_pCall)(void*, const HermesQueryHermesCapabilitiesData*); + void* m_pData; + }; + + struct HermesDeserializedSendHermesCapabilitiesCallback + { + void(*m_pCall)(void*, const HermesSendHermesCapabilitiesData*); + void* m_pData; + }; + + struct HermesDeserializationCallbacks + { + HermesDeserializationErrorCallback m_deserializationErrorCallback; + HermesDeserializedServiceDescriptionCallback m_serviceDescriptionCallback; + HermesDeserializedBoardAvailableCallback m_boardAvailableCallback; + HermesDeserializedRevokeBoardAvailableCallback m_revokeBoardAvailableCallback; + HermesDeserializedMachineReadyCallback m_machineReadyCallback; + HermesDeserializedRevokeMachineReadyCallback m_revokeMachineReadyCallback; + HermesDeserializedStartTransportCallback m_startTransportCallback; + HermesDeserializedStopTransportCallback m_stopTransportCallback; + HermesDeserializedTransportFinishedCallback m_transportFinishedCallback; + HermesDeserializedBoardForecastCallback m_boardForecastCallback; + HermesDeserializedQueryBoardInfoCallback m_queryBoardInfoCallback; + HermesDeserializedSendBoardInfoCallback m_sendBoardInfoCallback; + HermesDeserializedNotificationCallback m_notificationCallback; + HermesDeserializedCheckAliveCallback m_checkAliveCallback; + HermesDeserializedGetConfigurationCallback m_getConfigurationCallback; + HermesDeserializedSetConfigurationCallback m_setConfigurationCallback; + HermesDeserializedCurrentConfigurationCallback m_currentConfigurationCallback; + HermesDeserializedSupervisoryServiceDescriptionCallback m_supervisoryServiceDescriptionCallback; + HermesDeserializedBoardArrivedCallback m_boardArrivedCallback; + HermesDeserializedBoardDepartedCallback m_boardDepartedCallback; + HermesDeserializedQueryWorkOrderInfoCallback m_queryWorkOrderInfoCallback; + HermesDeserializedSendWorkOrderInfoCallback m_sendWorkOrderInfoCallback; + HermesDeserializedReplyWorkOrderInfoCallback m_replyWorkOrderInfoCallback; + HermesDeserializedCommandCallback m_commandCallback; + HermesDeserializedQueryHermesCapabilitiesCallback m_queryHermesCapabilitiesCallback; + HermesDeserializedSendHermesCapabilitiesCallback m_sendHermesCapabilitiesCallback; + }; + HERMESPROTOCOL_API void HermesDeserialize(HermesStringView, const HermesDeserializationCallbacks*); #ifdef __cplusplus } diff --git a/src/include/HermesSerialization.hpp b/src/include/HermesSerialization.hpp index ef14a74..200225e 100644 --- a/src/include/HermesSerialization.hpp +++ b/src/include/HermesSerialization.hpp @@ -1,4 +1,19 @@ -// Copyright (c) ASM Assembly Systems GmbH & Co. KG +/*********************************************************************** +Copyright 2018 ASM Assembly Systems GmbH & Co. KG + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + #pragma once #include "HermesSerialization.h" @@ -7,172 +22,288 @@ namespace Hermes { - class StringHandle - { - public: - StringHandle() = default; - StringHandle(HermesStringHandle* pHandle) : m_pHandle(pHandle) {} - - StringHandle(const StringHandle&) = delete; - StringHandle& operator=(const StringHandle&) = delete; - - StringHandle(StringHandle&& rhs) noexcept: m_pHandle(rhs.m_pHandle) - { - rhs.m_pHandle = nullptr; - } - - StringHandle& operator=(StringHandle&& rhs) noexcept - { - StringHandle(std::move(rhs)).swap(*this); - return *this; - } - - std::string value() const { return view(); } - StringView view() const + template + std::string SerializeToXml_(const DataT& data, SerializationFunctionT serializationFunction) + { + Converter2C converter(data); + auto pApiData = converter.CPointer(); + std::string result; + HermesSerializationCallback callback{[](void* pResult, HermesStringView stringView) { - auto stringView = ::HermesStringViewFromHandle(m_pHandle); - return{stringView.m_pData, stringView.m_size}; - } + *static_cast(pResult) = ToCpp(stringView); + }, &result}; + serializationFunction(pApiData, callback); + return result; + } - explicit operator bool() const { return m_pHandle ? true : false; } - bool operator!() const { return !m_pHandle; } + inline std::string ToXml(const ServiceDescriptionData& data) { return SerializeToXml_(data, &::HermesSerializeServiceDescription); } + inline std::string ToXml(const BoardAvailableData& data) { return SerializeToXml_(data, &::HermesSerializeBoardAvailable); } + inline std::string ToXml(const RevokeBoardAvailableData& data) { return SerializeToXml_(data, &::HermesSerializeRevokeBoardAvailable); } + inline std::string ToXml(const MachineReadyData& data) { return SerializeToXml_(data, &::HermesSerializeMachineReady); } + inline std::string ToXml(const RevokeMachineReadyData& data) { return SerializeToXml_(data, &::HermesSerializeRevokeMachineReady); } + inline std::string ToXml(const StartTransportData& data) { return SerializeToXml_(data, &::HermesSerializeStartTransport); } + inline std::string ToXml(const StopTransportData& data) { return SerializeToXml_(data, &::HermesSerializeStopTransport); } + inline std::string ToXml(const TransportFinishedData& data) { return SerializeToXml_(data, &::HermesSerializeTransportFinished); } + inline std::string ToXml(const BoardForecastData& data) { return SerializeToXml_(data, &::HermesSerializeBoardForecast); } + inline std::string ToXml(const QueryBoardInfoData& data) { return SerializeToXml_(data, &::HermesSerializeQueryBoardInfo); } + inline std::string ToXml(const SendBoardInfoData& data) { return SerializeToXml_(data, &::HermesSerializeSendBoardInfo); } + inline std::string ToXml(const NotificationData& data) { return SerializeToXml_(data, &::HermesSerializeNotification); } + inline std::string ToXml(const CheckAliveData& data) { return SerializeToXml_(data, &::HermesSerializeCheckAlive); } + inline std::string ToXml(const GetConfigurationData& data) { return SerializeToXml_(data, &::HermesSerializeGetConfiguration); } + inline std::string ToXml(const SetConfigurationData& data) { return SerializeToXml_(data, &::HermesSerializeSetConfiguration); } + inline std::string ToXml(const CurrentConfigurationData& data) { return SerializeToXml_(data, &::HermesSerializeCurrentConfiguration); } + inline std::string ToXml(const SupervisoryServiceDescriptionData& data) { return SerializeToXml_(data, &::HermesSerializeSupervisoryServiceDescription); } + inline std::string ToXml(const BoardArrivedData& data) { return SerializeToXml_(data, &::HermesSerializeBoardArrived); } + inline std::string ToXml(const BoardDepartedData& data) { return SerializeToXml_(data, &::HermesSerializeBoardDeparted); } + inline std::string ToXml(const QueryWorkOrderInfoData& data) { return SerializeToXml_(data, &::HermesSerializeQueryWorkOrderInfo); } + inline std::string ToXml(const SendWorkOrderInfoData& data) { return SerializeToXml_(data, &::HermesSerializeSendWorkOrderInfo); } + inline std::string ToXml(const ReplyWorkOrderInfoData& data) { return SerializeToXml_(data, &::HermesSerializeReplyWorkOrderInfo); } + inline std::string ToXml(const CommandData& data) { return SerializeToXml_(data, &::HermesSerializeCommand); } + inline std::string ToXml(const QueryHermesCapabilitiesData& data) { return SerializeToXml_(data, &::HermesSerializeQueryHermesCapabilities); } + inline std::string ToXml(const SendHermesCapabilitiesData& data) { return SerializeToXml_(data, &::HermesSerializeSendHermesCapabilities); } - void swap(StringHandle& rhs) noexcept { std::swap(m_pHandle, rhs.m_pHandle); } - friend void swap(StringHandle& lhs, StringHandle& rhs) noexcept { lhs.swap(rhs); } - private: - HermesStringHandle* m_pHandle{nullptr}; - }; + template + void SetDeserializationCallback_(Optional& optionalData, HermesDeserializationCallbacks& callbacks); - inline std::string ToXml(const ServiceDescription& data) + template<> + inline void SetDeserializationCallback_(Optional& optionalData, HermesDeserializationCallbacks& callbacks) { - auto apiData = ToC(data); - return StringHandle(::HermesXmlFromServiceDescription(&apiData)).value(); + callbacks.m_serviceDescriptionCallback.m_pData = &optionalData; + callbacks.m_serviceDescriptionCallback.m_pCall = [](void* pOptionalData, const HermesServiceDescriptionData* pData) + { + *static_cast*>(pOptionalData) = Hermes::ToCpp(*pData); + }; } - inline std::string ToXml(const BoardAvailableData& data) + template<> + inline void SetDeserializationCallback_(Optional& optionalData, HermesDeserializationCallbacks& callbacks) { - auto apiData = ToC(data); - return StringHandle(::HermesXmlFromBoardAvailableData(&apiData)).value(); + callbacks.m_boardAvailableCallback.m_pData = &optionalData; + callbacks.m_boardAvailableCallback.m_pCall = [](void* pOptionalData, const HermesBoardAvailableData* pData) + { + *static_cast*>(pOptionalData) = Hermes::ToCpp(*pData); + }; } - inline std::string ToXml(const RevokeBoardAvailableData& data) + template<> + inline void SetDeserializationCallback_(Optional& optionalData, HermesDeserializationCallbacks& callbacks) { - auto apiData = ToC(data); - return StringHandle(::HermesXmlFromRevokeBoardAvailableData(&apiData)).value(); + callbacks.m_revokeBoardAvailableCallback.m_pData = &optionalData; + callbacks.m_revokeBoardAvailableCallback.m_pCall = [](void* pOptionalData, const HermesRevokeBoardAvailableData* pData) + { + *static_cast*>(pOptionalData) = Hermes::ToCpp(*pData); + }; } - inline std::string ToXml(const MachineReadyData& data) + template<> + inline void SetDeserializationCallback_(Optional& optionalData, HermesDeserializationCallbacks& callbacks) { - auto apiData = ToC(data); - return StringHandle(::HermesXmlFromMachineReadyData(&apiData)).value(); + callbacks.m_machineReadyCallback.m_pData = &optionalData; + callbacks.m_machineReadyCallback.m_pCall = [](void* pOptionalData, const HermesMachineReadyData* pData) + { + *static_cast*>(pOptionalData) = Hermes::ToCpp(*pData); + }; } - inline std::string ToXml(const RevokeMachineReadyData& data) + template<> + inline void SetDeserializationCallback_(Optional& optionalData, HermesDeserializationCallbacks& callbacks) { - auto apiData = ToC(data); - return StringHandle(::HermesXmlFromRevokeMachineReadyData(&apiData)).value(); + callbacks.m_revokeMachineReadyCallback.m_pData = &optionalData; + callbacks.m_revokeMachineReadyCallback.m_pCall = [](void* pOptionalData, const HermesRevokeMachineReadyData* pData) + { + *static_cast*>(pOptionalData) = Hermes::ToCpp(*pData); + }; } - inline std::string ToXml(const StartTransportData& data) + template<> + inline void SetDeserializationCallback_(Optional& optionalData, HermesDeserializationCallbacks& callbacks) { - auto apiData = ToC(data); - return StringHandle(::HermesXmlFromStartTransportData(&apiData)).value(); + callbacks.m_startTransportCallback.m_pData = &optionalData; + callbacks.m_startTransportCallback.m_pCall = [](void* pOptionalData, const HermesStartTransportData* pData) + { + *static_cast*>(pOptionalData) = Hermes::ToCpp(*pData); + }; } - inline std::string ToXml(const StopTransportData& data) + template<> + inline void SetDeserializationCallback_(Optional& optionalData, HermesDeserializationCallbacks& callbacks) { - auto apiData = ToC(data); - return StringHandle(::HermesXmlFromStopTransportData(&apiData)).value(); + callbacks.m_stopTransportCallback.m_pData = &optionalData; + callbacks.m_stopTransportCallback.m_pCall = [](void* pOptionalData, const HermesStopTransportData* pData) + { + *static_cast*>(pOptionalData) = Hermes::ToCpp(*pData); + }; } - inline std::string ToXml(const TransportFinishedData& data) + template<> + inline void SetDeserializationCallback_(Optional& optionalData, HermesDeserializationCallbacks& callbacks) { - auto apiData = ToC(data); - return StringHandle(::HermesXmlFromTransportFinishedData(&apiData)).value(); + callbacks.m_transportFinishedCallback.m_pData = &optionalData; + callbacks.m_transportFinishedCallback.m_pCall = [](void* pOptionalData, const HermesTransportFinishedData* pData) + { + *static_cast*>(pOptionalData) = Hermes::ToCpp(*pData); + }; } - inline std::string ToXml(const NotificationData& data) + template<> + inline void SetDeserializationCallback_(Optional& optionalData, HermesDeserializationCallbacks& callbacks) { - auto apiData = ToC(data); - return StringHandle(::HermesXmlFromNotificationData(&apiData)).value(); + callbacks.m_boardForecastCallback.m_pData = &optionalData; + callbacks.m_boardForecastCallback.m_pCall = [](void* pOptionalData, const HermesBoardForecastData* pData) + { + *static_cast*>(pOptionalData) = Hermes::ToCpp(*pData); + }; } - inline std::string ToXml(const CheckAliveData& data) + template<> + inline void SetDeserializationCallback_(Optional& optionalData, HermesDeserializationCallbacks& callbacks) { - auto apiData = ToC(data); - return StringHandle(::HermesXmlFromCheckAliveData(&apiData)).value(); + callbacks.m_queryBoardInfoCallback.m_pData = &optionalData; + callbacks.m_queryBoardInfoCallback.m_pCall = [](void* pOptionalData, const HermesQueryBoardInfoData* pData) + { + *static_cast*>(pOptionalData) = Hermes::ToCpp(*pData); + }; } - inline std::string ToXml(const SetConfigurationData& data) + template<> + inline void SetDeserializationCallback_(Optional& optionalData, HermesDeserializationCallbacks& callbacks) { - auto apiData = ToC(data); - return StringHandle(::HermesXmlFromSetConfigurationData(&apiData)).value(); + callbacks.m_sendBoardInfoCallback.m_pData = &optionalData; + callbacks.m_sendBoardInfoCallback.m_pCall = [](void* pOptionalData, const HermesSendBoardInfoData* pData) + { + *static_cast*>(pOptionalData) = Hermes::ToCpp(*pData); + }; } - inline std::string ToXml(const GetConfigurationData& data) + template<> + inline void SetDeserializationCallback_(Optional& optionalData, HermesDeserializationCallbacks& callbacks) { - auto apiData = ToC(data); - return StringHandle(::HermesXmlFromGetConfigurationData(&apiData)).value(); + callbacks.m_notificationCallback.m_pData = &optionalData; + callbacks.m_notificationCallback.m_pCall = [](void* pOptionalData, const HermesNotificationData* pData) + { + *static_cast*>(pOptionalData) = Hermes::ToCpp(*pData); + }; } - inline std::string ToXml(const CurrentConfigurationData& data) + template<> + inline void SetDeserializationCallback_(Optional& optionalData, HermesDeserializationCallbacks& callbacks) { - auto apiData = ToC(data); - return StringHandle(::HermesXmlFromCurrentConfigurationData(&apiData)).value(); + callbacks.m_checkAliveCallback.m_pData = &optionalData; + callbacks.m_checkAliveCallback.m_pCall = [](void* pOptionalData, const HermesCheckAliveData* pData) + { + *static_cast*>(pOptionalData) = Hermes::ToCpp(*pData); + }; } - - namespace Detail - { - template struct OptionalGetter; - template<> struct OptionalGetter { static const HermesServiceDescription* Get(HermesDataHandle* pHandle) { return ::HermesServiceDescriptionFromHandle(pHandle); } }; - template<> struct OptionalGetter { static const HermesBoardAvailableData* Get(HermesDataHandle* pHandle) { return ::HermesBoardAvailableDataFromHandle(pHandle); } }; - template<> struct OptionalGetter { static const HermesRevokeBoardAvailableData* Get(HermesDataHandle* pHandle) { return ::HermesRevokeBoardAvailableDataFromHandle(pHandle); } }; - template<> struct OptionalGetter { static const HermesMachineReadyData* Get(HermesDataHandle* pHandle) { return ::HermesMachineReadyDataFromHandle(pHandle); } }; - template<> struct OptionalGetter { static const HermesRevokeMachineReadyData* Get(HermesDataHandle* pHandle) { return ::HermesRevokeMachineReadyDataFromHandle(pHandle); } }; - template<> struct OptionalGetter { static const HermesStartTransportData* Get(HermesDataHandle* pHandle) { return ::HermesStartTransportDataFromHandle(pHandle); } }; - template<> struct OptionalGetter { static const HermesStopTransportData* Get(HermesDataHandle* pHandle) { return ::HermesStopTransportDataFromHandle(pHandle); } }; - template<> struct OptionalGetter { static const HermesTransportFinishedData* Get(HermesDataHandle* pHandle) { return ::HermesTransportFinishedDataFromHandle(pHandle); } }; - template<> struct OptionalGetter { static const HermesNotificationData* Get(HermesDataHandle* pHandle) { return ::HermesNotificationDataFromHandle(pHandle); } }; - template<> struct OptionalGetter { static const HermesCheckAliveData* Get(HermesDataHandle* pHandle) { return ::HermesCheckAliveDataFromHandle(pHandle); } }; - template<> struct OptionalGetter { static const HermesGetConfigurationData* Get(HermesDataHandle* pHandle) { return ::HermesGetConfigurationDataFromHandle(pHandle); } }; - template<> struct OptionalGetter { static const HermesSetConfigurationData* Get(HermesDataHandle* pHandle) { return ::HermesSetConfigurationDataFromHandle(pHandle); } }; - template<> struct OptionalGetter { static const HermesCurrentConfigurationData* Get(HermesDataHandle* pHandle) { return ::HermesCurrentConfigurationDataFromHandle(pHandle); } }; - + template<> + inline void SetDeserializationCallback_(Optional& optionalData, HermesDeserializationCallbacks& callbacks) + { + callbacks.m_getConfigurationCallback.m_pData = &optionalData; + callbacks.m_getConfigurationCallback.m_pCall = [](void* pOptionalData, const HermesGetConfigurationData* pData) + { + *static_cast*>(pOptionalData) = Hermes::ToCpp(*pData); + }; } - - class DataHandle + template<> + inline void SetDeserializationCallback_(Optional& optionalData, HermesDeserializationCallbacks& callbacks) { - public: - DataHandle() = default; - DataHandle(HermesDataHandle* pHandle) : m_pHandle(pHandle) {} - - DataHandle(const DataHandle&) = delete; - DataHandle& operator=(const DataHandle&) = delete; - - DataHandle(DataHandle&& rhs) noexcept: m_pHandle(rhs.m_pHandle) + callbacks.m_setConfigurationCallback.m_pData = &optionalData; + callbacks.m_setConfigurationCallback.m_pCall = [](void* pOptionalData, const HermesSetConfigurationData* pData) { - rhs.m_pHandle = nullptr; - } - - DataHandle& operator=(DataHandle&& rhs) noexcept + *static_cast*>(pOptionalData) = Hermes::ToCpp(*pData); + }; + } + template<> + inline void SetDeserializationCallback_(Optional& optionalData, HermesDeserializationCallbacks& callbacks) + { + callbacks.m_currentConfigurationCallback.m_pData = &optionalData; + callbacks.m_currentConfigurationCallback.m_pCall = [](void* pOptionalData, const HermesCurrentConfigurationData* pData) { - DataHandle(std::move(rhs)).swap(*this); - return *this; - } - - HermesDataHandle* get() const { return m_pHandle; } - - explicit operator bool() const { return m_pHandle ? true : false; } - bool operator!() const { return !m_pHandle; } - - void swap(DataHandle& rhs) noexcept { std::swap(m_pHandle, rhs.m_pHandle); } - friend void swap(DataHandle& lhs, DataHandle& rhs) noexcept { lhs.swap(rhs); } - - private: - HermesDataHandle* m_pHandle{ nullptr }; - }; - - template - Optional ToOptionalData(StringView view) + *static_cast*>(pOptionalData) = Hermes::ToCpp(*pData); + }; + } + template<> + inline void SetDeserializationCallback_(Optional& optionalData, HermesDeserializationCallbacks& callbacks) { - DataHandle handle(::HermesDataFromXml(ToC(view))); - if (!handle) - return{}; - - if (auto* pData = Detail::OptionalGetter::Get(handle.get())) - return ToCpp(*pData); + callbacks.m_supervisoryServiceDescriptionCallback.m_pData = &optionalData; + callbacks.m_supervisoryServiceDescriptionCallback.m_pCall = [](void* pOptionalData, const HermesSupervisoryServiceDescriptionData* pData) + { + *static_cast*>(pOptionalData) = Hermes::ToCpp(*pData); + }; + } + template<> + inline void SetDeserializationCallback_(Optional& optionalData, HermesDeserializationCallbacks& callbacks) + { + callbacks.m_boardArrivedCallback.m_pData = &optionalData; + callbacks.m_boardArrivedCallback.m_pCall = [](void* pOptionalData, const HermesBoardArrivedData* pData) + { + *static_cast*>(pOptionalData) = Hermes::ToCpp(*pData); + }; + } + template<> + inline void SetDeserializationCallback_(Optional& optionalData, HermesDeserializationCallbacks& callbacks) + { + callbacks.m_boardDepartedCallback.m_pData = &optionalData; + callbacks.m_boardDepartedCallback.m_pCall = [](void* pOptionalData, const HermesBoardDepartedData* pData) + { + *static_cast*>(pOptionalData) = Hermes::ToCpp(*pData); + }; + } + template<> + inline void SetDeserializationCallback_(Optional& optionalData, HermesDeserializationCallbacks& callbacks) + { + callbacks.m_queryWorkOrderInfoCallback.m_pData = &optionalData; + callbacks.m_queryWorkOrderInfoCallback.m_pCall = [](void* pOptionalData, const HermesQueryWorkOrderInfoData* pData) + { + *static_cast*>(pOptionalData) = Hermes::ToCpp(*pData); + }; + } + template<> + inline void SetDeserializationCallback_(Optional& optionalData, HermesDeserializationCallbacks& callbacks) + { + callbacks.m_sendWorkOrderInfoCallback.m_pData = &optionalData; + callbacks.m_sendWorkOrderInfoCallback.m_pCall = [](void* pOptionalData, const HermesSendWorkOrderInfoData* pData) + { + *static_cast*>(pOptionalData) = Hermes::ToCpp(*pData); + }; + } + template<> + inline void SetDeserializationCallback_(Optional& optionalData, HermesDeserializationCallbacks& callbacks) + { + callbacks.m_replyWorkOrderInfoCallback.m_pData = &optionalData; + callbacks.m_replyWorkOrderInfoCallback.m_pCall = [](void* pOptionalData, const HermesReplyWorkOrderInfoData* pData) + { + *static_cast*>(pOptionalData) = Hermes::ToCpp(*pData); + }; + } + template<> + inline void SetDeserializationCallback_(Optional& optionalData, HermesDeserializationCallbacks& callbacks) + { + callbacks.m_commandCallback.m_pData = &optionalData; + callbacks.m_commandCallback.m_pCall = [](void* pOptionalData, const HermesCommandData* pData) + { + *static_cast*>(pOptionalData) = Hermes::ToCpp(*pData); + }; + } + + template<> + inline void SetDeserializationCallback_(Optional& optionalData, HermesDeserializationCallbacks& callbacks) + { + callbacks.m_queryHermesCapabilitiesCallback.m_pData = &optionalData; + callbacks.m_queryHermesCapabilitiesCallback.m_pCall = [](void* pOptionalData, const HermesQueryHermesCapabilitiesData* pData) + { + *static_cast*>(pOptionalData) = Hermes::ToCpp(*pData); + }; + } - return{}; + template<> + inline void SetDeserializationCallback_(Optional& optionalData, HermesDeserializationCallbacks& callbacks) + { + callbacks.m_sendHermesCapabilitiesCallback.m_pData = &optionalData; + callbacks.m_sendHermesCapabilitiesCallback.m_pCall = [](void* pOptionalData, const HermesSendHermesCapabilitiesData* pData) + { + *static_cast*>(pOptionalData) = Hermes::ToCpp(*pData); + }; + } + + template + Optional FromXml(StringView xml) + { + Optional optionalData; + HermesDeserializationCallbacks callbacks{}; + SetDeserializationCallback_(optionalData, callbacks); + ::HermesDeserialize(ToC(xml), &callbacks); + return optionalData; } + } diff --git a/src/include/HermesStringView.h b/src/include/HermesStringView.h new file mode 100644 index 0000000..b4386a2 --- /dev/null +++ b/src/include/HermesStringView.h @@ -0,0 +1,28 @@ +// Copyright (c) ASM Assembly Systems GmbH & Co. KG +// +// C interface helper for Hermes +// +#ifndef HERMESSTRINGVIEW_H +#define HERMESSTRINGVIEW_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + // Not part of The Hermes Standard, but used extensively: a non-owning string type, in the spirit of std::string_view. + // This relieves us from the need to terminate all strings with \0. + // Note that all the C interface structures are non-owning and need to be backed up by actual storage. + struct HermesStringView + { + const char* m_pData; // if nullptr then we have no string at all - not even an empty string + size_t m_size; + }; + +#ifdef __cplusplus +} +#endif + +#endif //HERMESSTRINGVIEW_H + diff --git a/src/include/HermesStringView.hpp b/src/include/HermesStringView.hpp index 18e2728..98f05d8 100644 --- a/src/include/HermesStringView.hpp +++ b/src/include/HermesStringView.hpp @@ -17,7 +17,11 @@ limitations under the License. // Copyright (c) ASM Assembly Systems GmbH & Co. KG #pragma once +#include #include +#include +#include + // while we have not got std::string_view at our disposal, we make our own: namespace Hermes @@ -25,9 +29,9 @@ namespace Hermes class StringView { public: - StringView() = default; - StringView(const char* pStr) : m_pData(pStr), m_size(::strlen(pStr)) {} - StringView(const char* pData, std::size_t size) : m_pData(pData), m_size(size) {} + constexpr StringView() = default; + StringView(const char* pStr) : m_pData(pStr), m_size(std::strlen(pStr)) {} + constexpr StringView(const char* pData, std::size_t size) : m_pData(pData), m_size(size) {} StringView(const std::string& str) : m_pData(str.data()), m_size(str.size()) {} StringView& operator=(const std::string& str) { @@ -44,11 +48,43 @@ namespace Hermes operator std::string() const { return std::string(m_pData, m_size); } - const std::string cpp_str() const { return std::string(m_pData); } - const char* data() const { return m_pData; } - std::size_t size() const { return m_size; } - std::size_t length() const { return m_size; } - bool empty() const { return m_size == 0U; } + constexpr const char* data() const { return m_pData; } + constexpr std::size_t size() const { return m_size; } + constexpr std::size_t length() const { return m_size; } + constexpr bool empty() const { return m_size == 0U; } + constexpr StringView substr(std::size_t pos, std::size_t count = std::string::npos) const { return{m_pData + pos, std::min(count, m_size - pos)}; } + + std::size_t find(char c, size_t pos = 0U) + { + if (pos >= m_size) + return std::string::npos; + + auto* pFound = Traits_::find(m_pData + pos, m_size - pos, c); + return pFound ? pFound - m_pData : std::string::npos; + } + + std::size_t find(StringView v) const + { + // empty string always matches: + if (v.empty()) + return 0U; + + // do not bother if size is too large: + if (m_size < v.m_size) + return std::string::npos; + + const char* pMatch; + const char* pLast = m_pData + m_size - v.m_size + 1; + for (auto* p = m_pData; + (pMatch = Traits_::find(p, pLast - p, *v.m_pData)) != nullptr; + p = pMatch + 1) + { + if (Traits_::compare(pMatch, v.m_pData, v.m_size) == 0) + return pMatch - m_pData; + } + return std::string::npos; + } + int compare(StringView rhs) { @@ -63,6 +99,7 @@ namespace Hermes return 1; return 0; } + int compare(std::size_t pos, std::size_t count, StringView rhs) { return substr(pos, count).compare(rhs); } friend std::ostream& operator<<(std::ostream& os, StringView sv) { @@ -73,6 +110,7 @@ namespace Hermes private: const char* m_pData = nullptr; std::size_t m_size = 0U; + using Traits_ = std::char_traits; }; inline bool operator==(StringView lhs, StringView rhs) @@ -84,4 +122,4 @@ namespace Hermes { return !operator==(lhs, rhs); } -} +} \ No newline at end of file diff --git a/test/BoostTestHermes/BoardForecastTest.cpp b/test/BoostTestHermes/BoardForecastTest.cpp new file mode 100644 index 0000000..9a97e1d --- /dev/null +++ b/test/BoostTestHermes/BoardForecastTest.cpp @@ -0,0 +1,67 @@ +// Copyright (c) ASM Assembly Systems GmbH & Co. KG +#include "stdafx.h" + +#include "Runner.h" +#include "Sinks.h" + +using namespace Hermes; + +BOOST_AUTO_TEST_CASE(BoardForecastTest) +{ + TestCaseScope scope("BoardForecastTest"); + + std::string upstreamMachineId{"UpstreamMachineId"}; + std::string downstreamMachineId{"DownstreamMachineId"}; + + DownstreamSink downstreamSink; + Hermes::Downstream downstream(1U, downstreamSink); + Runner downstreamRunner(downstream); + + UpstreamSink upstreamSink; + Hermes::Upstream upstream(1U, upstreamSink); + Runner upstreamRunner(upstream); + + // suppress periodic CheckAlive on both sides + DownstreamSettings downstreamSettings{upstreamMachineId, 50101}; + downstreamSettings.m_checkAlivePeriodInSeconds = 0; + downstream.Enable(downstreamSettings); + + Hermes::UpstreamSettings upstreamSettings(downstreamMachineId, "127.0.0.1", 50101); + upstreamSettings.m_checkAlivePeriodInSeconds = 0; + upstream.Enable(upstreamSettings); + + // set ServiceDescription accordingly: + Hermes::ServiceDescriptionData upstreamServiceDescription{downstreamMachineId, 1U}; + upstreamServiceDescription.m_supportedFeatures.m_optionalFeatureBoardForecast = FeatureBoardForecast{}; + Hermes::ServiceDescriptionData downstreamServiceDescription{upstreamMachineId, 1U}; + downstreamServiceDescription.m_supportedFeatures.m_optionalFeatureBoardForecast = FeatureBoardForecast{}; + + // wait until connection is established + WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eSOCKET_CONNECTED; }); + WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eSOCKET_CONNECTED; }); + upstream.Signal(upstreamSink.m_sessionId, upstreamServiceDescription); + WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eSERVICE_DESCRIPTION_DOWNSTREAM; }); + downstream.Signal(downstreamSink.m_sessionId, downstreamServiceDescription); + + WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eNOT_AVAILABLE_NOT_READY; }); + WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eNOT_AVAILABLE_NOT_READY; }); + + // verify ServiceDescription: + BOOST_TEST(downstreamSink.m_serviceDescription == upstreamServiceDescription); + BOOST_TEST(upstreamSink.m_serviceDescription == downstreamServiceDescription); + + // make sure, we have no data to start with: + BOOST_TEST(!upstreamSink.m_boardForecastData.m_optionalBoardId); + + // Respond with SendBoardInfo from upstream to downstream + BoardForecastData forecast{EBoardQuality::eGOOD, EFlippedBoard::eBOTTOM_SIDE_IS_UP}; + forecast.m_optionalTopBarcode = "Top"; + forecast.m_optionalBottomBarcode = "Bottom"; + forecast.m_optionalBoardId = "BoardId"; + forecast.m_optionalBoardIdCreatedBy = "CreatedBy"; + + downstream.Signal(downstreamSink.m_sessionId, forecast); + WaitFor(upstreamSink, [&]() { return upstreamSink.m_boardForecastData.m_optionalTopBarcode.has_value(); }); + BOOST_TEST(upstreamSink.m_boardForecastData == forecast); + +} diff --git a/test/BoostTestHermes/BoostTestHermes.vcxproj b/test/BoostTestHermes/BoostTestHermes.vcxproj index a6b0676..609346e 100644 --- a/test/BoostTestHermes/BoostTestHermes.vcxproj +++ b/test/BoostTestHermes/BoostTestHermes.vcxproj @@ -26,32 +26,32 @@ SAK Win32Proj BoostTestHermes - 8.1 + 10.0 Application true - v140 + v143 NotSet Application false - v140 + v143 true NotSet Application true - v140 + v143 NotSet Application false - v140 + v143 true NotSet @@ -74,23 +74,23 @@ - true - ..\..\..\bin\$(Configuration)\$(PlatformTarget)\ + ..\..\bin\$(PlatformTarget)\$(Configuration)\ ..\..\..\tmp\$(ProjectName)_$(Configuration)_$(PlatformTarget)\ + false - true - ..\..\..\bin\$(Configuration)\$(PlatformTarget)\ + ..\..\bin\$(PlatformTarget)\$(Configuration)\ ..\..\..\tmp\$(ProjectName)_$(Configuration)_$(PlatformTarget)\ + false false - ..\..\..\bin\$(Configuration)\$(PlatformTarget)\ + ..\..\bin\$(PlatformTarget)\$(Configuration)\ ..\..\..\tmp\$(ProjectName)_$(Configuration)_$(PlatformTarget)\ false - ..\..\..\bin\$(Configuration)\$(PlatformTarget)\ + ..\..\bin\$(PlatformTarget)\$(Configuration)\ ..\..\..\tmp\$(ProjectName)_$(Configuration)_$(PlatformTarget)\ @@ -98,13 +98,15 @@ Use Level4 Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(ProjectDir)\..\..\..\References; $(ProjectDir)\..\..\include; $(ProjectDir)\..\..\ + _WINDOWS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(ProjectDir)\..\..\References; $(ProjectDir)\..\..\src\include; $(ProjectDir)\..\..\ + stdcpp20 + ProgramDatabase Console true - ..\..\..\References\dynamic_runtime_libs.$(Configuration).$(PlatformTarget)\;..\..\..\lib\$(Configuration)\$(PlatformTarget)\ + ..\..\References\lib32;..\..\..\..\lib\$(Configuration)\$(PlatformTarget)\ Rpcrt4.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) @@ -116,13 +118,15 @@ Use Level4 Disabled - _DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(ProjectDir)\..\..\..\References; $(ProjectDir)\..\..\include; $(ProjectDir)\..\..\ + _WINDOWS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(ProjectDir)\..\..\References;$(ProjectDir)\..\..\src\include;$(ProjectDir)\..\..\ + stdcpp20 + ProgramDatabase Console true - ..\..\..\References\dynamic_runtime_libs.$(Configuration).$(PlatformTarget)\;..\..\..\lib\$(Configuration)\$(PlatformTarget)\ + ..\..\References\lib64;..\..\..\..\lib\$(Configuration)\$(PlatformTarget)\ Rpcrt4.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) @@ -136,8 +140,9 @@ MaxSpeed true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(ProjectDir)\..\..\..\References; $(ProjectDir)\..\..\include; $(ProjectDir)\..\..\ + _WINDOWS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(ProjectDir)\..\..\References; $(ProjectDir)\..\..\src\include; $(ProjectDir)\..\..\ + stdcpp20 Console @@ -145,7 +150,7 @@ true true Rpcrt4.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - ..\..\..\References\dynamic_runtime_libs.$(Configuration).$(PlatformTarget)\;..\..\..\lib\$(Configuration)\$(PlatformTarget)\ + ..\..\References\lib32;..\..\..\..\lib\$(Configuration)\$(PlatformTarget)\ $(TargetPath) --run_test="*" --detect_memory_leaks=1 @@ -158,15 +163,16 @@ MaxSpeed true true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(ProjectDir)\..\..\..\References; $(ProjectDir)\..\..\include; $(ProjectDir)\..\..\ + _WINDOWS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(ProjectDir)\..\..\References;$(ProjectDir)\..\..\src\include;$(ProjectDir)\..\..\ + stdcpp20 Console true true true - ..\..\..\References\dynamic_runtime_libs.$(Configuration).$(PlatformTarget)\;..\..\..\lib\$(Configuration)\$(PlatformTarget)\ + ..\..\References\lib64;..\..\..\..\lib\$(Configuration)\$(PlatformTarget)\ Rpcrt4.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) @@ -183,10 +189,14 @@ + + + + Create @@ -218,9 +228,10 @@ + - + {a52420c5-d236-47b7-883e-2166e83c2f43} diff --git a/test/BoostTestHermes/BoostTestHermes.vcxproj.filters b/test/BoostTestHermes/BoostTestHermes.vcxproj.filters index 2c6c5c6..96d2512 100644 --- a/test/BoostTestHermes/BoostTestHermes.vcxproj.filters +++ b/test/BoostTestHermes/BoostTestHermes.vcxproj.filters @@ -63,5 +63,20 @@ Tests + + Tests + + + Tests + + + Tests + + + Tests + + + Tests + \ No newline at end of file diff --git a/test/BoostTestHermes/CApiTest.cpp b/test/BoostTestHermes/CApiTest.cpp index c4b4fcc..6c4d490 100644 --- a/test/BoostTestHermes/CApiTest.cpp +++ b/test/BoostTestHermes/CApiTest.cpp @@ -1,5 +1,5 @@ /*********************************************************************** -Copyright 2018 ASM Assembly Systems GmbH & Co. KG +Copyright ASM Assembly Systems GmbH & Co. KG Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -18,15 +18,18 @@ limitations under the License. #include #ifdef _WINDOWS -# include +#include #else -# include + #include #endif #include #include #include #include +#include // generators +#include // streaming operators etc. + // some infrastructure to aid testing: namespace @@ -104,12 +107,12 @@ namespace std::cout << in_name << '#' << sessionId << '('; switch (type) { - case eHERMES_TRACE_SENT: std::cout << "Sent: "; break; - case eHERMES_TRACE_RECEIVED: std::cout << "Received: "; break; - case eHERMES_TRACE_DEBUG: std::cout << "Debug: "; break; - case eHERMES_TRACE_INFO: std::cout << "Info: "; break; - case eHERMES_TRACE_WARNING: std::cout << "Warning: "; break; - case eHERMES_TRACE_ERROR: std::cout << "Error: "; break; + case eHERMES_TRACE_TYPE_SENT: std::cout << "Sent: "; break; + case eHERMES_TRACE_TYPE_RECEIVED: std::cout << "Received: "; break; + case eHERMES_TRACE_TYPE_DEBUG: std::cout << "Debug: "; break; + case eHERMES_TRACE_TYPE_INFO: std::cout << "Info: "; break; + case eHERMES_TRACE_TYPE_WARNING: std::cout << "Warning: "; break; + case eHERMES_TRACE_TYPE_ERROR: std::cout << "Error: "; break; default: std::cout << "Unknown: "; } std::cout.write(trace.m_pData, trace.m_size); @@ -130,8 +133,8 @@ class DownstreamProxy m_laneId(laneId), m_pHermes(0), m_threadHandle(0), - m_state(eHERMES_NOT_CONNECTED), m_sessionId(0U), + m_state(eHERMES_STATE_NOT_CONNECTED), m_bottomBarcode("ABCDEF"), m_width(210.0), m_configuration() @@ -139,12 +142,14 @@ class DownstreamProxy m_configuration.m_downstreamLaneId = m_laneId; HermesDownstreamCallbacks callbacks = { {&DownstreamProxy::OnConnected_, this}, - {&DownstreamProxy::OnServiceDescription_, this}, + {&DownstreamProxy::OnServiceDescriptionData_, this}, {&DownstreamProxy::OnMachineReady_, this}, {0, 0}, // OnRevokeMachineReady {&DownstreamProxy::OnStartTransport_, this}, {&DownstreamProxy::OnStopTransport_, this}, + {0, 0}, // OnSendBoardInfo {0, 0}, // OnNotification + {0, 0}, // OnCommand {0, 0}, // OnState {0, 0}, // OnCheckAlive {0, 0}, // OnDisconnected @@ -186,7 +191,8 @@ class DownstreamProxy m_configuration.m_port, cCHECK_ALIVE_PERIOD, cRECONNECT_TIMEOUT, - eHERMES_CHECK_SEND_AND_RECEIVE + eHERMES_CHECK_ALIVE_RESPONSE_MODE_AUTO, + eHERMES_CHECK_STATE_SEND_AND_RECEIVE }; ::EnableHermesDownstream(m_pHermes, &settings); } @@ -195,8 +201,8 @@ class DownstreamProxy const char* cTEXT = "Connection was disabled"; HermesNotificationData notification = { - eHERMES_CONNECTION_RESET_BECAUSE_OF_CHANGED_CONFIGURATION, - eHERMES_INFO, + eHERMES_NOTIFICATION_CODE_CONNECTION_RESET_BECAUSE_OF_CHANGED_CONFIGURATION, + eHERMES_SEVERITY_INFO, {cTEXT, static_cast(::strlen(cTEXT))} }; ::DisableHermesDownstream(m_pHermes, ¬ification); @@ -257,7 +263,6 @@ class DownstreamProxy unsigned m_sessionId; EHermesState m_state; - #ifdef _WINDOWS static DWORD WINAPI Run_(void* pVoid) #else @@ -276,14 +281,14 @@ class DownstreamProxy pThis->m_state = state; } - static void OnServiceDescription_(void* pVoid, unsigned sessionId, EHermesState state, const HermesServiceDescription*) + static void OnServiceDescriptionData_(void* pVoid, unsigned sessionId, EHermesState state, const HermesServiceDescriptionData*) { DownstreamProxy* pThis = static_cast(pVoid); if (pThis->m_sessionId != sessionId) return; pThis->m_state = state; - HermesServiceDescription serviceDescription = + HermesServiceDescriptionData serviceDescription = { {pThis->m_machineId.data(), static_cast(pThis->m_machineId.size())}, pThis->m_laneId, @@ -300,20 +305,17 @@ class DownstreamProxy pThis->m_state = state; - GUID guid; - ::UuidCreateSequential(&guid); - RPC_CSTR guidString; - ::UuidToStringA(&guid, &guidString); - pThis->m_boardId = reinterpret_cast(guidString); - ::RpcStringFreeA(&guidString); + std::stringstream guid; + guid << boost::uuids::random_generator()(); + pThis->m_boardId = guid.str(); HermesBoardAvailableData boardAvailableData = { {pThis->m_boardId.data(), static_cast(pThis->m_boardId.size())}, {pThis->m_machineId.data(), static_cast(pThis->m_machineId.size())}, - eHERMES_GOOD_BOARD_QUALITY, + eHERMES_BOARD_QUALITY_GOOD, {0, 0}, - eHERMES_BOARD_TOP_SIDE_IS_UP, + eHERMES_FLIPPED_BOARD_TOP_SIDE_IS_UP, {0, 0}, {pThis->m_bottomBarcode.data(), static_cast(pThis->m_bottomBarcode.size())}, 0, @@ -335,7 +337,7 @@ class DownstreamProxy HermesTransportFinishedData transportFinishedData = { - eHERMES_TRANSFER_COMPLETE, + eHERMES_TRANSFER_STATE_COMPLETE, data->m_boardId, }; ::SignalHermesTransportFinished(pThis->m_pHermes, pThis->m_sessionId, &transportFinishedData); @@ -374,20 +376,22 @@ class UpstreamProxy m_laneId(laneId), m_pHermes(0), m_threadHandle(0), - m_state(eHERMES_NOT_CONNECTED), + m_state(eHERMES_STATE_NOT_CONNECTED), m_sessionId(0U), - m_width(0.0), - m_configuration() + m_width(0.0) { m_configuration.m_upstreamLaneId = m_laneId; HermesUpstreamCallbacks callbacks = { {&UpstreamProxy::OnConnected_, this}, - {&UpstreamProxy::OnServiceDescription_, this}, + {&UpstreamProxy::OnServiceDescriptionData_, this}, {&UpstreamProxy::OnBoardAvailable_, this}, {0, 0}, // OnRevokeBoardAvailable {&UpstreamProxy::OnTransportFinished_, this}, + {0, 0}, // OnBoardForecast + {0, 0}, // OnSendBoardInfo {0, 0}, // OnNotification + {0, 0}, // OnCommand {0, 0}, // OnState {0, 0}, // OnCheckAlive {0, 0}, // OnDisconnected @@ -428,7 +432,8 @@ class UpstreamProxy m_configuration.m_port, cCHECK_ALIVE_PERIOD, cRECONNECT_TIMEOUT, - eHERMES_CHECK_SEND_AND_RECEIVE + eHERMES_CHECK_ALIVE_RESPONSE_MODE_AUTO, + eHERMES_CHECK_STATE_SEND_AND_RECEIVE }; ::EnableHermesUpstream(m_pHermes, &settings); } @@ -437,8 +442,8 @@ class UpstreamProxy const char* cTEXT = "Connection was disabled"; HermesNotificationData notification = { - eHERMES_CONNECTION_RESET_BECAUSE_OF_CHANGED_CONFIGURATION, - eHERMES_INFO, + eHERMES_NOTIFICATION_CODE_CONNECTION_RESET_BECAUSE_OF_CHANGED_CONFIGURATION, + eHERMES_SEVERITY_INFO, {cTEXT, static_cast(::strlen(cTEXT))} }; ::DisableHermesUpstream(m_pHermes, ¬ification); @@ -469,15 +474,16 @@ class UpstreamProxy std::string m_boardId; std::string m_boardIdCreatedBy; std::string m_bottomBarcode; - double m_width; - HermesUpstreamConfiguration m_configuration; + double m_width{}; + HermesUpstreamConfiguration m_configuration{}; private: - unsigned m_laneId; - HermesUpstream* m_pHermes; + unsigned m_laneId{}; + HermesUpstream* m_pHermes{}; std::string m_serverAddress; // this is the actual storage behind m_configuration.m_hostAddress! #ifdef _WINDOWS HANDLE m_threadHandle; + #else pthread_t m_threadHandle; #endif @@ -498,7 +504,7 @@ class UpstreamProxy pThis->m_sessionId = sessionId; pThis->m_state = state; - HermesServiceDescription serviceDescription = + HermesServiceDescriptionData serviceDescription = { {pThis->m_machineId.data(), static_cast(pThis->m_machineId.size())}, pThis->m_laneId, @@ -507,7 +513,7 @@ class UpstreamProxy ::SignalHermesUpstreamServiceDescription(pThis->m_pHermes, pThis->m_sessionId, &serviceDescription); } - static void OnServiceDescription_(void* pVoid, unsigned sessionId, EHermesState state, const HermesServiceDescription*) + static void OnServiceDescriptionData_(void* pVoid, unsigned sessionId, EHermesState state, const HermesServiceDescriptionData*) { UpstreamProxy* pThis = static_cast(pVoid); if (pThis->m_sessionId != sessionId) @@ -515,7 +521,7 @@ class UpstreamProxy pThis->m_state = state; - HermesMachineReadyData machineReadyData = {eHERMES_ANY_BOARD_QUALITY}; + HermesMachineReadyData machineReadyData = {eHERMES_BOARD_QUALITY_ANY}; ::SignalHermesMachineReady(pThis->m_pHermes, pThis->m_sessionId, &machineReadyData); } @@ -549,7 +555,7 @@ class UpstreamProxy HermesStopTransportData stopTransportData = { - eHERMES_TRANSFER_COMPLETE, + eHERMES_TRANSFER_STATE_COMPLETE, data->m_boardId }; ::SignalHermesStopTransport(pThis->m_pHermes, pThis->m_sessionId, &stopTransportData); @@ -584,7 +590,6 @@ class ConfigurationProxy }; m_pHermes = ::CreateHermesConfigurationService(&callbacks); - #ifdef _WINDOWS m_threadHandle = ::CreateThread(0, 0, &ConfigurationProxy::Run_, this, 0, 0); #else @@ -637,7 +642,7 @@ class ConfigurationProxy DownstreamProxy m_downstream1; DownstreamProxy m_downstream2; - HermesConfigurationService* m_pHermes; + HermesConfigurationService* m_pHermes{}; #ifdef _WINDOWS HANDLE m_threadHandle; #else @@ -659,35 +664,35 @@ class ConfigurationProxy Trace("ConfigurationProxy", sessionId, type, trace); } - static void OnGetConfiguration_(void* pVoid, uint32_t sessionId, const HermesConnectionInfo*, const HermesGetConfigurationData*) + static void OnGetConfiguration_(void* pVoid, uint32_t sessionId, const HermesGetConfigurationData*, const HermesConnectionInfo*) { const HermesUpstreamConfiguration *upstreamConfigurations[cMAX_LANE_COUNT]; const HermesDownstreamConfiguration *downstreamConfigurations[cMAX_LANE_COUNT]; ConfigurationProxy* pThis = static_cast(pVoid); HermesCurrentConfigurationData data = {{pThis->m_machineId.data(), static_cast(pThis->m_machineId.size())}}; - data.m_downstreamConfigurations = downstreamConfigurations; - data.m_upstreamConfigurations = upstreamConfigurations; + data.m_downstreamConfigurations.m_pData = downstreamConfigurations; + data.m_upstreamConfigurations.m_pData = upstreamConfigurations; for (unsigned laneId = 1; laneId <= cMAX_LANE_COUNT; ++laneId) { UpstreamProxy& upstreamProxy = *pThis->GetUpstreamProxy(laneId); if (upstreamProxy.m_configuration.m_port) { - upstreamConfigurations[data.m_upstreamConfigurationCount] = &upstreamProxy.m_configuration; - ++data.m_upstreamConfigurationCount; + upstreamConfigurations[data.m_upstreamConfigurations.m_size] = &upstreamProxy.m_configuration; + ++data.m_upstreamConfigurations.m_size; } DownstreamProxy& downstreamProxy = *pThis->GetDownstreamProxy(laneId); if (downstreamProxy.m_configuration.m_port) { - downstreamConfigurations[data.m_downstreamConfigurationCount] = &downstreamProxy.m_configuration; - ++data.m_downstreamConfigurationCount; + downstreamConfigurations[data.m_downstreamConfigurations.m_size] = &downstreamProxy.m_configuration; + ++data.m_downstreamConfigurations.m_size; } } ::SignalHermesCurrentConfiguration(pThis->m_pHermes, sessionId, &data); } - static void OnSetConfiguration_(void* pVoid, uint32_t sessionId, const HermesConnectionInfo*, const HermesSetConfigurationData* pData) + static void OnSetConfiguration_(void* pVoid, uint32_t sessionId, const HermesSetConfigurationData* pData, const HermesConnectionInfo*) { const char* cINVALID_LANE = "Invalid lane"; HermesUpstreamConfiguration upstreamConfigs[cMAX_LANE_COUNT] = {{1U}, {2U}}; @@ -696,16 +701,16 @@ class ConfigurationProxy ConfigurationProxy* pThis = static_cast(pVoid); pThis->m_machineId.assign(pData->m_machineId.m_pData, pData->m_machineId.m_size); - for (unsigned i = 0U; i < pData->m_upstreamConfigurationCount; ++i) + for (unsigned i = 0U; i < pData->m_upstreamConfigurations.m_size; ++i) { - const HermesUpstreamConfiguration* pConfig = pData->m_upstreamConfigurations[i]; + const HermesUpstreamConfiguration* pConfig = pData->m_upstreamConfigurations.m_pData[i]; UpstreamProxy* pProxy = pThis->GetUpstreamProxy(pConfig->m_upstreamLaneId); if (!pProxy) { HermesNotificationData notification = { - eHERMES_CONFIGURATION_ERROR, - eHERMES_INFO, + eHERMES_NOTIFICATION_CODE_CONFIGURATION_ERROR, + eHERMES_SEVERITY_INFO, {cINVALID_LANE, static_cast(::strlen(cINVALID_LANE))} }; ::SignalHermesConfigurationNotification(pThis->m_pHermes, sessionId, ¬ification); @@ -715,16 +720,16 @@ class ConfigurationProxy upstreamConfigs[pConfig->m_upstreamLaneId - 1U].m_port = pConfig->m_port; } - for (unsigned i = 0U; i < pData->m_downstreamConfigurationCount; ++i) + for (unsigned i = 0U; i < pData->m_downstreamConfigurations.m_size; ++i) { - const HermesDownstreamConfiguration* pConfig = pData->m_downstreamConfigurations[i]; + const HermesDownstreamConfiguration* pConfig = pData->m_downstreamConfigurations.m_pData[i]; DownstreamProxy* pProxy = pThis->GetDownstreamProxy(pConfig->m_downstreamLaneId); if (!pProxy) { HermesNotificationData notification = { - eHERMES_CONFIGURATION_ERROR, - eHERMES_INFO, + eHERMES_NOTIFICATION_CODE_CONFIGURATION_ERROR, + eHERMES_SEVERITY_INFO, {cINVALID_LANE, static_cast(::strlen(cINVALID_LANE))} }; ::SignalHermesConfigurationNotification(pThis->m_pHermes, sessionId, ¬ification); @@ -803,13 +808,13 @@ class ConfigurationClient std::size_t upstreamCount = configuration.m_upstreamConfigurations.size(); std::vector upstreamConfigs(upstreamCount); std::vector upstreamPointers(upstreamCount); - data.m_upstreamConfigurationCount = static_cast(upstreamCount); - data.m_upstreamConfigurations = upstreamPointers.data(); + data.m_upstreamConfigurations.m_size = upstreamCount; + data.m_upstreamConfigurations.m_pData = upstreamPointers.data(); for (std::size_t i = 0U; i < upstreamCount; ++i) { const LaneConfiguration& myConfig = configuration.m_upstreamConfigurations[i]; - HermesUpstreamConfiguration upstreamConfig = {myConfig.m_laneId, - {myConfig.m_ipAddress.data(), static_cast(myConfig.m_ipAddress.size())}, + HermesUpstreamConfiguration upstreamConfig = {myConfig.m_laneId, {}, + {myConfig.m_ipAddress.data(), myConfig.m_ipAddress.size()}, myConfig.m_port }; upstreamConfigs[i] = upstreamConfig; @@ -819,22 +824,22 @@ class ConfigurationClient std::size_t downstreamCount = configuration.m_downstreamConfigurations.size(); std::vector downstreamConfigs(downstreamCount); std::vector downstreamPointers(downstreamCount); - data.m_downstreamConfigurationCount = static_cast(downstreamCount); - data.m_downstreamConfigurations = downstreamPointers.data(); + data.m_downstreamConfigurations.m_size = downstreamCount; + data.m_downstreamConfigurations.m_pData = downstreamPointers.data(); for (std::size_t i = 0U; i < downstreamCount; ++i) { const LaneConfiguration& myConfig = configuration.m_downstreamConfigurations[i]; - HermesDownstreamConfiguration downstreamConfig = {myConfig.m_laneId, {0, 0}, myConfig.m_port}; + HermesDownstreamConfiguration downstreamConfig = {myConfig.m_laneId, {}, {}, myConfig.m_port}; if (!myConfig.m_ipAddress.empty()) { downstreamConfig.m_optionalClientAddress.m_pData = myConfig.m_ipAddress.data(); - downstreamConfig.m_optionalClientAddress.m_size = static_cast(myConfig.m_ipAddress.size()); + downstreamConfig.m_optionalClientAddress.m_size = myConfig.m_ipAddress.size(); } downstreamConfigs[i] = downstreamConfig; downstreamPointers[i] = &downstreamConfigs[i]; } - HermesStringView hostName = {sLocalHost.data(), static_cast(sLocalHost.size())}; + HermesStringView hostName = {sLocalHost.data(), sLocalHost.size()}; ::SetHermesConfiguration(hostName, &data, 60U, &callbacks); if (pSuccess) { @@ -860,9 +865,9 @@ class ConfigurationClient pConfiguration->m_machineId.assign(pData->m_optionalMachineId.m_pData, pData->m_optionalMachineId.m_size); pConfiguration->m_upstreamConfigurations.clear(); pConfiguration->m_downstreamConfigurations.clear(); - for (unsigned i = 0; i < pData->m_downstreamConfigurationCount; ++i) + for (unsigned i = 0; i < pData->m_downstreamConfigurations.m_size; ++i) { - const HermesDownstreamConfiguration* pConfig = pData->m_downstreamConfigurations[i]; + const HermesDownstreamConfiguration* pConfig = pData->m_downstreamConfigurations.m_pData[i]; LaneConfiguration laneConfig = { pConfig->m_downstreamLaneId, @@ -871,9 +876,9 @@ class ConfigurationClient }; pConfiguration->m_downstreamConfigurations.push_back(laneConfig); } - for (unsigned i = 0; i < pData->m_upstreamConfigurationCount; ++i) + for (unsigned i = 0; i < pData->m_upstreamConfigurations.m_size; ++i) { - const HermesUpstreamConfiguration* pConfig = pData->m_upstreamConfigurations[i]; + const HermesUpstreamConfiguration* pConfig = pData->m_upstreamConfigurations.m_pData[i]; LaneConfiguration laneConfig = { pConfig->m_upstreamLaneId, diff --git a/test/BoostTestHermes/CheckAliveTest.cpp b/test/BoostTestHermes/CheckAliveTest.cpp new file mode 100644 index 0000000..572b9c1 --- /dev/null +++ b/test/BoostTestHermes/CheckAliveTest.cpp @@ -0,0 +1,138 @@ +// Copyright (c) ASM Assembly Systems GmbH & Co. KG +#include "stdafx.h" + +#include "Runner.h" +#include "Sinks.h" + +using namespace Hermes; + +BOOST_AUTO_TEST_CASE(AutoCheckAliveResponseTest) +{ + TestCaseScope scope("AutoCheckAliveResponseTest"); + + std::string upstreamMachineId{"UpstreamMachineId"}; + std::string downstreamMachineId{"DownstreamMachineId"}; + + DownstreamSink downstreamSink; + Hermes::Downstream downstream(1U, downstreamSink); + Runner downstreamRunner(downstream); + + UpstreamSink upstreamSink; + Hermes::Upstream upstream(1U, upstreamSink); + Runner upstreamRunner(upstream); + + // suppress periodic CheckAlive on both sides, but auto-response is enabled: + DownstreamSettings downstreamSettings{upstreamMachineId, 50101}; + downstreamSettings.m_checkAlivePeriodInSeconds = 0; + downstream.Enable(downstreamSettings); + + Hermes::UpstreamSettings upstreamSettings(downstreamMachineId, "127.0.0.1", 50101); + upstreamSettings.m_checkAlivePeriodInSeconds = 0; + upstream.Enable(upstreamSettings); + + // wait until connection is established + WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eSOCKET_CONNECTED; }); + WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eSOCKET_CONNECTED; }); + upstream.Signal(upstreamSink.m_sessionId, Hermes::ServiceDescriptionData(downstreamMachineId, 1U)); + WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eSERVICE_DESCRIPTION_DOWNSTREAM; }); + downstream.Signal(downstreamSink.m_sessionId, Hermes::ServiceDescriptionData(upstreamMachineId, 1U)); + + WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eNOT_AVAILABLE_NOT_READY; }); + WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eNOT_AVAILABLE_NOT_READY; }); + + // Send CheckAlive from downstream to upstream: + { + downstream.Signal(downstreamSink.m_sessionId, CheckAliveData{ ECheckAliveType::ePING, std::string{"DownstreamId1"} }); + WaitFor(downstreamSink, [&]() { return downstreamSink.m_checkAliveData.m_optionalId.has_value(); }); + BOOST_TEST(*downstreamSink.m_checkAliveData.m_optionalId == "DownstreamId1"); + BOOST_TEST(downstreamSink.m_checkAliveData.m_optionalType.value_or(ECheckAliveType::eUNKNOWN) == ECheckAliveType::ePONG); + BOOST_TEST(upstreamSink.m_checkAliveData.m_optionalType.value_or(ECheckAliveType::eUNKNOWN) == ECheckAliveType::ePING); + BOOST_TEST(upstreamSink.m_checkAliveData.m_optionalId.value_or("") == "DownstreamId1"); + + // non-ping CheckAlive: no reaction: + downstream.Signal(downstreamSink.m_sessionId, CheckAliveData{ ECheckAliveType::ePONG, std::string{"DownstreamId2"} }); + WaitFor(upstreamSink, [&]() { return upstreamSink.m_checkAliveData.m_optionalType.value_or(ECheckAliveType::eUNKNOWN) == ECheckAliveType::ePONG; }); + BOOST_TEST(upstreamSink.m_checkAliveData.m_optionalId.value_or("") == "DownstreamId2"); + + downstream.Signal(downstreamSink.m_sessionId, CheckAliveData{}); + WaitFor(upstreamSink, [&]() { return !upstreamSink.m_checkAliveData.m_optionalType; }); + BOOST_TEST(!upstreamSink.m_checkAliveData.m_optionalId ); + + // we should not have received an answer in the meantime: + BOOST_TEST(downstreamSink.m_checkAliveData.m_optionalType.value_or(ECheckAliveType::eUNKNOWN) == ECheckAliveType::ePONG); + BOOST_TEST(downstreamSink.m_checkAliveData.m_optionalId.value_or("") == "DownstreamId1"); + } + + // Send CheckAlive from upstream to downstream: + { + upstream.Signal(upstreamSink.m_sessionId, CheckAliveData{ ECheckAliveType::ePING, std::string{"UpstreamId1"} }); + WaitFor(upstreamSink, [&]() { return upstreamSink.m_checkAliveData.m_optionalId.has_value(); }); + BOOST_TEST(*upstreamSink.m_checkAliveData.m_optionalId == "UpstreamId1"); + BOOST_TEST(upstreamSink.m_checkAliveData.m_optionalType.value_or(ECheckAliveType::eUNKNOWN) == ECheckAliveType::ePONG); + BOOST_TEST(downstreamSink.m_checkAliveData.m_optionalType.value_or(ECheckAliveType::eUNKNOWN) == ECheckAliveType::ePING); + BOOST_TEST(downstreamSink.m_checkAliveData.m_optionalId.value_or("") == "UpstreamId1"); + + // non-ping CheckAlive: no reaction: + upstream.Signal(upstreamSink.m_sessionId, CheckAliveData{ ECheckAliveType::ePONG, std::string{"UpstreamId2"} }); + WaitFor(downstreamSink, [&]() { return downstreamSink.m_checkAliveData.m_optionalType.value_or(ECheckAliveType::eUNKNOWN) == ECheckAliveType::ePONG; }); + BOOST_TEST(downstreamSink.m_checkAliveData.m_optionalId.value_or("") == "UpstreamId2"); + + upstream.Signal(upstreamSink.m_sessionId, CheckAliveData{}); + WaitFor(downstreamSink, [&]() { return !downstreamSink.m_checkAliveData.m_optionalType; }); + BOOST_TEST(!downstreamSink.m_checkAliveData.m_optionalId); + + // we should not have received an answer in the meantime: + BOOST_TEST(upstreamSink.m_checkAliveData.m_optionalType.value_or(ECheckAliveType::eUNKNOWN) == ECheckAliveType::ePONG); + BOOST_TEST(upstreamSink.m_checkAliveData.m_optionalId.value_or("") == "UpstreamId1"); + } +} + +BOOST_AUTO_TEST_CASE(ApplicationCheckAliveResponseTest) +{ + TestCaseScope scope("ApplicationCheckAliveResponseTest"); + + std::string upstreamMachineId{"UpstreamMachineId"}; + std::string downstreamMachineId{"DownstreamMachineId"}; + + DownstreamSink downstreamSink; + Hermes::Downstream downstream(1U, downstreamSink); + Runner downstreamRunner(downstream); + + UpstreamSink upstreamSink; + Hermes::Upstream upstream(1U, upstreamSink); + Runner upstreamRunner(upstream); + + // suppress periodic CheckAlive on both sides, but auto-response is enabled: + DownstreamSettings downstreamSettings{upstreamMachineId, 50101}; + downstreamSettings.m_checkAlivePeriodInSeconds = 0; + downstreamSettings.m_checkAliveResponseMode = ECheckAliveResponseMode::eAPPLICATION; + downstream.Enable(downstreamSettings); + + Hermes::UpstreamSettings upstreamSettings(downstreamMachineId, "127.0.0.1", 50101); + upstreamSettings.m_checkAlivePeriodInSeconds = 0; + upstreamSettings.m_checkAliveResponseMode = ECheckAliveResponseMode::eAPPLICATION; + upstream.Enable(upstreamSettings); + + // wait until connection is established + WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eSOCKET_CONNECTED; }); + WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eSOCKET_CONNECTED; }); + upstream.Signal(upstreamSink.m_sessionId, Hermes::ServiceDescriptionData(downstreamMachineId, 1U)); + WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eSERVICE_DESCRIPTION_DOWNSTREAM; }); + downstream.Signal(downstreamSink.m_sessionId, Hermes::ServiceDescriptionData(upstreamMachineId, 1U)); + + WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eNOT_AVAILABLE_NOT_READY; }); + WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eNOT_AVAILABLE_NOT_READY; }); + + // Send CheckAlive from downstream to upstream: + downstream.Signal(downstreamSink.m_sessionId, CheckAliveData{ ECheckAliveType::ePING, std::string{"DownstreamId"} }); + WaitFor(upstreamSink, [&]() { return upstreamSink.m_checkAliveData.m_optionalType.value_or(ECheckAliveType::eUNKNOWN) == ECheckAliveType::ePING; }); + + upstream.Signal(upstreamSink.m_sessionId, CheckAliveData{ ECheckAliveType::ePING, std::string{"UpstreamId"} }); + WaitFor(downstreamSink, [&]() { return downstreamSink.m_checkAliveData.m_optionalType.value_or(ECheckAliveType::eUNKNOWN) == ECheckAliveType::ePING; }); + + // no autoresponse should have been received: + BOOST_TEST(*upstreamSink.m_checkAliveData.m_optionalId == "DownstreamId"); + BOOST_TEST(*downstreamSink.m_checkAliveData.m_optionalId == "UpstreamId"); + +} + diff --git a/test/BoostTestHermes/ConfigurationTest.cpp b/test/BoostTestHermes/ConfigurationTest.cpp index 1822155..29a9293 100644 --- a/test/BoostTestHermes/ConfigurationTest.cpp +++ b/test/BoostTestHermes/ConfigurationTest.cpp @@ -1,5 +1,5 @@ /*********************************************************************** -Copyright 2018 ASM Assembly Systems GmbH & Co. KG +Copyright ASM Assembly Systems GmbH & Co. KG Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -152,11 +152,11 @@ BOOST_AUTO_TEST_CASE(SetHermesConfigurationTest) Hermes::SetConfigurationData sentConfig; sentConfig.m_machineId = "TX_5"; - sentConfig.m_downstreamConfigurations.emplace_back(1U, 0); // on lane 1, take default port - sentConfig.m_downstreamConfigurations.emplace_back(2U, "localhost", 50101); + sentConfig.m_downstreamConfigurations.emplace_back(1U, uint16_t{ 0 }); // on lane 1, take default port + sentConfig.m_downstreamConfigurations.emplace_back(2U, uint16_t{ 50101 }); - sentConfig.m_upstreamConfigurations.emplace_back(1U, "localhost", 50101); - sentConfig.m_upstreamConfigurations.emplace_back(2U, "127.0.0.1", 50102); + sentConfig.m_upstreamConfigurations.emplace_back(1U, "localhost", uint16_t{ 50101 }); + sentConfig.m_upstreamConfigurations.emplace_back(2U, "127.0.0.1", uint16_t{ 50102 }); // send it to a machine: Hermes::CurrentConfigurationData receivedConfig; diff --git a/test/BoostTestHermes/DownstreamTest.cpp b/test/BoostTestHermes/DownstreamTest.cpp index f9f1212..d6f57a4 100644 --- a/test/BoostTestHermes/DownstreamTest.cpp +++ b/test/BoostTestHermes/DownstreamTest.cpp @@ -1,4 +1,19 @@ -// Copyright (c) ASM Assembly Systems GmbH & Co. KG +/*********************************************************************** +Copyright ASM Assembly Systems GmbH & Co. KG + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + #include "stdafx.h" #include "Runner.h" @@ -64,9 +79,9 @@ BOOST_AUTO_TEST_CASE(DownstreamTest) WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eSOCKET_CONNECTED; }); WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eSOCKET_CONNECTED; }); - upstream.Signal(upstreamSink.m_sessionId, Hermes::ServiceDescription(downstreamMachineId, 1U)); + upstream.Signal(upstreamSink.m_sessionId, Hermes::ServiceDescriptionData(downstreamMachineId, 1U)); WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eSERVICE_DESCRIPTION_DOWNSTREAM; }); - downstream.Signal(downstreamSink.m_sessionId, Hermes::ServiceDescription(upstreamMachineId, 1U)); + downstream.Signal(downstreamSink.m_sessionId, Hermes::ServiceDescriptionData(upstreamMachineId, 1U)); WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eNOT_AVAILABLE_NOT_READY; }); WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eNOT_AVAILABLE_NOT_READY; }); @@ -81,9 +96,9 @@ BOOST_AUTO_TEST_CASE(DownstreamTest) WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eSOCKET_CONNECTED; }); WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eSOCKET_CONNECTED; }); - upstream.Signal(upstreamSink.m_sessionId, Hermes::ServiceDescription(downstreamMachineId, 1U)); + upstream.Signal(upstreamSink.m_sessionId, Hermes::ServiceDescriptionData(downstreamMachineId, 1U)); WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eSERVICE_DESCRIPTION_DOWNSTREAM; }); - downstream.Signal(downstreamSink.m_sessionId, Hermes::ServiceDescription(upstreamMachineId, 1U)); + downstream.Signal(downstreamSink.m_sessionId, Hermes::ServiceDescriptionData(upstreamMachineId, 1U)); WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eNOT_AVAILABLE_NOT_READY; }); WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eNOT_AVAILABLE_NOT_READY; }); @@ -117,6 +132,13 @@ BOOST_AUTO_TEST_CASE(DownstreamTest) upstream.Signal(upstreamSink.m_sessionId, upstreamNotification); WaitFor(downstreamSink, [&]() { return downstreamSink.m_notificationData == upstreamNotification; }); WaitFor(upstreamSink, [&]() { return upstreamSink.m_notificationData == downstreamNotification; }); + + CommandData downstreamCommand(4); + CommandData upstreamCommand(5); + downstream.Signal(downstreamSink.m_sessionId, downstreamCommand); + upstream.Signal(upstreamSink.m_sessionId, upstreamCommand); + WaitFor(downstreamSink, [&]() { return downstreamSink.m_commandData == upstreamCommand; }); + WaitFor(upstreamSink, [&]() { return upstreamSink.m_commandData == downstreamCommand; }); } { @@ -127,9 +149,9 @@ BOOST_AUTO_TEST_CASE(DownstreamTest) WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eSOCKET_CONNECTED; }); WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eSOCKET_CONNECTED; }); - upstream.Signal(upstreamSink.m_sessionId, Hermes::ServiceDescription(downstreamMachineId, 1U)); + upstream.Signal(upstreamSink.m_sessionId, Hermes::ServiceDescriptionData(downstreamMachineId, 1U)); WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eSERVICE_DESCRIPTION_DOWNSTREAM; }); - downstream.Signal(downstreamSink.m_sessionId, Hermes::ServiceDescription(upstreamMachineId, 1U)); + downstream.Signal(downstreamSink.m_sessionId, Hermes::ServiceDescriptionData(upstreamMachineId, 1U)); WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eNOT_AVAILABLE_NOT_READY; }); WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eNOT_AVAILABLE_NOT_READY; }); @@ -140,9 +162,9 @@ BOOST_AUTO_TEST_CASE(DownstreamTest) WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eSOCKET_CONNECTED; }); WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eSOCKET_CONNECTED; }); - upstream.Signal(upstreamSink.m_sessionId, Hermes::ServiceDescription(downstreamMachineId, 1U)); + upstream.Signal(upstreamSink.m_sessionId, Hermes::ServiceDescriptionData(downstreamMachineId, 1U)); WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eSERVICE_DESCRIPTION_DOWNSTREAM; }); - downstream.Signal(downstreamSink.m_sessionId, Hermes::ServiceDescription(upstreamMachineId, 1U)); + downstream.Signal(downstreamSink.m_sessionId, Hermes::ServiceDescriptionData(upstreamMachineId, 1U)); WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eNOT_AVAILABLE_NOT_READY && downstreamSink.m_sessionId == downstreamSessionId; }); WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eNOT_AVAILABLE_NOT_READY && upstreamSink.m_sessionId == upstreamSessionId; }); @@ -153,9 +175,9 @@ BOOST_AUTO_TEST_CASE(DownstreamTest) WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eSOCKET_CONNECTED; }); WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eSOCKET_CONNECTED; }); - upstream.Signal(upstreamSink.m_sessionId, Hermes::ServiceDescription(downstreamMachineId, 1U)); + upstream.Signal(upstreamSink.m_sessionId, Hermes::ServiceDescriptionData(downstreamMachineId, 1U)); WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eSERVICE_DESCRIPTION_DOWNSTREAM; }); - downstream.Signal(downstreamSink.m_sessionId, Hermes::ServiceDescription(upstreamMachineId, 1U)); + downstream.Signal(downstreamSink.m_sessionId, Hermes::ServiceDescriptionData(upstreamMachineId, 1U)); WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eNOT_AVAILABLE_NOT_READY && downstreamSink.m_sessionId == downstreamSessionId; }); WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eNOT_AVAILABLE_NOT_READY && upstreamSink.m_sessionId == upstreamSessionId; }); @@ -188,9 +210,9 @@ BOOST_AUTO_TEST_CASE(DownstreamAllowedHostTest) WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eSOCKET_CONNECTED; }); WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eSOCKET_CONNECTED; }); - upstream.Signal(upstreamSink.m_sessionId, Hermes::ServiceDescription(downstreamMachineId, 1U)); + upstream.Signal(upstreamSink.m_sessionId, Hermes::ServiceDescriptionData(downstreamMachineId, 1U)); WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eSERVICE_DESCRIPTION_DOWNSTREAM; }); - downstream.Signal(downstreamSink.m_sessionId, Hermes::ServiceDescription(upstreamMachineId, 1U)); + downstream.Signal(downstreamSink.m_sessionId, Hermes::ServiceDescriptionData(upstreamMachineId, 1U)); WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eNOT_AVAILABLE_NOT_READY; }); WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eNOT_AVAILABLE_NOT_READY; }); @@ -222,18 +244,16 @@ BOOST_AUTO_TEST_CASE(DownstreamHostNotAlloweHostTest) WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eNOT_CONNECTED; }); WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eDISCONNECTED; }); - downstreamConfig.m_optionalClientAddress.clear(); // should now accept anything + downstreamConfig.m_optionalClientAddress.reset(); // should now accept anything downstream.Enable(downstreamConfig); WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eSOCKET_CONNECTED; }); WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eSOCKET_CONNECTED; }); - upstream.Signal(upstreamSink.m_sessionId, Hermes::ServiceDescription(downstreamMachineId, 1U)); + upstream.Signal(upstreamSink.m_sessionId, Hermes::ServiceDescriptionData(downstreamMachineId, 1U)); WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eSERVICE_DESCRIPTION_DOWNSTREAM; }); - downstream.Signal(downstreamSink.m_sessionId, Hermes::ServiceDescription(upstreamMachineId, 1U)); + downstream.Signal(downstreamSink.m_sessionId, Hermes::ServiceDescriptionData(upstreamMachineId, 1U)); WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eNOT_AVAILABLE_NOT_READY; }); WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eNOT_AVAILABLE_NOT_READY; }); } - - - } + diff --git a/test/BoostTestHermes/HermesDataGenerators.h b/test/BoostTestHermes/HermesDataGenerators.h index e1a8e11..17b5056 100644 --- a/test/BoostTestHermes/HermesDataGenerators.h +++ b/test/BoostTestHermes/HermesDataGenerators.h @@ -1,4 +1,19 @@ -// Copyright (c) ASM Assembly Systems GmbH & Co. KG +/*********************************************************************** +Copyright ASMPT Assembly Systems GmbH & Co. KG + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + #pragma once #include @@ -20,14 +35,22 @@ struct SimpleSampleGenerator; template<> struct SimpleSampleGenerator { - static std::vector Generate() + static std::vector Generate(const std::string& defaultValue) { + if (defaultValue == std::string{"00000000-0000-0000-0000-000000000000"}) + return + { + std::string{"00000000-0000-0000-0000-000000000000"}, + std::string{"90abb804-ef8d-11e7-8c3f-9a214cf093ae"}, + std::string{"0e4c18f9-5f69-4dbe-9b1c-e705bf7d680f"} + }; return { std::string(), std::string("A"), std::string("Hello, world"), - std::string(10000, 'X') + std::string(10000, 'X'), + std::string("\x48\xE2\x82\xAC\x72\xC2\xB5\x65\xC3\x9F") }; } }; @@ -35,7 +58,7 @@ struct SimpleSampleGenerator template struct SimpleSampleGenerator::value>> { - static std::vector Generate() + static std::vector Generate(E) { std::vector result; result.reserve(size(E())); @@ -47,12 +70,39 @@ struct SimpleSampleGenerator::value>> } }; +template<> +struct SimpleSampleGenerator +{ + static std::vector Generate(Hermes::ETransferState) + { + return{Hermes::ETransferState::eNOT_STARTED, Hermes::ETransferState::eINCOMPLETE, Hermes::ETransferState::eCOMPLETE}; + } +}; + +template<> +struct SimpleSampleGenerator +{ + static std::vector Generate(Hermes::ESeverity) + { + return{Hermes::ESeverity::eFATAL, Hermes::ESeverity::eERROR, Hermes::ESeverity::eWARNING, Hermes::ESeverity::eINFO}; + } +}; + +template +struct SimpleSampleGenerator::value>> +{ + static std::vector Generate(const T&) + { + return{T{}}; + } +}; + template struct SimpleSampleGenerator> { - static std::vector> Generate() + static std::vector> Generate(const Hermes::Optional&) { - auto values = SimpleSampleGenerator::Generate(); + auto values = SimpleSampleGenerator::Generate(T()); return{values.begin(), values.end()}; } }; @@ -60,7 +110,7 @@ struct SimpleSampleGenerator> template struct SimpleSampleGenerator::value>> { - static std::vector Generate() + static std::vector Generate(const T&) { return GenerateSamples(); } @@ -69,16 +119,16 @@ struct SimpleSampleGenerator struct SimpleSampleGenerator> { - static std::vector> Generate() + static std::vector> Generate(const std::vector&) { - return{SimpleSampleGenerator::Generate()}; + return{SimpleSampleGenerator::Generate(T())}; } }; template struct SimpleSampleGenerator::value && std::is_integral::value>> { - static std::vector Generate() + static std::vector Generate(I) { return{std::numeric_limits::min(), -1, 0, 1, std::numeric_limits::max()}; } @@ -87,25 +137,34 @@ struct SimpleSampleGenerator::value && std template struct SimpleSampleGenerator::value && std::is_integral::value>> { - static std::vector Generate() + static std::vector Generate(U defaultValue) { - return{0, 1, std::numeric_limits::max()}; + return{ defaultValue, defaultValue + 1U, std::numeric_limits::max()}; + } +}; + +template<> +struct SimpleSampleGenerator +{ + static std::vector Generate(unsigned defaultValue) + { + return{ defaultValue, defaultValue + 1, static_cast(std::numeric_limits::max())}; } }; template<> struct SimpleSampleGenerator { - static std::vector Generate() + static std::vector Generate(double) { - return{-10000.0, -1.0, 0.0, 1.0, 10000.0}; + return{0.0, 0.375, 1.0, 10000.125}; }; }; template<> struct SimpleSampleGenerator { - static std::list Generate() + static std::list Generate(bool) { return{false, true}; }; @@ -135,36 +194,7 @@ struct MemberTraits using Member = MemberT; }; -//inline std::vector GenerateNonDefaultServiceDescription() -//{ -// std::vector result; -// AddNonDefaultSamples(result); -// -// return result; -//} -// -//inline std::vector GenerateNonDefaultMachineReadyData() -//{ -// std::vector result; -// AddNonDefaultSamples(result); -// return result; -//} - -//#define HERMES_TEST_ADD_NON_DEFAULT_SAMPLES(samples, member) \ -//AddNonDefaultSamples::Class, MemberTraits::Member, member>(samples) -// -//void AddAllNonDefaultSamples(std::vector& samples) -//{ -// HERMES_TEST_ADD_NON_DEFAULT_SAMPLES(samples, &Hermes::MachineReadyData::m_boardQuality); -//} -// -//void AddAllNonDefaultSamples(std::vector& samples) -//{ -// HERMES_TEST_ADD_NON_DEFAULT_SAMPLES(samples, &Hermes::ServiceDescription::m_laneId); -// HERMES_TEST_ADD_NON_DEFAULT_SAMPLES(samples, &Hermes::ServiceDescription::m_machineId); -//} - -//HERMES_ADD_SAMPLES(Hermes::MachineReadyData, (m_boardQuality)) + template std::vector GenerateNonDefaultSamples() { @@ -174,7 +204,7 @@ std::vector GenerateNonDefaultSamples() { using MemberType = std::remove_reference_t; auto defaultValue = member; - for (const auto& sampleValue : SimpleSampleGenerator::Generate()) + for (const auto& sampleValue : SimpleSampleGenerator::Generate(defaultValue)) { if (defaultValue == sampleValue) continue; // no defaults @@ -196,7 +226,7 @@ std::vector GenerateSamples() { using MemberType = std::remove_reference_t; auto defaultValue = member; - for (const auto& sampleValue : SimpleSampleGenerator::Generate()) + for (const auto& sampleValue : SimpleSampleGenerator::Generate(defaultValue)) { if (defaultValue == sampleValue) continue; // no defaults diff --git a/test/BoostTestHermes/HermesDataReflection.h b/test/BoostTestHermes/HermesDataReflection.h index 3b7d35d..af2dc59 100644 --- a/test/BoostTestHermes/HermesDataReflection.h +++ b/test/BoostTestHermes/HermesDataReflection.h @@ -1,20 +1,33 @@ -// Copyright (c) ASM Assembly Systems GmbH & Co. KG +/*********************************************************************** +Copyright ASM Assembly Systems GmbH & Co. KG + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + #pragma once #include #include -#include +#include -using HermesDataTypes = boost::mpl::vector< - //Hermes::CheckAliveData, - Hermes::UpstreamConfiguration, - Hermes::DownstreamConfiguration, +using HermesDataTypes = boost::mpl::vector24< + Hermes::CheckAliveData, //Hermes::GetConfigurationData, Hermes::SetConfigurationData, Hermes::CurrentConfigurationData, Hermes::ConnectionInfo, - Hermes::ServiceDescription, + Hermes::ServiceDescriptionData, Hermes::MachineReadyData, //Hermes::RevokeMachineReadyData, Hermes::BoardAvailableData, @@ -23,28 +36,53 @@ using HermesDataTypes = boost::mpl::vector< Hermes::StopTransportData, Hermes::TransportFinishedData, Hermes::NotificationData, + Hermes::BoardForecastData, + Hermes::QueryBoardInfoData, + Hermes::SendBoardInfoData, Hermes::UpstreamSettings, Hermes::DownstreamSettings, - Hermes::ConfigurationServiceSettings + Hermes::ConfigurationServiceSettings, + Hermes::SupervisoryServiceDescriptionData, + Hermes::BoardArrivedData, + Hermes::BoardDepartedData, + Hermes::QueryWorkOrderInfoData, + Hermes::SendWorkOrderInfoData, + Hermes::ReplyWorkOrderInfoData, + Hermes::CommandData + //Hermes::QueryHermesCapabilitiesData, + //Hermes::SendHermesCapabilitiesData >; BOOST_FUSION_ADAPT_STRUCT(Hermes::UpstreamConfiguration, m_upstreamLaneId, + m_optionalUpstreamInterfaceId, m_hostAddress, m_port ) BOOST_FUSION_ADAPT_STRUCT(Hermes::DownstreamConfiguration, m_downstreamLaneId, + m_optionalDownstreamInterfaceId, m_optionalClientAddress, m_port ) +BOOST_FUSION_ADAPT_STRUCT(Hermes::SubBoard, + m_pos, + m_optionalBc, + m_st +) +BOOST_FUSION_ADAPT_STRUCT(Hermes::CheckAliveData, + m_optionalType, + m_optionalId +) BOOST_FUSION_ADAPT_STRUCT(Hermes::SetConfigurationData, m_machineId, + m_optionalSupervisorySystemPort, m_upstreamConfigurations, m_downstreamConfigurations ) BOOST_FUSION_ADAPT_STRUCT(Hermes::CurrentConfigurationData, m_optionalMachineId, + m_optionalSupervisorySystemPort, m_upstreamConfigurations, m_downstreamConfigurations ) @@ -53,13 +91,38 @@ BOOST_FUSION_ADAPT_STRUCT(Hermes::ConnectionInfo, m_address, m_port ) -BOOST_FUSION_ADAPT_STRUCT(Hermes::ServiceDescription, - m_laneId, +BOOST_FUSION_ADAPT_STRUCT(Hermes::SupportedFeatures, + m_optionalFeatureBoardForecast, + m_optionalFeatureCheckAliveResponse, + m_optionalFeatureQueryBoardInfo, + m_optionalFeatureSendBoardInfo, + m_optionalFeatureCommand +) + +BOOST_FUSION_ADAPT_STRUCT(Hermes::ServiceDescriptionData, m_machineId, - m_version + m_laneId, + m_optionalInterfaceId, + m_version, + m_supportedFeatures ) BOOST_FUSION_ADAPT_STRUCT(Hermes::MachineReadyData, - m_failedBoard + m_failedBoard, + m_optionalForecastId, + m_optionalBoardId, + m_optionalProductTypeId, + m_optionalFlippedBoard, + m_optionalTopBarcode, + m_optionalBottomBarcode, + m_optionalLengthInMM, + m_optionalWidthInMM, + m_optionalThicknessInMM, + m_optionalConveyorSpeedInMMPerSecs, + m_optionalTopClearanceHeightInMM, + m_optionalBottomClearanceHeightInMM, + m_optionalWeightInGrams, + m_optionalWorkOrderId, + m_optionalBatchId ) //BOOST_FUSION_ADAPT_STRUCT(Hermes::RevokeMachineReadyData) BOOST_FUSION_ADAPT_STRUCT(Hermes::BoardAvailableData, @@ -75,7 +138,13 @@ BOOST_FUSION_ADAPT_STRUCT(Hermes::BoardAvailableData, m_optionalThicknessInMM, m_optionalConveyorSpeedInMMPerSecs, m_optionalTopClearanceHeightInMM, - m_optionalBottomClearanceHeightInMM + m_optionalBottomClearanceHeightInMM, + m_optionalWeightInGrams, + m_optionalWorkOrderId, + m_optionalBatchId, + m_optionalRoute, + m_optionalAction, + m_optionalSubBoards ) //BOOST_FUSION_ADAPT_STRUCT(Hermes::RevokeBoardAvailableData) BOOST_FUSION_ADAPT_STRUCT(Hermes::StartTransportData, @@ -95,12 +164,164 @@ BOOST_FUSION_ADAPT_STRUCT(Hermes::NotificationData, m_severity, m_description ) +BOOST_FUSION_ADAPT_STRUCT(Hermes::BoardForecastData, + m_optionalForecastId, + m_optionalTimeUntilAvailableInSeconds, + m_optionalBoardId, + m_optionalBoardIdCreatedBy, + m_failedBoard, + m_optionalProductTypeId, + m_flippedBoard, + m_optionalTopBarcode, + m_optionalBottomBarcode, + m_optionalLengthInMM, + m_optionalWidthInMM, + m_optionalThicknessInMM, + m_optionalConveyorSpeedInMMPerSecs, + m_optionalTopClearanceHeightInMM, + m_optionalBottomClearanceHeightInMM, + m_optionalWeightInGrams, + m_optionalWorkOrderId, + m_optionalBatchId +) +BOOST_FUSION_ADAPT_STRUCT(Hermes::QueryBoardInfoData, + m_optionalTopBarcode, + m_optionalBottomBarcode +) +BOOST_FUSION_ADAPT_STRUCT(Hermes::SendBoardInfoData, + m_optionalBoardId, + m_optionalBoardIdCreatedBy, + m_optionalFailedBoard, + m_optionalProductTypeId, + m_optionalFlippedBoard, + m_optionalTopBarcode, + m_optionalBottomBarcode, + m_optionalLengthInMM, + m_optionalWidthInMM, + m_optionalThicknessInMM, + m_optionalConveyorSpeedInMMPerSecs, + m_optionalTopClearanceHeightInMM, + m_optionalBottomClearanceHeightInMM, + m_optionalWeightInGrams, + m_optionalWorkOrderId, + m_optionalBatchId, + m_optionalRoute, + m_optionalAction, + m_optionalSubBoards +) +BOOST_FUSION_ADAPT_STRUCT(Hermes::SupervisoryFeatures, + m_optionalFeatureConfiguration, + m_optionalFeatureCheckAliveResponse, + m_optionalFeatureBoardTracking, + m_optionalFeatureQueryWorkOrderInfo, + m_optionalFeatureSendWorkOrderInfo, + m_optionalFeatureQueryHermesCapabilities, + m_optionalFeatureSendHermesCapabilities +) +BOOST_FUSION_ADAPT_STRUCT(Hermes::SupervisoryServiceDescriptionData, + m_systemId, + m_version, + m_supportedFeatures +) +BOOST_FUSION_ADAPT_STRUCT(Hermes::BoardArrivedData, + m_machineId, + m_upstreamLaneId, + m_optionalUpstreamInterfaceId, + m_optionalMagazineId, + m_optionalSlotId, + m_boardTransfer, + m_boardId, + m_boardIdCreatedBy, + m_failedBoard, + m_optionalProductTypeId, + m_flippedBoard, + m_optionalTopBarcode, + m_optionalBottomBarcode, + m_optionalLengthInMM, + m_optionalWidthInMM, + m_optionalThicknessInMM, + m_optionalConveyorSpeedInMMPerSecs, + m_optionalTopClearanceHeightInMM, + m_optionalBottomClearanceHeightInMM, + m_optionalWeightInGrams, + m_optionalWorkOrderId, + m_optionalBatchId, + m_optionalRoute, + m_optionalAction, + m_optionalSubBoards +) +BOOST_FUSION_ADAPT_STRUCT(Hermes::BoardDepartedData, + m_machineId, + m_downstreamLaneId, + m_optionalDownstreamInterfaceId, + m_optionalMagazineId, + m_optionalSlotId, + m_boardTransfer, + m_boardId, + m_boardIdCreatedBy, + m_failedBoard, + m_optionalProductTypeId, + m_flippedBoard, + m_optionalTopBarcode, + m_optionalBottomBarcode, + m_optionalLengthInMM, + m_optionalWidthInMM, + m_optionalThicknessInMM, + m_optionalConveyorSpeedInMMPerSecs, + m_optionalTopClearanceHeightInMM, + m_optionalBottomClearanceHeightInMM, + m_optionalWeightInGrams, + m_optionalWorkOrderId, + m_optionalBatchId, + m_optionalRoute, + m_optionalAction, + m_optionalSubBoards +) +BOOST_FUSION_ADAPT_STRUCT(Hermes::QueryWorkOrderInfoData, + m_optionalQueryId, + m_machineId, + m_optionalMagazineId, + m_optionalSlotId, + m_optionalBarcode, + m_optionalWorkOrderId, + m_optionalBatchId +) +BOOST_FUSION_ADAPT_STRUCT(Hermes::SendWorkOrderInfoData, + m_optionalQueryId, + m_optionalWorkOrderId, + m_optionalBatchId, + m_optionalBoardId, + m_optionalBoardIdCreatedBy, + m_optionalFailedBoard, + m_optionalProductTypeId, + m_optionalFlippedBoard, + m_optionalTopBarcode, + m_optionalBottomBarcode, + m_optionalLengthInMM, + m_optionalWidthInMM, + m_optionalThicknessInMM, + m_optionalConveyorSpeedInMMPerSecs, + m_optionalTopClearanceHeightInMM, + m_optionalBottomClearanceHeightInMM, + m_optionalWeightInGrams, + m_optionalRoute, + m_optionalSubBoards +) +BOOST_FUSION_ADAPT_STRUCT(Hermes::ReplyWorkOrderInfoData, + m_workOrderId, + m_optionalBatchId, + m_status +) +BOOST_FUSION_ADAPT_STRUCT(Hermes::CommandData, + m_command +) BOOST_FUSION_ADAPT_STRUCT(Hermes::UpstreamSettings, m_machineId, m_hostAddress, m_port, m_checkAlivePeriodInSeconds, m_reconnectWaitTimeInSeconds, + m_checkAliveResponseMode, m_checkState ) BOOST_FUSION_ADAPT_STRUCT(Hermes::DownstreamSettings, @@ -109,6 +330,7 @@ BOOST_FUSION_ADAPT_STRUCT(Hermes::DownstreamSettings, m_port, m_checkAlivePeriodInSeconds, m_reconnectWaitTimeInSeconds, + m_checkAliveResponseMode, m_checkState ) BOOST_FUSION_ADAPT_STRUCT(Hermes::ConfigurationServiceSettings, diff --git a/test/BoostTestHermes/HermesDataTest.cpp b/test/BoostTestHermes/HermesDataTest.cpp index acb8e18..666b567 100644 --- a/test/BoostTestHermes/HermesDataTest.cpp +++ b/test/BoostTestHermes/HermesDataTest.cpp @@ -27,8 +27,9 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(HermesCApiTest, T, HermesDataTypes) for (const auto& sample: samples) { - auto apiData = ToC(sample); - auto roundTrippedSample = Hermes::ToCpp(*(&apiData)); + Hermes::Converter2C converter(sample); + auto* pData = converter.CPointer(); + auto roundTrippedSample = Hermes::ToCpp(*pData); BOOST_TEST(sample == roundTrippedSample); BOOST_TEST(!(sample != roundTrippedSample)); } diff --git a/test/BoostTestHermes/QueryAndSendBoardInfoTest.cpp b/test/BoostTestHermes/QueryAndSendBoardInfoTest.cpp new file mode 100644 index 0000000..a9adb3a --- /dev/null +++ b/test/BoostTestHermes/QueryAndSendBoardInfoTest.cpp @@ -0,0 +1,79 @@ +// Copyright (c) ASM Assembly Systems GmbH & Co. KG +#include "stdafx.h" + +#include "Runner.h" +#include "Sinks.h" + +using namespace Hermes; + +BOOST_AUTO_TEST_CASE(QueryAndSendBoardInfoTest) +{ + TestCaseScope scope("QueryAndSendBoardInfoTest"); + + std::string upstreamMachineId{"UpstreamMachineId"}; + std::string downstreamMachineId{"DownstreamMachineId"}; + + DownstreamSink downstreamSink; + Hermes::Downstream downstream(1U, downstreamSink); + Runner downstreamRunner(downstream); + + UpstreamSink upstreamSink; + Hermes::Upstream upstream(1U, upstreamSink); + Runner upstreamRunner(upstream); + + // suppress periodic CheckAlive on both sides + DownstreamSettings downstreamSettings{upstreamMachineId, 50101}; + downstreamSettings.m_checkAlivePeriodInSeconds = 0; + downstream.Enable(downstreamSettings); + + Hermes::UpstreamSettings upstreamSettings(downstreamMachineId, "127.0.0.1", 50101); + upstreamSettings.m_checkAlivePeriodInSeconds = 0; + upstream.Enable(upstreamSettings); + + // set ServiceDescription accordingly: + Hermes::ServiceDescriptionData upstreamServiceDescription{downstreamMachineId, 1U}; + upstreamServiceDescription.m_supportedFeatures.m_optionalFeatureSendBoardInfo = FeatureSendBoardInfo{}; + Hermes::ServiceDescriptionData downstreamServiceDescription{upstreamMachineId, 1U}; + downstreamServiceDescription.m_supportedFeatures.m_optionalFeatureQueryBoardInfo = FeatureQueryBoardInfo{}; + + // wait until connection is established + WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eSOCKET_CONNECTED; }); + WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eSOCKET_CONNECTED; }); + upstream.Signal(upstreamSink.m_sessionId, upstreamServiceDescription); + WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eSERVICE_DESCRIPTION_DOWNSTREAM; }); + downstream.Signal(downstreamSink.m_sessionId, downstreamServiceDescription); + + WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eNOT_AVAILABLE_NOT_READY; }); + WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eNOT_AVAILABLE_NOT_READY; }); + + // verify ServiceDescription: + BOOST_TEST(downstreamSink.m_serviceDescription == upstreamServiceDescription); + BOOST_TEST(upstreamSink.m_serviceDescription == downstreamServiceDescription); + + // make sure, we have no data to start with: + BOOST_TEST(!downstreamSink.m_queryBoardInfoData.m_optionalTopBarcode); + BOOST_TEST(!upstreamSink.m_sendBoardInfoData.m_optionalTopBarcode); + + // Send QueryBoardInfo from downstream to upstream + QueryBoardInfoData query; + query.m_optionalTopBarcode = "Top"; + query.m_optionalBottomBarcode = "Bottom"; + upstream.Signal(upstreamSink.m_sessionId, query); + ::WaitFor(downstreamSink, [&]() { return downstreamSink.m_queryBoardInfoData.m_optionalTopBarcode.has_value(); }); + BOOST_TEST(downstreamSink.m_queryBoardInfoData == query); + + // Respond with SendBoardInfo from upstream to downstream + SendBoardInfoData info; + info.m_optionalTopBarcode = "TopResponse"; + info.m_optionalBottomBarcode = "BottomResponse"; + info.m_optionalBoardId = "BoardId"; + info.m_optionalBoardIdCreatedBy = "CreatedBy"; + + info.m_optionalSubBoards.emplace_back(Hermes::SubBoard{1, Hermes::ESubBoardState::eGOOD}); + info.m_optionalSubBoards.emplace_back(Hermes::SubBoard{2, Hermes::ESubBoardState::eSKIP}); + + downstream.Signal(downstreamSink.m_sessionId, info); + ::WaitFor(upstreamSink, [&]() { return upstreamSink.m_sendBoardInfoData.m_optionalTopBarcode.has_value(); }); + BOOST_TEST(upstreamSink.m_sendBoardInfoData == info); +} + diff --git a/test/BoostTestHermes/RawXmlTest.cpp b/test/BoostTestHermes/RawXmlTest.cpp new file mode 100644 index 0000000..6784ef5 --- /dev/null +++ b/test/BoostTestHermes/RawXmlTest.cpp @@ -0,0 +1,201 @@ +// Copyright (c) ASM Assembly Systems GmbH & Co. KG +#include "stdafx.h" + +#include "Runner.h" +#include "Sinks.h" + +#include + +using namespace Hermes; + + +BOOST_AUTO_TEST_CASE(TestRawXml) +{ + TestCaseScope scope("TestRawXml"); + + std::string upstreamMachineId{"UpstreamMachineId"}; + std::string downstreamMachineId{"DownstreamMachineId"}; + + std::string boardId{"123e4567-e89b-12d3-a456-426655440000"}; + + UpstreamSink upstreamSink; + Hermes::Upstream upstream(1U, upstreamSink); + Runner upstreamRunner(upstream); + upstream.Enable(Hermes::UpstreamSettings(downstreamMachineId, "localhost", 50101)); + + DownstreamSink downstreamSink; + Hermes::Downstream downstream(1U, downstreamSink); + Runner downstreamRunner(downstream); + downstream.Enable(Hermes::DownstreamSettings(downstreamMachineId, 50101)); + + WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eSOCKET_CONNECTED; }); + WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eSOCKET_CONNECTED; }); + upstream.Signal(upstreamSink.m_sessionId, ToXml(Hermes::ServiceDescriptionData(downstreamMachineId, 1U))); + WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eSERVICE_DESCRIPTION_DOWNSTREAM; }); + downstream.Signal(downstreamSink.m_sessionId, ToXml(Hermes::ServiceDescriptionData(upstreamMachineId, 1U))); + WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eNOT_AVAILABLE_NOT_READY; }); + WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eNOT_AVAILABLE_NOT_READY; }); + + { + NotificationData data{ENotificationCode::eCONFIGURATION_ERROR, ESeverity::eINFO, "myNotification"}; + auto rawXml = ToXml(data); + upstream.Signal(upstreamSink.m_sessionId, rawXml); + WaitFor(downstreamSink, [&]() { return downstreamSink.m_notificationData == data; }); + } + { + CheckAliveData data{}; + auto rawXml = ToXml(data); + upstream.Signal(upstreamSink.m_sessionId, rawXml); + } + + { + NotificationData data{ENotificationCode::eCONFIGURATION_ERROR, ESeverity::eINFO, "myNotification"}; + auto rawXml = ToXml(data); + downstream.Signal(downstreamSink.m_sessionId, rawXml); + WaitFor(upstreamSink, [&]() { return upstreamSink.m_notificationData == data; }); + } + { + CheckAliveData data{}; + auto rawXml = ToXml(data); + downstream.Signal(downstreamSink.m_sessionId, rawXml); + } + { + MachineReadyData data{}; + auto rawXml = ToXml(data); + upstream.Signal(upstreamSink.m_sessionId, rawXml); + WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eMACHINE_READY; }); + } + { + RevokeMachineReadyData data{}; + auto rawXml = ToXml(data); + upstream.Signal(upstreamSink.m_sessionId, rawXml); + WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eNOT_AVAILABLE_NOT_READY; }); + } + { + BoardAvailableData data{boardId, upstreamMachineId, Hermes::EBoardQuality::eANY, Hermes::EFlippedBoard::eSIDE_UP_IS_UNKNOWN}; + auto rawXml = ToXml(data); + downstream.Signal(downstreamSink.m_sessionId, rawXml); + WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eBOARD_AVAILABLE; }); + } + { + RevokeBoardAvailableData data{}; + auto rawXml = ToXml(data); + downstream.Signal(downstreamSink.m_sessionId, rawXml); + WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eBOARD_AVAILABLE; }); + } + { + MachineReadyData data{}; + auto rawXml = ToXml(data); + upstream.Signal(upstreamSink.m_sessionId, rawXml); + WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eMACHINE_READY; }); + } + { + BoardAvailableData data{boardId, upstreamMachineId, Hermes::EBoardQuality::eGOOD, Hermes::EFlippedBoard::eTOP_SIDE_IS_UP}; + auto rawXml = ToXml(data); + downstream.Signal(downstreamSink.m_sessionId, rawXml); + WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eAVAILABLE_AND_READY; }); + } + { + StartTransportData data{boardId}; + auto rawXml = ToXml(data); + upstream.Signal(upstreamSink.m_sessionId, rawXml); + WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eTRANSPORTING; }); + } + { + TransportFinishedData data{ETransferState::eCOMPLETE, boardId}; + auto rawXml = ToXml(data); + downstream.Signal(downstreamSink.m_sessionId, rawXml); + WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eTRANSPORT_FINISHED; }); + } + { + StopTransportData data{ETransferState::eCOMPLETE, boardId}; + auto rawXml = ToXml(data); + upstream.Signal(upstreamSink.m_sessionId, rawXml); + WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eNOT_AVAILABLE_NOT_READY; }); + WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eNOT_AVAILABLE_NOT_READY; }); + } + { + NotificationData data{ENotificationCode::eMACHINE_SHUTDOWN, ESeverity::eINFO, "myShutdown"}; + upstream.Reset(data); + } + { + NotificationData data{ENotificationCode::eMACHINE_SHUTDOWN, ESeverity::eINFO, "myShutdown"}; + downstream.Reset(data); + } +} + +BOOST_AUTO_TEST_CASE(TestVerticalRawXml) +{ + TestCaseScope scope("TestVerticalRawXml"); + + std::string serviceId{ "VerticalServiceId" }; + std::string clientId{ "VerticalClientId" }; + uint16_t verticalPort{ 50201 }; + + std::string boardId{ "123e4567-e89b-12d3-a456-426655440000" }; + + VerticalServiceSink serviceSink; + Hermes::VerticalService service{ serviceSink }; + Runner serviceRunner{ service }; + VerticalServiceSettings serviceSettings{ serviceId, verticalPort }; + serviceSettings.m_checkAlivePeriodInSeconds = 0.0; + service.Enable(serviceSettings); + + VerticalClientSink clientSink; + Hermes::VerticalClient client(clientSink); + Runner clientRunner(client); + Hermes::VerticalClientSettings clientSettings{ clientId, "localhost", verticalPort }; + clientSettings.m_checkAlivePeriodInSeconds = 0.0; + client.Enable(clientSettings); + + WaitFor(clientSink, [&]() { return clientSink.m_state == EVerticalState::eSOCKET_CONNECTED; }); + WaitFor(serviceSink, [&]() { return !serviceSink.m_sessionMap.empty(); }); + + auto& serviceSession = serviceSink.m_sessionMap.begin()->second; + auto serviceSessionId = serviceSink.m_sessionMap.begin()->first; + auto clientSessionId = clientSink.m_sessionId; + + client.Signal(clientSessionId, ToXml(Hermes::SupervisoryServiceDescriptionData(clientId))); + WaitFor(serviceSink, [&]() { return serviceSession.m_state == EVerticalState::eSUPERVISORY_SERVICE_DESCRIPTION; }); + service.Signal(serviceSessionId, Hermes::SupervisoryServiceDescriptionData(serviceId)); + WaitFor(clientSink, [&]() { return clientSink.m_state == EVerticalState::eCONNECTED; }); + + { + NotificationData data{ ENotificationCode::eCONFIGURATION_ERROR, ESeverity::eINFO, "myNotification" }; + auto rawXml = ToXml(data); + client.Signal(clientSessionId, rawXml); + WaitFor(serviceSink, [&]() { return serviceSession.m_notificationData == data; }); + } + { + CheckAliveData data{}; + auto rawXml = ToXml(data); + client.Signal(clientSessionId, rawXml); + WaitFor(serviceSink, [&]() { return serviceSession.m_checkAliveData == data; }); + } + { + GetConfigurationData data{}; + auto rawXml = ToXml(data); + client.Signal(clientSessionId, rawXml); + WaitFor(serviceSink, [&]() { return serviceSession.m_getConfigurationData == data; }); + } + { + SetConfigurationData data{}; + data.m_machineId = "MyId"; + data.m_downstreamConfigurations.emplace_back(2U, verticalPort); + data.m_upstreamConfigurations.emplace_back(2U, "MyAddress", verticalPort); + auto rawXml = ToXml(data); + client.Signal(clientSessionId, rawXml); + WaitFor(serviceSink, [&]() { return serviceSession.m_setConfigurationData == data; }); + } + { + SendWorkOrderInfoData data{}; + data.m_optionalBottomBarcode = "BottomBarcode"; + auto rawXml = ToXml(data); + client.Signal(clientSessionId, rawXml); + WaitFor(serviceSink, [&]() { return serviceSession.m_sendWorkOrderInfoData == data; }); + } + { + NotificationData data{ ENotificationCode::eMACHINE_SHUTDOWN, ESeverity::eINFO, "myShutdown" }; + client.Reset(ToXml(data)); + } +} diff --git a/test/BoostTestHermes/SerializerTest.cpp b/test/BoostTestHermes/SerializerTest.cpp index a10b573..2a6a373 100644 --- a/test/BoostTestHermes/SerializerTest.cpp +++ b/test/BoostTestHermes/SerializerTest.cpp @@ -1,4 +1,19 @@ -// Copyright (c) ASM Assembly Systems GmbH & Co. KG +/*********************************************************************** +Copyright 2018 ASM Assembly Systems GmbH & Co. KG + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + #include "stdafx.h" #include @@ -10,33 +25,57 @@ #include +#include + using EmptyHermesDataTypes = boost::mpl::vector< - Hermes::CheckAliveData, Hermes::RevokeBoardAvailableData, Hermes::RevokeMachineReadyData, Hermes::GetConfigurationData>; using NonEmptyHermesDataTypes = boost::mpl::vector< - Hermes::ServiceDescription, + Hermes::CheckAliveData, + Hermes::ServiceDescriptionData, Hermes::NotificationData, Hermes::BoardAvailableData, Hermes::MachineReadyData, Hermes::StartTransportData, Hermes::StopTransportData, + Hermes::BoardForecastData, + Hermes::QueryBoardInfoData, + Hermes::SendBoardInfoData, Hermes::TransportFinishedData, Hermes::SetConfigurationData, - Hermes::CurrentConfigurationData>; + Hermes::CurrentConfigurationData, + Hermes::SupervisoryServiceDescriptionData, + Hermes::BoardArrivedData, + Hermes::BoardDepartedData, + Hermes::QueryWorkOrderInfoData, + Hermes::SendWorkOrderInfoData>; +template +void ToFile(unsigned counter, const std::string& xml) +{ + std::string typeName{typeid(T).name()}; + auto pos = typeName.find(':'); + if (pos != std::string::npos) + { + typeName.erase(0U, pos + 2U); + } + std::string fileName{"C:\\GeneratedHermesData\\" + typeName + std::to_string(counter) + ".xml"}; + std::ofstream file{fileName}; + file << xml; +} BOOST_AUTO_TEST_CASE_TEMPLATE(TestEmptyHermesDataTypes, DataT, EmptyHermesDataTypes) { DataT data; std::string xml = ToXml(data); - auto optionalData = Hermes::ToOptionalData(xml); + //ToFile(1U, xml); + auto optionalData = Hermes::FromXml(xml); BOOST_CHECK(optionalData); if (optionalData) { - BOOST_CHECK_EQUAL(data, *optionalData); + BOOST_TEST(data == *optionalData); } } @@ -46,15 +85,74 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(TestNonEmptyHermesDataTypes, DataT, NonEmptyHermes for (const auto& data : samples) { std::string xml = ToXml(data); - auto optionalData = Hermes::ToOptionalData(xml); + //ToFile(++counter, xml); + + auto optionalData = Hermes::FromXml(xml); BOOST_CHECK(optionalData); if (optionalData) { - BOOST_CHECK_EQUAL(data, *optionalData); + BOOST_TEST(data == optionalData); } } } +template +void TestSubBoardsCutoff_(T& data, const uint16_t maxSubBoards) +{ + auto& subBoards = data.m_optionalSubBoards; + + data.m_optionalSubBoards.reserve(maxSubBoards + 1); + for (uint16_t i{ 0 }; i < maxSubBoards; ++i) + { + subBoards.emplace_back(); + subBoards.back().m_pos = i + 1; + subBoards.back().m_optionalBc = std::to_string(i); + } + // maxCount and contents were carefully tweaked to yield slightly less or equal to max message size: + auto xml = ToXml(data); + BOOST_CHECK(xml.size() <= cHERMES_MAX_MESSAGE_SIZE); + auto optionalData = Hermes::FromXml(xml); + BOOST_CHECK(optionalData == data); + subBoards.emplace_back(); + subBoards.back().m_optionalBc = "AVeryLongBarcodeStringThatWillSurelyExceedTheMaximumHermesMessageSizeOf65536Bytes"; + xml = ToXml(data); + BOOST_CHECK(xml.size() < cHERMES_MAX_MESSAGE_SIZE/2); // size should have become a lot smaller + optionalData = Hermes::FromXml(xml); + BOOST_CHECK(optionalData != data); + subBoards.clear(); + BOOST_CHECK(optionalData == data); +} + +BOOST_AUTO_TEST_CASE(TestBoardAvailableSubBoardInfoSerializationCutOff) +{ + Hermes::BoardAvailableData data{ "0e4c18f9-5f69-4dbe-9b1c-e705bf7d680f", "123456", Hermes::EBoardQuality::eGOOD, + Hermes::EFlippedBoard::eTOP_SIDE_IS_UP }; + + TestSubBoardsCutoff_(data, 1777); +} + +BOOST_AUTO_TEST_CASE(TestBoardArrivedSubBoardInfoSerializationCutOff) +{ + Hermes::BoardArrivedData data{ "M", 1, Hermes::EBoardArrivedTransfer::eINSERTED, + "0e4c18f9-4dbe-9b1c-e705bf7d680f", "Cr", Hermes::EBoardQuality::eGOOD, Hermes::EFlippedBoard::eTOP_SIDE_IS_UP }; + + TestSubBoardsCutoff_(data, 1776); +} + +BOOST_AUTO_TEST_CASE(TestBoardDepartedSubBoardInfoSerializationCutOff) +{ + Hermes::BoardDepartedData data{ "M", 1, Hermes::EBoardDepartedTransfer::eREMOVED, + "0e4c18f9-9b1c-e705bf7d680f", "Cr", Hermes::EBoardQuality::eGOOD, Hermes::EFlippedBoard::eTOP_SIDE_IS_UP }; + + TestSubBoardsCutoff_(data, 1776); +} + +BOOST_AUTO_TEST_CASE(TestSendWorkOrderInfoSubBoardInfoSerializationCutOff) +{ + Hermes::SendWorkOrderInfoData data{std::string{"MyVeryLongQueryId"}}; + + TestSubBoardsCutoff_(data, 1778); +} diff --git a/test/BoostTestHermes/Sinks.h b/test/BoostTestHermes/Sinks.h index 8db5f0d..8d57f98 100644 --- a/test/BoostTestHermes/Sinks.h +++ b/test/BoostTestHermes/Sinks.h @@ -45,11 +45,14 @@ namespace Hermes unsigned m_sessionId{0U}; EState m_state{EState::eNOT_CONNECTED}; ConnectionInfo m_connectionInfo; - ServiceDescription m_serviceDescription; + ServiceDescriptionData m_serviceDescription; MachineReadyData m_machineReadyData; StartTransportData m_startTransportData; StopTransportData m_stopTransportData; + QueryBoardInfoData m_queryBoardInfoData; NotificationData m_notificationData; + CommandData m_commandData; + CheckAliveData m_checkAliveData; void OnConnected(unsigned sessionId, EState state, const Hermes::ConnectionInfo& connectionInfo) override { @@ -59,7 +62,7 @@ namespace Hermes m_connectionInfo = connectionInfo; } - void On(unsigned sessionId, EState state, const Hermes::ServiceDescription& serviceDescription) override + void On(unsigned sessionId, EState state, const Hermes::ServiceDescriptionData& serviceDescription) override { ChangeLock lock(this); m_state = state; @@ -74,6 +77,20 @@ namespace Hermes m_sessionId = sessionId; } + void On(unsigned sessionId, const Hermes::CommandData& data) override + { + ChangeLock lock(this); + m_commandData = data; + m_sessionId = sessionId; + } + + void On(unsigned sessionId, const Hermes::CheckAliveData& data) override + { + ChangeLock lock(this); + m_checkAliveData = data; + m_sessionId = sessionId; + } + void OnState(unsigned sessionId, EState state) override { ChangeLock lock(this); @@ -88,7 +105,6 @@ namespace Hermes m_sessionId = sessionId; } - void On(unsigned sessionId, EState state, const Hermes::MachineReadyData& data) override { ChangeLock lock(this); @@ -120,6 +136,12 @@ namespace Hermes m_sessionId = sessionId; } + void On(unsigned sessionId, const Hermes::QueryBoardInfoData& data) override + { + ChangeLock lock(this); + m_queryBoardInfoData = data; + m_sessionId = sessionId; + } void OnTrace(unsigned sessionId, ETraceType type, StringView trace) override { @@ -136,10 +158,14 @@ namespace Hermes unsigned m_sessionId{0U}; EState m_state{EState::eNOT_CONNECTED}; ConnectionInfo m_connectionInfo; - ServiceDescription m_serviceDescription; + ServiceDescriptionData m_serviceDescription; BoardAvailableData m_boardAvailableData; TransportFinishedData m_transportFinishedData; + BoardForecastData m_boardForecastData; + SendBoardInfoData m_sendBoardInfoData; NotificationData m_notificationData; + CommandData m_commandData; + CheckAliveData m_checkAliveData; void OnConnected(unsigned sessionId, EState state, const Hermes::ConnectionInfo& connectionInfo) override { @@ -149,7 +175,7 @@ namespace Hermes m_connectionInfo = connectionInfo; } - void On(unsigned sessionId, EState state, const Hermes::ServiceDescription& serviceDescription) override + void On(unsigned sessionId, EState state, const Hermes::ServiceDescriptionData& serviceDescription) override { ChangeLock lock(this); m_state = state; @@ -164,6 +190,20 @@ namespace Hermes m_notificationData = data; } + void On(unsigned sessionId, const Hermes::CommandData& data) override + { + ChangeLock lock(this); + m_sessionId = sessionId; + m_commandData = data; + } + + void On(unsigned sessionId, const Hermes::CheckAliveData& data) override + { + ChangeLock lock(this); + m_checkAliveData = data; + m_sessionId = sessionId; + } + void OnState(unsigned sessionId, EState state) override { ChangeLock lock(this); @@ -202,6 +242,21 @@ namespace Hermes m_transportFinishedData = data; } + void On(unsigned sessionId, EState state, const Hermes::BoardForecastData& data) override + { + ChangeLock lock(this); + m_state = state; + m_sessionId = sessionId; + m_boardForecastData = data; + } + + void On(unsigned sessionId, const Hermes::SendBoardInfoData& data) override + { + ChangeLock lock(this); + m_sessionId = sessionId; + m_sendBoardInfoData = data; + } + void OnTrace(unsigned sessionId, ETraceType type, StringView trace) override { TestTrace("UpstreamTrace", type, sessionId, trace); @@ -209,6 +264,197 @@ namespace Hermes }; + struct VerticalServiceSink : IVerticalServiceCallback + { + Mutex m_mutex; + Cv m_cv; + using ChangeLock = ::ChangeLock; + + struct Session + { + unsigned m_sessionId{ 0U }; + EVerticalState m_state{ EVerticalState::eNOT_CONNECTED }; + Hermes::Optional m_connectionInfo; + Hermes::Optional m_serviceDescription; + Hermes::Optional m_getConfigurationData; + Hermes::Optional m_setConfigurationData; + Hermes::Optional m_sendWorkOrderInfoData; + Hermes::Optional m_notificationData; + Hermes::Optional m_checkAliveData; + Hermes::Optional m_queryHermesCapabilitiesData; + }; + std::map m_sessionMap; + + void OnConnected(unsigned sessionId, EVerticalState state, const Hermes::ConnectionInfo& connectionInfo) override + { + ChangeLock lock(this); + auto& session = m_sessionMap[sessionId]; + session.m_state = state; + session.m_sessionId = sessionId; + session.m_connectionInfo = connectionInfo; + } + + void On(unsigned sessionId, EVerticalState state, const Hermes::SupervisoryServiceDescriptionData& serviceDescription) override + { + ChangeLock lock(this); + auto& session = m_sessionMap[sessionId]; + session.m_state = state; + session.m_serviceDescription = serviceDescription; + } + + void On(unsigned sessionId, const Hermes::GetConfigurationData& data, const ConnectionInfo&) override + { + ChangeLock lock(this); + m_sessionMap[sessionId].m_getConfigurationData = data; + } + + void On(unsigned sessionId, const Hermes::SetConfigurationData& data, const ConnectionInfo&) override + { + ChangeLock lock(this); + m_sessionMap[sessionId].m_setConfigurationData = data; + } + + void On(unsigned sessionId, const Hermes::SendWorkOrderInfoData& data) override + { + ChangeLock lock(this); + m_sessionMap[sessionId].m_sendWorkOrderInfoData = data; + } + + void On(unsigned sessionId, const Hermes::NotificationData& data) override + { + ChangeLock lock(this); + m_sessionMap[sessionId].m_notificationData = data; + } + + void On(unsigned sessionId, const Hermes::CheckAliveData& data) override + { + ChangeLock lock(this); + m_sessionMap[sessionId].m_checkAliveData = data; + } + + void On(unsigned sessionId, const Hermes::QueryHermesCapabilitiesData& data) override + { + ChangeLock lock(this); + m_sessionMap[sessionId].m_queryHermesCapabilitiesData = data; + } + + void OnDisconnected(unsigned sessionId, EVerticalState state, const Hermes::Error&) override + { + ChangeLock lock(this); + m_sessionMap[sessionId].m_state = state; + } + + void OnTrace(unsigned sessionId, ETraceType type, StringView trace) override + { + TestTrace("VerticalServiceTrace", type, sessionId, trace); + } + + }; + + struct VerticalClientSink : IVerticalClientCallback + { + Mutex m_mutex; + Cv m_cv; + using ChangeLock = ::ChangeLock; + + unsigned m_sessionId{ 0U }; + EVerticalState m_state{ EVerticalState::eNOT_CONNECTED }; + Hermes::Optional m_connectionInfo; + Hermes::Optional m_serviceDescription; + Hermes::Optional m_currentConfigurationData; + Hermes::Optional m_boardArrivedData; + Hermes::Optional m_boardDepartedData; + Hermes::Optional m_queryWorkOrderInfoData; + Hermes::Optional m_replyWorkOrderInfoData; + Hermes::Optional m_notificationData; + Hermes::Optional m_checkAliveData; + Hermes::Optional m_sendHermesCapabilitiesData; + + void OnConnected(unsigned sessionId, EVerticalState state, const Hermes::ConnectionInfo& connectionInfo) override + { + ChangeLock lock(this); + m_state = state; + m_sessionId = sessionId; + m_connectionInfo = connectionInfo; + } + void On(unsigned sessionId, EVerticalState state, const Hermes::SupervisoryServiceDescriptionData& serviceDescription) override + { + ChangeLock lock(this); + m_state = state; + m_sessionId = sessionId; + m_serviceDescription = serviceDescription; + } + + void On(unsigned sessionId, const Hermes::CurrentConfigurationData& data) override + { + ChangeLock lock(this); + m_sessionId = sessionId; + m_currentConfigurationData = data; + } + + void On(unsigned sessionId, const Hermes::BoardArrivedData& data) override + { + ChangeLock lock(this); + m_sessionId = sessionId; + m_boardArrivedData = data; + } + + void On(unsigned sessionId, const Hermes::BoardDepartedData& data) override + { + ChangeLock lock(this); + m_sessionId = sessionId; + m_boardDepartedData = data; + } + + void On(unsigned sessionId, const Hermes::QueryWorkOrderInfoData& data) override + { + ChangeLock lock(this); + m_sessionId = sessionId; + m_queryWorkOrderInfoData = data; + } + + void On(unsigned sessionId, const Hermes::ReplyWorkOrderInfoData& data) override + { + ChangeLock lock(this); + m_sessionId = sessionId; + m_replyWorkOrderInfoData = data; + } + + void On(unsigned sessionId, const Hermes::SendHermesCapabilitiesData& data) override + { + ChangeLock lock(this); + m_sessionId = sessionId; + m_sendHermesCapabilitiesData = data; + } + + void On(unsigned sessionId, const Hermes::NotificationData& data) override + { + ChangeLock lock(this); + m_sessionId = sessionId; + m_notificationData = data; + } + + void On(unsigned sessionId, const Hermes::CheckAliveData& data) override + { + ChangeLock lock(this); + m_sessionId = sessionId; + m_checkAliveData = data; + } + + void OnDisconnected(unsigned sessionId, EVerticalState state, const Hermes::Error&) override + { + ChangeLock lock(this); + m_sessionId = sessionId; + m_state = state; + } + + + void OnTrace(unsigned sessionId, ETraceType type, StringView trace) override + { + TestTrace("VerticalClientTrace", type, sessionId, trace); + } + + }; } diff --git a/test/BoostTestHermes/UpstreamTest.cpp b/test/BoostTestHermes/UpstreamTest.cpp index 1fe8741..523b177 100644 --- a/test/BoostTestHermes/UpstreamTest.cpp +++ b/test/BoostTestHermes/UpstreamTest.cpp @@ -1,4 +1,19 @@ -// Copyright (c) ASM Assembly Systems GmbH & Co. KG +/*********************************************************************** +Copyright ASM Assembly Systems GmbH & Co. KG + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + #include "stdafx.h" #include "Runner.h" @@ -65,9 +80,9 @@ BOOST_AUTO_TEST_CASE(UpstreamTest) WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eSOCKET_CONNECTED; }); WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eSOCKET_CONNECTED; }); - upstream.Signal(upstreamSink.m_sessionId, Hermes::ServiceDescription(downstreamMachineId, 1U)); + upstream.Signal(upstreamSink.m_sessionId, Hermes::ServiceDescriptionData(downstreamMachineId, 1U)); WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eSERVICE_DESCRIPTION_DOWNSTREAM; }); - downstream.Signal(downstreamSink.m_sessionId, Hermes::ServiceDescription(upstreamMachineId, 1U)); + downstream.Signal(downstreamSink.m_sessionId, Hermes::ServiceDescriptionData(upstreamMachineId, 1U)); WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eNOT_AVAILABLE_NOT_READY; }); WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eNOT_AVAILABLE_NOT_READY; }); } @@ -81,9 +96,9 @@ BOOST_AUTO_TEST_CASE(UpstreamTest) WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eSOCKET_CONNECTED; }); WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eSOCKET_CONNECTED; }); - upstream.Signal(upstreamSink.m_sessionId, Hermes::ServiceDescription(downstreamMachineId, 1U)); + upstream.Signal(upstreamSink.m_sessionId, Hermes::ServiceDescriptionData(downstreamMachineId, 1U)); WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eSERVICE_DESCRIPTION_DOWNSTREAM; }); - downstream.Signal(downstreamSink.m_sessionId, Hermes::ServiceDescription(upstreamMachineId, 1U)); + downstream.Signal(downstreamSink.m_sessionId, Hermes::ServiceDescriptionData(upstreamMachineId, 1U)); WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eNOT_AVAILABLE_NOT_READY; }); WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eNOT_AVAILABLE_NOT_READY; }); @@ -116,6 +131,13 @@ BOOST_AUTO_TEST_CASE(UpstreamTest) upstream.Signal(upstreamSink.m_sessionId, upstreamNotification); WaitFor(downstreamSink, [&]() { return downstreamSink.m_notificationData == upstreamNotification; }); WaitFor(upstreamSink, [&]() { return upstreamSink.m_notificationData == downstreamNotification; }); + + CommandData downstreamCommand(0); + CommandData upstreamCommand(1); + downstream.Signal(downstreamSink.m_sessionId, downstreamCommand); + upstream.Signal(upstreamSink.m_sessionId, upstreamCommand); + WaitFor(downstreamSink, [&]() { return downstreamSink.m_commandData == upstreamCommand; }); + WaitFor(upstreamSink, [&]() { return upstreamSink.m_commandData == downstreamCommand; }); } { @@ -126,9 +148,9 @@ BOOST_AUTO_TEST_CASE(UpstreamTest) WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eSOCKET_CONNECTED; }); WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eSOCKET_CONNECTED; }); - upstream.Signal(upstreamSink.m_sessionId, Hermes::ServiceDescription(downstreamMachineId, 1U)); + upstream.Signal(upstreamSink.m_sessionId, Hermes::ServiceDescriptionData(downstreamMachineId, 1U)); WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eSERVICE_DESCRIPTION_DOWNSTREAM; }); - downstream.Signal(downstreamSink.m_sessionId, Hermes::ServiceDescription(upstreamMachineId, 1U)); + downstream.Signal(downstreamSink.m_sessionId, Hermes::ServiceDescriptionData(upstreamMachineId, 1U)); WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eNOT_AVAILABLE_NOT_READY; }); WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eNOT_AVAILABLE_NOT_READY; }); @@ -137,9 +159,9 @@ BOOST_AUTO_TEST_CASE(UpstreamTest) downstream.Reset(NotificationData(ENotificationCode::eCONNECTION_RESET_BECAUSE_OF_CHANGED_CONFIGURATION, ESeverity::eINFO, "ResetDownstream")); WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eSOCKET_CONNECTED; }); WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eSOCKET_CONNECTED; }); - upstream.Signal(upstreamSink.m_sessionId, Hermes::ServiceDescription(downstreamMachineId, 1U)); + upstream.Signal(upstreamSink.m_sessionId, Hermes::ServiceDescriptionData(downstreamMachineId, 1U)); WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eSERVICE_DESCRIPTION_DOWNSTREAM; }); - downstream.Signal(downstreamSink.m_sessionId, Hermes::ServiceDescription(upstreamMachineId, 1U)); + downstream.Signal(downstreamSink.m_sessionId, Hermes::ServiceDescriptionData(upstreamMachineId, 1U)); WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eNOT_AVAILABLE_NOT_READY && upstreamSink.m_sessionId == upstreamSessionId; }); WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eNOT_AVAILABLE_NOT_READY && downstreamSink.m_sessionId == downstreamSessionId; }); @@ -148,9 +170,9 @@ BOOST_AUTO_TEST_CASE(UpstreamTest) upstream.Reset(NotificationData(ENotificationCode::eCONNECTION_RESET_BECAUSE_OF_CHANGED_CONFIGURATION, ESeverity::eINFO, "ResetUpstream")); WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eSOCKET_CONNECTED; }); WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eSOCKET_CONNECTED; }); - upstream.Signal(upstreamSink.m_sessionId, Hermes::ServiceDescription(downstreamMachineId, 1U)); + upstream.Signal(upstreamSink.m_sessionId, Hermes::ServiceDescriptionData(downstreamMachineId, 1U)); WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eSERVICE_DESCRIPTION_DOWNSTREAM; }); - downstream.Signal(downstreamSink.m_sessionId, Hermes::ServiceDescription(upstreamMachineId, 1U)); + downstream.Signal(downstreamSink.m_sessionId, Hermes::ServiceDescriptionData(upstreamMachineId, 1U)); WaitFor(upstreamSink, [&]() { return upstreamSink.m_state == EState::eNOT_AVAILABLE_NOT_READY && upstreamSink.m_sessionId == upstreamSessionId; }); WaitFor(downstreamSink, [&]() { return downstreamSink.m_state == EState::eNOT_AVAILABLE_NOT_READY && downstreamSink.m_sessionId == downstreamSessionId; }); diff --git a/test/BoostTestHermes/VerticalTest.cpp b/test/BoostTestHermes/VerticalTest.cpp new file mode 100644 index 0000000..7402b5c --- /dev/null +++ b/test/BoostTestHermes/VerticalTest.cpp @@ -0,0 +1,451 @@ +// Copyright (c) ASM Assembly Systems GmbH & Co. KG +#include "stdafx.h" + +#include "Runner.h" +#include "Sinks.h" + +#include + +#include +#include + +using namespace Hermes; + +BOOST_AUTO_TEST_CASE(VerticalServicePostTest) +{ + TestCaseScope scope("VerticalServicePostTest"); + + std::string called1; + bool called2 = false; + std::mutex m_mutex; + using Lock = std::unique_lock; + std::condition_variable cv; + + VerticalServiceSink verticalServiceSink; + Hermes::VerticalService verticalService(verticalServiceSink); + + std::string postedValue = "Posted!"; + verticalService.Post([&, postedValue]() + { + Lock lock(m_mutex); + called1 = postedValue; + }); + + { + Runner runner(verticalService); + verticalService.Post([&]() + { + Lock lock(m_mutex); + called2 = true; + cv.notify_all(); + }); + Lock lock(m_mutex); + while (!called2) + cv.wait(lock); + } + + BOOST_TEST(called1 == postedValue); + BOOST_TEST(called2); +} + +BOOST_AUTO_TEST_CASE(VerticalClientPostTest) +{ + TestCaseScope scope("VerticalClientPostTest"); + + std::string called1; + bool called2 = false; + std::mutex m_mutex; + using Lock = std::unique_lock; + std::condition_variable cv; + + VerticalClientSink verticalClientSink; + Hermes::VerticalClient verticalClient(verticalClientSink); + + std::string postedValue = "Posted!"; + verticalClient.Post([&, postedValue]() + { + Lock lock(m_mutex); + called1 = postedValue; + }); + + { + Runner runner(verticalClient); + verticalClient.Post([&]() + { + Lock lock(m_mutex); + called2 = true; + cv.notify_all(); + }); + Lock lock(m_mutex); + while (!called2) + cv.wait(lock); + } + + BOOST_TEST(called1 == postedValue); + BOOST_TEST(called2); +} + +// helper structure to hold the stuff associated with a client +struct Client +{ + int m_id; + std::string m_systemId{ "MyClient_" + std::to_string(m_id) }; + VerticalClientSink m_sink; + Hermes::VerticalClient m_impl{ m_sink }; + Runner m_runner{ m_impl }; + + template + void Signal(const T& data) + { + m_impl.Signal(m_sink.m_sessionId, data); + } + + Client(int id) : m_id{ id } {} +}; +using ClientUp = std::unique_ptr; +using Clients = std::vector; + +struct Service +{ + std::string m_systemId{ "MyService" }; + VerticalServiceSink m_sink; + Hermes::VerticalService m_impl{ m_sink }; + Runner m_runner{ m_impl }; + + template + void Signal(unsigned sessionId, const T& data) + { + m_impl.Signal(sessionId, data); + } + + template + void Signal(const T& data) + { + m_impl.Signal(data); + } +}; + +BOOST_AUTO_TEST_CASE(VerticalTest) +{ + TestCaseScope scope("VerticalTest"); + + Service service; + service.m_impl.Enable(Hermes::VerticalServiceSettings(service.m_systemId, 50100)); + + Clients clients; + + Hermes::SupervisoryServiceDescriptionData serviceDescription{ service.m_systemId }; + serviceDescription.m_supportedFeatures.m_optionalFeatureCheckAliveResponse = Hermes::FeatureCheckAliveResponse{}; + serviceDescription.m_supportedFeatures.m_optionalFeatureSendWorkOrderInfo = Hermes::FeatureSendWorkOrderInfo{}; + serviceDescription.m_supportedFeatures.m_optionalFeatureQueryHermesCapabilities = Hermes::FeatureQueryHermesCapabilities{}; + + Hermes::SupervisoryServiceDescriptionData clientDescription{ std::string{} }; + clientDescription.m_supportedFeatures.m_optionalFeatureBoardTracking = Hermes::FeatureBoardTracking{}; + clientDescription.m_supportedFeatures.m_optionalFeatureCheckAliveResponse = Hermes::FeatureCheckAliveResponse{}; + clientDescription.m_supportedFeatures.m_optionalFeatureQueryWorkOrderInfo = Hermes::FeatureQueryWorkOrderInfo{}; + clientDescription.m_supportedFeatures.m_optionalFeatureConfiguration = Hermes::FeatureConfiguration{}; + clientDescription.m_supportedFeatures.m_optionalFeatureSendHermesCapabilities = Hermes::FeatureSendHermesCapabilities{}; + + const std::size_t cCLIENT_COUNT = 10; + + std::array queryWorkOrderInfos; + std::array sendWorkOrderInfos; + std::array replyWorkOrderInfos; + std::array boardsArrived; + std::array boardsDeparted; + std::array setConfigurations; + std::array getConfigurations; + std::array currentConfigurations; + std::array notifications; + + + for (auto i = 0U; i < cCLIENT_COUNT; ++i) + { + auto sessionId = i + 1U; + auto id = std::to_string(sessionId); + queryWorkOrderInfos[i] = QueryWorkOrderInfoData{ "MyQuery_" + id }; + sendWorkOrderInfos[i] = SendWorkOrderInfoData{ "MyInfo_" + id }; + replyWorkOrderInfos[i] = ReplyWorkOrderInfoData{ "MyInfo_" + id, EReplyWorkOrderInfoStatus::eACCEPTED_AND_READY }; + boardsArrived[i] = BoardArrivedData{"ArrivedId_" + id, sessionId, EBoardArrivedTransfer::eINSERTED, "Id_" + id, "myself" + , EBoardQuality::eGOOD, EFlippedBoard::eTOP_SIDE_IS_UP}; + boardsDeparted[i] = BoardDepartedData{ "DepartedId_" + id, sessionId, EBoardDepartedTransfer::eTRANSFERRED, "Id_" + id, "myself" + , EBoardQuality::eGOOD, EFlippedBoard::eTOP_SIDE_IS_UP }; + setConfigurations[i] = SetConfigurationData{ "SetConfigId_" + id }; + getConfigurations[i] = GetConfigurationData{}; + currentConfigurations[i].m_optionalMachineId = "CurrentConfigId_" + id; + notifications[i] = NotificationData{ ENotificationCode::eCONFIGURATION_ERROR, ESeverity::eWARNING, "MyNotification_" + id }; + + clients.emplace_back(std::make_unique(i)); + auto& client = *clients.back(); + client.m_impl.Enable(Hermes::VerticalClientSettings(client.m_systemId, "127.0.0.1", 50100)); + + // wait for connection: + WaitFor(client.m_sink, [&]() { return client.m_sink.m_state == Hermes::EVerticalState::eSOCKET_CONNECTED; }); + WaitFor(service.m_sink, [&]() { return service.m_sink.m_sessionMap.size() == sessionId; }); + + auto& serviceSession = service.m_sink.m_sessionMap.rbegin()->second; + BOOST_TEST(serviceSession.m_state == Hermes::EVerticalState::eSOCKET_CONNECTED); + + // exchange service description: + client.Signal(clientDescription); + WaitFor(service.m_sink, [&]() { return serviceSession.m_state == Hermes::EVerticalState::eSUPERVISORY_SERVICE_DESCRIPTION; }); + service.Signal( serviceSession.m_sessionId, serviceDescription ); + + WaitFor(client.m_sink, [&]() { return client.m_sink.m_state == Hermes::EVerticalState::eCONNECTED; }); + } + + for (auto i = 0U; i < cCLIENT_COUNT; ++i) + { + auto sessionId = i + 1U; + auto& client = *clients[i]; + + service.Signal(sessionId, boardsArrived[i]); + service.Signal(sessionId, boardsDeparted[i]); + service.Signal(sessionId, currentConfigurations[i]); + service.Signal(sessionId, queryWorkOrderInfos[i]); + service.Signal(sessionId, replyWorkOrderInfos[i]); + service.Signal(sessionId, notifications[i]); + + client.Signal(sendWorkOrderInfos[i]); + client.Signal(getConfigurations[i]); + client.Signal(setConfigurations[i]); + client.Signal(notifications[i]); + } + + for (auto i = 0U; i < cCLIENT_COUNT; ++i) + { + auto sessionId = i + 1U; + auto& serviceSessionSink = service.m_sink.m_sessionMap[sessionId]; + auto& clientSink = clients[i]->m_sink; + + WaitFor(clientSink, [&]() { return clientSink.m_notificationData == notifications[i]; }); + BOOST_TEST(clientSink.m_boardArrivedData == boardsArrived[i]); + BOOST_TEST(clientSink.m_boardDepartedData == boardsDeparted[i]); + BOOST_TEST(clientSink.m_currentConfigurationData == currentConfigurations[i]); + BOOST_TEST(clientSink.m_queryWorkOrderInfoData == queryWorkOrderInfos[i]); + BOOST_TEST(clientSink.m_replyWorkOrderInfoData == replyWorkOrderInfos[i]); + + WaitFor(service.m_sink, [&]() { return serviceSessionSink.m_notificationData == notifications[i]; }); + BOOST_TEST(serviceSessionSink.m_sendWorkOrderInfoData == sendWorkOrderInfos[i]); + BOOST_TEST(serviceSessionSink.m_getConfigurationData == getConfigurations[i]); + BOOST_TEST(serviceSessionSink.m_setConfigurationData == setConfigurations[i]); + } + + // disconnect + std::array disableNotifications; + for (auto i = 0U; i < cCLIENT_COUNT; ++i) + { + disableNotifications[i] = NotificationData{ ENotificationCode::eMACHINE_SHUTDOWN, ESeverity::eINFO, "Disabled" }; + clients[i]->m_impl.Disable(disableNotifications[i]); + } + + for (auto i = 0U; i < cCLIENT_COUNT; ++i) + { + auto sessionId = i + 1U; + auto& serviceSessionSink = service.m_sink.m_sessionMap[sessionId]; + auto& clientSink = clients[i]->m_sink; + + WaitFor(service.m_sink, [&]() { return serviceSessionSink.m_state == EVerticalState::eDISCONNECTED; }); + BOOST_TEST(clientSink.m_notificationData == notifications[i]); + BOOST_TEST(serviceSessionSink.m_notificationData == disableNotifications[i]); + } + +} + +BOOST_AUTO_TEST_CASE(VerticalBoardTrackingTest) +{ + TestCaseScope scope("VerticalBoardTrackingTest"); + + Service service; + service.m_impl.Enable(Hermes::VerticalServiceSettings(service.m_systemId, 50100)); + + Clients clients; + + Hermes::SupervisoryServiceDescriptionData serviceDescription{ service.m_systemId }; + serviceDescription.m_supportedFeatures.m_optionalFeatureCheckAliveResponse = Hermes::FeatureCheckAliveResponse{}; + serviceDescription.m_supportedFeatures.m_optionalFeatureSendWorkOrderInfo = Hermes::FeatureSendWorkOrderInfo{}; + + Hermes::SupervisoryServiceDescriptionData clientDescription{ std::string{} }; + clientDescription.m_supportedFeatures.m_optionalFeatureBoardTracking = Hermes::FeatureBoardTracking{}; + clientDescription.m_supportedFeatures.m_optionalFeatureCheckAliveResponse = Hermes::FeatureCheckAliveResponse{}; + clientDescription.m_supportedFeatures.m_optionalFeatureQueryWorkOrderInfo = Hermes::FeatureQueryWorkOrderInfo{}; + clientDescription.m_supportedFeatures.m_optionalFeatureConfiguration = Hermes::FeatureConfiguration{}; + + BoardArrivedData boardArrivedData{ "Arrived", 1, EBoardArrivedTransfer::eINSERTED, "ArrivedId", "myself" + , EBoardQuality::eGOOD, EFlippedBoard::eTOP_SIDE_IS_UP }; + BoardDepartedData boardDepartedData{ "Departed", 2, EBoardDepartedTransfer::eTRANSFERRED, "DepartedId", "myself" + , EBoardQuality::eBAD, EFlippedBoard::eBOTTOM_SIDE_IS_UP }; + + const std::size_t cCLIENT_COUNT = 10; + + std::array, cCLIENT_COUNT> boardsArrived; + std::array, cCLIENT_COUNT> boardsDeparted; + + for (auto i = 0U; i < cCLIENT_COUNT; ++i) + { + auto sessionId = i + 1U; + auto id = std::to_string(sessionId); + + // only every second client is subsribed to the BoardTracking: + if (i % 2 == 0) + { + boardsArrived[i] = boardArrivedData; + boardsDeparted[i] = boardDepartedData; + clientDescription.m_supportedFeatures.m_optionalFeatureBoardTracking = Hermes::FeatureBoardTracking{}; + } + else + { + clientDescription.m_supportedFeatures.m_optionalFeatureBoardTracking.reset(); + } + + clients.emplace_back(std::make_unique(i)); + auto& client = *clients.back(); + client.m_impl.Enable(Hermes::VerticalClientSettings(client.m_systemId, "127.0.0.1", 50100)); + + // wait for connection: + WaitFor(client.m_sink, [&]() { return client.m_sink.m_state == Hermes::EVerticalState::eSOCKET_CONNECTED; }); + WaitFor(service.m_sink, [&]() { return service.m_sink.m_sessionMap.size() == sessionId; }); + + auto& serviceSession = service.m_sink.m_sessionMap.rbegin()->second; + BOOST_TEST(serviceSession.m_state == Hermes::EVerticalState::eSOCKET_CONNECTED); + + // exchange service description: + client.Signal(clientDescription); + WaitFor(service.m_sink, [&]() { return serviceSession.m_state == Hermes::EVerticalState::eSUPERVISORY_SERVICE_DESCRIPTION; }); + service.Signal(serviceSession.m_sessionId, serviceDescription); + + WaitFor(client.m_sink, [&]() { return client.m_sink.m_state == Hermes::EVerticalState::eCONNECTED; }); + } + + + service.Signal(boardArrivedData); + service.Signal(boardDepartedData); + NotificationData notificationData{ ENotificationCode::eMACHINE_SHUTDOWN, ESeverity::eINFO, "Synchronizer" }; + + for (auto i = 0U; i < cCLIENT_COUNT; ++i) + { + // to sure that we've awaited each client, send a notification message + auto sessionId = i + 1U; + service.Signal(sessionId, notificationData); + + auto& clientSink = clients[i]->m_sink; + WaitFor(clientSink, [&]() { return clientSink.m_notificationData == notificationData; }); + BOOST_TEST(clientSink.m_boardArrivedData == boardsArrived[i]); + BOOST_TEST(clientSink.m_boardDepartedData == boardsDeparted[i]); + } + + // disconnect + NotificationData disableNotification{ ENotificationCode::eMACHINE_SHUTDOWN, ESeverity::eINFO, "Disabled" }; + service.m_impl.Disable(disableNotification); + + // wait for all clients not connected + for (auto i = 0U; i < cCLIENT_COUNT; ++i) + { + auto& clientSink = clients[i]->m_sink; + WaitFor(clientSink, [&]() { return clientSink.m_state == Hermes::EVerticalState::eDISCONNECTED; }); + WaitFor(clientSink, [&]() { return clientSink.m_notificationData == disableNotification; }); + } + + for (const auto& entry : service.m_sink.m_sessionMap) + { + BOOST_TEST(entry.second.m_state == Hermes::EVerticalState::eDISCONNECTED); + } + + clients.clear(); // desctruction should terminate all client threads +} + +BOOST_AUTO_TEST_CASE(VerticalCheckAliveTest) +{ + TestCaseScope scope("VerticalCheckAliveTest"); + + Service service; + VerticalServiceSettings serviceSettings{ service.m_systemId, 50200 }; + serviceSettings.m_checkAlivePeriodInSeconds = 0.0; + serviceSettings.m_checkAliveResponseMode = ECheckAliveResponseMode::eAUTO; + service.m_impl.Enable(serviceSettings); + + Client client{ 1 }; + VerticalClientSettings clientSettings{ client.m_systemId, "localhost", 50200 }; + clientSettings.m_checkAlivePeriodInSeconds = 0.0; + clientSettings.m_checkAliveResponseMode = ECheckAliveResponseMode::eAUTO; + client.m_impl.Enable(clientSettings); + + // wait for connection: + WaitFor(client.m_sink, [&]() { return client.m_sink.m_state == Hermes::EVerticalState::eSOCKET_CONNECTED; }); + WaitFor(service.m_sink, [&]() { return service.m_sink.m_sessionMap.size() == 1U; }); + + auto& serviceSession = service.m_sink.m_sessionMap.begin()->second; + BOOST_TEST(serviceSession.m_state == Hermes::EVerticalState::eSOCKET_CONNECTED); + + CheckAliveData ping; + ping.m_optionalId = "Hi"; + ping.m_optionalType = ECheckAliveType::ePING; + + CheckAliveData pong; + pong.m_optionalId = ping.m_optionalId; + pong.m_optionalType = ECheckAliveType::ePONG; + + // client to service: + client.m_impl.Signal(client.m_id, ping); + WaitFor(service.m_sink, [&]() { return serviceSession.m_checkAliveData == ping; }); + // should auto-reply with pong: + WaitFor(client.m_sink, [&]() { return client.m_sink.m_checkAliveData == pong; }); + + // service to client: + service.m_impl.Signal(serviceSession.m_sessionId, ping); + WaitFor(client.m_sink, [&]() { return client.m_sink.m_checkAliveData == ping; }); + // should auto-reply with pong: + WaitFor(service.m_sink, [&]() { return serviceSession.m_checkAliveData == pong; }); +} + +BOOST_AUTO_TEST_CASE(QueryAndSendHermesCapabilities) +{ + TestCaseScope scope("VerticalHermesCapabilitiesTest"); + + Service service; + VerticalServiceSettings serviceSettings{ service.m_systemId, 50200 }; + serviceSettings.m_checkAlivePeriodInSeconds = 0.0; + serviceSettings.m_checkAliveResponseMode = ECheckAliveResponseMode::eAUTO; + service.m_impl.Enable(serviceSettings); + + Client client{ 1 }; + VerticalClientSettings clientSettings{ client.m_systemId, "localhost", 50200 }; + clientSettings.m_checkAlivePeriodInSeconds = 0.0; + clientSettings.m_checkAliveResponseMode = ECheckAliveResponseMode::eAUTO; + client.m_impl.Enable(clientSettings); + + // wait for connection: + WaitFor(client.m_sink, [&]() { return client.m_sink.m_state == Hermes::EVerticalState::eSOCKET_CONNECTED; }); + WaitFor(service.m_sink, [&]() { return service.m_sink.m_sessionMap.size() == 1U; }); + + auto& serviceSession = service.m_sink.m_sessionMap.begin()->second; + BOOST_TEST(serviceSession.m_state == Hermes::EVerticalState::eSOCKET_CONNECTED); + + QueryHermesCapabilitiesData query; + // client to service: + client.m_impl.Signal(client.m_id, query); + + WaitFor(service.m_sink, [&]() + { + return serviceSession.m_queryHermesCapabilitiesData.has_value() == true; + }); + + // Und jetzt in die andere Richtung + SendHermesCapabilitiesData reply; + reply.m_attributes.m_action = 1; + reply.m_attributes.m_batchId = 5; + reply.m_attributes.m_bottomBarcode = 4; + // usw. + reply.m_optionalMessages.m_optionalMessageBoardArrived = MessageBoardArrived(); + reply.m_optionalMessages.m_optionalMessageBoardForecast = MessageBoardForecast(); + // usw. + + auto zumAnschaun = ToXml(reply); + + service.m_impl.Signal(serviceSession.m_sessionId, reply); + WaitFor(client.m_sink, [&]() { return client.m_sink.m_sendHermesCapabilitiesData == reply; }); +} + + + + pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy