diff --git a/rclc_examples/src/example_parameter_server.c b/rclc_examples/src/example_parameter_server.c index 2832639b..9c2a12b2 100644 --- a/rclc_examples/src/example_parameter_server.c +++ b/rclc_examples/src/example_parameter_server.c @@ -36,8 +36,10 @@ void timer_callback(rcl_timer_t * timer, int64_t last_call_time) rclc_parameter_set_int(¶m_server, "param2", (int64_t) value); } -bool on_parameter_changed(const Parameter * old_param, const Parameter * new_param) +bool on_parameter_changed(const Parameter * old_param, const Parameter * new_param, void * context) { + (void) context; + if (old_param == NULL) { printf("Creating new parameter %s\n", new_param->name.data); } else if (new_param == NULL) { @@ -46,13 +48,19 @@ bool on_parameter_changed(const Parameter * old_param, const Parameter * new_par printf("Parameter %s modified.", old_param->name.data); switch (old_param->value.type) { case RCLC_PARAMETER_BOOL: - printf(" Old value: %d, New value: %d (bool)", old_param->value.bool_value, new_param->value.bool_value); + printf( + " Old value: %d, New value: %d (bool)", old_param->value.bool_value, + new_param->value.bool_value); break; case RCLC_PARAMETER_INT: - printf(" Old value: %ld, New value: %ld (int)", old_param->value.integer_value, new_param->value.integer_value); + printf( + " Old value: %ld, New value: %ld (int)", old_param->value.integer_value, + new_param->value.integer_value); break; case RCLC_PARAMETER_DOUBLE: - printf(" Old value: %f, New value: %f (double)", old_param->value.double_value, new_param->value.double_value); + printf( + " Old value: %f, New value: %f (double)", old_param->value.double_value, + new_param->value.double_value); break; default: break; @@ -106,7 +114,7 @@ int main() // Add parameters constrains rclc_add_parameter_description(¶m_server, "param2", "Second parameter", "Only even numbers"); - rclc_add_parameter_constraints_integer(¶m_server, "param2", -10, 120, 2); + rclc_add_parameter_constraints_integer(¶m_server, "param2", -10, 120, 2); rclc_add_parameter_description(¶m_server, "param3", "Third parameter", ""); rclc_set_parameter_read_only(¶m_server, "param3", true); diff --git a/rclc_parameter/include/rclc_parameter/rclc_parameter.h b/rclc_parameter/include/rclc_parameter/rclc_parameter.h index 23618308..f02cf8df 100644 --- a/rclc_parameter/include/rclc_parameter/rclc_parameter.h +++ b/rclc_parameter/include/rclc_parameter/rclc_parameter.h @@ -68,10 +68,10 @@ typedef struct rcl_interfaces__msg__ParameterEvent ParameterEvent; // Number of RCLC executor handles required for a parameter server #define RCLC_PARAMETER_EXECUTOR_HANDLES_NUMBER 5 -#define PARAMETER_MODIFICATION_REJECTED 4001 -#define PARAMETER_TYPE_MISMATCH 4002 -#define UNSUPORTED_ON_LOW_MEM 4003 -#define DISABLE_ON_CALLBACK 40004 +#define RCLC_PARAMETER_MODIFICATION_REJECTED 4001 +#define RCLC_PARAMETER_TYPE_MISMATCH 4002 +#define RCLC_PARAMETER_UNSUPORTED_ON_LOW_MEM 4003 +#define RCLC_PARAMETER_DISABLED_ON_CALLBACK 40004 /** * Parameter event callback. @@ -92,11 +92,13 @@ typedef struct rcl_interfaces__msg__ParameterEvent ParameterEvent; * * \param[in] param Parameter actual value, `NULL` for new parameter request. * \param[in] new_value Parameter new value, `NULL` for parameter removal request. + * \param[in] context Context of the callback. * \return `true` to accept the parameter event. The operation will be rejected on `false` return. */ -typedef bool (* ModifiedParameter_Callback)( +typedef bool (* rclc_parameter_callback_t)( const Parameter * old_param, - const Parameter * new_param); + const Parameter * new_param, + void * context); // Allowed RCLC parameter types typedef enum rclc_parameter_type_t @@ -146,7 +148,8 @@ typedef struct rclc_parameter_server_t ParameterEvent event_list; - ModifiedParameter_Callback on_modification; + rclc_parameter_callback_t on_modification; + void * context; bool on_callback; bool notify_changed_over_dds; @@ -236,7 +239,31 @@ RCLC_PARAMETER_PUBLIC rcl_ret_t rclc_executor_add_parameter_server( rclc_executor_t * executor, rclc_parameter_server_t * parameter_server, - ModifiedParameter_Callback on_modification); + rclc_parameter_callback_t on_modification); + +/** + * Adds a RCLC parameter server to an RCLC executor + * + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | Yes + * Thread-Safe | No + * Uses Atomics | No + * Lock-Free | No + * + * \param[in] executor RCLC executor + * \param[in] parameter_server preallocated rclc_parameter_server_t + * \param[in] on_modification on parameter modification callback + * \param[in] context context of the parameter modification callback + * \return `RCL_RET_OK` if success + */ +RCLC_PARAMETER_PUBLIC +rcl_ret_t rclc_executor_add_parameter_server_with_context( + rclc_executor_t * executor, + rclc_parameter_server_t * parameter_server, + rclc_parameter_callback_t on_modification, + void * context); /** * Adds a RCLC parameter to a server diff --git a/rclc_parameter/src/rclc_parameter/parameter_server.c b/rclc_parameter/src/rclc_parameter/parameter_server.c index 40607a50..67235b46 100644 --- a/rclc_parameter/src/rclc_parameter/parameter_server.c +++ b/rclc_parameter/src/rclc_parameter/parameter_server.c @@ -256,9 +256,9 @@ rclc_parameter_server_set_service_callback( if (ret == RCL_RET_INVALID_ARGUMENT) { rclc_parameter_set_string(message, "Set parameter error"); - } else if (ret == PARAMETER_MODIFICATION_REJECTED) { + } else if (ret == RCLC_PARAMETER_MODIFICATION_REJECTED) { rclc_parameter_set_string(message, "Rejected by server"); - } else if (ret == PARAMETER_TYPE_MISMATCH) { + } else if (ret == RCLC_PARAMETER_TYPE_MISMATCH) { rclc_parameter_set_string(message, "Type mismatch"); } else { response->results.data[i].successful = true; @@ -1067,7 +1067,19 @@ rcl_ret_t rclc_executor_add_parameter_server( rclc_executor_t * executor, rclc_parameter_server_t * parameter_server, - ModifiedParameter_Callback on_modification) + rclc_parameter_callback_t on_modification) +{ + return rclc_executor_add_parameter_server_with_context( + executor, parameter_server, + on_modification, NULL); +} + +rcl_ret_t +rclc_executor_add_parameter_server_with_context( + rclc_executor_t * executor, + rclc_parameter_server_t * parameter_server, + rclc_parameter_callback_t on_modification, + void * context) { RCL_CHECK_FOR_NULL_WITH_MSG( executor, "executor is a null pointer", return RCL_RET_INVALID_ARGUMENT); @@ -1077,6 +1089,7 @@ rclc_executor_add_parameter_server( rcl_ret_t ret; parameter_server->on_modification = on_modification; + parameter_server->context = context; ret = rclc_executor_add_service_with_context( executor, ¶meter_server->list_service, @@ -1121,7 +1134,7 @@ rclc_add_parameter( parameter_name, "parameter_name is a null pointer", return RCL_RET_INVALID_ARGUMENT); if (parameter_server->on_callback) { - return DISABLE_ON_CALLBACK; + return RCLC_PARAMETER_DISABLED_ON_CALLBACK; } size_t index = parameter_server->parameter_list.size; @@ -1223,7 +1236,7 @@ rclc_delete_parameter( parameter_name, "parameter_name is a null pointer", return RCL_RET_INVALID_ARGUMENT); if (parameter_server->on_callback) { - return DISABLE_ON_CALLBACK; + return RCLC_PARAMETER_DISABLED_ON_CALLBACK; } // Find parameter @@ -1286,7 +1299,7 @@ rclc_parameter_set_bool( parameter_name, "parameter_name is a null pointer", return RCL_RET_INVALID_ARGUMENT); if (parameter_server->on_callback) { - return DISABLE_ON_CALLBACK; + return RCLC_PARAMETER_DISABLED_ON_CALLBACK; } Parameter * parameter = @@ -1297,18 +1310,16 @@ rclc_parameter_set_bool( } if (parameter->value.type != RCLC_PARAMETER_BOOL) { - return PARAMETER_TYPE_MISMATCH; + return RCLC_PARAMETER_TYPE_MISMATCH; } - if (parameter_server->on_modification) { - Parameter new_parameter = *parameter; - new_parameter.value.bool_value = value; + Parameter new_parameter = *parameter; + new_parameter.value.bool_value = value; - if (RCL_RET_OK != - rclc_parameter_execute_callback(parameter_server, parameter, &new_parameter)) - { - return PARAMETER_MODIFICATION_REJECTED; - } + if (RCL_RET_OK != + rclc_parameter_execute_callback(parameter_server, parameter, &new_parameter)) + { + return RCLC_PARAMETER_MODIFICATION_REJECTED; } if (parameter_server->notify_changed_over_dds) { @@ -1333,7 +1344,7 @@ rclc_parameter_set_int( parameter_name, "parameter_name is a null pointer", return RCL_RET_INVALID_ARGUMENT); if (parameter_server->on_callback) { - return DISABLE_ON_CALLBACK; + return RCLC_PARAMETER_DISABLED_ON_CALLBACK; } Parameter * parameter = @@ -1344,18 +1355,16 @@ rclc_parameter_set_int( } if (parameter->value.type != RCLC_PARAMETER_INT) { - return PARAMETER_TYPE_MISMATCH; + return RCLC_PARAMETER_TYPE_MISMATCH; } - if (parameter_server->on_modification) { - Parameter new_parameter = *parameter; - new_parameter.value.integer_value = value; + Parameter new_parameter = *parameter; + new_parameter.value.integer_value = value; - if (RCL_RET_OK != - rclc_parameter_execute_callback(parameter_server, parameter, &new_parameter)) - { - return PARAMETER_MODIFICATION_REJECTED; - } + if (RCL_RET_OK != + rclc_parameter_execute_callback(parameter_server, parameter, &new_parameter)) + { + return RCLC_PARAMETER_MODIFICATION_REJECTED; } if (parameter_server->notify_changed_over_dds) { @@ -1380,7 +1389,7 @@ rclc_parameter_set_double( parameter_name, "parameter_name is a null pointer", return RCL_RET_INVALID_ARGUMENT); if (parameter_server->on_callback) { - return DISABLE_ON_CALLBACK; + return RCLC_PARAMETER_DISABLED_ON_CALLBACK; } Parameter * parameter = @@ -1391,18 +1400,16 @@ rclc_parameter_set_double( } if (parameter->value.type != RCLC_PARAMETER_DOUBLE) { - return PARAMETER_TYPE_MISMATCH; + return RCLC_PARAMETER_TYPE_MISMATCH; } - if (parameter_server->on_modification) { - Parameter new_parameter = *parameter; - new_parameter.value.double_value = value; + Parameter new_parameter = *parameter; + new_parameter.value.double_value = value; - if (RCL_RET_OK != - rclc_parameter_execute_callback(parameter_server, parameter, &new_parameter)) - { - return PARAMETER_MODIFICATION_REJECTED; - } + if (RCL_RET_OK != + rclc_parameter_execute_callback(parameter_server, parameter, &new_parameter)) + { + return RCLC_PARAMETER_MODIFICATION_REJECTED; } if (parameter_server->notify_changed_over_dds) { @@ -1544,7 +1551,7 @@ rcl_ret_t rclc_add_parameter_description( const char * additional_constraints) { if (parameter_server->low_mem_mode) { - return UNSUPORTED_ON_LOW_MEM; + return RCLC_PARAMETER_UNSUPORTED_ON_LOW_MEM; } size_t index = rclc_parameter_search_index(¶meter_server->parameter_list, parameter_name); @@ -1576,7 +1583,7 @@ rcl_ret_t rclc_set_parameter_read_only( const char * parameter_name, bool read_only) { if (parameter_server->on_callback) { - return DISABLE_ON_CALLBACK; + return RCLC_PARAMETER_DISABLED_ON_CALLBACK; } size_t index = rclc_parameter_search_index(¶meter_server->parameter_list, parameter_name); @@ -1599,7 +1606,7 @@ rcl_ret_t rclc_add_parameter_constraints_double( double to_value, double step) { if (parameter_server->on_callback) { - return DISABLE_ON_CALLBACK; + return RCLC_PARAMETER_DISABLED_ON_CALLBACK; } size_t index = rclc_parameter_search_index(¶meter_server->parameter_list, parameter_name); @@ -1628,7 +1635,7 @@ rcl_ret_t rclc_add_parameter_constraints_integer( int64_t to_value, uint64_t step) { if (parameter_server->on_callback) { - return DISABLE_ON_CALLBACK; + return RCLC_PARAMETER_DISABLED_ON_CALLBACK; } size_t index = rclc_parameter_search_index(¶meter_server->parameter_list, parameter_name); @@ -1659,11 +1666,11 @@ rcl_ret_t rclc_parameter_execute_callback( if (parameter_server->on_modification) { parameter_server->on_callback = true; - ret = parameter_server->on_modification(old_param, new_param); + ret = parameter_server->on_modification(old_param, new_param, parameter_server->context); parameter_server->on_callback = false; } - return ret ? RCL_RET_OK : PARAMETER_MODIFICATION_REJECTED; + return ret ? RCL_RET_OK : RCLC_PARAMETER_MODIFICATION_REJECTED; } #if __cplusplus diff --git a/rclc_parameter/test/rclc_parameter/test_parameter.cpp b/rclc_parameter/test/rclc_parameter/test_parameter.cpp index e957004a..0c3d1351 100644 --- a/rclc_parameter/test/rclc_parameter/test_parameter.cpp +++ b/rclc_parameter/test/rclc_parameter/test_parameter.cpp @@ -110,16 +110,10 @@ class ParameterTestBase : public ::testing::TestWithParam(10000)), + : callback_calls(0), + default_spin_timeout(std::chrono::duration(10000)), options(GetParam()) - { - callcack_calls = 0; - user_return = true; - strncpy(old_parameter_name, "", sizeof(old_parameter_name)); - strncpy(new_parameter_name, "", sizeof(new_parameter_name)); - new_parameter_value.type = RCLC_PARAMETER_NOT_SET; - old_parameter_value.type = RCLC_PARAMETER_NOT_SET; - } + {} ~ParameterTestBase() {} @@ -142,9 +136,10 @@ class ParameterTestBase : public ::testing::TestWithParamname.data, sizeof(new_parameter_name)); - rclc_parameter_value_copy(&new_parameter_value, &new_param->value); - } - - if (old_param == NULL) { - strncpy(old_parameter_name, "null", sizeof(old_parameter_name)); - old_parameter_value.type = RCLC_PARAMETER_NOT_SET; - } else { - strncpy(old_parameter_name, old_param->name.data, sizeof(old_parameter_name)); - rclc_parameter_value_copy(&old_parameter_value, &old_param->value); - } - - callcack_calls++; - return user_return; + ParameterTestBase * obj = reinterpret_cast(context); + obj->callback_calls++; + return obj->on_parameter_changed(old_param, new_param); } protected: // Callback - static int callcack_calls; - static bool user_return; - static char old_parameter_name[RCLC_PARAMETER_MAX_STRING_LENGTH]; - static char new_parameter_name[RCLC_PARAMETER_MAX_STRING_LENGTH]; - static ParameterValue new_parameter_value; - static ParameterValue old_parameter_value; + size_t callback_calls; + std::function on_parameter_changed; // Rclcpp std::shared_ptr param_client_node; @@ -233,15 +212,8 @@ class ParameterTestBase : public ::testing::TestWithParam bool { + EXPECT_EQ(strcmp(old_param->name.data, param_name), 0); + EXPECT_EQ(strcmp(new_param->name.data, param_name), 0); + EXPECT_EQ(old_param->value.type, RCLC_PARAMETER_BOOL); + EXPECT_EQ(new_param->value.type, RCLC_PARAMETER_BOOL); + EXPECT_EQ(old_param->value.bool_value, get_value); + EXPECT_EQ(new_param->value.bool_value, set_value); + return true; + }; + ASSERT_EQ(rclc_parameter_set_bool(¶m_server, param_name, set_value), RCL_RET_OK); - ASSERT_EQ(strcmp(old_parameter_name, param_name), 0); - ASSERT_EQ(strcmp(new_parameter_name, param_name), 0); - ASSERT_EQ(old_parameter_value.type, RCLC_PARAMETER_BOOL); - ASSERT_EQ(new_parameter_value.type, RCLC_PARAMETER_BOOL); - ASSERT_EQ(old_parameter_value.bool_value, get_value); - ASSERT_EQ(new_parameter_value.bool_value, set_value); - ASSERT_EQ(callcack_calls, expected_callcack_calls); - expected_callcack_calls++; + EXPECT_EQ(callback_calls, expected_callback_calls); + expected_callback_calls++; // Get new value ASSERT_EQ(rclc_parameter_get_bool(¶m_server, param_name, &get_value), RCL_RET_OK); @@ -279,15 +255,19 @@ TEST_P(ParameterTestBase, rclc_set_get_parameter) { ASSERT_EQ(get_value, 0); // Set value + on_parameter_changed = [&](const Parameter * old_param, const Parameter * new_param) -> bool { + EXPECT_EQ(strcmp(old_param->name.data, param_name), 0); + EXPECT_EQ(strcmp(new_param->name.data, param_name), 0); + EXPECT_EQ(old_param->value.type, RCLC_PARAMETER_INT); + EXPECT_EQ(new_param->value.type, RCLC_PARAMETER_INT); + EXPECT_EQ(old_param->value.integer_value, get_value); + EXPECT_EQ(new_param->value.integer_value, set_value); + return true; + }; + ASSERT_EQ(rclc_parameter_set_int(¶m_server, param_name, set_value), RCL_RET_OK); - ASSERT_EQ(strcmp(old_parameter_name, param_name), 0); - ASSERT_EQ(strcmp(new_parameter_name, param_name), 0); - ASSERT_EQ(old_parameter_value.type, RCLC_PARAMETER_INT); - ASSERT_EQ(new_parameter_value.type, RCLC_PARAMETER_INT); - ASSERT_EQ(old_parameter_value.integer_value, 0); - ASSERT_EQ(new_parameter_value.integer_value, set_value); - ASSERT_EQ(callcack_calls, expected_callcack_calls); - expected_callcack_calls++; + ASSERT_EQ(callback_calls, expected_callback_calls); + expected_callback_calls++; // Get new value ASSERT_EQ(rclc_parameter_get_int(¶m_server, param_name, &get_value), RCL_RET_OK); @@ -304,17 +284,21 @@ TEST_P(ParameterTestBase, rclc_set_get_parameter) { ASSERT_EQ(get_value, 0.0); // Set value + on_parameter_changed = [&](const Parameter * old_param, const Parameter * new_param) -> bool { + EXPECT_EQ(strcmp(old_param->name.data, param_name), 0); + EXPECT_EQ(strcmp(new_param->name.data, param_name), 0); + EXPECT_EQ(old_param->value.type, RCLC_PARAMETER_DOUBLE); + EXPECT_EQ(new_param->value.type, RCLC_PARAMETER_DOUBLE); + EXPECT_EQ(old_param->value.double_value, get_value); + EXPECT_EQ(new_param->value.double_value, set_value); + return true; + }; + ASSERT_EQ( rclc_parameter_set_double( ¶m_server, param_name, set_value), RCL_RET_OK); - ASSERT_EQ(strcmp(old_parameter_name, param_name), 0); - ASSERT_EQ(strcmp(new_parameter_name, param_name), 0); - ASSERT_EQ(old_parameter_value.type, RCLC_PARAMETER_DOUBLE); - ASSERT_EQ(new_parameter_value.type, RCLC_PARAMETER_DOUBLE); - ASSERT_EQ(old_parameter_value.double_value, 0.0); - ASSERT_EQ(new_parameter_value.double_value, set_value); - ASSERT_EQ(callcack_calls, expected_callcack_calls); - expected_callcack_calls++; + ASSERT_EQ(callback_calls, expected_callback_calls); + expected_callback_calls++; // Get new value ASSERT_EQ(rclc_parameter_get_double(¶m_server, param_name, &get_value), RCL_RET_OK); @@ -322,7 +306,6 @@ TEST_P(ParameterTestBase, rclc_set_get_parameter) { } // Fail with user reject - user_return = false; { const char * param_name = "param3"; double set_value = 0.05; @@ -333,11 +316,15 @@ TEST_P(ParameterTestBase, rclc_set_get_parameter) { ASSERT_EQ(rclc_parameter_get_double(¶m_server, param_name, &first_get_value), RCL_RET_OK); // Set value + on_parameter_changed = [&](const Parameter *, const Parameter *) -> bool { + return false; + }; + ASSERT_EQ( rclc_parameter_set_double( ¶m_server, param_name, - set_value), PARAMETER_MODIFICATION_REJECTED); - ASSERT_EQ(callcack_calls, 4); + set_value), RCLC_PARAMETER_MODIFICATION_REJECTED); + ASSERT_EQ(callback_calls, expected_callback_calls); // Get value ASSERT_EQ(rclc_parameter_get_double(¶m_server, param_name, &second_get_value), RCL_RET_OK); @@ -346,7 +333,7 @@ TEST_P(ParameterTestBase, rclc_set_get_parameter) { } TEST_P(ParameterTestBase, rclcpp_set_get_parameter) { - int expected_callcack_calls = 1; + size_t expected_callback_calls = 1; // List parameters check std::vector param_names = {"param1", "param2", "param3"}; @@ -367,18 +354,21 @@ TEST_P(ParameterTestBase, rclcpp_set_get_parameter) { bool get_value = parameters_client->get_parameter(param_name); ASSERT_EQ(get_value, false); + // Prepare RCLC callback + on_parameter_changed = [&](const Parameter *, const Parameter * new_param) -> bool { + EXPECT_EQ(new_param->value.type, RCLC_PARAMETER_BOOL); + EXPECT_EQ(strcmp(new_param->name.data, param_name.c_str()), 0); + EXPECT_EQ(new_param->value.bool_value, param[0].as_bool()); + return true; + }; + // Set value auto result = parameters_client->set_parameters(param, default_spin_timeout); ASSERT_FALSE(result.empty()); ASSERT_TRUE(result[0].successful); ASSERT_EQ(result[0].reason, ""); - - // Check callback values - ASSERT_EQ(callcack_calls, expected_callcack_calls); - ASSERT_EQ(new_parameter_value.type, RCLC_PARAMETER_BOOL); - ASSERT_EQ(new_parameter_name, param_name); - ASSERT_EQ(new_parameter_value.bool_value, param[0].as_bool()); - expected_callcack_calls++; + ASSERT_EQ(callback_calls, expected_callback_calls); + expected_callback_calls++; // Get new value get_value = parameters_client->get_parameter(param_name); @@ -393,6 +383,14 @@ TEST_P(ParameterTestBase, rclcpp_set_get_parameter) { int get_value = parameters_client->get_parameter(param_name); ASSERT_EQ(get_value, false); + // Prepare RCLC callback + on_parameter_changed = [&](const Parameter *, const Parameter * new_param) -> bool { + EXPECT_EQ(new_param->value.type, RCLC_PARAMETER_INT); + EXPECT_EQ(strcmp(new_param->name.data, param_name.c_str()), 0); + EXPECT_EQ(new_param->value.integer_value, param[0].as_int()); + return true; + }; + // Set value auto result = parameters_client->set_parameters(param, default_spin_timeout); ASSERT_FALSE(result.empty()); @@ -400,11 +398,8 @@ TEST_P(ParameterTestBase, rclcpp_set_get_parameter) { ASSERT_EQ(result[0].reason, ""); // Check callback values - ASSERT_EQ(callcack_calls, expected_callcack_calls); - ASSERT_EQ(new_parameter_value.type, RCLC_PARAMETER_INT); - ASSERT_EQ(new_parameter_name, param_name); - ASSERT_EQ(new_parameter_value.integer_value, param[0].as_int()); - expected_callcack_calls++; + ASSERT_EQ(callback_calls, expected_callback_calls); + expected_callback_calls++; // Get new value get_value = parameters_client->get_parameter(param_name); @@ -419,6 +414,14 @@ TEST_P(ParameterTestBase, rclcpp_set_get_parameter) { double get_value = parameters_client->get_parameter(param_name); ASSERT_EQ(get_value, false); + // Prepare RCLC callback + on_parameter_changed = [&](const Parameter *, const Parameter * new_param) -> bool { + EXPECT_EQ(new_param->value.type, RCLC_PARAMETER_DOUBLE); + EXPECT_EQ(strcmp(new_param->name.data, param_name.c_str()), 0); + EXPECT_EQ(new_param->value.double_value, param[0].as_double()); + return true; + }; + // Set value auto result = parameters_client->set_parameters(param, default_spin_timeout); ASSERT_FALSE(result.empty()); @@ -426,11 +429,8 @@ TEST_P(ParameterTestBase, rclcpp_set_get_parameter) { ASSERT_EQ(result[0].reason, ""); // Check callback values - ASSERT_EQ(callcack_calls, expected_callcack_calls); - ASSERT_EQ(new_parameter_value.type, RCLC_PARAMETER_DOUBLE); - ASSERT_EQ(new_parameter_name, param_name); - ASSERT_EQ(new_parameter_value.double_value, param[0].as_double()); - expected_callcack_calls++; + ASSERT_EQ(callback_calls, expected_callback_calls); + expected_callback_calls++; // Get new value get_value = parameters_client->get_parameter(param_name); @@ -438,7 +438,6 @@ TEST_P(ParameterTestBase, rclcpp_set_get_parameter) { } // Fail with user reject - user_return = false; { std::vector param = {rclcpp::Parameter(param_names[2], -0.05)}; const std::string param_name = param[0].get_name(); @@ -446,13 +445,18 @@ TEST_P(ParameterTestBase, rclcpp_set_get_parameter) { // Get initial value double first_get_value = parameters_client->get_parameter(param_name); + // Prepare RCLC callback + on_parameter_changed = [&](const Parameter *, const Parameter *) -> bool { + return false; + }; + // Set value auto result = parameters_client->set_parameters(param, default_spin_timeout); ASSERT_FALSE(result.empty()); ASSERT_FALSE(result[0].successful); ASSERT_EQ(result[0].reason, "Rejected by server"); - ASSERT_EQ(callcack_calls, expected_callcack_calls); - expected_callcack_calls++; + ASSERT_EQ(callback_calls, expected_callback_calls); + expected_callback_calls++; // Get value double second_get_value = parameters_client->get_parameter(param_name); @@ -465,6 +469,12 @@ TEST_P(ParameterTestBase, rclc_delete_parameter) { const char * param_name = "param1"; bool param_value; + // Fail if callback is call + on_parameter_changed = [&](const Parameter *, const Parameter *) -> bool { + EXPECT_TRUE(false); // Callback should not be called + return false; + }; + ASSERT_EQ(rclc_parameter_get_bool(¶m_server, param_name, ¶m_value), RCL_RET_OK); // Delete parameter @@ -475,32 +485,46 @@ TEST_P(ParameterTestBase, rclc_delete_parameter) { // Fail on deleted parameter EXPECT_EQ(rclc_delete_parameter(¶m_server, param_name), RCL_RET_ERROR); + + // No callback calls + ASSERT_EQ(callback_calls, 0U); } TEST_P(ParameterTestBase, rclcpp_delete_parameter) { - int expected_callcack_calls = 1; + size_t expected_callback_calls = 1; // Use RCLCPP to delete and check parameters - user_return = false; const std::vector parameters = {"param1"}; + + on_parameter_changed = [&](const Parameter * old_param, const Parameter * new_param) -> bool { + EXPECT_NE(old_param, nullptr); + EXPECT_EQ(new_param, nullptr); + return false; + }; + auto result = parameters_client->delete_parameters(parameters, default_spin_timeout); ASSERT_FALSE(result.empty()); ASSERT_FALSE(result[0].successful); ASSERT_EQ(result[0].reason, "Rejected by server"); - ASSERT_EQ(callcack_calls, expected_callcack_calls); - expected_callcack_calls++; + ASSERT_EQ(callback_calls, expected_callback_calls); + expected_callback_calls++; auto list_params = parameters_client->list_parameters({}, 4, default_spin_timeout); ASSERT_EQ(list_params.names.size(), 3u); ASSERT_EQ(list_params.names[0], parameters[0]); - user_return = true; + on_parameter_changed = [&](const Parameter * old_param, const Parameter * new_param) -> bool { + EXPECT_NE(old_param, nullptr); + EXPECT_EQ(new_param, nullptr); + return true; + }; + result = parameters_client->delete_parameters(parameters, default_spin_timeout); ASSERT_FALSE(result.empty()); ASSERT_TRUE(result[0].successful); ASSERT_EQ(result[0].reason, ""); - ASSERT_EQ(callcack_calls, expected_callcack_calls); - expected_callcack_calls++; + ASSERT_EQ(callback_calls, expected_callback_calls); + expected_callback_calls++; // Use auxiliar RCLCPP node for check list_params = parameters_client->list_parameters({}, 4, default_spin_timeout); @@ -508,23 +532,30 @@ TEST_P(ParameterTestBase, rclcpp_delete_parameter) { ASSERT_EQ( std::find( list_params.names.begin(), - list_params.names.end(), parameters[0]), list_params.names.end()); + list_params.names.end(), + parameters[0]), + list_params.names.end()); } TEST_P(ParameterTestBase, rclcpp_add_parameter) { std::vector param = {rclcpp::Parameter("param4", 10.5)}; if (options.allow_undeclared_parameters) { - int expected_callcack_calls = 1; + size_t expected_callback_calls = 1; // Reject add parameter - user_return = false; + on_parameter_changed = [&](const Parameter * old_param, const Parameter * new_param) -> bool { + EXPECT_EQ(old_param, nullptr); + EXPECT_NE(new_param, nullptr); + return false; + }; + auto result = parameters_client->set_parameters(param, default_spin_timeout); ASSERT_FALSE(result.empty()); ASSERT_FALSE(result[0].successful); ASSERT_EQ(result[0].reason, "New parameter rejected"); - ASSERT_EQ(callcack_calls, expected_callcack_calls); - expected_callcack_calls++; + ASSERT_EQ(callback_calls, expected_callback_calls); + expected_callback_calls++; auto list_params = parameters_client->list_parameters({}, 4, default_spin_timeout); ASSERT_EQ(list_params.names.size(), 3u); @@ -534,12 +565,17 @@ TEST_P(ParameterTestBase, rclcpp_add_parameter) { param[0].get_name()), list_params.names.end()); // Accept add parameter - user_return = true; + on_parameter_changed = [&](const Parameter * old_param, const Parameter * new_param) -> bool { + EXPECT_EQ(old_param, nullptr); + EXPECT_NE(new_param, nullptr); + return true; + }; + result = parameters_client->set_parameters(param, default_spin_timeout); ASSERT_FALSE(result.empty()); ASSERT_TRUE(result[0].successful); ASSERT_EQ(result[0].reason, "New parameter added"); - ASSERT_EQ(callcack_calls, expected_callcack_calls); + ASSERT_EQ(callback_calls, expected_callback_calls); list_params = parameters_client->list_parameters({}, 4, default_spin_timeout); ASSERT_EQ(list_params.names.size(), 4u); @@ -550,21 +586,30 @@ TEST_P(ParameterTestBase, rclcpp_add_parameter) { ASSERT_EQ(param_value, 10.5); // Reject parameter on full server - user_return = false; + on_parameter_changed = [&](const Parameter *, const Parameter *) -> bool { + EXPECT_TRUE(false); // Callback should not be called + return false; + }; + param.clear(); param.push_back(rclcpp::Parameter("param5", 12.2)); result = parameters_client->set_parameters(param, default_spin_timeout); ASSERT_FALSE(result.empty()); ASSERT_FALSE(result[0].successful); ASSERT_EQ(result[0].reason, "Parameter server is full"); - ASSERT_EQ(callcack_calls, expected_callcack_calls); + ASSERT_EQ(callback_calls, expected_callback_calls); } else { + on_parameter_changed = [&](const Parameter *, const Parameter *) -> bool { + EXPECT_TRUE(false); // Callback should not be called + return false; + }; + // Reject add parameter auto result = parameters_client->set_parameters(param, default_spin_timeout); ASSERT_FALSE(result.empty()); ASSERT_FALSE(result[0].successful); ASSERT_EQ(result[0].reason, "Parameter not found"); - ASSERT_EQ(callcack_calls, 0); + ASSERT_EQ(callback_calls, 0U); auto list_params = parameters_client->list_parameters({}, 4, default_spin_timeout); ASSERT_EQ(list_params.names.size(), 3u); @@ -581,11 +626,16 @@ TEST_P(ParameterTestBase, rclcpp_read_only_parameter) { std::vector param = {rclcpp::Parameter("param2", 50)}; // Reject set parameter on read only parameter + on_parameter_changed = [&](const Parameter *, const Parameter *) -> bool { + EXPECT_TRUE(false); // Callback should not be called + return false; + }; + auto result = parameters_client->set_parameters(param, default_spin_timeout); ASSERT_FALSE(result.empty()); ASSERT_FALSE(result[0].successful); ASSERT_EQ(result[0].reason, "Read only parameter"); - ASSERT_EQ(callcack_calls, 0); + ASSERT_EQ(callback_calls, 0U); // Check read only flag on descriptor std::vector params = {param[0].get_name()}; @@ -668,7 +718,9 @@ TEST_P(ParameterTestBase, rclcpp_parameter_description_low) { // Set parameter constrains ASSERT_EQ( - rclc_add_parameter_description(¶m_server, "param2", "", ""), UNSUPORTED_ON_LOW_MEM); + rclc_add_parameter_description( + ¶m_server, "param2", "", + ""), RCLC_PARAMETER_UNSUPORTED_ON_LOW_MEM); ASSERT_EQ( rclc_add_parameter_constraints_integer( ¶m_server, "param2", int_from, int_to, @@ -742,6 +794,10 @@ TEST_P(ParameterTestBase, notify_changed_over_dds) { std::this_thread::sleep_for(500ms); // Parameter change event + on_parameter_changed = [&](const Parameter *, const Parameter *) -> bool { + return true; + }; + ASSERT_EQ(rclc_parameter_set_bool(¶m_server, "param1", false), RCL_RET_OK); ASSERT_EQ( rclcpp::spin_until_future_complete(