diff --git a/rcl_action/CMakeLists.txt b/rcl_action/CMakeLists.txt
index e0ef84928..70fa46420 100644
--- a/rcl_action/CMakeLists.txt
+++ b/rcl_action/CMakeLists.txt
@@ -6,14 +6,11 @@ find_package(ament_cmake_ros REQUIRED)
find_package(action_msgs REQUIRED)
find_package(rcl REQUIRED)
-find_package(rcutils REQUIRED)
-# find_package(rmw REQUIRED)
include_directories(
include
${action_msgs_INCLUDE_DIRS}
${rcl_INCLUDE_DIRS}
- ${rcutils_INCLUDE_DIRS}
)
# Default to C11
@@ -34,77 +31,63 @@ add_executable(test_compile_headers
src/test_compile_headers.c
)
-# set(rcl_action_sources
-# src/action_server.c
-# src/action_client.c
-# src/action_goal.c
-# src/transition_map.c
-# )
-# set_source_files_properties(
-# ${rcl_action_sources}
-# PROPERTIES language "C"
-# )
-
-### C-Library depending only on RCL
-# add_library(
-# ${PROJECT_NAME}
-# ${rcl_action_sources}
-# )
+set(rcl_action_sources
+ src/${PROJECT_NAME}/goal_state_machine.c
+)
-# specific order: dependents before dependencies
-# ament_target_dependencies(${PROJECT_NAME}
-# "rcl"
-# "action_msgs"
-# "rosidl_generator_c"
-# "rcutils"
-# )
+set_source_files_properties(
+ ${rcl_action_sources}
+ PROPERTIES language "C"
+)
+
+add_library(
+ ${PROJECT_NAME}
+ ${rcl_action_sources}
+)
+
+ament_target_dependencies(${PROJECT_NAME}
+ "rcl"
+ "action_msgs"
+)
# Causes the visibility macros to use dllexport rather than dllimport,
# which is appropriate when building the dll but not consuming it.
-# target_compile_definitions(${PROJECT_NAME} PRIVATE "RCL_ACTION_BUILDING_DLL")
+target_compile_definitions(${PROJECT_NAME} PRIVATE "RCL_ACTION_BUILDING_DLL")
-# install(TARGETS ${PROJECT_NAME}
-# ARCHIVE DESTINATION lib
-# LIBRARY DESTINATION lib
-# RUNTIME DESTINATION bin
-# )
+install(
+ DIRECTORY include/
+ DESTINATION include
+)
+
+install(TARGETS ${PROJECT_NAME}
+ ARCHIVE DESTINATION lib
+ LIBRARY DESTINATION lib
+ RUNTIME DESTINATION bin
+)
if(BUILD_TESTING)
find_package(ament_cmake_gtest REQUIRED)
find_package(ament_lint_auto REQUIRED)
ament_lint_auto_find_test_dependencies()
-
+ ament_find_gtest()
# Gtests
- # ament_add_gtest(test_action_server
- # test/test_action_server.cpp
- # )
- # if(TARGET test_action_server)
- # target_include_directories(test_action_server PUBLIC
- # ${rcl_INCLUDE_DIRS}
- # )
- # target_link_libraries(test_action_server ${PROJECT_NAME})
- # endif()
- # ament_add_gtest(test_action_client
- # test/test_action_client.cpp
- # )
- # if(TARGET test_action_client)
- # target_include_directories(test_action_client PUBLIC
- # ${rcl_INCLUDE_DIRS}
- # )
- # target_link_libraries(test_action_client ${PROJECT_NAME})
- # endif()
+ ament_add_gtest(test_goal_state_machine
+ test/rcl_action/test_goal_state_machine.cpp
+ )
+ if(TARGET test_goal_state_machine)
+ target_include_directories(test_goal_state_machine PUBLIC
+ ${rcl_INCLUDE_DIRS}
+ )
+ target_link_libraries(test_goal_state_machine
+ ${PROJECT_NAME}
+ )
+ endif()
endif()
# specific order: dependents before dependencies
ament_export_include_directories(include)
-# ament_export_libraries(${PROJECT_NAME})
+ament_export_libraries(${PROJECT_NAME})
ament_export_dependencies(ament_cmake)
ament_export_dependencies(rcl)
-# ament_export_dependencies(action_msgs)
-ament_export_dependencies(rcutils)
+ament_export_dependencies(action_msgs)
ament_package()
-
-install(
- DIRECTORY include/
- DESTINATION include
-)
diff --git a/rcl_action/include/rcl_action/goal_state_machine.h b/rcl_action/include/rcl_action/goal_state_machine.h
index 3420d07e9..72a2cecf7 100644
--- a/rcl_action/include/rcl_action/goal_state_machine.h
+++ b/rcl_action/include/rcl_action/goal_state_machine.h
@@ -24,83 +24,6 @@ extern "C"
#include "rcl_action/visibility_control.h"
-typedef rcl_action_goal_state_t
-(* rcl_action_goal_event_handler)(rcl_action_goal_state_t, rcl_action_goal_event_t);
-
-// Transition event handlers
-static inline rcl_action_goal_state_t
-_execute_event_handler(rcl_action_goal_state_t state, rcl_action_goal_event_t event)
-{
- if (GOAL_STATE_ACCEPTED != state || GOAL_EVENT_EXECUTE != event) {
- return GOAL_STATE_UNKNOWN;
- }
- return GOAL_STATE_EXECUTING;
-}
-
-static inline rcl_action_goal_state_t
-_cancel_event_handler(rcl_action_goal_state_t state, rcl_action_goal_event_t event)
-{
- if (GOAL_STATE_ACCEPTED != state ||
- GOAL_STATE_EXECUTING != state ||
- GOAL_EVENT_CANCEL != event)
- {
- return GOAL_STATE_UNKNOWN;
- }
- return GOAL_STATE_CANCELING;
-}
-
-static inline rcl_action_goal_state_t
-_set_succeeded_event_handler(rcl_action_goal_state_t state, rcl_action_goal_event_t event)
-{
- if (GOAL_STATE_EXECUTING != state ||
- GOAL_STATE_CANCELING != state ||
- GOAL_EVENT_SET_SUCCEEDED != event)
- {
- return GOAL_STATE_UNKNOWN;
- }
- return GOAL_STATE_SUCCEEDED;
-}
-
-static inline rcl_action_goal_state_t
-_set_aborted_event_handler(rcl_action_goal_state_t state, rcl_action_goal_event_t event)
-{
- if (GOAL_STATE_EXECUTING != state ||
- GOAL_STATE_CANCELING != state ||
- GOAL_EVENT_SET_ABORTED != event)
- {
- return GOAL_STATE_UNKNOWN;
- }
- return GOAL_STATE_ABORTED;
-}
-
-static inline rcl_action_goal_state_t
-_set_canceled_event_handler(rcl_action_goal_state_t state, rcl_action_goal_event_t event)
-{
- if (GOAL_STATE_CANCELING != state || GOAL_EVENT_SET_CANCELED != event) {
- return GOAL_STATE_UNKNOWN;
- }
- return GOAL_STATE_CANCELED;
-}
-
-// Transition map
-rcl_action_goal_event_handler
- _goal_state_transition_map[GOAL_STATE_NUM_STATES][GOAL_EVENT_NUM_EVENTS] = {
- [GOAL_STATE_ACCEPTED] = {
- [GOAL_EVENT_EXECUTE] = _execute_event_handler,
- [GOAL_EVENT_CANCEL] = _cancel_event_handler,
- },
- [GOAL_STATE_EXECUTING] = {
- [GOAL_EVENT_CANCEL] = _cancel_event_handler,
- [GOAL_EVENT_SET_SUCCEEDED] = _set_succeeded_event_handler,
- [GOAL_EVENT_SET_ABORTED] = _set_aborted_event_handler,
- },
- [GOAL_STATE_CANCELING] = {
- [GOAL_EVENT_SET_SUCCEEDED] = _set_succeeded_event_handler,
- [GOAL_EVENT_SET_ABORTED] = _set_aborted_event_handler,
- [GOAL_EVENT_SET_CANCELED] = _set_canceled_event_handler,
- },
-};
-
/// Transition a goal from one state to the next.
/**
* Given a goal state and a goal event, return the next state.
@@ -108,22 +31,14 @@ rcl_action_goal_event_handler
* \param[in] state the state to transition from
* \param[in] event the event triggering a transition
* \return the next goal state if the transition is valid, or
- * \return `GOAl_STATE_UNKNOWN` if the transition is invalid or an error occured
+ * \return `GOAL_STATE_UNKNOWN` if the transition is invalid or an error occured
*/
RCL_ACTION_PUBLIC
RCL_WARN_UNUSED
-inline rcl_action_goal_state_t
+rcl_action_goal_state_t
rcl_action_transition_goal_state(
const rcl_action_goal_state_t state,
- const rcl_action_goal_event_t event)
-{
- // rcl_action_goal_event_handler ** transition_map = get_state_transition_map();
- rcl_action_goal_event_handler handler = _goal_state_transition_map[state][event];
- if (NULL == handler) {
- return GOAL_STATE_UNKNOWN;
- }
- return handler(state, event);
-}
+ const rcl_action_goal_event_t event);
#ifdef __cplusplus
}
diff --git a/rcl_action/include/rcl_action/types.h b/rcl_action/include/rcl_action/types.h
index ff0be45e2..605bd8a63 100644
--- a/rcl_action/include/rcl_action/types.h
+++ b/rcl_action/include/rcl_action/types.h
@@ -72,7 +72,7 @@ typedef int8_t rcl_action_goal_state_t;
#define GOAL_STATE_SUCCEEDED action_msgs__msg__GoalStatus__STATUS_SUCCEEDED
#define GOAL_STATE_CANCELED action_msgs__msg__GoalStatus__STATUS_CANCELED
#define GOAL_STATE_ABORTED action_msgs__msg__GoalStatus__STATUS_ABORTED
-#define GOAL_STATE_NUM_STATES 6 // not counting `UNKNOWN`
+#define GOAL_STATE_NUM_STATES 7
/// Goal state transition events
typedef enum rcl_action_goal_event_t
diff --git a/rcl_action/package.xml b/rcl_action/package.xml
index 7a1e7b6e4..c5eab74f5 100644
--- a/rcl_action/package.xml
+++ b/rcl_action/package.xml
@@ -11,15 +11,9 @@
action_msgs
rcl
- rcutils
- rmw_implementation
- rosidl_generator_c
action_msgs
rcl
- rcutils
- rmw_implementation
- rosidl_generator_c
ament_cmake_gtest
ament_lint_common
diff --git a/rcl_action/src/rcl_action/goal_state_machine.c b/rcl_action/src/rcl_action/goal_state_machine.c
new file mode 100644
index 000000000..4056cff43
--- /dev/null
+++ b/rcl_action/src/rcl_action/goal_state_machine.c
@@ -0,0 +1,111 @@
+// Copyright 2018 Open Source Robotics Foundation, Inc.
+//
+// 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.
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "rcl_action/goal_state_machine.h"
+
+
+typedef rcl_action_goal_state_t
+(* rcl_action_goal_event_handler)(rcl_action_goal_state_t, rcl_action_goal_event_t);
+
+// Transition event handlers
+rcl_action_goal_state_t
+_execute_event_handler(rcl_action_goal_state_t state, rcl_action_goal_event_t event)
+{
+ if (GOAL_STATE_ACCEPTED != state || GOAL_EVENT_EXECUTE != event) {
+ return GOAL_STATE_UNKNOWN;
+ }
+ return GOAL_STATE_EXECUTING;
+}
+
+rcl_action_goal_state_t
+_cancel_event_handler(rcl_action_goal_state_t state, rcl_action_goal_event_t event)
+{
+ if ((GOAL_STATE_ACCEPTED != state && GOAL_STATE_EXECUTING != state) ||
+ GOAL_EVENT_CANCEL != event)
+ {
+ return GOAL_STATE_UNKNOWN;
+ }
+ return GOAL_STATE_CANCELING;
+}
+
+rcl_action_goal_state_t
+_set_succeeded_event_handler(rcl_action_goal_state_t state, rcl_action_goal_event_t event)
+{
+ if ((GOAL_STATE_EXECUTING != state && GOAL_STATE_CANCELING != state) ||
+ GOAL_EVENT_SET_SUCCEEDED != event)
+ {
+ return GOAL_STATE_UNKNOWN;
+ }
+ return GOAL_STATE_SUCCEEDED;
+}
+
+rcl_action_goal_state_t
+_set_aborted_event_handler(rcl_action_goal_state_t state, rcl_action_goal_event_t event)
+{
+ if ((GOAL_STATE_EXECUTING != state && GOAL_STATE_CANCELING != state) ||
+ GOAL_EVENT_SET_ABORTED != event)
+ {
+ return GOAL_STATE_UNKNOWN;
+ }
+ return GOAL_STATE_ABORTED;
+}
+
+rcl_action_goal_state_t
+_set_canceled_event_handler(rcl_action_goal_state_t state, rcl_action_goal_event_t event)
+{
+ if (GOAL_STATE_CANCELING != state || GOAL_EVENT_SET_CANCELED != event) {
+ return GOAL_STATE_UNKNOWN;
+ }
+ return GOAL_STATE_CANCELED;
+}
+
+// Transition map
+static rcl_action_goal_event_handler
+ _goal_state_transition_map[GOAL_STATE_NUM_STATES][GOAL_EVENT_NUM_EVENTS] = {
+ [GOAL_STATE_ACCEPTED] = {
+ [GOAL_EVENT_EXECUTE] = _execute_event_handler,
+ [GOAL_EVENT_CANCEL] = _cancel_event_handler,
+ },
+ [GOAL_STATE_EXECUTING] = {
+ [GOAL_EVENT_CANCEL] = _cancel_event_handler,
+ [GOAL_EVENT_SET_SUCCEEDED] = _set_succeeded_event_handler,
+ [GOAL_EVENT_SET_ABORTED] = _set_aborted_event_handler,
+ },
+ [GOAL_STATE_CANCELING] = {
+ [GOAL_EVENT_SET_SUCCEEDED] = _set_succeeded_event_handler,
+ [GOAL_EVENT_SET_ABORTED] = _set_aborted_event_handler,
+ [GOAL_EVENT_SET_CANCELED] = _set_canceled_event_handler,
+ },
+};
+
+rcl_action_goal_state_t
+rcl_action_transition_goal_state(
+ const rcl_action_goal_state_t state,
+ const rcl_action_goal_event_t event)
+{
+ rcl_action_goal_event_handler handler = _goal_state_transition_map[state][event];
+ if (NULL == handler) {
+ return GOAL_STATE_UNKNOWN;
+ }
+ return handler(state, event);
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/rcl_action/test/rcl_action/test_goal_state_machine.cpp b/rcl_action/test/rcl_action/test_goal_state_machine.cpp
new file mode 100644
index 000000000..32d710204
--- /dev/null
+++ b/rcl_action/test/rcl_action/test_goal_state_machine.cpp
@@ -0,0 +1,152 @@
+// Copyright 2018 Open Source Robotics Foundation, Inc.
+//
+// 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
+
+#include "rcl_action/goal_state_machine.h"
+
+
+TEST(TestGoalStateMachine, test_valid_transitions)
+{
+ rcl_action_goal_state_t state = rcl_action_transition_goal_state(
+ GOAL_STATE_ACCEPTED,
+ GOAL_EVENT_EXECUTE);
+ EXPECT_EQ(GOAL_STATE_EXECUTING, state);
+ state = rcl_action_transition_goal_state(
+ GOAL_STATE_ACCEPTED,
+ GOAL_EVENT_CANCEL);
+ EXPECT_EQ(GOAL_STATE_CANCELING, state);
+ state = rcl_action_transition_goal_state(
+ GOAL_STATE_EXECUTING,
+ GOAL_EVENT_CANCEL);
+ EXPECT_EQ(GOAL_STATE_CANCELING, state);
+ state = rcl_action_transition_goal_state(
+ GOAL_STATE_EXECUTING,
+ GOAL_EVENT_SET_SUCCEEDED);
+ EXPECT_EQ(GOAL_STATE_SUCCEEDED, state);
+ state = rcl_action_transition_goal_state(
+ GOAL_STATE_EXECUTING,
+ GOAL_EVENT_SET_ABORTED);
+ EXPECT_EQ(GOAL_STATE_ABORTED, state);
+ state = rcl_action_transition_goal_state(
+ GOAL_STATE_CANCELING,
+ GOAL_EVENT_SET_CANCELED);
+ EXPECT_EQ(GOAL_STATE_CANCELED, state);
+ state = rcl_action_transition_goal_state(
+ GOAL_STATE_CANCELING,
+ GOAL_EVENT_SET_ABORTED);
+ EXPECT_EQ(GOAL_STATE_ABORTED, state);
+}
+
+TEST(TestGoalStateMachine, test_invalid_transitions)
+{
+ // Invalid from ACCEPTED
+ rcl_action_goal_state_t state = rcl_action_transition_goal_state(
+ GOAL_STATE_ACCEPTED,
+ GOAL_EVENT_SET_SUCCEEDED);
+ EXPECT_EQ(GOAL_STATE_UNKNOWN, state);
+ state = rcl_action_transition_goal_state(
+ GOAL_STATE_ACCEPTED,
+ GOAL_EVENT_SET_ABORTED);
+ EXPECT_EQ(GOAL_STATE_UNKNOWN, state);
+ state = rcl_action_transition_goal_state(
+ GOAL_STATE_ACCEPTED,
+ GOAL_EVENT_SET_CANCELED);
+ EXPECT_EQ(GOAL_STATE_UNKNOWN, state);
+
+ // Invalid from EXECUTING
+ state = rcl_action_transition_goal_state(
+ GOAL_STATE_EXECUTING,
+ GOAL_EVENT_EXECUTE);
+ EXPECT_EQ(GOAL_STATE_UNKNOWN, state);
+ state = rcl_action_transition_goal_state(
+ GOAL_STATE_EXECUTING,
+ GOAL_EVENT_SET_CANCELED);
+ EXPECT_EQ(GOAL_STATE_UNKNOWN, state);
+
+ // Invalid from CANCELING
+ state = rcl_action_transition_goal_state(
+ GOAL_STATE_CANCELING,
+ GOAL_EVENT_EXECUTE);
+ EXPECT_EQ(GOAL_STATE_UNKNOWN, state);
+ state = rcl_action_transition_goal_state(
+ GOAL_STATE_CANCELING,
+ GOAL_EVENT_CANCEL);
+ EXPECT_EQ(GOAL_STATE_UNKNOWN, state);
+
+ // Invalid from SUCCEEDED
+ state = rcl_action_transition_goal_state(
+ GOAL_STATE_SUCCEEDED,
+ GOAL_EVENT_EXECUTE);
+ EXPECT_EQ(GOAL_STATE_UNKNOWN, state);
+ state = rcl_action_transition_goal_state(
+ GOAL_STATE_SUCCEEDED,
+ GOAL_EVENT_CANCEL);
+ EXPECT_EQ(GOAL_STATE_UNKNOWN, state);
+ state = rcl_action_transition_goal_state(
+ GOAL_STATE_SUCCEEDED,
+ GOAL_EVENT_SET_SUCCEEDED);
+ EXPECT_EQ(GOAL_STATE_UNKNOWN, state);
+ state = rcl_action_transition_goal_state(
+ GOAL_STATE_SUCCEEDED,
+ GOAL_EVENT_SET_ABORTED);
+ EXPECT_EQ(GOAL_STATE_UNKNOWN, state);
+ state = rcl_action_transition_goal_state(
+ GOAL_STATE_SUCCEEDED,
+ GOAL_EVENT_SET_CANCELED);
+ EXPECT_EQ(GOAL_STATE_UNKNOWN, state);
+
+ // Invalid from ABORTED
+ state = rcl_action_transition_goal_state(
+ GOAL_STATE_ABORTED,
+ GOAL_EVENT_EXECUTE);
+ EXPECT_EQ(GOAL_STATE_UNKNOWN, state);
+ state = rcl_action_transition_goal_state(
+ GOAL_STATE_ABORTED,
+ GOAL_EVENT_CANCEL);
+ EXPECT_EQ(GOAL_STATE_UNKNOWN, state);
+ state = rcl_action_transition_goal_state(
+ GOAL_STATE_ABORTED,
+ GOAL_EVENT_SET_SUCCEEDED);
+ EXPECT_EQ(GOAL_STATE_UNKNOWN, state);
+ state = rcl_action_transition_goal_state(
+ GOAL_STATE_ABORTED,
+ GOAL_EVENT_SET_ABORTED);
+ EXPECT_EQ(GOAL_STATE_UNKNOWN, state);
+ state = rcl_action_transition_goal_state(
+ GOAL_STATE_ABORTED,
+ GOAL_EVENT_SET_CANCELED);
+ EXPECT_EQ(GOAL_STATE_UNKNOWN, state);
+
+ // Invalid from CANCELED
+ state = rcl_action_transition_goal_state(
+ GOAL_STATE_CANCELED,
+ GOAL_EVENT_EXECUTE);
+ EXPECT_EQ(GOAL_STATE_UNKNOWN, state);
+ state = rcl_action_transition_goal_state(
+ GOAL_STATE_CANCELED,
+ GOAL_EVENT_CANCEL);
+ EXPECT_EQ(GOAL_STATE_UNKNOWN, state);
+ state = rcl_action_transition_goal_state(
+ GOAL_STATE_CANCELED,
+ GOAL_EVENT_SET_SUCCEEDED);
+ EXPECT_EQ(GOAL_STATE_UNKNOWN, state);
+ state = rcl_action_transition_goal_state(
+ GOAL_STATE_CANCELED,
+ GOAL_EVENT_SET_ABORTED);
+ EXPECT_EQ(GOAL_STATE_UNKNOWN, state);
+ state = rcl_action_transition_goal_state(
+ GOAL_STATE_CANCELED,
+ GOAL_EVENT_SET_CANCELED);
+ EXPECT_EQ(GOAL_STATE_UNKNOWN, state);
+}