Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Participant parameters #165

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions SilKit/IntegrationTests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,10 @@ add_silkit_test_to_executable(SilKitIntegrationTests
SOURCES ITest_SimTask.cpp
)

add_silkit_test_to_executable(SilKitIntegrationTests
SOURCES ITest_GetParameter.cpp
)

add_silkit_test_to_executable(SilKitFunctionalTests
SOURCES FTest_WallClockCoupling.cpp
)
Expand Down
7 changes: 7 additions & 0 deletions SilKit/IntegrationTests/Hourglass/MockCapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -770,6 +770,13 @@ extern "C"
return globalCapi->SilKit_Participant_GetLogger(outLogger, participant);
}

SilKit_ReturnCode SilKitCALL SilKit_Participant_GetParameter(const char** outParameterValue,
SilKit_Parameter parameter,
SilKit_Participant* participant)
{
return globalCapi->SilKit_Participant_GetParameter(outParameterValue, parameter, participant);
}

// ParticipantConfiguration

SilKit_ReturnCode SilKitCALL SilKit_ParticipantConfiguration_FromString(
Expand Down
3 changes: 3 additions & 0 deletions SilKit/IntegrationTests/Hourglass/MockCapi.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,9 @@ class MockCapi

MOCK_METHOD(SilKit_ReturnCode, SilKit_Participant_GetLogger,
(SilKit_Logger * *outLogger, SilKit_Participant* participant));

MOCK_METHOD(SilKit_ReturnCode, SilKit_Participant_GetParameter,
(const char** outParameterValue, SilKit_Parameter parameter, SilKit_Participant* participant));

// ParticipantConfiguration

Expand Down
70 changes: 70 additions & 0 deletions SilKit/IntegrationTests/ITest_GetParameter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// SPDX-FileCopyrightText: 2023 Vector Informatik GmbH
//
// SPDX-License-Identifier: MIT

#include <memory>
#include <string>

#include "gtest/gtest.h"
#include "silkit/vendor/CreateSilKitRegistry.hpp"
#include "silkit/SilKit.hpp"

namespace {

struct ITest_GetParameter : public testing::Test
{

void checkGetParameterValues(SilKit::IParticipant* participant, std::unordered_map<SilKit::Parameter, std::string> expected)
{
for (auto it : expected)
{
EXPECT_EQ(it.second, participant->GetParameter(it.first));
}
}

const std::string _registryUriAnyPort = "silkit://127.0.0.1:0";
};

// Check that GetParameter return the values set via api
TEST_F(ITest_GetParameter, get_parameter_set_by_api)
{
const std::string participantNameByApi = "P1";

auto emptyParticipantConfig = SilKit::Config::ParticipantConfigurationFromString("");

auto registry = SilKit::Vendor::Vector::CreateSilKitRegistry(emptyParticipantConfig);
auto registryUriByApi = registry->StartListening(_registryUriAnyPort);

auto participant = SilKit::CreateParticipant(emptyParticipantConfig, participantNameByApi, registryUriByApi);

checkGetParameterValues(participant.get(), {{SilKit::Parameter::ParticipantName, participantNameByApi},
{SilKit::Parameter::RegistryUri, registryUriByApi}});
}

// Config values take precedence over api values
// Check that GetParameter actually return the config values if both are set
TEST_F(ITest_GetParameter, get_parameter_set_by_config)
{
const std::string participantNameByApi = "P2";
const std::string registryUriByApi = "silkit://127.0.0.42:0";

const std::string participantNameByConfig = "P1";

auto emptyParticipantConfig = SilKit::Config::ParticipantConfigurationFromString("");

auto registry = SilKit::Vendor::Vector::CreateSilKitRegistry(emptyParticipantConfig);
auto registryUriByConfig = registry->StartListening(_registryUriAnyPort);

std::ostringstream ss;
ss << R"({ "ParticipantName": ")" << participantNameByConfig << R"(", "Middleware": { "RegistryUri": ")"
<< registryUriByConfig << R"(" }})";
auto participantConfig = SilKit::Config::ParticipantConfigurationFromString(ss.str());

