Class: LIBUSB::Context
- Inherits:
-
Object
- Object
- LIBUSB::Context
- Defined in:
- lib/libusb/context.rb,
lib/libusb/eventmachine.rb
Overview
Class representing a libusb session.
Defined Under Namespace
Classes: CompletionFlag, EMPollfdHandler, HotplugCallback, Pollfd
Instance Method Summary collapse
-
#debug=(level) ⇒ Object
deprecated
Deprecated.
Use #set_option instead using the
:OPTION_LOG_LEVEL
option. -
#devices(filter_hash = {}) ⇒ Array<LIBUSB::Device>
Obtain a list of devices currently attached to the USB system, optionally matching certain criteria.
-
#eventmachine_register ⇒ Object
Register libusb's file descriptors and timeouts to EventMachine.
- #eventmachine_unregister ⇒ Object
-
#exit ⇒ Object
Deinitialize libusb.
-
#handle_events(timeout = nil, completion_flag = nil) ⇒ Object
Handle any pending events in blocking mode.
-
#initialize ⇒ Context
constructor
Initialize libusb context.
-
#interrupt_event_handler ⇒ Object
Interrupt any active thread that is handling events.
-
#next_timeout ⇒ Float?
Determine the next internal timeout that libusb needs to handle.
-
#on_hotplug_event(args = {}) {|device, event| ... } ⇒ HotplugCallback
Register a hotplug event notification.
-
#on_pollfd_added {|pollfd| ... } ⇒ Object
Register a notification block for file descriptor additions.
-
#on_pollfd_removed {|pollfd| ... } ⇒ Object
Register a notification block for file descriptor removals.
-
#pollfds ⇒ Array<Pollfd>
Retrieve a list of file descriptors that should be polled by your main loop as libusb event sources.
-
#set_option(option, *args) ⇒ Object
Set a libusb option from the option list.
Constructor Details
#initialize ⇒ Context
Initialize libusb context.
100 101 102 103 104 105 106 107 108 |
# File 'lib/libusb/context.rb', line 100 def initialize m = FFI::MemoryPointer.new :pointer res = Call.libusb_init(m) LIBUSB.raise_error res, "in libusb_init" if res!=0 @ctx = m.read_pointer @on_pollfd_added = nil @on_pollfd_removed = nil @hotplug_callbacks = {} end |
Instance Method Details
#debug=(level) ⇒ Object
Use #set_option instead using the :OPTION_LOG_LEVEL
option.
118 119 120 |
# File 'lib/libusb/context.rb', line 118 def debug=(level) Call.libusb_set_debug(@ctx, level) end |
#devices(filter_hash = {}) ⇒ Array<LIBUSB::Device>
Obtain a list of devices currently attached to the USB system, optionally matching certain criteria.
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 |
# File 'lib/libusb/context.rb', line 248 def devices(filter_hash={}) device_list.select do |dev| ( !filter_hash[:bClass] || (dev.bDeviceClass==CLASS_PER_INTERFACE ? dev.settings.map(&:bInterfaceClass).&([filter_hash[:bClass]].flatten).any? : [filter_hash[:bClass]].flatten.include?(dev.bDeviceClass))) && ( !filter_hash[:bSubClass] || (dev.bDeviceClass==CLASS_PER_INTERFACE ? dev.settings.map(&:bInterfaceSubClass).&([filter_hash[:bSubClass]].flatten).any? : [filter_hash[:bSubClass]].flatten.include?(dev.bDeviceSubClass))) && ( !filter_hash[:bProtocol] || (dev.bDeviceClass==CLASS_PER_INTERFACE ? dev.settings.map(&:bInterfaceProtocol).&([filter_hash[:bProtocol]].flatten).any? : [filter_hash[:bProtocol]].flatten.include?(dev.bDeviceProtocol))) && ( !filter_hash[:bMaxPacketSize0] || [filter_hash[:bMaxPacketSize0]].flatten.include?(dev.bMaxPacketSize0) ) && ( !filter_hash[:idVendor] || [filter_hash[:idVendor]].flatten.include?(dev.idVendor) ) && ( !filter_hash[:idProduct] || [filter_hash[:idProduct]].flatten.include?(dev.idProduct) ) && ( !filter_hash[:bcdUSB] || [filter_hash[:bcdUSB]].flatten.include?(dev.bcdUSB) ) && ( !filter_hash[:bcdDevice] || [filter_hash[:bcdDevice]].flatten.include?(dev.bcdDevice) ) end end |
#eventmachine_register ⇒ Object
Register libusb's file descriptors and timeouts to EventMachine.
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/libusb/eventmachine.rb', line 34 def eventmachine_register @eventmachine_attached_fds = {} @eventmachine_timer = nil pollfds = self.pollfds if pollfds pollfds.each do |pollfd| eventmachine_add_pollfd(pollfd) end self.on_pollfd_added do |pollfd| eventmachine_add_pollfd(pollfd) end self.on_pollfd_removed do |pollfd| eventmachine_rm_pollfd(pollfd) end else # Libusb pollfd API is not available on this platform. # Use simple polling timer, instead: EventMachine.add_periodic_timer(0.01) do @eventmachine_timer = self.handle_events 0 end end end |
#eventmachine_unregister ⇒ Object
60 61 62 63 64 65 |
# File 'lib/libusb/eventmachine.rb', line 60 def eventmachine_unregister @eventmachine_timer.cancel if @eventmachine_timer @eventmachine_attached_fds.each do |fd, watcher| watcher.detach end end |
#exit ⇒ Object
Deinitialize libusb.
Should be called after closing all open devices and before your application terminates.
113 114 115 |
# File 'lib/libusb/context.rb', line 113 def exit Call.libusb_exit(@ctx) end |
#handle_events(timeout = nil, completion_flag = nil) ⇒ Object
Handle any pending events in blocking mode.
This method must be called when libusb is running asynchronous transfers. This gives libusb the opportunity to reap pending transfers, invoke callbacks, etc.
If a zero timeout is passed, this function will handle any already-pending events and then immediately return in non-blocking style.
If a non-zero timeout is passed and no events are currently pending, this method will block waiting for events to handle up until the specified timeout. If an event arrives or a signal is raised, this method will return early.
If the parameter completion_flag is used, then after obtaining the event handling lock this function will return immediately if the flag is set to completed. This allows for race free waiting for the completion of a specific transfer. See source of Transfer#submit_and_wait for a use case of completion_flag.
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
# File 'lib/libusb/context.rb', line 195 def handle_events(timeout=nil, completion_flag=nil) if completion_flag && !completion_flag.is_a?(Context::CompletionFlag) raise ArgumentError, "completion_flag is not a CompletionFlag" end if timeout timeval = Call::Timeval.new timeval.in_ms = timeout res = if Call.respond_to?(:libusb_handle_events_timeout_completed) Call.libusb_handle_events_timeout_completed(@ctx, timeval, completion_flag) else Call.libusb_handle_events_timeout(@ctx, timeval) end else res = if Call.respond_to?(:libusb_handle_events_completed) Call.libusb_handle_events_completed(@ctx, completion_flag ) else Call.libusb_handle_events(@ctx) end end LIBUSB.raise_error res, "in libusb_handle_events" if res<0 end |
#interrupt_event_handler ⇒ Object
Interrupt any active thread that is handling events.
This is mainly useful for interrupting a dedicated event handling thread when an application wishes to call #exit.
Available since libusb-1.0.21.
225 226 227 |
# File 'lib/libusb/context.rb', line 225 def interrupt_event_handler Call.libusb_interrupt_event_handler(@ctx) end |
#next_timeout ⇒ Float?
Determine the next internal timeout that libusb needs to handle.
You only need to use this function if you are calling poll() or select() or similar on libusb's file descriptors yourself - you do not need to use it if you are calling #handle_events directly.
You should call this function in your main loop in order to determine how long to wait for select() or poll() to return results. libusb needs to be called into at this timeout, so you should use it as an upper bound on your select() or poll() call.
When the timeout has expired, call into #handle_events (perhaps in non-blocking mode) so that libusb can handle the timeout.
This function may return zero. If this is the case, it indicates that libusb has a timeout that has already expired so you should call #handle_events immediately. A return code of nil
indicates that there are no pending timeouts.
On some platforms, this function will always returns nil
(no pending timeouts). See libusb's notes on time-based events.
318 319 320 321 322 323 |
# File 'lib/libusb/context.rb', line 318 def next_timeout timeval = Call::Timeval.new res = Call.libusb_get_next_timeout @ctx, timeval LIBUSB.raise_error res, "in libusb_get_next_timeout" if res<0 res == 1 ? timeval.in_s : nil end |
#on_hotplug_event(args = {}) {|device, event| ... } ⇒ HotplugCallback
Register a hotplug event notification.
Register a callback with the LIBUSB::Context. The callback will fire when a matching event occurs on a matching device. The callback is armed until either it is deregistered with LIBUSB::Context::HotplugCallback#deregister or the supplied block returns :finish
to indicate it is finished processing events.
If the flag HOTPLUG_ENUMERATE is passed the callback will be called with a :HOTPLUG_EVENT_DEVICE_ARRIVED for all devices already plugged into the machine. Note that libusb modifies its internal device list from a separate thread, while calling hotplug callbacks from #handle_events, so it is possible for a device to already be present on, or removed from, its internal device list, while the hotplug callbacks still need to be dispatched. This means that when using HOTPLUG_ENUMERATE, your callback may be called twice for the arrival of the same device, once from #on_hotplug_event and once from #handle_events; and/or your callback may be called for the removal of a device for which an arrived call was never made.
Since libusb version 1.0.16.
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 |
# File 'lib/libusb/context.rb', line 396 def on_hotplug_event(args={}, &block) events = args.delete(:events) || (HOTPLUG_EVENT_DEVICE_ARRIVED | HOTPLUG_EVENT_DEVICE_LEFT) flags = args.delete(:flags) || 0 vendor_id = args.delete(:vendor_id) || HOTPLUG_MATCH_ANY product_id = args.delete(:product_id) || HOTPLUG_MATCH_ANY dev_class = args.delete(:dev_class) || HOTPLUG_MATCH_ANY raise ArgumentError, "invalid params #{args.inspect}" unless args.empty? handle = HotplugCallback.new self, @ctx, @hotplug_callbacks block2 = proc do |ctx, pDevice, event, _user_data| raise "internal error: unexpected context" unless @ctx==ctx dev = Device.new @ctx, pDevice blres = block.call(dev, event) case blres when :finish 1 when :repeat 0 else raise ArgumentError, "hotplug event handler must return :finish or :repeat" end end res = Call.libusb_hotplug_register_callback(@ctx, events, flags, vendor_id, product_id, dev_class, block2, nil, handle) LIBUSB.raise_error res, "in libusb_hotplug_register_callback" if res<0 # Avoid GC'ing of the block: @hotplug_callbacks[handle[:handle]] = block2 return handle end |
#on_pollfd_added {|pollfd| ... } ⇒ Object
Register a notification block for file descriptor additions.
This block will be invoked for every new file descriptor that libusb uses as an event source.
Note that file descriptors may have been added even before you register these notifiers (e.g. at #initialize time).
334 335 336 337 338 339 340 |
# File 'lib/libusb/context.rb', line 334 def on_pollfd_added &block @on_pollfd_added = proc do |fd, events, _| pollfd = Pollfd.new fd, events block.call pollfd end Call.libusb_set_pollfd_notifiers @ctx, @on_pollfd_added, @on_pollfd_removed, nil end |
#on_pollfd_removed {|pollfd| ... } ⇒ Object
Register a notification block for file descriptor removals.
This block will be invoked for every removed file descriptor that libusb uses as an event source.
Note that the removal notifier may be called during #exit (e.g. when it is closing file descriptors that were opened and added to the poll set at #initialize time). If you don't want this, overwrite the notifier immediately before calling #exit.
353 354 355 356 357 358 359 |
# File 'lib/libusb/context.rb', line 353 def on_pollfd_removed &block @on_pollfd_removed = proc do |fd, _| pollfd = Pollfd.new fd block.call pollfd end Call.libusb_set_pollfd_notifiers @ctx, @on_pollfd_added, @on_pollfd_removed, nil end |
#pollfds ⇒ Array<Pollfd>
Retrieve a list of file descriptors that should be polled by your main loop as libusb event sources.
As file descriptors are a Unix-specific concept, this function is not available on Windows and will always return nil
.
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 |
# File 'lib/libusb/context.rb', line 277 def pollfds ppPollfds = Call.libusb_get_pollfds(@ctx) return nil if ppPollfds.null? offs = 0 pollfds = [] while !(pPollfd=ppPollfds.get_pointer(offs)).null? pollfd = Call::Pollfd.new pPollfd pollfds << Pollfd.new(pollfd[:fd], pollfd[:events]) offs += FFI.type_size :pointer end if Call.respond_to?(:libusb_free_pollfds) Call.libusb_free_pollfds(ppPollfds) else Stdio.free(ppPollfds) end pollfds end |
#set_option(option, *args) ⇒ Object
Set a libusb option from the option list.
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/libusb/context.rb', line 131 def set_option(option, *args) if Call.respond_to?(:libusb_set_option) # Available since libusb-1.0.22 ffi_args = case option when :OPTION_LOG_LEVEL, LIBUSB::OPTION_LOG_LEVEL expect_option_args(1, args.length) [:libusb_log_level, args[0]] when :OPTION_USE_USBDK, LIBUSB::OPTION_USE_USBDK expect_option_args(0, args.length) [] else raise ArgumentError, "unknown option #{option.inspect}" end res = Call.libusb_set_option(@ctx, option, *ffi_args) LIBUSB.raise_error res, "in libusb_set_option" if res<0 else # Fallback to deprecated function, if the gem is linked to an older libusb. raise ArgumentError, "unknown option #{option.inspect}" unless [:OPTION_LOG_LEVEL, LIBUSB::OPTION_LOG_LEVEL].include?(option) Call.libusb_set_debug(@ctx, *args) end end |