Class: LIBUSB::Device

Inherits:
Object
  • Object
show all
Includes:
Comparable
Defined in:
lib/libusb/device.rb

Overview

Class representing a USB device detected on the system.

Devices of the system can be obtained with Context#devices .

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(context, pDev) ⇒ Device

Returns a new instance of Device.



29
30
31
32
33
34
35
36
37
38
# File 'lib/libusb/device.rb', line 29

def initialize context, pDev
  @context = context
  @pDev = pDev
  register_context(context.instance_variable_get(:@ctx), :libusb_unref_device)
  Call.libusb_ref_device(pDev)

  @pDevDesc = Call::DeviceDescriptor.new
  res = Call.libusb_get_device_descriptor(@pDev, @pDevDesc)
  LIBUSB.raise_error res, "in libusb_get_device_descriptor" if res!=0
end

Instance Attribute Details

#contextContext (readonly)

Returns the context this device belongs to.

Returns:

  • (Context)

    the context this device belongs to.



27
28
29
# File 'lib/libusb/device.rb', line 27

def context
  @context
end

Instance Method Details

#<=>(o) ⇒ Object



401
402
403
404
405
# File 'lib/libusb/device.rb', line 401

def <=>(o)
  t = bus_number<=>o.bus_number
  t = device_address<=>o.device_address if t==0
  t
end

#bcdDeviceObject

Device release number in binary-coded decimal.



298
299
300
# File 'lib/libusb/device.rb', line 298

def bcdDevice
  @pDevDesc[:bcdDevice]
end

#bcdUSBInteger

USB specification release number which device complies too

Returns:

  • (Integer)

    in binary-coded decimal



257
258
259
# File 'lib/libusb/device.rb', line 257

def bcdUSB
  @pDevDesc[:bcdUSB]
end

#bDescriptorTypeObject

Device Descriptor (0x01)



250
251
252
# File 'lib/libusb/device.rb', line 250

def bDescriptorType
  @pDevDesc[:bDescriptorType]
end

#bDeviceClassObject

USB-IF class code for the device (Assigned by USB Org)

  • If equal to 0x00, each interface specifies it’s own class code

  • If equal to 0xFF, the class code is vendor specified

  • Otherwise field is valid Class Code



266
267
268
# File 'lib/libusb/device.rb', line 266

def bDeviceClass
  @pDevDesc[:bDeviceClass]
end

#bDeviceProtocolObject

USB-IF protocol code for the device, qualified by the #bDeviceClass and #bDeviceSubClass values (Assigned by USB Org)



278
279
280
# File 'lib/libusb/device.rb', line 278

def bDeviceProtocol
  @pDevDesc[:bDeviceProtocol]
end

#bDeviceSubClassObject

USB-IF subclass code for the device, qualified by the #bDeviceClass value (Assigned by USB Org)



272
273
274
# File 'lib/libusb/device.rb', line 272

def bDeviceSubClass
  @pDevDesc[:bDeviceSubClass]
end

#bLengthObject

Size of the Descriptor in Bytes (18 bytes)



245
246
247
# File 'lib/libusb/device.rb', line 245

def bLength
  @pDevDesc[:bLength]
end

#bMaxPacketSize0Object

Maximum Packet Size for Endpoint 0. Valid Sizes are 8, 16, 32, 64



283
284
285
# File 'lib/libusb/device.rb', line 283

def bMaxPacketSize0
  @pDevDesc[:bMaxPacketSize0]
end

#bNumConfigurationsObject

Number of Possible Configurations



318
319
320
# File 'lib/libusb/device.rb', line 318

def bNumConfigurations
  @pDevDesc[:bNumConfigurations]
end

#bus_numberObject

Get the number of the bus that a device is connected to.



87
88
89
# File 'lib/libusb/device.rb', line 87

def bus_number
  Call.libusb_get_bus_number(@pDev)
end

#config_descriptor(index) ⇒ Object

Obtain a config descriptor of the device.

Parameters:

  • index (Fixnum)

    number of the config descriptor

Returns:

  • Configuration



235
236
237
238
239
240
241
242
# File 'lib/libusb/device.rb', line 235

def config_descriptor(index)
  ppConfig = FFI::MemoryPointer.new :pointer
  res = Call.libusb_get_config_descriptor(@pDev, index, ppConfig)
  LIBUSB.raise_error res, "in libusb_get_config_descriptor" if res!=0
  pConfig = ppConfig.read_pointer
  config = Configuration.new(self, pConfig)
  config
end

#configurationsArray<Configuration>

Return configurations of the device.

Returns:



379
380
381
382
383
384
385
386
387
388
389
# File 'lib/libusb/device.rb', line 379

def configurations
  configs = []
  bNumConfigurations.times do |config_index|
    begin
      configs << config_descriptor(config_index)
    rescue RuntimeError
      # On Windows some devices don't return it's configuration.
    end
  end
  configs
end

#device_addressObject

Get the address of the device on the bus it is connected to.



92
93
94
# File 'lib/libusb/device.rb', line 92

def device_address
  Call.libusb_get_device_address(@pDev)
end

#device_speedSymbol

Get the negotiated connection speed for a device. Available since libusb-1.0.9.

Returns:

  • (Symbol)

    a Speeds symbol, where :SPEED_UNKNOWN means that the OS doesn’t know or doesn’t support returning the negotiated speed.



149
150
151
# File 'lib/libusb/device.rb', line 149

def device_speed
  Call.libusb_get_device_speed(@pDev)
end

#endpointsArray<Endpoint>

Return all endpoints of all interfaces of this device.

Returns:



399
# File 'lib/libusb/device.rb', line 399

def endpoints() self.settings.map {|d| d.endpoints }.flatten end

#idProductObject

USB-IF product ID (Assigned by Manufacturer)



293
294
295
# File 'lib/libusb/device.rb', line 293

def idProduct
  @pDevDesc[:idProduct]
end

#idVendorObject

USB-IF vendor ID (Assigned by USB Org)



288
289
290
# File 'lib/libusb/device.rb', line 288

def idVendor
  @pDevDesc[:idVendor]
end

#iManufacturerObject

Index of string descriptor describing manufacturer.



303
304
305
# File 'lib/libusb/device.rb', line 303

def iManufacturer
  @pDevDesc[:iManufacturer]
end

#inspectObject



323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
# File 'lib/libusb/device.rb', line 323

def inspect
  attrs = []
  attrs << "#{self.bus_number}/#{self.device_address}"
  attrs << ("%04x:%04x" % [self.idVendor, self.idProduct])
  attrs << self.manufacturer
  attrs << self.product
  attrs << self.serial_number
  if self.bDeviceClass == LIBUSB::CLASS_PER_INTERFACE
    devclass = self.settings.map {|i|
      LIBUSB.dev_string(i.bInterfaceClass, i.bInterfaceSubClass, i.bInterfaceProtocol)
    }.join(", ")
  else
    devclass = LIBUSB.dev_string(self.bDeviceClass, self.bDeviceSubClass, self.bDeviceProtocol)
  end
  attrs << "(#{devclass})"
  attrs.compact!
  "\#<#{self.class} #{attrs.join(' ')}>"
end

#interfacesArray<Interface>

Return all interfaces of this device.

Returns:



393
# File 'lib/libusb/device.rb', line 393

def interfaces() self.configurations.map {|d| d.interfaces }.flatten end

#iProductObject

Index of string descriptor describing product.



308
309
310
# File 'lib/libusb/device.rb', line 308

def iProduct
  @pDevDesc[:iProduct]
end

#iSerialNumberObject

Index of string descriptor containing device serial number.



313
314
315
# File 'lib/libusb/device.rb', line 313

def iSerialNumber
  @pDevDesc[:iSerialNumber]
end

#manufacturerObject

Return manufacturer of the device

Returns:

  • String



352
353
354
355
356
357
# File 'lib/libusb/device.rb', line 352

def manufacturer
  return @manufacturer if defined? @manufacturer
  @manufacturer = try_string_descriptor_ascii(self.iManufacturer)
  @manufacturer = @manufacturer.strip if @manufacturer
  @manufacturer
end

#max_alt_packet_size(interface, alternate_setting, endpoint) ⇒ Fixnum