auto participant = SilKit::CreateParticipant(participantConfig, participantNameByApi, registryUriByApi);

checkGetParameterValues(participant.get(), {{SilKit::Parameter::ParticipantName, participantNameByConfig},
{SilKit::Parameter::RegistryUri, registryUriByConfig}});

}

} //end namespace
29 changes: 29 additions & 0 deletions SilKit/include/silkit/capi/Parameters.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// SPDX-FileCopyrightText: 2024 Vector Informatik GmbH
//
// SPDX-License-Identifier: MIT

#pragma once
#include <stdint.h>
#include "SilKitMacros.h"

#pragma pack(push)
#pragma pack(8)

SILKIT_BEGIN_DECLS

/*! Internal parameter provider. */
typedef struct SilKit_ParamterProvider SilKit_ParamterProvider;

/*! A parameter set by an API call and/or the participant configuration. */
typedef int16_t SilKit_Parameter;

/*! An undefined parameter */
#define SilKit_Parameter_Undefined ((SilKit_Parameter)0)
/*! The name of the participant */
#define SilKit_Parameter_ParticipantName ((SilKit_Parameter)1)
/*! The registry URI */
#define SilKit_Parameter_ReistryUri ((SilKit_Parameter)2)

SILKIT_END_DECLS

#pragma pack(pop)
19 changes: 19 additions & 0 deletions SilKit/include/silkit/capi/Participant.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "silkit/capi/SilKitMacros.h"
#include "silkit/capi/Types.h"
#include "silkit/capi/Logger.h"
#include "silkit/capi/Parameters.h"

#pragma pack(push)
#pragma pack(8)
Expand Down Expand Up @@ -80,6 +81,24 @@ SilKitAPI SilKit_ReturnCode SilKitCALL SilKit_Participant_GetLogger(SilKit_Logge
typedef SilKit_ReturnCode(SilKitFPTR* SilKit_Participant_GetLogger_t)(SilKit_Logger** outLogger,
SilKit_Participant* participant);


/*! \brief Retrieve a parameter from a participant.
*
* \param outParameterValue The string value of the parameter (out parameter).
* \param parameter The parameter to get.
* \param participant The participant to get the parameter from.
*
* Returns the current value of the given parameter.
* Useful for parameters that are passed to the participant via the API and the participant configuration.
*/
SilKitAPI SilKit_ReturnCode SilKitCALL SilKit_Participant_GetParameter(const char** outParameterValue,
SilKit_Parameter parameter,
SilKit_Participant* participant);
Comment on lines +94 to +96
Copy link
Member

@VDanielEdwards VDanielEdwards Jan 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we return a single const char * (which is owned by the SIL Kit participant and not to be deallocated by the user) then we have to ensure that the string this is pointing to never changes / gets reallocated. This will work for the current set of parameters (participant name and registry uri won't change), but who knows if we want to provide parameters that could change in the future.

I would propose an API that copies the strings to user-provided buffer in a similar manner to snprintf. It must be allowed to specify the data-pointer as nullptr which will only fill in the size (which can then be used to create an appropriately sized buffer).

Same as with the C++ API, I think copying is fine here - these parameters shouldn't be performance critical or queried in hot-loops.

Suggested change
SilKitAPI SilKit_ReturnCode SilKitCALL SilKit_Participant_GetParameter(const char** outParameterValue,
SilKit_Parameter parameter,
SilKit_Participant* participant);
SilKitAPI SilKit_ReturnCode SilKitCALL SilKit_Participant_GetParameter(char* outParameterValueData,
size_t *outParameterValueSize,
SilKit_Parameter parameter,
SilKit_Participant* participant);


typedef SilKit_ReturnCode(SilKitFPTR* SilKit_Participant_GetParameter_t)(const char** outParameterValue,
SilKit_Parameter parameter,
SilKit_Participant* participant);

SILKIT_END_DECLS

#pragma pack(pop)
1 change: 1 addition & 0 deletions SilKit/include/silkit/capi/SilKit.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "silkit/capi/Version.h"
#include "silkit/capi/NetworkSimulator.h"
#include "silkit/capi/EventProducer.h"
#include "silkit/capi/Parameters.h"

SILKIT_BEGIN_DECLS

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// SPDX-FileCopyrightText: 2024 Vector Informatik GmbH
//
// SPDX-License-Identifier: MIT

#pragma once

#include <string>
#include "silkit/capi/Parameters.h"

namespace SilKit {
DETAIL_SILKIT_DETAIL_VN_NAMESPACE_BEGIN
namespace Impl {

class ParameterProvider
{
public:
inline ParameterProvider();

inline ~ParameterProvider() = default;

inline auto GetParameter(SilKit_Participant* participant, Parameter parameter) -> const std::string&;

private:
std::unordered_map<Parameter, std::string> _parameterValues;
};

} // namespace Impl
DETAIL_SILKIT_DETAIL_VN_NAMESPACE_CLOSE
} // namespace SilKit


// ================================================================================
// Inline Implementations
// ================================================================================

#include "silkit/detail/impl/ThrowOnError.hpp"

namespace SilKit {
DETAIL_SILKIT_DETAIL_VN_NAMESPACE_BEGIN
namespace Impl {

ParameterProvider::ParameterProvider()
{
}

auto ParameterProvider::GetParameter(SilKit_Participant* participant, Parameter parameter) -> const std::string&
{
const char* cParameterValue;
SilKit_Parameter cParameter = static_cast<SilKit_Parameter>(parameter);
const auto returnCode = SilKit_Participant_GetParameter(&cParameterValue, cParameter, participant);
_parameterValues[parameter] = std::string(cParameterValue);
ThrowOnError(returnCode);
return _parameterValues[parameter];
}

} // namespace Impl
DETAIL_SILKIT_DETAIL_VN_NAMESPACE_CLOSE
} // namespace SilKit
13 changes: 13 additions & 0 deletions SilKit/include/silkit/detail/impl/participant/Participant.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@

#include "silkit/detail/impl/netsim/NetworkSimulator.hpp"

#include "silkit/detail/impl/participant/ParameterProvider.hpp"

namespace SilKit {
DETAIL_SILKIT_DETAIL_VN_NAMESPACE_BEGIN
namespace Impl {
Expand Down Expand Up @@ -100,6 +102,8 @@ class Participant : public SilKit::IParticipant

inline auto GetLogger() -> SilKit::Services::Logging::ILogger* override;

inline auto GetParameter(SilKit::Parameter parameter) -> const std::string& override;

inline auto ExperimentalCreateNetworkSimulator() -> SilKit::Experimental::NetworkSimulation::INetworkSimulator*;

inline auto ExperimentalCreateSystemController()
Expand Down Expand Up @@ -141,6 +145,8 @@ class Participant : public SilKit::IParticipant
std::unique_ptr<Impl::Services::Logging::Logger> _logger;

std::unique_ptr<Impl::Experimental::NetworkSimulation::NetworkSimulator> _networkSimulator;

std::unique_ptr<Impl::ParameterProvider> _parameterProvider;
};

} // namespace Impl
Expand All @@ -160,6 +166,7 @@ Participant::Participant(SilKit_Participant* participant)
: _participant{participant}
{
_logger = std::make_unique<Services::Logging::Logger>(_participant);
_parameterProvider = std::make_unique<ParameterProvider>();
}

Participant::~Participant()
Expand Down Expand Up @@ -241,6 +248,12 @@ auto Participant::GetLogger() -> SilKit::Services::Logging::ILogger*
return _logger.get();
}


auto Participant::GetParameter(SilKit::Parameter parameter) -> const std::string&
{
return _parameterProvider->GetParameter(_participant, parameter);
}

auto Participant::ExperimentalCreateSystemController()
-> SilKit::Experimental::Services::Orchestration::ISystemController*
{
Expand Down
5 changes: 5 additions & 0 deletions SilKit/include/silkit/participant/IParticipant.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "silkit/services/rpc/RpcSpec.hpp"
#include "silkit/services/rpc/RpcDatatypes.hpp"

#include "silkit/participant/parameters.hpp"

namespace SilKit {

/*! \brief Communication interface to be used by SIL Kit participants
Expand Down Expand Up @@ -99,6 +101,9 @@ class IParticipant

//! \brief Return the ILogger at this SIL Kit participant.
virtual auto GetLogger() -> Services::Logging::ILogger* = 0;

//! \brief Get a parameter set by an API call and/or the participant configuration.
virtual auto GetParameter(SilKit::Parameter parameter) -> const std::string& = 0;
Copy link
Member

@VDanielEdwards VDanielEdwards Jan 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would produce a new std::string on each invocation. This API shouldn't be called more than once per parameter (under normal circumstances) anyway. This will also simplify the implementation, because the caching in the Hourglass-API can be dropped.

Suggested change
virtual auto GetParameter(SilKit::Parameter parameter) -> const std::string& = 0;
virtual auto GetParameter(SilKit::Parameter parameter) -> std::string = 0;

};

} // namespace SilKit
23 changes: 23 additions & 0 deletions SilKit/include/silkit/participant/parameters.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-FileCopyrightText: 2024 Vector Informatik GmbH
//
// SPDX-License-Identifier: MIT

#pragma once

#include "silkit/capi/Parameters.h"

namespace SilKit {

// note: never reuse old numbers!
//! \brief Available parameters to query
enum class Parameter : SilKit_Parameter
{
//! An undefined parameter
Undefined = SilKit_Parameter_Undefined,
//! The name of the participant
ParticipantName = SilKit_Parameter_ParticipantName,
//! The registry URI
RegistryUri = SilKit_Parameter_ReistryUri,
};

} // namespace SilKit
1 change: 1 addition & 0 deletions SilKit/source/capi/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,5 @@ add_silkit_test_to_executable(SilKitUnitTests SOURCES Test_CapiLin.cpp LIBS S_Si
add_silkit_test_to_executable(SilKitUnitTests SOURCES Test_CapiSymbols.cpp LIBS S_SilKitImpl)
add_silkit_test_to_executable(SilKitUnitTests SOURCES Test_CapiNetSim.cpp LIBS S_SilKitImpl I_SilKit_Core_Mock_Participant)
add_silkit_test_to_executable(SilKitUnitTests SOURCES Test_CapiExceptions.cpp LIBS S_SilKitImpl)
add_silkit_test_to_executable(SilKitUnitTests SOURCES Test_CapiGetParameter.cpp LIBS S_SilKitImpl)

15 changes: 15 additions & 0 deletions SilKit/source/capi/CapiParticipant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "silkit/SilKit.hpp"
#include "silkit/services/logging/ILogger.hpp"
#include "silkit/services/orchestration/all.hpp"
#include "silkit/participant/parameters.hpp"

#include "CapiImpl.hpp"
#include "TypeConversion.hpp"
Expand Down Expand Up @@ -102,6 +103,20 @@ try
}
CAPI_CATCH_EXCEPTIONS

SilKit_ReturnCode SilKitCALL SilKit_Participant_GetParameter(const char** outParameterValue, SilKit_Parameter parameter,
SilKit_Participant* participant)
try
{
ASSERT_VALID_OUT_PARAMETER(outParameterValue);
ASSERT_VALID_POINTER_PARAMETER(participant);

auto cppParticipant = reinterpret_cast<SilKit::IParticipant*>(participant);
auto cppParameter = static_cast<SilKit::Parameter>(parameter);
*outParameterValue = cppParticipant->GetParameter(cppParameter).c_str();
return SilKit_ReturnCode_SUCCESS;
}
CAPI_CATCH_EXCEPTIONS


SilKit_ReturnCode SilKitCALL SilKit_ParticipantConfiguration_FromString(
SilKit_ParticipantConfiguration** outParticipantConfiguration, const char* participantConfigurationString)
Expand Down
Loading
Loading