Last active
August 29, 2015 14:06
-
-
Save bithive/9ff23c9ade9330081fb7 to your computer and use it in GitHub Desktop.
A class for getting events from a Griffin PowerMate
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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