Calculate the maximum packet size which a specific endpoint is capable of sending or receiving in the duration of 1 microframe

Only the active configuration is examined. The calculation is based on the wMaxPacketSize field in the endpoint descriptor as described in section 9.6.6 in the USB 2.0 specifications.

If acting on an isochronous or interrupt endpoint, this function will multiply the value found in bits 0:10 by the number of transactions per microframe (determined by bits 11:12). Otherwise, this function just returns the numeric value found in bits 0:10. For USB 3.0 device, it will attempts to retrieve the Endpoint Companion Descriptor to return wBytesPerInterval.

This function is useful for setting up isochronous transfers, for example you might pass the return value from this function to IsochronousTransfer.packet_lengths= in order to set the length field of every isochronous packet in a transfer.

Available since libusb-1.0.27.

Parameters:

  • interface (Interface, Fixnum)

    the interface or its bInterfaceNumber of the interface the endpoint belongs to

  • alternate_setting (Setting, Fixnum)

    the alternate setting or its bAlternateSetting

  • endpoint (Endpoint, Fixnum)

    (address of) the endpoint in question

Returns:

  • (Fixnum)

    the maximum packet size which can be sent/received on this endpoint

See Also:



194
195
196
197
198
199
200
201
# File 'lib/libusb/device.rb', line 194

def max_alt_packet_size(interface, alternate_setting, endpoint)
  interface = interface.bInterfaceNumber if interface.respond_to? :bInterfaceNumber
  alternate_setting = alternate_setting.bAlternateSetting if alternate_setting.respond_to? :bAlternateSetting
  endpoint = endpoint.bEndpointAddress if endpoint.respond_to? :bEndpointAddress
  res = Call.libusb_get_max_alt_packet_size(@pDev, interface, alternate_setting, endpoint)
  LIBUSB.raise_error res, "in libusb_get_max_alt_packet_size" unless res>=0
  res
end

#max_iso_packet_size(endpoint) ⇒ Fixnum

Calculate the maximum packet size which a specific endpoint is capable is sending or receiving in the duration of 1 microframe.

Only the active configution is examined. The calculation is based on the wMaxPacketSize field in the endpoint descriptor as described in section 9.6.6 in the USB 2.0 specifications.

If acting on an isochronous or interrupt endpoint, this function will multiply the value found in bits 0:10 by the number of transactions per microframe (determined by bits 11:12). Otherwise, this function just returns the numeric value found in bits 0:10.

This function is useful for setting up isochronous transfers, for example you might use the return value from this function to call IsoPacket#alloc_buffer in order to set the length field of an isochronous packet in a transfer.

Parameters:

  • endpoint (Endpoint, Fixnum)

    (address of) the endpoint in question

Returns:

  • (Fixnum)

    the maximum packet size which can be sent/received on this endpoint

See Also:



224
225
226
227
228
229
# File 'lib/libusb/device.rb', line 224

def max_iso_packet_size(endpoint)
  endpoint = endpoint.bEndpointAddress if endpoint.respond_to? :bEndpointAddress
  res = Call.libusb_get_max_iso_packet_size(@pDev, endpoint)
  LIBUSB.raise_error res, "in libusb_get_max_iso_packet_size" unless res>=0
  res
end

#max_packet_size(endpoint) ⇒ Fixnum

Convenience function to retrieve the wMaxPacketSize value for a particular endpoint in the active device configuration.

Parameters:

  • endpoint (Endpoint, Fixnum)

    (address of) the endpoint in question

Returns:

  • (Fixnum)

    the wMaxPacketSize value



159
160
161
162
163
164
# File 'lib/libusb/device.rb', line 159

def max_packet_size(endpoint)
  endpoint = endpoint.bEndpointAddress if endpoint.respond_to? :bEndpointAddress
  res = Call.libusb_get_max_packet_size(@pDev, endpoint)
  LIBUSB.raise_error res, "in libusb_get_max_packet_size" unless res>=0
  res
end

#openDevHandle

Open the device and obtain a device handle.

A handle allows you to perform I/O on the device in question. This is a non-blocking function; no requests are sent over the bus.

