Class: Syskit::Robot::MasterDeviceInstance

Inherits:
DeviceInstance show all
Includes:
MetaRuby::DSLs::FindThroughMethodMissing
Defined in:
lib/syskit/robot/master_device_instance.rb

Overview

Subclass of DeviceInstance used to represent root devices

Direct Known Subclasses

ComBus

Defined Under Namespace

Classes: DRoby

Constant Summary collapse

KNOWN_PARAMETERS =
{ :period => nil, :sample_size => nil, :device_id => nil }

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from DeviceInstance

#doc, #instanciate, #period, #to_action

Constructor Details

#initialize(robot, name, device_model, options, driver_model, task_arguments) ⇒ MasterDeviceInstance

Returns a new instance of MasterDeviceInstance



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/syskit/robot/master_device_instance.rb', line 46

def initialize(robot, name, device_model, options,
               driver_model, task_arguments)
    @robot, @name, @device_model, @task_arguments =
        robot, name, device_model, task_arguments
    @slaves      = Hash.new
    @conf = Array.new
    @com_busses = Array.new

    driver_model = driver_model.to_instance_requirements
    @driver_model = driver_model.service
    @requirements = driver_model.to_component_model
    requirements.name = "#{name}_dev"
    requirements.with_arguments(:"#{driver_model.service.name}_dev" => self)
    requirements.with_arguments(**task_arguments)

    sample_size 1
    burst   0
end

Instance Attribute Details

#com_bussesObject (readonly)

The communication busses this device is attached to



15
16
17
# File 'lib/syskit/robot/master_device_instance.rb', line 15

def com_busses
  @com_busses
end

#combus_client_in_srvBoundDataService? (readonly)

The data service of #task_model that is used to receive data from the attached com bus for this device. If nil, the task is not expecting to receive any data from the communication bus (only send)

Returns:



106
107
108
# File 'lib/syskit/robot/master_device_instance.rb', line 106

def combus_client_in_srv
  @combus_client_in_srv
end

#combus_client_out_srvBoundDataService? (readonly)

The data service of #task_model that is used to send data to the attached com bus for this device. If nil, the task is not expecting to send any data from the communication bus (only receives)

Returns:



114
115
116
# File 'lib/syskit/robot/master_device_instance.rb', line 114

def combus_client_out_srv
  @combus_client_out_srv
end

#configurationObject (readonly)

Configuration data structure



36
37
38
# File 'lib/syskit/robot/master_device_instance.rb', line 36

def configuration
  @configuration
end

#configuration_blockObject (readonly)

Block given to #configure to configure the device. It will be yield a data structure that represents the set of properties of the underlying task

Note that it is executed twice. Once at loading time to verify that the block is compatible with the data structure, and once at runtime to actually configure the task



44
45
46
# File 'lib/syskit/robot/master_device_instance.rb', line 44

def configuration_block
  @configuration_block
end

#device_modelObject (readonly)

The device model, as a subclass of Device



10
11
12
# File 'lib/syskit/robot/master_device_instance.rb', line 10

def device_model
  @device_model
end

#driver_modelBoundDataService (readonly)

The driver for this device

Returns:



34
35
36
# File 'lib/syskit/robot/master_device_instance.rb', line 34

def driver_model
  @driver_model
end

#nameObject (readonly)

The device name



8
9
10
# File 'lib/syskit/robot/master_device_instance.rb', line 8

def name
  @name
end

#requirementsSyskit::InstanceRequirements (readonly)

Additional specifications for deployment of the driver



18
19
20
# File 'lib/syskit/robot/master_device_instance.rb', line 18

def requirements
  @requirements
end

#robotObject (readonly)

The RobotDefinition instance we are built upon



6
7
8
# File 'lib/syskit/robot/master_device_instance.rb', line 6

def robot
  @robot
end

#slavesObject (readonly)

The device slaves, as a mapping from the slave's name to the SlaveDeviceInstance object



13
14
15
# File 'lib/syskit/robot/master_device_instance.rb', line 13

def slaves
  @slaves
end

Instance Method Details

#==(other) ⇒ Object



387
388
389
390
391
392
# File 'lib/syskit/robot/master_device_instance.rb', line 387

def ==(other)
    if other.kind_of?(MasterDeviceInstance)
        other.robot == robot &&
            other.name == name
    end
end

#advancedObject

Sets #advanced?



