Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Python API to control up to 256 LED #51

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 41 additions & 17 deletions blinkstick/blinkstick.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ class BlinkStick(object):
inverse = False
error_reporting = True
max_rgb_value = 255
mode = 0

def __init__(self, device=None, error_reporting=True):
"""
Expand All @@ -207,16 +208,17 @@ def __init__(self, device=None, error_reporting=True):
self.open_device(device)

self.bs_serial = self.get_serial()
self.mode = self.get_mode()

def _usb_get_string(self, device, index):
def _usb_get_string(self, device, length, index):
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My USB library seemed to require a length parameter which required a lot of changes like this. Not sure if this is appropriate for master. I could revert.

try:
return usb.util.get_string(device, index)
return usb.util.get_string(device, length, index)
except usb.USBError:
# Could not communicate with BlinkStick device
# attempt to find it again based on serial

if self._refresh_device():
return usb.util.get_string(self.device, index)
return usb.util.get_string(self.device, length, index)
else:
raise BlinkStickException("Could not communicate with BlinkStick {0} - it may have been removed".format(self.bs_serial))

Expand Down Expand Up @@ -269,7 +271,7 @@ def get_serial(self):
if sys.platform == "win32":
return self.device.serial_number
else:
return self._usb_get_string(self.device, 3)
return self._usb_get_string(self.device, 256, 3)

def get_manufacturer(self):
"""
Expand All @@ -281,7 +283,7 @@ def get_manufacturer(self):
if sys.platform == "win32":
return self.device.vendor_name
else:
return self._usb_get_string(self.device, 1)
return self._usb_get_string(self.device, 256, 1)


def get_description(self):
Expand All @@ -294,7 +296,7 @@ def get_description(self):
if sys.platform == "win32":
return self.device.product_name
else:
return self._usb_get_string(self.device, 2)
return self._usb_get_string(self.device, 256, 2)

def set_error_reporting(self, error_reporting):
"""
Expand Down Expand Up @@ -350,7 +352,7 @@ def _determine_rgb(self, red=0, green=0, blue=0, name=None, hex=None):
try:
if name:
# Special case for name="random"
if name == "random":
if name is "random":
red = randint(0, 255)
green = randint(0, 255)
blue = randint(0, 255)
Expand Down Expand Up @@ -417,8 +419,8 @@ def get_color(self, index=0, color_format='rgb'):
raise BlinkStickException("Could not return current color in format %s" % color_format)

def _determine_report_id(self, led_count):
report_id = 9
max_leds = 64
report_id = 10
max_leds = 128

if led_count <= 8 * 3:
max_leds = 8
Expand All @@ -432,6 +434,9 @@ def _determine_report_id(self, led_count):
elif led_count <= 64 * 3:
max_leds = 64
report_id = 9
elif led_count <= 128 * 3:
max_leds = 128
report_id = 10
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add support for report 10 here


return report_id, max_leds

Expand All @@ -445,15 +450,23 @@ def set_led_data(self, channel, data):
@param data: The LED data frame in GRB format
"""

report_id, max_leds = self._determine_report_id(len(data))

report = [0, channel]

for i in range(0, max_leds * 3):
if len(data) > i:
report.append(data[i])
else:
report.append(0)
if self.mode == 3:
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pack the data so each 24 bit RGB tuple is two interleaved 12 bit RGB tuples for mode 3

report_id, max_leds = self._determine_report_id(len(data)/2)
offset = max_leds * 3
for i in range(0, offset):
d = data[i]>>4
if len(data) > offset + i:
d += data[offset+i]&240
report.append(d)
else:
report_id, max_leds = self._determine_report_id(len(data))
for i in range(0, max_leds * 3):
if len(data) > i:
report.append(data[i])
else:
report.append(0)

self._usb_ctrl_transfer(0x20, 0x9, report_id, 0, bytes(bytearray(report)))

Expand All @@ -473,6 +486,16 @@ def get_led_data(self, count):

return device_bytes[2: 2 + count * 3]

def set_repeat(self, repeat):
"""
Set the number of repeats on the frame

@type repeat: int
@param mode: number of times to repeat the frame
"""
control_string = bytes(bytearray([20, repeat]))
self._usb_ctrl_transfer(0x20, 0x9, 0x14, 0, control_string)

def set_mode(self, mode):
"""
Set device mode for BlinkStick Pro. Device currently supports the following modes:
Expand All @@ -491,6 +514,7 @@ def set_mode(self, mode):
control_string = bytes(bytearray([4, mode]))

self._usb_ctrl_transfer(0x20, 0x9, 0x0004, 0, control_string)
self.mode = mode

def get_mode(self):
"""
Expand Down Expand Up @@ -1527,7 +1551,7 @@ def find_by_serial(serial=None):
else:
for d in _find_blicksticks():
try:
if usb.util.get_string(d, 3) == serial:
if usb.util.get_string(d, 256, 3) == serial:
devices = [d]
break
except Exception as e:
Expand Down