If called with a block, the handle is passed to the block and is closed when the block has finished.

You need proper device access:

  • Linux: read+write permissions to /dev/bus/usb/<bus>/<dev>

  • Windows: by installing a WinUSB-driver for the device (see README )

Returns:



58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/libusb/device.rb', line 58

def open
  ppHandle = FFI::MemoryPointer.new :pointer
  res = Call.libusb_open(@pDev, ppHandle)
  LIBUSB.raise_error res, "in libusb_open" if res!=0
  handle = DevHandle.new self, ppHandle.read_pointer
  return handle unless block_given?
  begin
    yield handle
  ensure
    handle.close
  end
end

#open_interface(interface) ⇒ Object

Open the device and claim an interface.

This is a convenience method to #open and LIBUSB::DevHandle#claim_interface. Must be called with a block. When the block has finished, the interface will be released and the device will be closed.

Parameters:

  • interface (Interface, Fixnum)

    the interface or it’s bInterfaceNumber you wish to claim



78
79
80
81
82
83
84
# File 'lib/libusb/device.rb', line 78

def open_interface(interface)
  open do |dev|
    dev.claim_interface(interface) do
      yield dev
    end
  end
end

#parentDevice?

Get the the parent from the specified device [EXPERIMENTAL]. Available since libusb-1.0.12.

Returns:

  • (Device, nil)

    the device parent or nil if not available

See Also:



112
113
114
115
116
117
118
119
120
# File 'lib/libusb/device.rb', line 112

def parent
  pppDevs = FFI::MemoryPointer.new :pointer
  Call.libusb_get_device_list(@context.instance_variable_get(:@ctx), pppDevs)
  ppDevs = pppDevs.read_pointer
  pParent = Call.libusb_get_parent(@pDev)
  parent = pParent.null? ? nil : Device.new(@context, pParent)
  Call.libusb_free_device_list(ppDevs, 1)
  parent
end

#port_numberFixnum?

Get the number of the port that a device is connected to. Available since libusb-1.0.12.

Returns:

  • (Fixnum, nil)

    the port number (nil if not available)

See Also:



102
103
104
105
# File 'lib/libusb/device.rb', line 102

def port_number
  r = Call.libusb_get_port_number(@pDev)
  r==0 ? nil : r
end

#port_numbersArray<Fixnum> Also known as: port_path

Get the list of all port numbers from root for the specified device. Available since libusb-1.0.12.

Returns:

  • (Array<Fixnum>)

See Also:



128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/libusb/device.rb', line 128

def port_numbers
  # As per the USB 3.0 specs, the current maximum limit for the depth is 7.
  path_len = 7
  pPath = FFI::MemoryPointer.new :pointer, path_len

  l = if Call.respond_to?(:libusb_get_port_numbers)
    Call.libusb_get_port_numbers(@pDev, pPath, path_len)
  else
    Call.libusb_get_port_path(@context.instance_variable_get(:@ctx), @pDev, pPath, path_len)
  end
  pPath.read_array_of_uint8(l)
end

#productObject

Return product name of the device.

Returns:

  • String



361
362
363
364
365
366
# File 'lib/libusb/device.rb', line 361

def product
  return @product if defined? @product
  @product = try_string_descriptor_ascii(self.iProduct)
  @product = @product.strip if @product
  @product
end

#serial_numberObject

Return serial number of the device.

Returns:

  • String



370
371
372
373
374
375
# File 'lib/libusb/device.rb', line 370

def serial_number
  return @serial_number if defined? @serial_number
  @serial_number = try_string_descriptor_ascii(self.iSerialNumber)
  @serial_number = @serial_number.strip if @serial_number
  @serial_number
end

#settingsArray<Setting>

Return all interface decriptions of this device.

Returns:



396
# File 'lib/libusb/device.rb', line 396

def settings() self.interfaces.map {|d| d.settings }.flatten end

#try_string_descriptor_ascii(i) ⇒ Object



342
343
344
345
346
347
348
# File 'lib/libusb/device.rb', line 342

def try_string_descriptor_ascii(i)
  begin
    open{|h| h.string_descriptor_ascii(i) }
  rescue
    "?"
  end
end