diff --git a/include/cse.h b/include/cse.h index ee423ef2e..ba79000f2 100644 --- a/include/cse.h +++ b/include/cse.h @@ -6,6 +6,7 @@ #ifndef CSE_H #define CSE_H +#include #include #include @@ -410,11 +411,11 @@ typedef struct cse_manipulator_s cse_manipulator; * The slave. * \param [in] variables * A pointer to an array of length `nv` that contains the (slave-specific) - * indices of variables to retrieve. + * indices of variables to set. * \param [in] nv * The length of the `variables` and `values` arrays. * \param [out] values - * A pointer to an array of length `nv` which will be filled with the + * A pointer to an array of length `nv` with the * values of the variables specified in `variables`, in the same order. * * \returns @@ -428,7 +429,7 @@ int cse_manipulator_slave_set_real( const double values[]); /** - * Resets any previously overridden values of real variables for one slave. + * Sets the values of integer variables for one slave. * * \param [in] manipulator * The manipulator. @@ -436,99 +437,51 @@ int cse_manipulator_slave_set_real( * The slave. * \param [in] variables * A pointer to an array of length `nv` that contains the (slave-specific) - * indices of variables to reset. + * indices of variables to set. * \param [in] nv - * The length of the `variables` array. + * The length of the `variables` and `values` arrays. + * \param [out] values + * A pointer to an array of length `nv` with the + * values of the variables specified in `variables`, in the same order. * * \returns * 0 on success and -1 on error. */ -int cse_manipulator_slave_reset_real( +int cse_manipulator_slave_set_integer( cse_manipulator* manipulator, cse_slave_index slaveIndex, const cse_variable_index variables[], - size_t nv); + size_t nv, + const int values[]); /** - * Retrieves the values of real variables for one slave. + * Sets the values of boolean variables for one slave. * - * \param [in] observer - * The observer. - * \param [in] slave + * \param [in] manipulator + * The manipulator. + * \param [in] slaveIndex * The slave. * \param [in] variables * A pointer to an array of length `nv` that contains the (slave-specific) - * indices of variables to retrieve. + * indices of variables to set. * \param [in] nv * The length of the `variables` and `values` arrays. * \param [out] values - * A pointer to an array of length `nv` which will be filled with the + * A pointer to an array of length `nv` with the * values of the variables specified in `variables`, in the same order. * * \returns * 0 on success and -1 on error. */ -int cse_observer_slave_get_real( - cse_observer* observer, - cse_slave_index slave, +int cse_manipulator_slave_set_boolean( + cse_manipulator* manipulator, + cse_slave_index slaveIndex, const cse_variable_index variables[], size_t nv, - double values[]); - -/** - * Retrieves a series of observed values, step numbers and times for a real variable. - * - * \param [in] observer the observer - * \param [in] slave index of the slave - * \param [in] variableIndex the variable index - * \param [in] fromStep the step number to start from - * \param [in] nSamples the number of samples to read - * \param [out] values the series of observed values - * \param [out] steps the corresponding step numbers - * \param [out] times the corresponding simulation times - * - * \returns - * The number of samples actually read, which may be smaller than `nSamples`. - */ -int64_t cse_observer_slave_get_real_samples( - cse_observer* observer, - cse_slave_index slave, - cse_variable_index variableIndex, - cse_step_number fromStep, - size_t nSamples, - double values[], - cse_step_number steps[], - cse_time_point times[]); - -/** - * Retrieves two time-synchronized series of observed values for two real variables. - * - * \param [in] observer the observer - * \param [in] slave1 index of the first slave - * \param [in] variableIndex1 the first variable index - * \param [in] slave2 index of the second slave - * \param [in] variableIndex2 the second variable index - * \param [in] fromStep the step number to start from - * \param [in] nSamples the number of samples to read - * \param [out] values1 the first series of observed values - * \param [out] values2 the second series of observed values - * - * \returns - * The number of samples actually read, which may be smaller than `nSamples`. - */ -int64_t cse_observer_slave_get_real_synchronized_series( - cse_observer* observer, - cse_slave_index slave1, - cse_variable_index variableIndex1, - cse_slave_index slave2, - cse_variable_index variableIndex2, - cse_step_number fromStep, - size_t nSamples, - double values1[], - double values2[]); + const bool values[]); /** - * Sets the values of integer variables for one slave. + * Sets the values of string variables for one slave. * * \param [in] manipulator * The manipulator. @@ -540,26 +493,28 @@ int64_t cse_observer_slave_get_real_synchronized_series( * \param [in] nv * The length of the `variables` and `values` arrays. * \param [out] values - * A pointer to an array of length `nv` which will be filled with the + * A pointer to an array of length `nv` with the * values of the variables specified in `variables`, in the same order. * * \returns * 0 on success and -1 on error. */ -int cse_manipulator_slave_set_integer( +int cse_manipulator_slave_set_string( cse_manipulator* manipulator, cse_slave_index slaveIndex, const cse_variable_index variables[], size_t nv, - const int values[]); + const char* values[]); /** - * Resets the values of any previously overridden integer variables for one slave. + * Resets any previously overridden variable values of a certain type for one slave. * * \param [in] manipulator * The manipulator. * \param [in] slaveIndex * The slave. + * \param [in] type + * The variable type. * \param [in] variables * A pointer to an array of length `nv` that contains the (slave-specific) * indices of variables to reset. @@ -569,12 +524,39 @@ int cse_manipulator_slave_set_integer( * \returns * 0 on success and -1 on error. */ -int cse_manipulator_slave_reset_integer( +int cse_manipulator_slave_reset( cse_manipulator* manipulator, cse_slave_index slaveIndex, + cse_variable_type type, const cse_variable_index variables[], size_t nv); +/** + * Retrieves the values of real variables for one slave. + * + * \param [in] observer + * The observer. + * \param [in] slave + * The slave. + * \param [in] variables + * A pointer to an array of length `nv` that contains the (slave-specific) + * indices of variables to retrieve. + * \param [in] nv + * The length of the `variables` and `values` arrays. + * \param [out] values + * A pointer to an array of length `nv` which will be filled with the + * values of the variables specified in `variables`, in the same order. + * + * \returns + * 0 on success and -1 on error. + */ +int cse_observer_slave_get_real( + cse_observer* observer, + cse_slave_index slave, + const cse_variable_index variables[], + size_t nv, + double values[]); + /** * Retrieves the values of integer variables for one slave. * @@ -601,6 +583,84 @@ int cse_observer_slave_get_integer( size_t nv, int values[]); +/** + * Retrieves the values of boolean variables for one slave. + * + * \param [in] observer + * The observer. + * \param [in] slave + * The slave index. + * \param [in] variables + * A pointer to an array of length `nv` that contains the (slave-specific) + * indices of variables to retrieve. + * \param [in] nv + * The length of the `variables` and `values` arrays. + * \param [out] values + * A pointer to an array of length `nv` which will be filled with the + * values of the variables specified in `variables`, in the same order. + * + * \returns + * 0 on success and -1 on error. + */ +int cse_observer_slave_get_boolean( + cse_observer* observer, + cse_slave_index slave, + const cse_variable_index variables[], + size_t nv, + bool values[]); + +/** + * Retrieves the values of string variables for one slave. + * + * \param [in] observer + * The observer. + * \param [in] slave + * The slave index. + * \param [in] variables + * A pointer to an array of length `nv` that contains the (slave-specific) + * indices of variables to retrieve. + * \param [in] nv + * The length of the `variables` and `values` arrays. + * \param [out] values + * A pointer to an array of length `nv` which will be filled with pointers + * to the values of the variables specified in `variables`, in the same order. + * The pointers are valid until the next call to `cse_observer_slave_get_string()`. + * + * \returns + * 0 on success and -1 on error. + */ +int cse_observer_slave_get_string( + cse_observer* observer, + cse_slave_index slave, + const cse_variable_index variables[], + size_t nv, + const char* values[]); + +/** + * Retrieves a series of observed values, step numbers and times for a real variable. + * + * \param [in] observer the observer + * \param [in] slave index of the slave + * \param [in] variableIndex the variable index + * \param [in] fromStep the step number to start from + * \param [in] nSamples the number of samples to read + * \param [out] values the series of observed values + * \param [out] steps the corresponding step numbers + * \param [out] times the corresponding simulation times + * + * \returns + * The number of samples actually read, which may be smaller than `nSamples`. + */ +int64_t cse_observer_slave_get_real_samples( + cse_observer* observer, + cse_slave_index slave, + cse_variable_index variableIndex, + cse_step_number fromStep, + size_t nSamples, + double values[], + cse_step_number steps[], + cse_time_point times[]); + /** * Retrieves a series of observed values, step numbers and times for an integer variable. * @@ -626,6 +686,33 @@ int64_t cse_observer_slave_get_integer_samples( cse_step_number steps[], cse_time_point times[]); +/** + * Retrieves two time-synchronized series of observed values for two real variables. + * + * \param [in] observer the observer + * \param [in] slave1 index of the first slave + * \param [in] variableIndex1 the first variable index + * \param [in] slave2 index of the second slave + * \param [in] variableIndex2 the second variable index + * \param [in] fromStep the step number to start from + * \param [in] nSamples the number of samples to read + * \param [out] values1 the first series of observed values + * \param [out] values2 the second series of observed values + * + * \returns + * The number of samples actually read, which may be smaller than `nSamples`. + */ +int64_t cse_observer_slave_get_real_synchronized_series( + cse_observer* observer, + cse_slave_index slave1, + cse_variable_index variableIndex1, + cse_slave_index slave2, + cse_variable_index variableIndex2, + cse_step_number fromStep, + size_t nSamples, + double values1[], + double values2[]); + /** * Retrieves the step numbers for a range given by a duration. * diff --git a/include/cse/manipulator.hpp b/include/cse/manipulator.hpp index 359346f3b..3dc9facee 100644 --- a/include/cse/manipulator.hpp +++ b/include/cse/manipulator.hpp @@ -119,14 +119,8 @@ class override_manipulator : public manipulator void override_boolean_variable(simulator_index, variable_index, bool value); /// Override the value of a variable with type `string` void override_string_variable(simulator_index, variable_index, const std::string& value); - /// Reset override of a variable with type `real` - void reset_real_variable(simulator_index, variable_index); - /// Reset override of a variable with type `integer` - void reset_integer_variable(simulator_index, variable_index); - /// Reset override of a variable with type `boolean` - void reset_boolean_variable(simulator_index, variable_index); - /// Reset override of a variable with type `string` - void reset_string_variable(simulator_index, variable_index); + /// Reset override of a variable + void reset_variable(simulator_index, variable_type, variable_index); ~override_manipulator() noexcept override; diff --git a/include/cse/observer/last_value_observer.hpp b/include/cse/observer/last_value_observer.hpp index 355976086..a00ab18e3 100644 --- a/include/cse/observer/last_value_observer.hpp +++ b/include/cse/observer/last_value_observer.hpp @@ -56,6 +56,16 @@ class last_value_observer : public last_value_provider gsl::span variables, gsl::span values) override; + void get_boolean( + simulator_index sim, + gsl::span variables, + gsl::span values) override; + + void get_string( + simulator_index sim, + gsl::span variables, + gsl::span values) override; + ~last_value_observer() noexcept override; private: diff --git a/include/cse/observer/last_value_provider.hpp b/include/cse/observer/last_value_provider.hpp index d73a747c0..39b217266 100644 --- a/include/cse/observer/last_value_provider.hpp +++ b/include/cse/observer/last_value_provider.hpp @@ -7,6 +7,8 @@ #include +#include + namespace cse { @@ -42,6 +44,30 @@ class last_value_provider : public observer simulator_index sim, gsl::span variables, gsl::span values) = 0; + + /** + * Retrieves the latest observed values for a range of boolean variables. + * + * \param [in] sim index of the simulator + * \param [in] variables the variable indices to retrieve values for + * \param [out] values a collection where the observed values will be stored + */ + virtual void get_boolean( + simulator_index sim, + gsl::span variables, + gsl::span values) = 0; + + /** + * Retrieves the latest observed values for a range of string variables. + * + * \param [in] sim index of the simulator + * \param [in] variables the variable indices to retrieve values for + * \param [out] values a collection where the observed values will be stored + */ + virtual void get_string( + simulator_index sim, + gsl::span variables, + gsl::span values) = 0; }; } // namespace cse diff --git a/src/c/cse.cpp b/src/c/cse.cpp index 37ab4d66c..fe55e6ee7 100644 --- a/src/c/cse.cpp +++ b/src/c/cse.cpp @@ -555,6 +555,55 @@ int cse_observer_slave_get_integer( } } +int cse_observer_slave_get_boolean( + cse_observer* observer, + cse_slave_index slave, + const cse_variable_index variables[], + size_t nv, + bool values[]) +{ + try { + const auto obs = std::dynamic_pointer_cast(observer->cpp_observer); + if (!obs) { + throw std::invalid_argument("Invalid observer! The provided observer must be a last_value_observer."); + } + obs->get_boolean(slave, gsl::make_span(variables, nv), gsl::make_span(values, nv)); + return success; + } catch (...) { + handle_current_exception(); + return failure; + } +} + +// This holds string variable values. +// Must only be used with `cse_observer_slave_get_string()`. +thread_local std::vector g_stringVariableBuffer; + +int cse_observer_slave_get_string( + cse_observer* observer, + cse_slave_index slave, + const cse_variable_index variables[], + size_t nv, + const char* values[]) +{ + try { + const auto obs = std::dynamic_pointer_cast(observer->cpp_observer); + if (!obs) { + throw std::invalid_argument("Invalid observer! The provided observer must be a last_value_observer."); + } + g_stringVariableBuffer.clear(); + g_stringVariableBuffer.resize(nv); + obs->get_string(slave, gsl::make_span(variables, nv), gsl::span(g_stringVariableBuffer)); + for (size_t i = 0; i < nv; i++) { + values[i] = g_stringVariableBuffer.at(i).c_str(); + } + return success; + } catch (...) { + handle_current_exception(); + return failure; + } +} + int64_t cse_observer_slave_get_real_samples( cse_observer* observer, cse_slave_index slave, @@ -864,11 +913,34 @@ int cse_manipulator_slave_set_integer( } } -int cse_manipulator_slave_reset_real( +int cse_manipulator_slave_set_boolean( cse_manipulator* manipulator, cse_slave_index slaveIndex, const cse_variable_index variables[], - size_t nv) + size_t nv, + const bool values[]) +{ + try { + const auto man = std::dynamic_pointer_cast(manipulator->cpp_manipulator); + if (!man) { + throw std::invalid_argument("Invalid manipulator!"); + } + for (size_t i = 0; i < nv; i++) { + man->override_boolean_variable(slaveIndex, variables[i], values[i]); + } + return success; + } catch (...) { + handle_current_exception(); + return failure; + } +} + +int cse_manipulator_slave_set_string( + cse_manipulator* manipulator, + cse_slave_index slaveIndex, + const cse_variable_index variables[], + size_t nv, + const char* values[]) { try { const auto man = std::dynamic_pointer_cast(manipulator->cpp_manipulator); @@ -876,7 +948,7 @@ int cse_manipulator_slave_reset_real( throw std::invalid_argument("Invalid manipulator!"); } for (size_t i = 0; i < nv; i++) { - man->reset_real_variable(slaveIndex, variables[i]); + man->override_string_variable(slaveIndex, variables[i], values[i]); } return success; } catch (...) { @@ -885,9 +957,10 @@ int cse_manipulator_slave_reset_real( } } -int cse_manipulator_slave_reset_integer( +int cse_manipulator_slave_reset( cse_manipulator* manipulator, cse_slave_index slaveIndex, + cse_variable_type type, const cse_variable_index variables[], size_t nv) { @@ -896,8 +969,9 @@ int cse_manipulator_slave_reset_integer( if (!man) { throw std::invalid_argument("Invalid manipulator!"); } + cse::variable_type vt = to_cpp_variable_type(type); for (size_t i = 0; i < nv; i++) { - man->reset_integer_variable(slaveIndex, variables[i]); + man->reset_variable(slaveIndex, vt, variables[i]); } return success; } catch (...) { diff --git a/src/cpp/cse/observer/slave_value_provider.hpp b/src/cpp/cse/observer/slave_value_provider.hpp index 67cbd828c..d7e5d4e48 100644 --- a/src/cpp/cse/observer/slave_value_provider.hpp +++ b/src/cpp/cse/observer/slave_value_provider.hpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -23,10 +24,14 @@ class slave_value_provider void observe(); void get_real(gsl::span variables, gsl::span values); void get_int(gsl::span variables, gsl::span values); + void get_boolean(gsl::span variables, gsl::span values); + void get_string(gsl::span variables, gsl::span values); private: std::unordered_map realSamples_; std::unordered_map intSamples_; + std::unordered_map boolSamples_; + std::unordered_map stringSamples_; observable* observable_; std::mutex lock_; }; diff --git a/src/cpp/observer/last_value_observer.cpp b/src/cpp/observer/last_value_observer.cpp index 74479416a..fed20352f 100644 --- a/src/cpp/observer/last_value_observer.cpp +++ b/src/cpp/observer/last_value_observer.cpp @@ -65,6 +65,24 @@ void last_value_observer::get_integer( valueProviders_.at(sim)->get_int(variables, values); } +void last_value_observer::get_boolean( + simulator_index sim, + gsl::span variables, + gsl::span values) +{ + CSE_INPUT_CHECK(variables.size() == values.size()); + valueProviders_.at(sim)->get_boolean(variables, values); +} + +void last_value_observer::get_string( + simulator_index sim, + gsl::span variables, + gsl::span values) +{ + CSE_INPUT_CHECK(variables.size() == values.size()); + valueProviders_.at(sim)->get_string(variables, values); +} + last_value_observer::~last_value_observer() noexcept = default; } // namespace cse diff --git a/src/cpp/observer/slave_value_provider.cpp b/src/cpp/observer/slave_value_provider.cpp index 668e03c54..bc2dcc921 100644 --- a/src/cpp/observer/slave_value_provider.cpp +++ b/src/cpp/observer/slave_value_provider.cpp @@ -32,11 +32,21 @@ slave_value_provider::slave_value_provider(observable* observable) { for (const auto& vd : observable->model_description().variables) { observable->expose_for_getting(vd.type, vd.index); - if (vd.type == cse::variable_type::real) { - realSamples_[vd.index] = double(); - } - if (vd.type == cse::variable_type::integer) { - intSamples_[vd.index] = int(); + switch (vd.type) { + case cse::variable_type::real: + realSamples_[vd.index] = double(); + break; + case cse::variable_type::integer: + intSamples_[vd.index] = int(); + break; + case cse::variable_type::boolean: + boolSamples_[vd.index] = bool(); + break; + case cse::variable_type::string: + stringSamples_[vd.index] = std::string(); + break; + default: + CSE_PANIC(); } } observe(); @@ -54,6 +64,12 @@ void slave_value_provider::observe() for (auto& [idx, value] : intSamples_) { value = observable_->get_integer(idx); } + for (auto& [idx, value] : boolSamples_) { + value = observable_->get_boolean(idx); + } + for (auto& [idx, value] : stringSamples_) { + value = observable_->get_string(idx); + } } void slave_value_provider::get_real(gsl::span variables, gsl::span values) @@ -68,4 +84,16 @@ void slave_value_provider::get_int(gsl::span variables, gs get(variables, intSamples_, values); } +void slave_value_provider::get_boolean(gsl::span variables, gsl::span values) +{ + std::lock_guard lock(lock_); + get(variables, boolSamples_, values); +} + +void slave_value_provider::get_string(gsl::span variables, gsl::span values) +{ + std::lock_guard lock(lock_); + get(variables, stringSamples_, values); +} + } // namespace cse diff --git a/src/cpp/override_manipulator.cpp b/src/cpp/override_manipulator.cpp index 3d0b71378..d9db10ced 100644 --- a/src/cpp/override_manipulator.cpp +++ b/src/cpp/override_manipulator.cpp @@ -1,4 +1,5 @@ #include "cse/manipulator.hpp" +#include #include @@ -172,32 +173,27 @@ void override_manipulator::override_string_variable( add_action(index, variable, variable_type::string, scenario::string_modifier{f}); } -void override_manipulator::reset_real_variable( - simulator_index index, - variable_index variable) -{ - add_action(index, variable, variable_type::real, scenario::real_modifier{nullptr}); -} - -void override_manipulator::reset_integer_variable( - simulator_index index, - variable_index variable) -{ - add_action(index, variable, variable_type::integer, scenario::integer_modifier{nullptr}); -} - -void override_manipulator::reset_boolean_variable( - simulator_index index, - variable_index variable) -{ - add_action(index, variable, variable_type::boolean, scenario::boolean_modifier{nullptr}); -} - -void override_manipulator::reset_string_variable( +void override_manipulator::reset_variable( simulator_index index, + variable_type type, variable_index variable) { - add_action(index, variable, variable_type::string, scenario::string_modifier{nullptr}); + switch (type) { + case variable_type::real: + add_action(index, variable, variable_type::real, scenario::real_modifier{nullptr}); + break; + case variable_type::integer: + add_action(index, variable, variable_type::integer, scenario::integer_modifier{nullptr}); + break; + case variable_type::boolean: + add_action(index, variable, variable_type::boolean, scenario::boolean_modifier{nullptr}); + break; + case variable_type::string: + add_action(index, variable, variable_type::string, scenario::string_modifier{nullptr}); + break; + default: + CSE_PANIC(); + } } override_manipulator::~override_manipulator() = default; diff --git a/test/c/multiple_fmus_execution_test.c b/test/c/multiple_fmus_execution_test.c index 242272a46..4df7d07d9 100644 --- a/test/c/multiple_fmus_execution_test.c +++ b/test/c/multiple_fmus_execution_test.c @@ -3,6 +3,7 @@ #include #include #include +#include #ifdef _WINDOWS # include @@ -87,6 +88,16 @@ int main() rc = cse_manipulator_slave_set_integer(manipulator, slave_index1, &intInVar, 1, &intInVal); if (rc < 0) { goto Lerror; } + cse_variable_index boolInVar = 0; + const bool boolInVal = true; + rc = cse_manipulator_slave_set_boolean(manipulator, slave_index1, &boolInVar, 1, &boolInVal); + if (rc < 0) { goto Lerror; } + + cse_variable_index strInVar = 0; + const char* strInVal = "foo"; + rc = cse_manipulator_slave_set_string(manipulator, slave_index1, &strInVar, 1, &strInVal); + if (rc < 0) { goto Lerror; } + rc = cse_execution_step(execution, 10); if (rc < 0) { goto Lerror; } @@ -116,17 +127,38 @@ int main() rc = cse_observer_slave_get_real(observer1, slave_index1, &realOutVar, 1, &realOutVal); if (rc < 0) { goto Lerror; } + if (realOutVal != 5.0) { + fprintf(stderr, "Expected value 5.0, got %f\n", realOutVal); + goto Lfailure; + } + cse_variable_index intOutVar = 0; int intOutVal = 10; rc = cse_observer_slave_get_integer(observer1, slave_index1, &intOutVar, 1, &intOutVal); if (rc < 0) { goto Lerror; } - if (realOutVal != 5.0) { - fprintf(stderr, "Expected value 0.0, got %f\n", realOutVal); + if (intOutVal != 42) { + fprintf(stderr, "Expected value 42, got %i\n", intOutVal); goto Lfailure; } - if (intOutVal != 42) { - fprintf(stderr, "Expected value 0, got %i\n", intOutVal); + + cse_variable_index boolOutVar = 0; + bool boolOutVal = false; + rc = cse_observer_slave_get_boolean(observer1, slave_index1, &boolOutVar, 1, &boolOutVal); + if (rc < 0) { goto Lerror; } + + if (boolOutVal != true) { + fprintf(stderr, "Expected value true, got %s\n", boolOutVal > 0 ? "true" : "false"); + goto Lfailure; + } + + cse_variable_index strOutVar = 0; + const char* strOutVal; + rc = cse_observer_slave_get_string(observer1, slave_index1, &strOutVar, 1, &strOutVal); + if (rc < 0) { goto Lerror; } + + if (0 != strncmp(strOutVal, "foo", SLAVE_NAME_MAX_SIZE)) { + fprintf(stderr, "Expected value foo, got %s\n", strOutVal); goto Lfailure; } diff --git a/test/cpp/CMakeLists.txt b/test/cpp/CMakeLists.txt index b59fb96ee..4220f1bb9 100644 --- a/test/cpp/CMakeLists.txt +++ b/test/cpp/CMakeLists.txt @@ -3,6 +3,7 @@ set(tests "fixed_step_algorithm_test" "file_observer_logging_test" "file_observer_logging_from_config_test" + "last_value_observer_test" "multi_fixed_step_algorithm_test" "ssp_parser_test" "time_series_observer_test" diff --git a/test/cpp/last_value_observer_test.cpp b/test/cpp/last_value_observer_test.cpp new file mode 100644 index 000000000..beb9571b2 --- /dev/null +++ b/test/cpp/last_value_observer_test.cpp @@ -0,0 +1,114 @@ +#include "mock_slave.hpp" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +// A helper macro to test various assertions +#define REQUIRE(test) \ + if (!(test)) throw std::runtime_error("Requirement not satisfied: " #test) + +int main() +{ + try { + constexpr cse::time_point startTime; + constexpr cse::duration stepSize = cse::to_duration(0.5); + + cse::log::set_global_output_level(cse::log::level::debug); + + // Set up execution + auto execution = cse::execution( + startTime, + std::make_unique(stepSize)); + + auto observer = std::make_shared(); + execution.add_observer(observer); + + const auto sim = execution.add_slave( + cse::make_pseudo_async(std::make_unique( + [](double x) { return x + 1.234; }, + [](int i) { return i + 1; }, + [](bool b) { return !b; }, + [](std::string_view s) { return std::string(s) + std::string("bar"); })), + "slave"); + + execution.step(); + + const cse::variable_index outIndex = 0; + const cse::variable_index inIndex = 1; + + double realInValue = -1.0; + double realOutValue = -1.0; + observer->get_real(sim, gsl::make_span(&inIndex, 1), gsl::make_span(&realInValue, 1)); + observer->get_real(sim, gsl::make_span(&outIndex, 1), gsl::make_span(&realOutValue, 1)); + REQUIRE(std::fabs(realInValue - 0.0) < 1.0e-9); + REQUIRE(std::fabs(realOutValue - 1.234) < 1.0e-9); + + int intInValue = -1; + int intOutValue = -1; + observer->get_integer(sim, gsl::make_span(&inIndex, 1), gsl::make_span(&intInValue, 1)); + observer->get_integer(sim, gsl::make_span(&outIndex, 1), gsl::make_span(&intOutValue, 1)); + REQUIRE(intInValue == 0); + REQUIRE(intOutValue == 1); + + bool boolInValue = false; + bool boolOutValue = true; + observer->get_boolean(sim, gsl::make_span(&inIndex, 1), gsl::make_span(&boolInValue, 1)); + observer->get_boolean(sim, gsl::make_span(&outIndex, 1), gsl::make_span(&boolOutValue, 1)); + REQUIRE(boolInValue == true); + REQUIRE(boolOutValue == false); + + std::string stringInValue; + std::string stringOutValue; + observer->get_string(sim, gsl::make_span(&inIndex, 1), gsl::make_span(&stringInValue, 1)); + observer->get_string(sim, gsl::make_span(&outIndex, 1), gsl::make_span(&stringOutValue, 1)); + REQUIRE(stringInValue == ""); + REQUIRE(stringOutValue == "bar"); + + auto manipulator = std::make_shared(); + execution.add_manipulator(manipulator); + + manipulator->override_real_variable(sim, inIndex, 2.0); + manipulator->override_integer_variable(sim, inIndex, 2); + manipulator->override_boolean_variable(sim, inIndex, false); + manipulator->override_string_variable(sim, inIndex, "foo"); + + execution.step(); + + observer->get_real(sim, gsl::make_span(&inIndex, 1), gsl::make_span(&realInValue, 1)); + observer->get_real(sim, gsl::make_span(&outIndex, 1), gsl::make_span(&realOutValue, 1)); + REQUIRE(std::fabs(realInValue - 2.0) < 1.0e-9); + REQUIRE(std::fabs(realOutValue - 3.234) < 1.0e-9); + + observer->get_integer(sim, gsl::make_span(&inIndex, 1), gsl::make_span(&intInValue, 1)); + observer->get_integer(sim, gsl::make_span(&outIndex, 1), gsl::make_span(&intOutValue, 1)); + REQUIRE(intInValue == 2); + REQUIRE(intOutValue == 3); + + observer->get_boolean(sim, gsl::make_span(&inIndex, 1), gsl::make_span(&boolInValue, 1)); + observer->get_boolean(sim, gsl::make_span(&outIndex, 1), gsl::make_span(&boolOutValue, 1)); + REQUIRE(boolInValue == false); + REQUIRE(boolOutValue == true); + + observer->get_string(sim, gsl::make_span(&inIndex, 1), gsl::make_span(&stringInValue, 1)); + observer->get_string(sim, gsl::make_span(&outIndex, 1), gsl::make_span(&stringOutValue, 1)); + REQUIRE(stringInValue == "foo"); + REQUIRE(stringOutValue == "foobar"); + + + } catch (const std::exception& e) { + std::cerr << "Error: " << e.what() << std::endl; + return 1; + } + + return 0; +}