forked from smasty/g203-led
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathg203-led.py
executable file
·155 lines (117 loc) · 3.67 KB
/
g203-led.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
149
150
151
152
153
154
155
#!env/bin/python
# Logitech G203 Prodigy Mouse LED control
# https://github.com/smasty/g203-led
# Author: Smasty, [email protected]
# Licensed under the MIT license.
import sys
import usb.core
import usb.util
import re
import binascii
g203_vendor_id = 0x046d
g203_product_id = 0xc084
default_rate = 10000
default_brightness = 100
dev = None
wIndex = None
def help():
print("""Logitech G203 Prodigy Mouse LED control
Usage:
\tg203-led solid {color} - Solid color mode
\tg203-led cycle [{rate} [{brightness}]] - Cycle through all colors
\tg203-led breathe {color} [{rate} [{brightness}]] - Single color breathing
\tg203-led intro {on|off} - Enable/disable startup effect
Arguments:
\tColor: RRGGBB (RGB hex value)
\tRate: 100-60000 (Number of milliseconds. Default: 10000ms)
\tBrightness: 0-100 (Percentage. Default: 100%)""")
def main():
if(len(sys.argv) < 2):
help()
sys.exit()
args = sys.argv + [None] * (5 - len(sys.argv))
mode = args[1]
if mode == 'solid':
set_led_solid(process_color(args[2]))
elif mode == 'cycle':
set_led_cycle(process_rate(args[2]), process_brightness(args[3]))
elif mode == 'breathe':
set_led_breathe(
process_color(args[2]),
process_rate(args[3]),
process_brightness(args[4])
)
elif mode == 'intro':
set_intro_effect(args[2])
else:
print_error('Unknown mode.')
def print_error(msg):
print('Error: ' + msg)
sys.exit(1)
def process_color(color):
if not color:
print_error('No color specifed.')
if color[0] == '#':
color = color[1:]
if not re.match('^[0-9a-fA-F]{6}$', color):
print_error('Invalid color specified.')
return color.lower()
def process_rate(rate):
if not rate:
rate = default_rate
try:
return '{:04x}'.format(max(100, min(65535, int(rate))))
except ValueError:
print_error('Invalid rate specified.')
def process_brightness(brightness):
if not brightness:
brightness = default_brightness
try:
return '{:02x}'.format(max(1, min(100, int(brightness))))
except ValueError:
print_error('Invalid brightness specified.')
def set_led_solid(color):
return set_led('01', color + '0000000000')
def set_led_breathe(color, rate, brightness):
return set_led('03', color + rate + '00' + brightness + '00')
def set_led_cycle(rate, brightness):
print(rate, brightness)
return set_led('02', '0000000000' + rate + brightness)
def set_led(mode, data):
global dev
global wIndex
prefix = '11ff0e3b00'
suffix = '000000000000'
send_command(prefix + mode + data + suffix)
def set_intro_effect(arg):
if arg == 'on' or arg == '1':
toggle = '01'
elif arg == 'off' or arg == '0':
toggle = '02'
else:
print_error('Invalid value.')
send_command('11ff0e5b0001'+toggle+'00000000000000000000000000')
def send_command(data):
attach_mouse()
dev.ctrl_transfer(0x21, 0x09, 0x0211, wIndex, binascii.unhexlify(data))
detach_mouse()
def attach_mouse():
global dev
global wIndex
dev = usb.core.find(idVendor=g203_vendor_id, idProduct=g203_product_id)
if dev is None:
print_error('Device {:04x}:{:04x} not found.'.format(g203_vendor_id, g203_product_id))
wIndex = 0x01
if dev.is_kernel_driver_active(wIndex) is True:
dev.detach_kernel_driver(wIndex)
usb.util.claim_interface(dev, wIndex)
def detach_mouse():
global dev
global wIndex
if wIndex is not None:
usb.util.release_interface(dev, wIndex)
dev.attach_kernel_driver(wIndex)
dev = None
wIndex = None
if __name__ == '__main__':
main()