rclrb 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,224 @@
1
+ module Rclrb
2
+ ##
3
+ # This module contains classes used to handle ROS messages.
4
+ # The content of Fields is internal API to rclrb and should not be directly called and is subject
5
+ # to change.
6
+ module Fields
7
+ # This function is used for building generic parse_ros_message_array function, that will read array elements one-by-one and call block to parse them
8
+ def Fields.__generic_parse_array data, length, field_size, &block
9
+ array = []
10
+ for i in 0...length
11
+ ptr = data + i * field_size
12
+ array.append block.call(ptr)
13
+ end
14
+ return array
15
+ end
16
+ # This function is used for building generic fill_ros_message_array function, that will write array elements one-by-one and call block to add them
17
+ def Fields.__generic_fill_ros_message_array array_pointer, value, field_size, &block
18
+ for i in 0...value.length
19
+ block.call array_pointer + i * field_size, value[i]
20
+ end
21
+ end
22
+
23
+
24
+ class AtomicField
25
+ attr_reader :init_value, :field_name, :ffi_type
26
+ def initialize(init_value, field_name, ffi_type, array_reader, array_writter)
27
+ @init_value = init_value
28
+ @field_name = "Rclrb::Fields::#{field_name}"
29
+ @ffi_type = ffi_type
30
+ @memory_size = FFI::type_size @ffi_type
31
+ @array_reader = array_reader
32
+ @array_writter = array_writter
33
+ end
34
+ def array_field()
35
+ @array_field = ArrayField.new(self) unless defined?(@array_field)
36
+ return @array_field
37
+ end
38
+ def parse_ros_message(data)
39
+ return data
40
+ end
41
+ def parse_ros_message_array(data, length)
42
+ if @array_reader
43
+ return data.send @array_reader, 0, length
44
+ else
45
+ return Fields.__generic_parse_array(data, length, self.ffi_size) { |ptr| ptr.get(@ffi_type, 0) }
46
+ end
47
+ end
48
+ def fill_ros_message(data, index, value)
49
+ data[index] = value
50
+ end
51
+ def fill_ros_message_array(array_pointer, value)
52
+ if @array_writter
53
+ return array_pointer.send @array_writter, 0, value
54
+ else
55
+ Fields.__generic_fill_ros_message_array(array_pointer, value, self.ffi_size) { |ptr, value| ptr.put @ffi_type, 0, value }
56
+ end
57
+ end
58
+ def destroy_ros_message(data)
59
+ end
60
+ def ffi_size()
61
+ return @memory_size
62
+ end
63
+ def is_atomic
64
+ return true
65
+ end
66
+ end
67
+ class StringField
68
+ def StringField.init_value()
69
+ return "\"\""
70
+ end
71
+ def StringField.field_name()
72
+ return "Rclrb::Fields::StringField"
73
+ end
74
+ def StringField.parse_ros_message(data)
75
+ length = data[:length]
76
+ return data[:string].get_string(0, length)
77
+ end
78
+ def StringField.parse_ros_message_array(data, length)
79
+ return Fields.__generic_parse_array(data, length, StringField.ffi_size) { |ptr| StringField.parse_ros_message FFIType.new(ptr) }
80
+ end
81
+ def StringField.fill_ros_message(data, index, value)
82
+ st = data[index]
83
+ str_pointer = Rclrb.rcl_allocate value.length + 1
84
+ st[:string] = str_pointer
85
+ str_pointer.put_string(0, value)
86
+ str_pointer.put_uint8(value.length, 0)
87
+ st[:length] = value.length
88
+ st[:capacity] = value.length + 1
89
+ end
90
+ def StringField.destroy_ros_message(data)
91
+ if data.kind_of? FFIType
92
+ Rclrb.rcl_deallocate data[:string]
93
+ else
94
+ return StringField.destroy_ros_message FFIType.new(data)
95
+ end
96
+ end
97
+ def StringField.array_field()
98
+ @@array_field = ArrayField.new(StringField) unless defined?(@@array_field)
99
+ return @@array_field
100
+ end
101
+ def StringField.ffi_type
102
+ return FFIType
103
+ end
104
+ def StringField.ffi_size
105
+ return FFIType.size
106
+ end
107
+ def StringField.is_atomic
108
+ return false
109
+ end
110
+ class FFIType < FFI::Struct
111
+ layout :string, :pointer, :length, :size_t, :capacity, :size_t
112
+ end
113
+ end
114
+ class TimeField
115
+ def TimeField.init_value()
116
+ return "Rclrb::Time.new()"
117
+ end
118
+ def TimeField.field_name()
119
+ return "Rclrb::Fields::TimeField"
120
+ end
121
+ def TimeField.parse_ros_message(data)
122
+ return Time.from_sec_nsec data[:sec], data[:nsec]
123
+ end
124
+ def TimeField.fill_ros_message(data, index, value)
125
+ st = data[index]
126
+ s, ns = value.to_sec_nsec
127
+ st[:sec] = s
128
+ st[:nsec] = ns
129
+ end
130
+ def TimeField.destroy_ros_message(data)
131
+ end
132
+ def TimeField.array_field()
133
+ @@array_field = ArrayField.new(TimeField) unless defined?(@@array_field)
134
+ return @@array_field
135
+ end
136
+ def TimeField.ffi_type
137
+ return FFIType
138
+ end
139
+ def TimeField.ffi_size
140
+ return FFIType.size
141
+ end
142
+ def TimeField.is_atomic
143
+ return false
144
+ end
145
+ class FFIType < FFI::Struct
146
+ layout :sec, :int32, :nsec, :uint32
147
+ end
148
+ end
149
+ class ArrayField
150
+ def initialize(field)
151
+ @field = field
152
+ end
153
+ def init_value()
154
+ return "[]"
155
+ end
156
+ def field_name()
157
+ return "#{@field.field_name}.array_field()"
158
+ end
159
+ def parse_ros_message(data)
160
+ return @field.parse_ros_message_array data[:array], data[:length]
161
+ end
162
+ def fill_ros_message(data, index, value)
163
+ array_pointer = Rclrb.rcl_allocate value.length * @field.ffi_size
164
+ @field.fill_ros_message_array array_pointer, value
165
+ arr = data[index]
166
+ arr[:array] = array_pointer
167
+ arr[:length] = value.length
168
+ arr[:capacity] = value.length
169
+ end
170
+ SIZE = CApi::POINTER_SIZE + 2 * CApi::SIZE_T_SIZE
171
+ def ros_size()
172
+ return SIZE
173
+ end
174
+ def destroy_ros_message(data)
175
+ length = data[:length]
176
+ unless @field.is_atomic
177
+ for i in 0...length
178
+ @field.destroy_ros_message data[:array] + i * @field.ffi_size
179
+ end
180
+ end
181
+ Rclrb.rcl_deallocate data[:array]
182
+ end
183
+ def is_atomic
184
+ return false
185
+ end
186
+ def ffi_type
187
+ return FFIType
188
+ end
189
+ class FFIType < FFI::Struct
190
+ layout :array, :pointer, :length, :size_t, :capacity, :size_t
191
+ end
192
+ end
193
+ Float64Field = AtomicField.new "0.0", "Float64Field", :double, :get_array_of_float64, :put_array_of_float64
194
+ Float32Field = AtomicField.new "0.0", "Float32Field", :float, :get_array_of_float32, :put_array_of_float32
195
+ ByteField = AtomicField.new "0", "ByteField", :uint8, :get_array_of_uint8, :put_array_of_uint8
196
+ CharField = AtomicField.new "0", "CharField", :uint8, :get_array_of_uint8, :put_array_of_uint8
197
+ BoolField = AtomicField.new "false", "BoolField", :bool, nil, nil
198
+ Int8Field = AtomicField.new "0", "Int8Field", :int8, :get_array_of_int8, :put_array_of_int8
199
+ Int16Field = AtomicField.new "0", "Int16Field", :int16, :get_array_of_int16, :put_array_of_int16
200
+ Int32Field = AtomicField.new "0", "Int32Field", :int32, :get_array_of_int32, :put_array_of_int32
201
+ Int64Field = AtomicField.new "0", "Int64Field", :int64, :get_array_of_int64, :put_array_of_int64
202
+ Uint8Field = AtomicField.new "0", "Uint8Field", :uint8, :get_array_of_uint8, :put_array_of_uint8
203
+ Uint16Field = AtomicField.new "0", "Uint16Field", :uint16, :get_array_of_uint16, :put_array_of_uint16
204
+ Uint32Field = AtomicField.new "0", "Uint32Field", :uint32, :get_array_of_uint32, :put_array_of_uint32
205
+ Uint64Field = AtomicField.new "0", "Uint64Field", :uint64, :get_array_of_uint64, :put_array_of_uint64
206
+
207
+ AtomicFields = { "float64" => Float64Field,
208
+ "float32" => Float32Field,
209
+ "char" => CharField,
210
+ "byte" => ByteField,
211
+ "bool" => BoolField,
212
+ "int8" => Int8Field,
213
+ "int16" => Int16Field,
214
+ "int32" => Int32Field,
215
+ "int64" => Int64Field,
216
+ "uint8" => Uint8Field,
217
+ "uint16" => Uint16Field,
218
+ "uint32" => Uint32Field,
219
+ "uint64" => Uint64Field,
220
+ "string" => StringField,
221
+ "builtin_interfaces/Time" => TimeField }
222
+
223
+ end
224
+ end
@@ -0,0 +1,82 @@
1
+ module Rclrb
2
+ #
3
+ # Define a future
4
+ #
5
+ #
6
+ class Future
7
+ ##
8
+ # Create a future with a nil result
9
+ def initialize
10
+ @result = nil
11
+ @observers = []
12
+ @mutex = Mutex.new
13
+ @resource = ConditionVariable.new
14
+ @exception = nil
15
+ end
16
+ ##
17
+ # Execute the block in a thread and return a Future.
18
+ # The block is expected to return a value which is set using set_value.
19
+ def Future.execute(&block)
20
+ f = Future.new
21
+ Thread.new do
22
+ begin
23
+ f.set_result block.call
24
+ rescue => ex
25
+ f.set_exception ex
26
+ end
27
+ end
28
+ return f
29
+ end
30
+ ##
31
+ # Add an observer, which is executed once the result is set.
32
+ def add_observer(&block)
33
+ @mutex.synchronize do
34
+ if @result.nil?
35
+ @observers.push block
36
+ else
37
+ block.call @result
38
+ end
39
+ end
40
+ end
41
+ ##
42
+ # Wait undefinitely for a result.
43
+ def wait_for_result()
44
+ @mutex.synchronize do
45
+ while @result.nil?
46
+ raise @exception unless @exception.nil?
47
+ @resource.wait(@mutex)
48
+ end
49
+ end
50
+ end
51
+ ##
52
+ # Returns true if it already has a result.
53
+ def has_result?
54
+ return not(@result.nil?)
55
+ end
56
+ ##
57
+ # Set that an exception occurs
58
+ def set_exception(ex)
59
+ @mutex.synchronize do
60
+ @exception = ex
61
+ @resource.signal
62
+ end
63
+ end
64
+ ##
65
+ # Set the result of the future
66
+ def set_result(result)
67
+ raise RclError.new "Result is already set" unless @result.nil?
68
+ @mutex.synchronize do
69
+ @result = result
70
+ @resource.signal
71
+ end
72
+ @observers.each() { |o| o.call Time.now, @result }
73
+ @observers = []
74
+ end
75
+ ##
76
+ # Wait for the result and return it
77
+ def result()
78
+ wait_for_result()
79
+ return @result
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,18 @@
1
+ module Rclrb
2
+ class GuardCondition
3
+ attr_reader :guard_condition_handle
4
+ def initialize
5
+ @guard_condition_handle = CApi.rcl_get_zero_initialized_guard_condition
6
+ CApi.handle_result CApi.rcl_guard_condition_init(@guard_condition_handle, Rclrb.rcl_context, CApi.rcl_guard_condition_get_default_options)
7
+ end
8
+ rclrb_finalize_with :@guard_condition_handle do |guard_condition_handle|
9
+ CApi.handle_result CApi.rcl_guard_condition_fini(guard_condition_handle)
10
+ end
11
+ def trigger()
12
+ CApi.handle_result CApi.rcl_trigger_guard_condition(@guard_condition_handle)
13
+ end
14
+ def spin(wait_set = nil)
15
+ wait_set.add self if wait_set
16
+ end
17
+ end
18
+ end
data/lib/rclrb/init.rb ADDED
@@ -0,0 +1,59 @@
1
+ module Rclrb
2
+
3
+ ##
4
+ # Initialise Rclrb with the given arguments
5
+ def Rclrb.init(arguments: [])
6
+ @@initOptions = CApi.rcl_get_zero_initialized_init_options()
7
+ @@context = CApi.rcl_get_zero_initialized_context()
8
+ @@allocator = CApi.rcutils_get_default_allocator
9
+ CApi.handle_result(CApi.rcl_init_options_init(@@initOptions, @@allocator))
10
+
11
+ # Prepare arguments
12
+ p_values = nil
13
+ if arguments.length > 0
14
+ strings = arguments.map { |k| FFI::MemoryPointer.from_string(k.to_s) }
15
+ p_values = FFI::MemoryPointer.new(:pointer, arguments.size + 1)
16
+ p_values.write_array_of_pointer(strings)
17
+ end
18
+
19
+ # Call init
20
+ CApi.handle_result(CApi.rcl_init(arguments.length, p_values, @@initOptions, @@context))
21
+
22
+ # Guard condition to shutdown execution when shutdown is called
23
+ @@signal_guard_condition = GuardCondition.new
24
+ @@shutdown_requested = false
25
+
26
+ # Setup signal to catch ctr+c
27
+ Rclrb.setup_signal
28
+ end
29
+ def Rclrb.setup_signal
30
+ Signal.trap("INT") {
31
+ puts "Interrupts called..."
32
+ Rclrb.shutdown()
33
+ }
34
+ end
35
+ ##
36
+ # Terminate Rclrb
37
+ def Rclrb.shutdown
38
+ @@shutdown_requested = true
39
+ @@signal_guard_condition.trigger
40
+ end
41
+ def Rclrb.rcl_context()
42
+ return @@context
43
+ end
44
+ def Rclrb.rcl_signal_guard_condition
45
+ return @@signal_guard_condition
46
+ end
47
+ def Rclrb.rcl_shutdown_requested?
48
+ return @@shutdown_requested
49
+ end
50
+ def Rclrb.rcl_allocator
51
+ return @@allocator
52
+ end
53
+ def Rclrb.rcl_allocate(size)
54
+ return @@allocator[:allocate].call size, @@allocator[:state]
55
+ end
56
+ def Rclrb.rcl_deallocate(ptr)
57
+ @@allocator[:deallocate].call ptr, @@allocator[:state]
58
+ end
59
+ end
@@ -0,0 +1,270 @@
1
+ module Rclrb
2
+ ##
3
+ # This module contains classes used to generate package to handle ROS messages.
4
+ # The content of Interfaces is internal API to rclrb and should not be directly called and is subject
5
+ # to change.
6
+ module Interfaces
7
+ def Interfaces.__parse_msg_srv_act_file package_name, path, filename, interface_type, interface_type_camel
8
+ definition = {}
9
+ definition[:name] = filename[0, filename.length - 4]
10
+ definition[:class_name] = "#{Rclrb.camelize(package_name)}::#{interface_type_camel}::#{definition[:name]}"
11
+ line_num = 0
12
+ fieldss = []
13
+ fields = []
14
+ constantss = []
15
+ constants = []
16
+ depends = []
17
+ ext_depends = []
18
+ File.open("#{path}/#{interface_type}/#{filename}").each do |line|
19
+ line_num += 1
20
+ # Remove comment
21
+ comment_index = line.index('#')
22
+ line = line[0, comment_index] unless comment_index.nil?
23
+ if line.index('=') != nil
24
+ l = line.split('=')
25
+ if l.length == 2
26
+ l2 = l[0].split(' ')
27
+ if l2.length == 2
28
+ constants.append "#{l2[1].upcase} = #{l[1]}"
29
+ else
30
+ raise ParseError.new "Cannot parse '#{path}/#{interface_type}/#{filename}', invalid constant definition on line number #{line_num}"
31
+ end
32
+ else
33
+ raise ParseError.new "Cannot parse '#{path}/#{interface_type}/#{filename}', invalid constant definition on line number #{line_num}"
34
+ end
35
+ else
36
+ l = line.split(' ', ).reject { |c| c.empty?}
37
+ if l.length == 2 or l.length == 3
38
+ type = l[0]
39
+ name = l[1]
40
+ array_index = type.index(/\[\d*\]/)
41
+ if array_index.nil?
42
+ base_type = type
43
+ is_array = false
44
+ else
45
+ base_type = type[0, array_index]
46
+ is_array = true
47
+ end
48
+
49
+ if Fields::AtomicFields.include? base_type
50
+ field_def = Fields::AtomicFields[base_type].field_name
51
+ if l.length == 3
52
+ field_init_value = l[2]
53
+ else
54
+ field_init_value = Fields::AtomicFields[base_type].init_value
55
+ end
56
+ else
57
+ if base_type == "Header"
58
+ field_def = "StdMsgs::#{interface_type_camel}::Header"
59
+ field_init_value = "StdMsgs::Header.new"
60
+ if package_name != "std_msgs"
61
+ ext_depends.append "std_msgs/msg"
62
+ end
63
+ elsif base_type.index("/").nil?
64
+ field_def = "#{Rclrb.camelize(package_name)}::Msg::#{base_type}"
65
+ field_init_value = "#{field_def}.new"
66
+ if interface_type != 'msg'
67
+ ext_depends.append "#{package_name}/msg"
68
+ end
69
+ else
70
+ base_type_split = base_type.split "/"
71
+ if base_type_split.length == 2
72
+ ext_depends.append "#{base_type_split[0]}/msg" unless base_type_split[0] == package_name
73
+ field_def = "#{Rclrb.camelize(base_type_split[0])}::Msg::#{base_type_split[1]}"
74
+ field_init_value = "#{field_def}.new"
75
+ else
76
+ raise ParseError.new "Cannot parse '#{path}/#{interface_type}/#{filename}', invalid type #{base_type} at line number #{line_num}"
77
+ end
78
+ end
79
+ depends.append field_def
80
+ end
81
+ if is_array
82
+ field_def += ".array_field"
83
+ field_init_value = []
84
+ end
85
+ fields.append({ :name => name, :field_def_name => field_def, :field_init_value => field_init_value })
86
+ elsif l.length == 1 and l[0] = "---"
87
+ fieldss.append(fields)
88
+ constantss.append(constants)
89
+ fields = []
90
+ constants = []
91
+ elsif l.length != 0
92
+ raise ParseError.new "Cannot parse '#{path}/#{interface_type}/#{filename}', invalid line number #{line_num}"
93
+ end
94
+ end
95
+ end
96
+ fieldss.append(fields)
97
+ constantss.append(constants)
98
+ definition[:fields] = fieldss
99
+ definition[:constants] = constantss
100
+ definition[:depends] = depends
101
+ definition[:ext_depends] = ext_depends.uniq
102
+ return definition
103
+ end
104
+ def Interfaces.__fields_body(index, klass_name)
105
+ str = <<-EOF
106
+ attr_accessor <%= mdef[:fields][#{index}].map { |f| ":" + f[:name] } .join(" ,") %>
107
+ <% mdef[:constants][#{index}].each do |constant| %>
108
+ <%= constant %>
109
+ <% end %>
110
+ def initialize()
111
+ <% mdef[:fields][#{index}].each do |field| %>
112
+ @<%= field[:name] %> = <%= field[:field_init_value] %>
113
+ <% end %>
114
+ end
115
+ class FFIType < FFI::Struct
116
+ layout <%= mdef[:fields][#{index}].map { |f| ":" + f[:name] + ", " + f[:field_def_name] + ".ffi_type" }.join(" ,") %>
117
+ end
118
+
119
+ def #{klass_name}.get_ffi_struct(data)
120
+ if data.kind_of? FFIType
121
+ return data
122
+ else
123
+ return FFIType.new data
124
+ end
125
+ end
126
+ def #{klass_name}.parse_ros_message(data)
127
+ msg = #{klass_name}.new
128
+ ffi_struct = #{klass_name}.get_ffi_struct(data)
129
+ <% mdef[:fields][#{index}].each do |field| %>
130
+ msg.<%= field[:name] %> = <%= field[:field_def_name] %>.parse_ros_message ffi_struct[:<%= field[:name] %>]
131
+ <% end %>
132
+ return msg
133
+ end
134
+ def #{klass_name}.parse_ros_message_array(data, length)
135
+ return Fields.__generic_parse_array(data, length, #{klass_name}.ffi_size) { |ptr| #{klass_name}.parse_ros_message(ptr) }
136
+ end
137
+ def #{klass_name}.destroy_ros_message(data)
138
+ ffi_struct = #{klass_name}.get_ffi_struct(data)
139
+ <% mdef[:fields][#{index}].each do |field| %>
140
+ <%= field[:field_def_name] %>.destroy_ros_message(ffi_struct[:<%= field[:name] %>])
141
+ <% end %>
142
+ end
143
+ def #{klass_name}.get_ros_message(msg)
144
+ ffi_struct = FFIType.new
145
+ #{klass_name}.__fill_ros_message(ffi_struct, msg)
146
+ return ffi_struct
147
+ end
148
+ def #{klass_name}.fill_ros_message(ffi_struct, member, msg)
149
+ #{klass_name}.__fill_ros_message(ffi_struct[member], msg)
150
+ end
151
+ def #{klass_name}.__fill_ros_message(ffi_struct, msg)
152
+ <% mdef[:fields][#{index}].each do |field| %>
153
+ <%= field[:field_def_name] %>.fill_ros_message(ffi_struct, :<%= field[:name] %>, msg.<%= field[:name] %>)
154
+ <% end %>
155
+ end
156
+ def #{klass_name}.fill_ros_message_array(array_pointer, value)
157
+ Fields.__generic_fill_ros_message_array(array_pointer, value, #{klass_name}.ffi_size) { |ptr, value| #{klass_name}.__fill_ros_message(ffi_type.new(ptr), value) }
158
+ end
159
+ def #{klass_name}.ffi_type
160
+ return FFIType
161
+ end
162
+ def #{klass_name}.ffi_size
163
+ return FFIType.size
164
+ end
165
+ def #{klass_name}.is_atomic
166
+ return false
167
+ end
168
+ EOF
169
+ end
170
+ def Interfaces.load_definitions package_name
171
+ is_msg_package = package_name.end_with? "/msg"
172
+ is_srv_package = package_name.end_with? "/srv"
173
+ if is_msg_package or is_srv_package
174
+ ros_package_name = package_name[0, package_name.size - 4]
175
+ else
176
+ return false
177
+ end
178
+ module_name = Rclrb.camelize ros_package_name
179
+ p = "#{`ros2 pkg prefix #{ros_package_name}`.chop}/share/#{ros_package_name}"
180
+ return false unless File.directory?(p)
181
+ if is_msg_package
182
+ msg_defs_unsorted = Dir.glob("*.msg", base: p + "/msg").map { |name| Interfaces.__parse_msg_srv_act_file(ros_package_name, p, name, "msg", "Msg") }
183
+ # msg_defs.sort! { |a| a[:depends].length }
184
+ msg_defs = []
185
+ current_index = 0
186
+ while msg_defs_unsorted.length > 0
187
+ if current_index >= msg_defs_unsorted.length
188
+ current_index = 0
189
+ end
190
+ add_to_msg_defs = true
191
+ msg_defs_unsorted[current_index][:depends].each() { |x|
192
+ if x.start_with? module_name
193
+ found = false
194
+ msg_defs.each() { |y|
195
+ if y[:class_name] == x
196
+ found = true
197
+ break
198
+ end
199
+ }
200
+ unless found
201
+ add_to_msg_defs = false
202
+ break
203
+ end
204
+ end
205
+ }
206
+ if add_to_msg_defs
207
+ msg_defs.push msg_defs_unsorted[current_index]
208
+ msg_defs_unsorted.delete_at current_index
209
+ else
210
+ current_index += 1
211
+ end
212
+ end
213
+
214
+ msg_defs.each() do |mdef|
215
+ mdef[:ext_depends].each() { |d| require d }
216
+ end
217
+ CApi.create_type_support_library(module_name, ros_package_name, "message", "msg", "RosidlMessageTypeSupportT", msg_defs.map {|mdef| mdef[:name]})
218
+ template = ERB.new <<-EOF
219
+ module <%= module_name %>
220
+ module Msg
221
+ <% msg_defs.each do |mdef| %>
222
+ class <%= mdef[:name] %>
223
+ def <%= mdef[:name] %>.type_support()
224
+ TypeSupportCApi::TypeSupport_msg_<%= mdef[:name] %>
225
+ end
226
+ #{Interfaces.__fields_body(0, "<%= mdef[:name] %>")}
227
+ def <%= mdef[:name] %>.array_field()
228
+ @@array_field = Fields::ArrayField.new(<%= mdef[:name] %>) unless defined?(@@array_field)
229
+ return @@array_field
230
+ end
231
+ end
232
+ <% end %>
233
+ end
234
+ end
235
+ EOF
236
+ # puts template.result(binding)
237
+ Object.class_eval template.result(binding)
238
+ return true
239
+ elsif is_srv_package
240
+ srv_defs = Dir.glob("*.srv", base: p + "/srv").map { |name| Interfaces.__parse_msg_srv_act_file(ros_package_name, p, name, "srv", "Srv") }
241
+ srv_defs.each() do |mdef|
242
+ mdef[:ext_depends].each() { |d| require d }
243
+ end
244
+ CApi.create_type_support_library module_name, ros_package_name, "service", "srv", "RosidlServiceTypeSupportT", srv_defs.map {|mdef| mdef[:name]}
245
+ template = ERB.new <<-EOF
246
+ module <%= module_name %>
247
+ module Srv
248
+ <% srv_defs.each do |mdef| %>
249
+ module <%= mdef[:name] %>
250
+ def <%= mdef[:name] %>.type_support()
251
+ TypeSupportCApi::TypeSupport_srv_<%= mdef[:name] %>
252
+ end
253
+ class Request
254
+ #{Interfaces.__fields_body(0, "Request")}
255
+ end
256
+ class Response
257
+ #{Interfaces.__fields_body(1, "Response")}
258
+ end
259
+ end
260
+ <% end %>
261
+ end
262
+ end
263
+ EOF
264
+ Object.class_eval template.result(binding)
265
+ return true
266
+ end
267
+ return false
268
+ end
269
+ end
270
+ end
@@ -0,0 +1,16 @@
1
+ module Rclrb
2
+ ##
3
+ # Uncamelize a string, for instance transform "ThisIsAnExample" to "this_is_an_example"
4
+ def Rclrb.uncamelize str
5
+ return str.gsub(/::/, '/')
6
+ .gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
7
+ .gsub(/([a-z\d])([A-Z])/,'\1_\2')
8
+ .tr("-", "_")
9
+ .downcase
10
+ end
11
+ ##
12
+ # Camelize a string, for instance transform "this_is_an_example" to "ThisIsAnExample"
13
+ def Rclrb.camelize str
14
+ return str.split("_").map(&:capitalize).join
15
+ end
16
+ end