Skip to content

Instantly share code, notes, and snippets.

@bithive
Last active August 29, 2015 14:06
Show Gist options
  • Save bithive/9ff23c9ade9330081fb7 to your computer and use it in GitHub Desktop.
Save bithive/9ff23c9ade9330081fb7 to your computer and use it in GitHub Desktop.
A class for getting events from a Griffin PowerMate
#!/usr/bin/env ruby
# Ruby interface for Griffin PowerMate
require 'usb'
class PowerMate
VENDOR_ID = 0x077d
PRODUCT_ID_NEW = 0x0410
PRODUCT_ID_OLD = 0x04AA
EVENT_UNIT = 256 # interval at which values will fall
EVENT_SIZE = 16 # how many bytes to read per event
EVENT_KEEP = 4 # number of events to keep for debouncing
EVENT_TIME = 0.25 # maximum time to keep events
attr_reader :handle, :dev
def self.find_dev
USB.devices.each do |dev|
if dev.idVendor == VENDOR_ID &&
(dev.idProduct == PRODUCT_ID_NEW || dev.idProduct == PRODUCT_ID_OLD)
return dev
end
end
end
def initialize(dev = nil)
@dev = dev || self.class.find_dev
@last = []
@time = Time.now.to_f
end
def connect
return false if connected?
@handle = dev.open
@handle.usb_claim_interface(0)
end
def disconnect
return false unless connected?
@handle.usb_close
@handle = nil
end
def connected?
not @handle.nil?
end
def button_press &block
@button_press = block
end
def dial_rotate &block
@dial_rotate = block
end
def process_input_events
connect unless connected?
loop do
buffer = '0' * EVENT_SIZE
epaddr = dev.endpoints.first.bEndpointAddress
nbytes = handle.usb_bulk_read(epaddr, buffer, 0)
next unless nbytes > 0
event = buffer.unpack("ldsxx")
handle_event event[2]
end
end
private
def handle_event code
time = Time.now.to_f
if time - @time > EVENT_TIME
@last.clear
end
if code == 0 || code == 1
if @last.empty?
@last << nil
@button_press.call
end
else
value = code / EVENT_UNIT
press = code % EVENT_UNIT == 1
@last << (code > 0)
@last.shift if @last.size > EVENT_KEEP
if @last.empty? || @last.uniq.size == 1
@dial_rotate.call value, press
end
end
@time = time
end
end
if __FILE__ == $0
trap :INT do
exit
end
pm = PowerMate.new
pm.button_press do
puts 'BUTTON PRESS'
end
pm.dial_rotate do |value, press|
print press ? 'PRESS' : 'FREE'
print ' ROTATE '
print value > 0 ? 'RIGHT' : 'LEFT'
print ' SPEED '
puts value.abs
end
pm.process_input_events
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment