forked from hellonarrativ/BigRedButton
-
Notifications
You must be signed in to change notification settings - Fork 0
/
buttonDriver.py
executable file
·148 lines (117 loc) · 3.55 KB
/
buttonDriver.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#!/usr/bin/env python2
from usb import core, util
import atexit
from time import sleep
from array import array
from subprocess import Popen
import shlex
'''
Extensive credit goes to https://gist.github.com/arr2036/9932438
I basically copied his c driver into python. I was able to figure out
what variables he chose for bmRequestType, but not why- and there were
a bunch of settings that I have no idea why they work. Fun stuff either
way! This requires libusb to be installed (I tested with v 1.0). It
also will not work on OSX. OSX kernel claims the device as a HID, and
the function to force the kernal to release HID devices has not yet
been written for libusb (and is apparently difficult).
'''
VENDOR_ID = 7476
PRODUCT_ID = 13
POLL_INTERVAL = .1
BUTTON_STATE_ERROR = -1
BUTTON_STATE_UNKNOWN = 0
BUTTON_STATE_LID_CLOSED = 0x15
BUTTON_STATE_PRESSED = 0x16
BUTTON_STATE_LID_OPEN = 0x17
should_exit = False
kernel_was_attached = False
warning_p = None
def get_device_handle():
dev = core.find(idVendor=VENDOR_ID, idProduct=PRODUCT_ID)
if dev is None:
raise SystemError("Device not found!")
interface = 0 # HID
# Free red button from kernel driver
# This does not work on OSX
if dev.is_kernel_driver_active(interface) is True:
dev.detach_kernel_driver(interface)
util.claim_interface(dev, interface)
kernel_was_attached = True
return dev
def set_button_control(dev):
# Transfer control to the button HID interface
bm_request_type = util.build_request_type(
util.CTRL_OUT,
util.CTRL_TYPE_CLASS,
util.CTRL_RECIPIENT_INTERFACE
)
state = array('B', [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02])
ret = dev.ctrl_transfer(bm_request_type, 0x09, 0x00, 0x00, state)
if ret < 0:
print "Error reading control response"
return -1
if ret == 0:
print "Device didn't sent enough data"
return -1
return 0
def read_button_state(dev):
if set_button_control(dev) < 0:
return -1
endpoint = dev[0][(0, 0)][0] # Interrupt IN
try:
data = dev.read(endpoint.bEndpointAddress, endpoint.wMaxPacketSize, timeout=2000)
except:
return -1
return data[0]
def stop_warning():
global warning_p
try:
warning_p.terminate()
warning_p = None
except:
pass
def cleanup():
print "Cleaning up"
stop_warning()
interface = 0
# release the device
util.release_interface(device_handle, interface)
# reattach the device to the OS kernel
device_handle.attach_kernel_driver(interface)
def button_pressed():
print "BAM"
stop_warning()
Popen(['mpg123','bam.mp3'], close_fds=True)
def button_not_pressed():
print "NO BAM"
stop_warning()
def lid_opened():
print "WARNING..."
global warning_p
args = shlex.split('mpg123 --loop -1 warning.mp3');
if not warning_p:
warning_p = Popen(args, close_fds=True)
command = {
BUTTON_STATE_LID_CLOSED: button_not_pressed,
BUTTON_STATE_PRESSED: button_pressed,
BUTTON_STATE_LID_OPEN: lid_opened
}
atexit.register(cleanup)
then = BUTTON_STATE_UNKNOWN
device_handle = get_device_handle()
if read_button_state(device_handle) == BUTTON_STATE_ERROR:
exit()
while True:
now = read_button_state(device_handle)
if now == BUTTON_STATE_ERROR:
sleep(POLL_INTERVAL)
continue
if then == now:
sleep(POLL_INTERVAL)
continue
if then == BUTTON_STATE_PRESSED:
# Released action - no op
then = now
continue
command[now]()
then = now