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.


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

def initialize context, pDev
  @context = context
  def pDev.unref_device(id)
    Call.libusb_unref_device(self)
  end
  ObjectSpace.define_finalizer(self, pDev.method(:unref_device))
  Call.libusb_ref_device(pDev)
  @pDev = 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.


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

def context
  @context
end

Instance Method Details

#<=>(o) ⇒ Object


359
360
361
362
363
# File 'lib/libusb/device.rb', line 359

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.


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

def bcdDevice
  @pDevDesc[:bcdDevice]
end

#bcdUSBInteger

USB specification release number which device complies too

Returns:

  • (Integer)

    in binary-coded decimal


215
216
217
# File 'lib/libusb/device.rb', line 215

def bcdUSB
  @pDevDesc[:bcdUSB]
end

#bDescriptorTypeObject

Device Descriptor (0x01)


208
209
210
# File 'lib/libusb/device.rb', line 208

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


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

def bDeviceClass
  @pDevDesc[:bDeviceClass]
end

#bDeviceProtocolObject

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


236
237
238
# File 'lib/libusb/device.rb', line 236

def bDeviceProtocol
  @pDevDesc[:bDeviceProtocol]
end

#bDeviceSubClassObject

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


230
231
232
# File 'lib/libusb/device.rb', line 230

def bDeviceSubClass
  @pDevDesc[:bDeviceSubClass]
end

#bLengthObject

Size of the Descriptor in Bytes (18 bytes)


203
204
205
# File 'lib/libusb/device.rb', line 203

def bLength
  @pDevDesc[:bLength]
end

#bMaxPacketSize0Object

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


241
242
243
# File 'lib/libusb/device.rb', line 241

def bMaxPacketSize0
  @pDevDesc[:bMaxPacketSize0]
end

#bNumConfigurationsObject

Number of Possible Configurations


276
277
278
# File 'lib/libusb/device.rb', line 276

def bNumConfigurations
  @pDevDesc[:bNumConfigurations]
end

#bus_numberObject

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


84
85
86
# File 'lib/libusb/device.rb', line 84

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


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

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:


337
338
339
340
341
342
343
344
345
346
347
# File 'lib/libusb/device.rb', line 337

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.


89
90
91
# File 'lib/libusb/device.rb', line 89

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.


146
147
148
# File 'lib/libusb/device.rb', line 146

def device_speed
  Call.libusb_get_device_speed(@pDev)
end

#endpointsArray<Endpoint>

Return all endpoints of all interfaces of this device.

Returns:


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

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

#idProductObject

USB-IF product ID (Assigned by Manufacturer)


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

def idProduct
  @pDevDesc[:idProduct]
end

#idVendorObject

USB-IF vendor ID (Assigned by USB Org)


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

def idVendor
  @pDevDesc[:idVendor]
end

#iManufacturerObject

Index of string descriptor describing manufacturer.


261
262
263
# File 'lib/libusb/device.rb', line 261

def iManufacturer
  @pDevDesc[:iManufacturer]
end

#inspectObject


281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
# File 'lib/libusb/device.rb', line 281

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:


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

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

#iProductObject

Index of string descriptor describing product.


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

def iProduct
  @pDevDesc[:iProduct]
end

#iSerialNumberObject

Index of string descriptor containing device serial number.


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

def iSerialNumber
  @pDevDesc[:iSerialNumber]
end

#manufacturerObject

Return manufacturer of the device

Returns:

  • String


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

def manufacturer
  return @manufacturer if defined? @manufacturer
  @manufacturer = try_string_descriptor_ascii(self.iManufacturer)
  @manufacturer.strip! if @manufacturer
  @manufacturer
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


182
183
184
185
186
187
# File 'lib/libusb/device.rb', line 182

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


156
157
158
159
160
161
# File 'lib/libusb/device.rb', line 156

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:


55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/libusb/device.rb', line 55

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


75
76
77
78
79
80
81
# File 'lib/libusb/device.rb', line 75

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:


109
110
111
112
113
114
115
116
117
# File 'lib/libusb/device.rb', line 109

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:


99
100
101
102
# File 'lib/libusb/device.rb', line 99

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:


125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/libusb/device.rb', line 125

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


319
320
321
322
323
324
# File 'lib/libusb/device.rb', line 319

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

#serial_numberObject

Return serial number of the device.

Returns:

  • String


328
329
330
331
332
333
# File 'lib/libusb/device.rb', line 328

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

#settingsArray<Setting>

Return all interface decriptions of this device.

Returns:


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

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

#try_string_descriptor_ascii(i) ⇒ Object


300
301
302
303
304
305
306
# File 'lib/libusb/device.rb', line 300

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