77
78
79
80
# File 'lib/syskit/robot/master_device_instance.rb', line 77

def advanced
    @advanced = true
    self
end

#advanced=(value) ⇒ Object

Whether this device should be hidden from the user interfaces



74
# File 'lib/syskit/robot/master_device_instance.rb', line 74

attr_predicate :advanced?, true

#advanced?Boolean

Whether this device should be hidden from the user interfaces

Returns:

  • (Boolean)


74
# File 'lib/syskit/robot/master_device_instance.rb', line 74

attr_predicate :advanced?, true

#argumentsObject

The arguments passed to the underlying device driver



327
328
329
# File 'lib/syskit/robot/master_device_instance.rb', line 327

def arguments
    requirements.arguments
end

#as_planObject



372
# File 'lib/syskit/robot/master_device_instance.rb', line 372

def as_plan; to_instance_requirements.as_plan end

#attach_to(com_bus, bus_to_client: true, client_to_bus: true, **options) ⇒ Object

Parameters:

  • bus_to_client (Boolean, String)

    whether the device expects a connection from the bus. It can be set to a string, in which case the string is used as the name of the service on the client's device driver that should be used for connection

  • client_to_bus (Boolean, String)

    whether the device expects a connection to the bus. It can be set to a string, in which case the string is used as the name of the service on the client device driver that should be used for connection



140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/syskit/robot/master_device_instance.rb', line 140

def attach_to(com_bus, bus_to_client: true, client_to_bus: true, **options)
    if com_bus.respond_to?(:to_str)
        com_bus, com_bus_name = robot.find_device(com_bus), com_bus
        if !com_bus
            raise ArgumentError, "no device declared with the name '#{com_bus_name}'"
        end
    end

    if srv_name = options.delete(:in)
        Roby.warn_deprecated "the in: option of MasterDeviceInstance#attach_to has been renamed to bus_to_client"
        bus_to_client = srv_name
    end
    if srv_name = options.delete(:out)
        Roby.warn_deprecated "the out: option of MasterDeviceInstance#attach_to has been renamed to client_to_bus"
        client_to_bus = srv_name
    end
    if !options.empty?
        raise ArgumentError, "unexpected options #{options}"
    end

    if bus_to_client && com_bus.model.bus_to_client?
        client_in_srv =
            if bus_to_client.respond_to?(:to_str)
                bus_to_client
            end
        client_in_srv_m  = com_bus.model.client_in_srv
        @combus_client_in_srv  =
            begin find_combus_client_srv(client_in_srv_m, client_in_srv)
            rescue AmbiguousServiceSelection
                raise ArgumentError, "#{driver_model.to_component_model} provides more than one input service to connect to the com bus, select one explicitely with the bus_to_client option"
            end
        if !combus_client_in_srv
            raise ArgumentError, "#{driver_model.to_component_model} does not provide an input service to connect to the com bus, and was expected to"
        end
    end

    if client_to_bus && com_bus.model.client_to_bus?
        client_out_srv =
            if client_to_bus.respond_to?(:to_str)
                client_to_bus
            end
        client_out_srv_m  = com_bus.model.client_out_srv
        @combus_client_out_srv  =
            begin find_combus_client_srv(client_out_srv_m, client_out_srv)
            rescue AmbiguousServiceSelection
                raise ArgumentError, "#{driver_model.to_component_model} provides more than one output service to connect to the com bus, select one explicitely with the client_to_bus option"
            end
        if !combus_client_out_srv
            raise ArgumentError, "#{driver_model.to_component_model} does not provide an output service to connect to the com bus, and was expected to"
        end
    end

    com_busses << com_bus
    com_bus.attached_devices << self
    com_bus.model.apply_attached_device_configuration_extensions(self)
    self
end

#attached_to?(com_bus) ⇒ Boolean

True if this device is attached to the given combus

Returns:

  • (Boolean)


96
97
98
# File 'lib/syskit/robot/master_device_instance.rb', line 96

def attached_to?(com_bus)
    com_busses.include?(com_bus)
end

#bus_to_client?Boolean

Whether this device sends messages to the bus it is attached to

It will return false if not attached to a bus

Returns:

  • (Boolean)


126
127
128
# File 'lib/syskit/robot/master_device_instance.rb', line 126

def bus_to_client?
    !!combus_client_in_srv
end

#client_to_bus?Boolean

