Skip to content

Commit

Permalink
python: added two examples from community (this is so great!)
Browse files Browse the repository at this point in the history
  • Loading branch information
todbot committed Jan 29, 2013
1 parent 55835cd commit 4d362c3
Show file tree
Hide file tree
Showing 3 changed files with 210 additions and 0 deletions.
19 changes: 19 additions & 0 deletions python/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@

Using Python to control blink(1)
================================

There are two ways to get Python to access blink(1):

- Use the PyUSB library to construct USB HID requests
- Wrap the "blink1-lib" C-library located in blink1/commandline

The PyUSB is very easy to use, but creates an additional dependency for shipped code.
Wrapping the C-library means you need to deal with platform-specific issues.

Thanks to members of the blink(1) community, both of these techniques have working examples:

- Aaron Blondeau's script "blink1hid-demo.py" shows how to construct raw HID reports
that send commands to blink(1)

- Stephen Youndt's script "blink1-ctypes.py" shows how to wrap the C library

125 changes: 125 additions & 0 deletions python/blink1-ctypes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
#/usr/bin/python
"""
blink1.py -- Python interface to libblink1 through the magic of ctypes
import blink1
dev = blink1.open()
blink1.setRGB(d, 255,0,0) # Red
...
Do not:
from blink1 import *
or you will polute your namespace with some very common names (i.e. File I/O)
Make sure the "blink1-lib" shared library / DLL is in your path
for more info see:
https://getsatisfaction.com/thingm/topics/more_comprehensive_python_support
Thanks to Stephen Youndt for this
"""

from ctypes import *
from ctypes.util import find_library
import inspect, os
import glob
# Find the library
localpath = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
libname = find_library("blink1")
if libname is None:
libname = find_library("Blink1")
if libname is None:
libname = find_library("blink1-lib")
if libname is None:
libname = glob.glob(os.path.join(localpath, '[Bb]link1-lib.so'))[-1]
if libname is None:
libname = glob.glob(os.path.join(localpath, 'blink1-lib.dll'))[-1]
if libname is None:
libname = glob.glob(os.path.join(localpath, 'lib[Bb]link1*'))[-1]
# If we found the library, load it
assert libname is not None
libblink1 = CDLL(libname)
vid = libblink1.blink1_vid
vid.restype = c_int
pid = libblink1.blink1_pid
pid.restype = c_int
sortPaths = libblink1.blink1_sortPaths
sortSerials = libblink1.blink1_sortSerials
enumerate = libblink1.blink1_enumerate
enumerate.restype = c_int
enumerateByVidPid = libblink1.blink1_enumerateByVidPid
enumerateByVidPid.restype = c_int
enumerateByVidPid.argtypes = [c_int, c_int]
getCachedPath = libblink1.blink1_getCachedPath
getCachedPath.restype = c_char_p
getCachedPath.argtypes = [c_int]
getCachedSerial = libblink1.blink1_getCachedSerial
getCachedSerial.restype = c_wchar_p
getCachedSerial.argtypes = [c_int]
getCachedCount = libblink1.blink1_getCachedCount
getCachedCount.restype = c_int
open = libblink1.blink1_open
open.restype = c_void_p
openByPath = libblink1.blink1_openByPath
openByPath.restype = c_void_p
openByPath.argtypes = [c_char_p]
openBySerial = libblink1.blink1_openBySerial
openBySerial.restype = c_void_p
openBySerial.argtypes = [c_wchar_p]
openById = libblink1.blink1_openById
openById.restype = c_void_p
openById.argtypes = [c_int]
close = libblink1.blink1_close
close.argtypes = [c_void_p]
write = libblink1.blink1_write
write.restype = c_int
write.argtypes = [c_void_p, c_void_p, c_int]
read = libblink1.blink1_read
read.restype = c_int
read.argtypes = [c_void_p, c_void_p, c_int]
getSerialNumber = libblink1.blink1_getSerialNumber
getSerialNumber.restype = c_int
getSerialNumber.argtypes = [c_void_p, c_char_p]
getVersion = libblink1.blink1_getVersion
getVersion.restype = c_int
getVersion.argtypes = [c_void_p]
fadeToRGB = libblink1.blink1_fadeToRGB
fadeToRGB.restype = c_int
fadeToRGB.argtypes = [c_void_p, c_ushort, c_ubyte, c_ubyte, c_ubyte]
setRGB = libblink1.blink1_setRGB
setRGB.restype = c_int
setRGB.argtypes = [c_void_p, c_ubyte, c_ubyte, c_ubyte]
eeread = libblink1.blink1_eeread
eeread.restype = c_int
eeread.argtypes = [c_void_p, c_ushort, c_void_p]
eewrite = libblink1.blink1_eewrite
eewrite.restype = c_int
eewrite.argtypes = [c_void_p, c_ushort, c_void_p]
serialnumread = libblink1.blink1_serialnumread
serialnumread.restype = c_int
serialnumread.argtypes = [c_void_p, c_void_p]
serialnumwrite = libblink1.blink1_serialnumwrite
serialnumwrite.restype = c_int
serialnumwrite.argtypes = [c_void_p, c_void_p]
serverdown = libblink1.blink1_serverdown
serverdown.restype = c_int
serverdown.argtypes = [c_void_p, c_ubyte, c_ushort]
play = libblink1.blink1_play
play.restype = c_int
play.argtypes = [c_void_p, c_ubyte, c_ubyte]
writePatternLine = libblink1.blink1_writePatternLine
writePatternLine.restype = c_int
writePatternLine.argtypes = [c_void_p, c_ushort, c_ubyte, c_ubyte, c_ubyte, c_ubyte]
readPatternLine = libblink1.blink1_readPatternLine
readPatternLine.restype = c_int
readPatternLine.argtypes = [c_void_p, c_void_p, c_void_p, c_void_p, c_void_p, c_void_p]
error_msg = libblink1.blink1_error_msg
error_msg.restype = c_char_p
error_msg.argtypes = [c_int]
enableDegamma = libblink1.blink1_enableDegamma
disableDegamma = libblink1.blink1_disableDegamma
degamma = libblink1.blink1_degamma
degamma.restype = c_int
degamma.argtypes = [c_int]
sleep = libblink1.blink1_sleep
sleep.argtypes = [c_ushort]

