diff --git a/src/ros2cs/ros2cs_core/ActionServer.cs b/src/ros2cs/ros2cs_core/ActionServer.cs new file mode 100644 index 00000000..e3061f19 --- /dev/null +++ b/src/ros2cs/ros2cs_core/ActionServer.cs @@ -0,0 +1,143 @@ +// Copyright 2019-2021 Robotec.ai +// +// 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. + +using System; +using ROS2.Internal; +using action_msgs.srv; +using action_msgs.msg; + +namespace ROS2 +{ + + /// Enum to indicate handling of new goal + public enum ActionGoalResponse + { + REJECT, + ACCEPT_AND_EXECUTE, + ACCEPT_AND_DEFER + } + + public class ActionServer: IActionServer + where TGoalRequest : Message, new() + where TGoalResponse : Message, new() + where TFeedback : Message, new() + where TResultRequest : Message, new() + where TResultResponse : Message, new() + { + + /// Service to cancel action (same for every action) + private Service serviceCancel; + + /// Service to reply to a result request + private Service serviceResult; + + /// Service to register a new goal + private Service serviceGoal; + + /// Topic to which action status is published (same for every action) + private Publisher publisherStatus; + + /// Topic to which action progress is published + private Publisher publisherFeedback; + + /// + /// Internal constructor + /// + /// Use to construct new Instances + internal ActionServer( + string topic, + Node node, + Func handleGoal, + Func handleCancel, + Action handleAccepted + ) + { + string prefix = topic + "_action/"; + + QualityOfServiceProfile qos_service = new QualityOfServiceProfile(QosPresetProfile.SERVICES_DEFAULT); + QualityOfServiceProfile qos_status = new QualityOfServiceProfile(QosPresetProfile.ACTION_STATUS_DEFAULT); + + // Default service and topic: + + this.serviceCancel = node.CreateService( + prefix + "cancel_goal", + handleCancel, + qos_service + ); + + this.publisherStatus = node.CreatePublisher( + prefix + "status", + qos_status + ); + + // Custom: + + this.serviceGoal = node.CreateService( + prefix + "send_goal", + onGoalReceive, + qos_service + ); + + this.serviceResult = node.CreateService( + prefix + "get_result", + onResultReceive, + qos_service + ); + } + + public void Dispose() + { + DestroyActionServer(); + } + + /// + /// Callback for the goal service + /// + /// Most of the logic will be in the user defined function, but we wrap it here. + /// + private TGoalResponse onGoalReceive(TGoalRequest request) + { + TGoalResponse response = new TGoalResponse(); + return response; + } + + private TResultResponse onResultReceive(TResultRequest request) + { + TResultResponse response = new TResultResponse(); + return response; + } + + /// + /// Callback for cancel service + /// + private CancelGoal_Response defaultOnCancelReceive(CancelGoal_Request request) + { + CancelGoal_Response response = new CancelGoal_Response() + { + Return_code = CancelGoal_Response.ERROR_REJECTED + }; + return response; + } + + + /// + public bool IsDisposed { get { return IsDisposed; } } + private bool disposed = false; + + private void DestroyActionServer() + { + + } + } +} diff --git a/src/ros2cs/ros2cs_core/CMakeLists.txt b/src/ros2cs/ros2cs_core/CMakeLists.txt index d5f2955a..00974fcb 100644 --- a/src/ros2cs/ros2cs_core/CMakeLists.txt +++ b/src/ros2cs/ros2cs_core/CMakeLists.txt @@ -25,6 +25,7 @@ if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang") endif() find_package(ros2cs_common REQUIRED) +find_package(action_msgs REQUIRED) find_package(ament_cmake_export_assemblies REQUIRED) find_package(ament_cmake REQUIRED) find_package(dotnet_cmake_module REQUIRED) @@ -36,6 +37,7 @@ find_package(DotNETExtra REQUIRED) # Used by ros2cs_native find_package(rcl REQUIRED) +find_package(rcl_action REQUIRED) find_package(rcutils REQUIRED) find_package(rmw REQUIRED) find_package(rosidl_generator_c REQUIRED) @@ -63,6 +65,7 @@ add_library( ament_target_dependencies(ros2cs_native "rcl" + "rcl_action" "rcutils" "rmw" "rosidl_generator_c" @@ -77,6 +80,7 @@ set(CS_INTERFACES interfaces/INode.cs interfaces/IClient.cs interfaces/IService.cs + interfaces/IActionServer.cs interfaces/IPublisher.cs interfaces/ISubscription.cs ) @@ -100,6 +104,7 @@ set(CS_SOURCES Clock.cs Client.cs Service.cs + ActionServer.cs Node.cs Publisher.cs QualityOfServiceProfile.cs @@ -113,6 +118,10 @@ set(_assembly_deps_dll "") foreach(_assembly_dep ${ros2cs_common_ASSEMBLIES_DLL}) list(APPEND _assembly_deps_dll "${_assembly_dep}") endforeach() +foreach(_assembly_dep ${action_msgs_ASSEMBLIES_DLL}) + list(APPEND _assembly_deps_dll "${_assembly_dep}") +endforeach() + add_dotnet_library(${PROJECT_NAME} SOURCES @@ -125,8 +134,10 @@ install_dotnet(${PROJECT_NAME} DESTINATION lib/dotnet) ament_export_assemblies_dll("lib/dotnet/${PROJECT_NAME}.dll") ament_export_dependencies(ros2cs_common) +ament_export_dependencies(action_msgs) ament_export_dependencies(ament_cmake) ament_export_dependencies(rcl) +ament_export_dependencies(rcl_action) ament_export_dependencies(rosidl_generator_c) option(STANDALONE_BUILD "Deploy standalone libraries with build" OFF) diff --git a/src/ros2cs/ros2cs_core/Node.cs b/src/ros2cs/ros2cs_core/Node.cs index 6911c2d1..833b0c18 100644 --- a/src/ros2cs/ros2cs_core/Node.cs +++ b/src/ros2cs/ros2cs_core/Node.cs @@ -15,6 +15,8 @@ using System; using System.Linq; using System.Collections.Generic; +using action_msgs.srv; +using action_msgs.msg; namespace ROS2 { @@ -65,6 +67,7 @@ internal List Services private HashSet publishers; private HashSet clients; private HashSet services; + private HashSet action_servers; private readonly object mutex = new object(); private bool disposed = false; @@ -82,6 +85,7 @@ internal Node(string nodeName, ref rcl_context_t context) publishers = new HashSet(); clients = new HashSet(); services = new HashSet(); + action_servers = new HashSet(); nodeHandle = NativeRcl.rcl_get_zero_initialized_node(); defaultNodeOptions = NativeRclInterface.rclcs_node_create_default_options(); @@ -187,7 +191,7 @@ public bool RemoveClient(IClientBase client) return null; } - Service service = new Service(topic, this, callback, qos); + Service service = new Service(topic, this, callback, qos); services.Add(service); logger.LogInfo("Created service for topic " + topic); return service; @@ -210,6 +214,41 @@ public bool RemoveService(IServiceBase service) } } + public ActionServer + CreateActionServer( + string topic, + Func handleGoal, + Func handleCancel, + Action handleAccepted + ) + where TGoalRequest : Message, new() + where TGoalResponse : Message, new() + where TFeedback : Message, new() + where TResultRequest : Message, new() + where TResultResponse : Message, new() + { + lock (mutex) + { + if (disposed || !Ros2cs.Ok()) + { + logger.LogWarning("Cannot create action server as the class is already disposed or shutdown was called"); + return null; + } + + ActionServer action_server = + new ActionServer( + topic, + this, + handleGoal, + handleCancel, + handleAccepted + ); + action_servers.Add(action_server); + logger.LogInfo("Created action server for topic " + topic); + return action_server; + } + } + /// Create a publisher for this node for a given topic, qos and message type /// public Publisher CreatePublisher(string topic, QualityOfServiceProfile qos = null) where T : Message, new() diff --git a/src/ros2cs/ros2cs_core/QualityOfServiceProfile.cs b/src/ros2cs/ros2cs_core/QualityOfServiceProfile.cs index 2c9e281c..3f6498ba 100644 --- a/src/ros2cs/ros2cs_core/QualityOfServiceProfile.cs +++ b/src/ros2cs/ros2cs_core/QualityOfServiceProfile.cs @@ -25,7 +25,8 @@ public enum QosPresetProfile DEFAULT, SERVICES_DEFAULT, PARAMETER_EVENTS, - SYSTEM_DEFAULT + SYSTEM_DEFAULT, + ACTION_STATUS_DEFAULT, } public enum HistoryPolicy diff --git a/src/ros2cs/ros2cs_core/interfaces/IActionServer.cs b/src/ros2cs/ros2cs_core/interfaces/IActionServer.cs new file mode 100644 index 00000000..b7b47f82 --- /dev/null +++ b/src/ros2cs/ros2cs_core/interfaces/IActionServer.cs @@ -0,0 +1,31 @@ +// Copyright 2019-2021 Robotec.ai +// +// 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. + +namespace ROS2 +{ + public interface IActionServerBase : IExtendedDisposable + { + + } + + /// Generic base interface for all actions (either server or client) + public interface IActionServer : IActionServerBase + where TGoalRequest : Message, new() + where TGoalResponse : Message, new() + where TFeedback : Message, new() + where TResultRequest : Message, new() + where TResultResponse : Message, new() + { + } +} diff --git a/src/ros2cs/ros2cs_core/interfaces/INode.cs b/src/ros2cs/ros2cs_core/interfaces/INode.cs index 90b59d4c..ae1b6eb6 100644 --- a/src/ros2cs/ros2cs_core/interfaces/INode.cs +++ b/src/ros2cs/ros2cs_core/interfaces/INode.cs @@ -14,6 +14,8 @@ using System; using System.Collections.Generic; +using action_msgs.srv; +using action_msgs.msg; namespace ROS2 { @@ -47,6 +49,20 @@ public interface INode: IExtendedDisposable /// Service for the topic Service CreateService(string topic, Func callback, QualityOfServiceProfile qos = null) where I : Message, new() where O : Message, new(); + /// Create an action server for this node + ActionServer + CreateActionServer( + string topic, + Func handleGoal, + Func handleCancel, + Action handleAccepted + ) + where TGoalRequest : Message, new() + where TGoalResponse : Message, new() + where TFeedback : Message, new() + where TResultRequest : Message, new() + where TResultResponse : Message, new(); + /// Remove a service /// Note that this does not call Dispose on Service /// Service created with earlier CreateService call diff --git a/src/ros2cs/ros2cs_core/native/rmw_native_interface.c b/src/ros2cs/ros2cs_core/native/rmw_native_interface.c index a2fe8d6d..a523d3f1 100644 --- a/src/ros2cs/ros2cs_core/native/rmw_native_interface.c +++ b/src/ros2cs/ros2cs_core/native/rmw_native_interface.c @@ -16,6 +16,7 @@ #include #include #include +#include ROSIDL_GENERATOR_C_EXPORT rmw_qos_profile_t * rmw_native_interface_create_qos_profile(int profile) @@ -27,7 +28,8 @@ rmw_qos_profile_t * rmw_native_interface_create_qos_profile(int profile) DEFAULT, SERVICES_DEFAULT, PARAMETER_EVENTS, - SYSTEM_DEFAULT + SYSTEM_DEFAULT, + ACTION_STATUS_DEFAULT }; rmw_qos_profile_t * preset_profile = (rmw_qos_profile_t *)malloc(sizeof(rmw_qos_profile_t)); @@ -40,6 +42,7 @@ rmw_qos_profile_t * rmw_native_interface_create_qos_profile(int profile) case SERVICES_DEFAULT: *preset_profile = rmw_qos_profile_services_default; break; case PARAMETER_EVENTS: *preset_profile = rmw_qos_profile_parameter_events; break; case SYSTEM_DEFAULT: *preset_profile = rmw_qos_profile_system_default; break; + case ACTION_STATUS_DEFAULT: *preset_profile = rcl_action_qos_profile_status_default; break; default: *preset_profile = rmw_qos_profile_unknown; break; } diff --git a/src/ros2cs/ros2cs_examples/CMakeLists.txt b/src/ros2cs/ros2cs_examples/CMakeLists.txt index cf8c062f..e3052eee 100644 --- a/src/ros2cs/ros2cs_examples/CMakeLists.txt +++ b/src/ros2cs/ros2cs_examples/CMakeLists.txt @@ -20,6 +20,7 @@ find_package(ament_cmake REQUIRED) find_package(ros2cs_common REQUIRED) find_package(ros2cs_core REQUIRED) find_package(std_msgs REQUIRED) +find_package(action_msgs REQUIRED) find_package(sensor_msgs REQUIRED) find_package(example_interfaces REQUIRED) find_package(builtin_interfaces REQUIRED) @@ -35,6 +36,7 @@ set(_assemblies_dep_dlls ${ros2cs_common_ASSEMBLIES_DLL} ${ros2cs_core_ASSEMBLIES_DLL} ${std_msgs_ASSEMBLIES_DLL} + ${action_msgs_ASSEMBLIES_DLL} ${sensor_msgs_ASSEMBLIES_DLL} ${example_interfaces_ASSEMBLIES_DLL} ${builtin_interfaces_ASSEMBLIES_DLL} @@ -76,11 +78,18 @@ add_dotnet_executable(ros2cs_service ${_assemblies_dep_dlls} ) +add_dotnet_executable(ros2cs_actionserver + ROS2ActionServer.cs + INCLUDE_DLLS + ${_assemblies_dep_dlls} +) + install_dotnet(ros2cs_listener DESTINATION lib/${PROJECT_NAME}/dotnet) install_dotnet(ros2cs_talker DESTINATION lib/${PROJECT_NAME}/dotnet) install_dotnet(ros2cs_performance_talker DESTINATION lib/${PROJECT_NAME}/dotnet) install_dotnet(ros2cs_performance_listener DESTINATION lib/${PROJECT_NAME}/dotnet) install_dotnet(ros2cs_client DESTINATION lib/${PROJECT_NAME}/dotnet) install_dotnet(ros2cs_service DESTINATION lib/${PROJECT_NAME}/dotnet) +install_dotnet(ros2cs_actionserver DESTINATION lib/${PROJECT_NAME}/dotnet) ament_package() diff --git a/src/ros2cs/ros2cs_examples/ROS2ActionServer.cs b/src/ros2cs/ros2cs_examples/ROS2ActionServer.cs new file mode 100644 index 00000000..eda9b74b --- /dev/null +++ b/src/ros2cs/ros2cs_examples/ROS2ActionServer.cs @@ -0,0 +1,88 @@ +// Copyright 2019-2021 Robotec.ai +// +// 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. + +using System; +using action_msgs.srv; +using ROS2; +using example_interfaces.action; + +namespace Examples +{ + /// A simple action server class to illustrate Ros2cs + public class ROS2ActionServer + { + public static IActionServer< + Fibonacci_SendGoal_Request, + Fibonacci_SendGoal_Response, + Fibonacci_Feedback, + Fibonacci_GetResult_Request, + Fibonacci_GetResult_Response + > my_action_server; + + public static void Main(string[] args) + { + Console.WriteLine("ActionServer start"); + Ros2cs.Init(); + INode node = Ros2cs.CreateNode("action_server"); + my_action_server = node.CreateActionServer< + Fibonacci_SendGoal_Request, + Fibonacci_SendGoal_Response, + Fibonacci_Feedback, + Fibonacci_GetResult_Request, + Fibonacci_GetResult_Response>( + "fibonacci", + handle_goal, + handle_cancel, + handle_accepted + ); + + Ros2cs.Spin(node); + Ros2cs.Shutdown(); + } + + /// + /// Callback on receiving a goal - must return quickly! + /// + public static ActionGoalResponse handle_goal(Fibonacci_SendGoal_Request request) + { + Console.WriteLine("Receiving new action goal..."); + + return ActionGoalResponse.ACCEPT_AND_EXECUTE; + } + + /// + /// Callback on receiving a cancel request - must return quickly! + /// + public static CancelGoal_Response handle_cancel(CancelGoal_Request request) + { + CancelGoal_Response response = new CancelGoal_Response(); + return response; + } + + public static void handle_accepted(Fibonacci_SendGoal_Request request) + { + return; + } + + /// + /// Actual action + /// + /// This function should be called from a different thread and does not need to return any time soon. + /// + public static void execute() + { + return; + } + } +} diff --git a/src/ros2cs/rosidl_generator_cs/cmake/rosidl_generator_cs_generate_interfaces.cmake b/src/ros2cs/rosidl_generator_cs/cmake/rosidl_generator_cs_generate_interfaces.cmake index b263cb8c..7228fe8e 100644 --- a/src/ros2cs/rosidl_generator_cs/cmake/rosidl_generator_cs_generate_interfaces.cmake +++ b/src/ros2cs/rosidl_generator_cs/cmake/rosidl_generator_cs_generate_interfaces.cmake @@ -65,7 +65,7 @@ foreach(_idl_file ${rosidl_generate_interfaces_ABS_IDL_FILES}) ) list(APPEND _type_support_by_generated_msg_c_files "${_typesupport_impl}") endforeach() - elseif(_parent_folder STREQUAL "srv") + elseif(_parent_folder STREQUAL "srv" OR _parent_folder STREQUAL "action") list(APPEND _generated_srv_cs_files "${_output_path}/${_parent_folder}/${_module_name}.cs" ) @@ -78,7 +78,6 @@ foreach(_idl_file ${rosidl_generate_interfaces_ABS_IDL_FILES}) ) list(APPEND _type_support_by_generated_srv_c_files "${_typesupport_impl}") endforeach() - elseif(_parent_folder STREQUAL "action") else() message(FATAL_ERROR "Interface file with unknown parent folder: ${_idl_file}") endif() diff --git a/src/ros2cs/rosidl_generator_cs/resource/idl.c.em b/src/ros2cs/rosidl_generator_cs/resource/idl.c.em index 999eb127..8df3c8a8 100644 --- a/src/ros2cs/rosidl_generator_cs/resource/idl.c.em +++ b/src/ros2cs/rosidl_generator_cs/resource/idl.c.em @@ -33,7 +33,6 @@ TEMPLATE( }@ @[end for]@ -@# TODO (adamdbrw): Add services and actions @####################################################################### @# Handle service @@ -60,5 +59,82 @@ TEMPLATE( }@ @[end for]@ @[end if]@ -@# // endif +@####################################################################### +@# Handle action +@####################################################################### +@{ +from rosidl_parser.definition import Action +}@ + +@[if include_parts[1] == "action"]@ + +@[for action in content.get_elements_of_type(Action)]@ + +@# Goal Service Request: +@{ +TEMPLATE( + 'srv.c.em', + package_name=package_name, + interface_path=interface_path, + service=action.send_goal_service, + message=action.send_goal_service.request_message, + include_parts=include_parts, + get_c_type=get_c_type + ) +}@ + +@# Goal Service Response: +@{ +TEMPLATE( + 'srv.c.em', + package_name=package_name, + interface_path=interface_path, + service=action.send_goal_service, + message=action.send_goal_service.response_message, + include_parts=include_parts, + get_c_type=get_c_type + ) +}@ + +@# Feedback Message: +@{ +TEMPLATE( + 'msg.c.em', + package_name=package_name, + interface_path=interface_path, + message=action.feedback, + include_parts=include_parts, + get_c_type=get_c_type + ) +}@ + +@# Result Service Request: +@{ +TEMPLATE( + 'srv.c.em', + package_name=package_name, + interface_path=interface_path, + service=action.get_result_service, + message=action.get_result_service.request_message, + include_parts=include_parts, + get_c_type=get_c_type + ) +}@ + +@# Result Service Response: +@{ +TEMPLATE( + 'srv.c.em', + package_name=package_name, + interface_path=interface_path, + service=action.get_result_service, + message=action.get_result_service.response_message, + include_parts=include_parts, + get_c_type=get_c_type + ) +}@ + +@[end for]@ + +@[end if]@ diff --git a/src/ros2cs/rosidl_generator_cs/resource/idl.cs.em b/src/ros2cs/rosidl_generator_cs/resource/idl.cs.em index 3ac8ffeb..6633467a 100644 --- a/src/ros2cs/rosidl_generator_cs/resource/idl.cs.em +++ b/src/ros2cs/rosidl_generator_cs/resource/idl.cs.em @@ -82,5 +82,148 @@ TEMPLATE( }@ @[end for]@ @[end if]@ -@# // endif +@####################################################################### +@# Handle action +@####################################################################### +@{ +from rosidl_parser.definition import Action +}@ + +@[if include_parts[1] == "action"]@ + +@[for action in content.get_elements_of_type(Action)]@ + +@# Goal Message: +@{ +TEMPLATE( + 'msg.cs.em', + package_name=package_name, + interface_path=interface_path, + message=action.goal, + include_directives=include_directives, + get_dotnet_type=get_dotnet_type, + get_field_name=get_field_name, + constant_value_to_dotnet=constant_value_to_dotnet, + get_c_type=get_c_type, + get_marshal_type=get_marshal_type, + get_marshal_array_type=get_marshal_array_type, + get_csbuild_tool=get_csbuild_tool + ) +}@ + +@# Feedback Message: +@{ +TEMPLATE( + 'msg.cs.em', + package_name=package_name, + interface_path=interface_path, + message=action.feedback, + include_directives=include_directives, + get_dotnet_type=get_dotnet_type, + get_field_name=get_field_name, + constant_value_to_dotnet=constant_value_to_dotnet, + get_c_type=get_c_type, + get_marshal_type=get_marshal_type, + get_marshal_array_type=get_marshal_array_type, + get_csbuild_tool=get_csbuild_tool + ) +}@ + +@# Result Message: +@{ +TEMPLATE( + 'msg.cs.em', + package_name=package_name, + interface_path=interface_path, + message=action.result, + include_directives=include_directives, + get_dotnet_type=get_dotnet_type, + get_field_name=get_field_name, + constant_value_to_dotnet=constant_value_to_dotnet, + get_c_type=get_c_type, + get_marshal_type=get_marshal_type, + get_marshal_array_type=get_marshal_array_type, + get_csbuild_tool=get_csbuild_tool + ) +}@ + +@# Goal Service Request: +@{ +TEMPLATE( + 'srv.cs.em', + package_name=package_name, + interface_path=interface_path, + service=action.send_goal_service, + message=action.send_goal_service.request_message, + include_directives=include_directives, + get_dotnet_type=get_dotnet_type, + get_field_name=get_field_name, + constant_value_to_dotnet=constant_value_to_dotnet, + get_c_type=get_c_type, + get_marshal_type=get_marshal_type, + get_marshal_array_type=get_marshal_array_type, + get_csbuild_tool=get_csbuild_tool + ) +}@ + +@# Goal Service Response: +@{ +TEMPLATE( + 'srv.cs.em', + package_name=package_name, + interface_path=interface_path, + service=action.send_goal_service, + message=action.send_goal_service.response_message, + include_directives=include_directives, + get_dotnet_type=get_dotnet_type, + get_field_name=get_field_name, + constant_value_to_dotnet=constant_value_to_dotnet, + get_c_type=get_c_type, + get_marshal_type=get_marshal_type, + get_marshal_array_type=get_marshal_array_type, + get_csbuild_tool=get_csbuild_tool + ) +}@ + +@# Result Service Request: +@{ +TEMPLATE( + 'srv.cs.em', + package_name=package_name, + interface_path=interface_path, + service=action.get_result_service, + message=action.get_result_service.request_message, + include_directives=include_directives, + get_dotnet_type=get_dotnet_type, + get_field_name=get_field_name, + constant_value_to_dotnet=constant_value_to_dotnet, + get_c_type=get_c_type, + get_marshal_type=get_marshal_type, + get_marshal_array_type=get_marshal_array_type, + get_csbuild_tool=get_csbuild_tool + ) +}@ + +@# Result Service Response: +@{ +TEMPLATE( + 'srv.cs.em', + package_name=package_name, + interface_path=interface_path, + service=action.get_result_service, + message=action.get_result_service.response_message, + include_directives=include_directives, + get_dotnet_type=get_dotnet_type, + get_field_name=get_field_name, + constant_value_to_dotnet=constant_value_to_dotnet, + get_c_type=get_c_type, + get_marshal_type=get_marshal_type, + get_marshal_array_type=get_marshal_array_type, + get_csbuild_tool=get_csbuild_tool + ) +}@ + +@[end for]@ + +@[end if]@