Whether this device sends messages to the bus it is attached to

It will return false if not attached to a bus

Returns:

  • (Boolean)


119
120
121
# File 'lib/syskit/robot/master_device_instance.rb', line 119

def client_to_bus?
    !!combus_client_out_srv
end

#device_idObject

:method:device_id

call-seq:

device_id(device_id, definition)
device_id => current_id or nil

The device ID. It is dependent on the method of communication to the device. For a serial line, it would be the device file (/dev/ttyS0):

device(XsensImu).
    device_id('/dev/ttyS0')

For CAN, it would be the device ID and mask:

device(Motors).
    device_id(0x0, 0x700)


241
242
243
244
245
246
247
# File 'lib/syskit/robot/master_device_instance.rb', line 241

dsl_attribute(:device_id) do |*values|
    if values.size > 1
        values
    else
        values.first
    end
end

#droby_dump(peer) ⇒ Object



383
384
385
# File 'lib/syskit/robot/master_device_instance.rb', line 383

def droby_dump(peer)
    DRoby.new(name, peer.dump(device_model), peer.dump(driver_model))
end

#each_fullfilled_model(&block) ⇒ Object



374
375
376
# File 'lib/syskit/robot/master_device_instance.rb', line 374

def each_fullfilled_model(&block)
    device_model.each_fullfilled_model(&block)
end

#each_slave(&block) ⇒ Object

Enumerates the slaves that are known for this device, as

slave_name, SlaveDeviceInstance object

pairs



251
252
253
# File 'lib/syskit/robot/master_device_instance.rb', line 251

def each_slave(&block)
    slaves.each_value(&block)
end

#find_combus_client_srv(srv_m, srv_name) ⇒ Object

Finds in #driver_model.component_model the data service that should be used to interface with a combus

Parameters:

  • the (Model<DataService>)

    data service model for the client interface to the combus

  • the (String, nil)

    expected data service name, or nil if none is given. In this case, one is searched by type



205
206
207
208
209
210
211
212
213
214
215
216
217
218
# File 'lib/syskit/robot/master_device_instance.rb', line 205

def find_combus_client_srv(srv_m, srv_name)
    driver_task_model = driver_model.to_component_model
		if srv_name
		    result = driver_task_model.find_data_service(srv_name)
		    if !result
			raise ArgumentError, "#{srv_name} is specified as a client service on device #{name} for combus #{com_bus.name}, but it is not a data service on #{driver_task_model}"
        elsif !result.fullfills?(srv_m)
            raise ArgumentError, "#{srv_name} is specified as a client service on device #{name} for combus #{com_bus.name}, but it does not provide the required service from #{com_bus.model}"
		    end
        result
		else
		    driver_task_model.find_data_service_from_type(srv_m)
		end
end

#find_through_method_missing(m, args) ⇒ Object



312
313
314
315
# File 'lib/syskit/robot/master_device_instance.rb', line 312

def find_through_method_missing(m, args)
    MetaRuby::DSLs.find_through_method_missing(
        self, m, args, '_dev'.freeze => :slave) || super
end

#full_nameObject



69
70
71
# File 'lib/syskit/robot/master_device_instance.rb', line 69

def full_name
    name
end

#has_slave?(slave_service) ⇒ Boolean

Returns:

  • (Boolean)


255
256
257
258
259
260
# File 'lib/syskit/robot/master_device_instance.rb', line 255

def has_slave?(slave_service)
    return true if slaves[slave_service]

    slave_name = "#{driver_model.full_name}.#{slave_service}"
    !!task_model.find_data_service(slave_name)
end

#has_through_method_missing?(m) ⇒ Boolean

Returns:

  • (Boolean)


307
308
309
310
# File 'lib/syskit/robot/master_device_instance.rb', line 307

def has_through_method_missing?(m)
    MetaRuby::DSLs.has_through_method_missing?(
        self, m, '_dev'.freeze => :has_slave?) || super
end

#modelObject



20
# File 'lib/syskit/robot/master_device_instance.rb', line 20

def model; device_model end

#prefer_deployed_tasks(hints) ⇒ Object

Specify deployment selection hints for the device's driver



338
339
340
341
# File 'lib/syskit/robot/master_device_instance.rb', line 338

def prefer_deployed_tasks(hints)
		requirements.prefer_deployed_tasks(hints)
		self
end

#pretty_print(pp) ⇒ Object