66 changes: 66 additions & 0 deletions python/blink1hid-demo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/usr/bin/python
"""
blink1hid-demo.py -- Low-level HID access with Python
Thanks to Aaron Blondeau for this
As he says:
"I am working on controlling a Blink1 from an Android.
In order to understand how the set feature calls work without wearing out
the usb port on my Android I have created a python script that uses the pyusb library.
The code is as follows if you wish to share and save some time for other folks."
"""

import usb # https://github.com/walac/pyusb
# + "brew install libusb" on osx
# + libusb-win32 (inf method) on windows

#Find the Blink1
dev = usb.core.find(idVendor=0x27b8, idProduct=0x01ed)
assert dev is not None

#The Blink1 takes 8 bytes of input
# 1=report_id (0)
# 2=action (c = fade to rgb, n = set rgb now)
# 3=red
# 4=green
# 5=blue
# 6=th : time/cs high (T >>8) where time 'T' is a number of 10msec ticks
# 7=tl : time/cs low (T & 0xff)
# 8=step (0)

# once a buffer is set with these bytes, we need to do what blink1_write / hid_send_feature_report does
# https://github.com/todbot/blink1/blob/master/commandline/blink1-lib.c
# https://github.com/signal11/hidapi/blob/master/libusb/hid.c

#set color to red
bmRequestTypeOut = usb.util.build_request_type(usb.util.CTRL_OUT, usb.util.CTRL_TYPE_CLASS, usb.util.CTRL_RECIPIENT_INTERFACE)
action = 0x6E # ='n' (set rgb now)
red = 0xFF
green = 0x00
blue = 0x00
dev.ctrl_transfer(bmRequestTypeOut, 0x09, (3 << 8) | 0x01, 0, [0x00, action, red, green, blue, 0x00, 0x00, 0x00, 0x00])

#then fade to blue
action = 0x63 # ='c' (fade to rgb)
red = 0x00
green = 0x00
blue = 0xFF
T = 5000/10 #5 seconds worth of 10msec tics
th = (T & 0xff00) >> 8
tl = T & 0x00ff
dev.ctrl_transfer(bmRequestTypeOut, 0x09, (3 << 8) | 0x01, 0, [0x00, action, red, green, blue, th, tl, 0x00, 0x00])

#get version number
import time
import string
action = 0x76 # ='v' (version)
dev.ctrl_transfer(bmRequestTypeOut, 0x09, (3 << 8) | 0x01, 0, [0x00, action, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
time.sleep(.05)
bmRequestTypeIn = usb.util.build_request_type(usb.util.CTRL_IN, usb.util.CTRL_TYPE_CLASS, usb.util.CTRL_RECIPIENT_INTERFACE)
version_raw = dev.ctrl_transfer(bmRequestTypeIn, 0x01, (3 << 8) | 0x01, 0, 8)
version = ''.join(chr(i) for i in version_raw) # items in the array should correspond to ascii codes for something like "v 100"
version = filter(lambda x: x in string.printable, version)
print version #the c code must tack on an extra 0?

0 comments on commit 4d362c3

Please sign in to comment.