27
28
29
# File 'lib/syskit/robot/master_device_instance.rb', line 27

def pretty_print(pp)
    pp.text "MasterDeviceInstance(#{short_name}_dev)"
end

#short_nameObject

Defined to be consistent with task and data service models



23
24
25
# File 'lib/syskit/robot/master_device_instance.rb', line 23

def short_name
    "#{name}[#{model.short_name}]"
end

#slave(slave_name) ⇒ Syskit::Robot::SlaveDeviceInstance #slave(dynamic_service_name, : as=>slave_name) ⇒ Syskit::Robot::SlaveDeviceInstance

Gets the required slave device, or creates a dynamic one

Overloads:



276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
# File 'lib/syskit/robot/master_device_instance.rb', line 276

def slave(slave_service, options = Hash.new)
    options = Kernel.validate_options options, :as => nil
    if existing_slave = slaves[slave_service]
        return existing_slave
    end

    # If slave_service is a string, it should refer to an actual
    # service on +task_model+
    task_model = driver_model.to_component_model

    slave_name = "#{driver_model.full_name}.#{slave_service}"
    srv = task_model.find_data_service(slave_name)
    if !srv
        if options[:as]
            new_task_model = task_model.ensure_model_is_specialized
            srv = new_task_model.require_dynamic_service(slave_service, :as => options[:as])
        end
        if !srv
            raise ArgumentError, "there is no service #{slave_name} and no dynamic service in #{task_model.short_name}"
        end
        @driver_model = driver_model.attach(new_task_model)
    end

    device_instance = SlaveDeviceInstance.new(self, srv)
    slaves[srv.name] = device_instance
    if srv.model.respond_to?(:apply_device_configuration_extensions)
        srv.model.apply_device_configuration_extensions(device_instance)
    end
    robot.devices["#{name}.#{srv.name}"] = device_instance
end

#to_action_modelActions::Model::Action

Create an action model that represent an instanciation of this device

Returns:

  • (Actions::Model::Action)


362
363
364
365
366
367
368
369
370
# File 'lib/syskit/robot/master_device_instance.rb', line 362

def to_action_model
    profile = robot.profile
    req = to_instance_requirements
    profile.inject_di_context(req)
    action_model = Actions::Models::Action.
        new(req, doc || "device from profile #{profile.name}")
    action_model.name = "#{name}_dev"
    action_model
end

#to_instance_requirementsObject

Returns the InstanceRequirements object that can be used to represent this device



351
352
353
354
355
356
# File 'lib/syskit/robot/master_device_instance.rb', line 351

def to_instance_requirements
    result = requirements.dup
    robot.inject_di_context(result)
    result.select_service(driver_model)
    result
end

#to_sObject



65
66
67
# File 'lib/syskit/robot/master_device_instance.rb', line 65

def to_s
    "device(#{device_model}, as: #{full_name})"
end

#use(dependency_injection) ⇒ Object

If this device's driver is a composition, allows to specify dependency injections for it



321
322
323
324
# File 'lib/syskit/robot/master_device_instance.rb', line 321

def use(dependency_injection)
    requirements.use(dependency_injection)
    self
end

#use_conf(*conf) ⇒ Object

Deprecated.


83
84
85
86
# File 'lib/syskit/robot/master_device_instance.rb', line 83

def use_conf(*conf)
    Roby.warn_deprecated "MasterDeviceInstance#use_conf is deprecated. Use #with_conf instead"
    with_conf(*conf)
end

#use_deployments(hints) ⇒ Object



343
344
345
346
347
# File 'lib/syskit/robot/master_device_instance.rb', line 343

def use_deployments(hints)
    Roby.warn_deprecated "MasterDeviceInstance#use_deployments is deprecated. Use #prefer_deployed_tasks instead"
    prefer_deployed_tasks(hints)
    self
end

#with_arguments(arguments = Hash.new) ⇒ Object

Add arguments to the underlying device driver



332
333
334
335
# File 'lib/syskit/robot/master_device_instance.rb', line 332

def with_arguments(arguments = Hash.new)
    requirements.with_arguments(arguments)
    self
end

#with_conf(*conf) ⇒ Object

Declares that the following configuration chain should be used for this device



90
91
92
93
# File 'lib/syskit/robot/master_device_instance.rb', line 90

def with_conf(*conf)
    requirements.with_conf(*conf)
    self
end