reorg, rename, refactor
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,2 +1,3 @@
|
|||||||
.svn/
|
.svn/
|
||||||
*.pyc
|
*.pyc
|
||||||
|
contrib/usbenum.txt
|
||||||
40
contrib/usbenum.py
Normal file
40
contrib/usbenum.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# usbenum.py: enumerate usb devices using pyusb module
|
||||||
|
# from http://wiki.erazor-zone.de/wiki:projects:python:pyusb:setup:examples:usbenum
|
||||||
|
# copyright 2005 Wander Lairson Costa
|
||||||
|
|
||||||
|
import usb
|
||||||
|
|
||||||
|
busses = usb.busses()
|
||||||
|
|
||||||
|
for bus in busses:
|
||||||
|
devices = bus.devices
|
||||||
|
for dev in devices:
|
||||||
|
print "Device:", dev.filename
|
||||||
|
print " Device class:",dev.deviceClass
|
||||||
|
print " Device sub class:",dev.deviceSubClass
|
||||||
|
print " Device protocol:",dev.deviceProtocol
|
||||||
|
print " Max packet size:",dev.maxPacketSize
|
||||||
|
print " idVendor:",dev.idVendor
|
||||||
|
print " idProduct:",dev.idProduct
|
||||||
|
print " Device Version:",dev.deviceVersion
|
||||||
|
for config in dev.configurations:
|
||||||
|
print " Configuration:", config.value
|
||||||
|
print " Total length:", config.totalLength
|
||||||
|
print " selfPowered:", config.selfPowered
|
||||||
|
print " remoteWakeup:", config.remoteWakeup
|
||||||
|
print " maxPower:", config.maxPower
|
||||||
|
for intf in config.interfaces:
|
||||||
|
print " Interface:",intf[0].interfaceNumber
|
||||||
|
for alt in intf:
|
||||||
|
print " Alternate Setting:",alt.alternateSetting
|
||||||
|
print " Interface class:",alt.interfaceClass
|
||||||
|
print " Interface sub class:",alt.interfaceSubClass
|
||||||
|
print " Interface protocol:",alt.interfaceProtocol
|
||||||
|
for ep in alt.endpoints:
|
||||||
|
print " Endpoint:",hex(ep.address)
|
||||||
|
print " Type:",ep.type
|
||||||
|
print " Max packet size:",ep.maxPacketSize
|
||||||
|
print " Interval:",ep.interval
|
||||||
|
|
||||||
204
my_pybuddy.py
204
my_pybuddy.py
@@ -1,204 +0,0 @@
|
|||||||
import usb
|
|
||||||
import time
|
|
||||||
import sys
|
|
||||||
from time import sleep
|
|
||||||
|
|
||||||
## configuration
|
|
||||||
tsleep = 0.5
|
|
||||||
usbvendor = 0x1130
|
|
||||||
usbproduct = 0001
|
|
||||||
|
|
||||||
## iBUDDY class
|
|
||||||
class BuddyDevice:
|
|
||||||
SETUP = (0x22, 0x09, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00)
|
|
||||||
MESS = (0x55, 0x53, 0x42, 0x43, 0x00, 0x40, 0x02)
|
|
||||||
|
|
||||||
LEFT = 0
|
|
||||||
RIGHT = 1
|
|
||||||
|
|
||||||
UP = 0
|
|
||||||
DOWN = 1
|
|
||||||
|
|
||||||
finalMess = 0xFF
|
|
||||||
battery = 0
|
|
||||||
product = 0
|
|
||||||
|
|
||||||
def __init__(self, battery, buddy_product):
|
|
||||||
try:
|
|
||||||
self.dev=UsbDevice(usbvendor, buddy_product, battery)
|
|
||||||
self.dev.open()
|
|
||||||
self.dev.handle.reset()
|
|
||||||
self.resetMessage()
|
|
||||||
self.pumpMessage()
|
|
||||||
self.battery=battery
|
|
||||||
self.product=buddy_product
|
|
||||||
except NoBuddyException, e:
|
|
||||||
raise NoBuddyException()
|
|
||||||
|
|
||||||
# commands are sent as disabled bits
|
|
||||||
def setReverseBitValue(self,num,value):
|
|
||||||
if (value==1):
|
|
||||||
temp = 0xFF - (1<<num)
|
|
||||||
self.finalMess = self.finalMess & temp
|
|
||||||
elif (value==0):
|
|
||||||
temp = 1 << num
|
|
||||||
self.finalMess = self.finalMess | temp
|
|
||||||
|
|
||||||
def getReverseBitValue(self,num):
|
|
||||||
temp = self.finalMess
|
|
||||||
temp = temp >> num
|
|
||||||
res = not(temp&1)
|
|
||||||
return res
|
|
||||||
|
|
||||||
def setHeadColor(self, red, green, blue):
|
|
||||||
self.setReverseBitValue(4,red)
|
|
||||||
self.setReverseBitValue(5,green)
|
|
||||||
self.setReverseBitValue(6,blue)
|
|
||||||
|
|
||||||
def setHeart(self, status):
|
|
||||||
self.setReverseBitValue(7,status)
|
|
||||||
|
|
||||||
def pumpMessage(self):
|
|
||||||
self.send(self.finalMess)
|
|
||||||
|
|
||||||
def resetMessage(self):
|
|
||||||
self.finalMess = 0xFF
|
|
||||||
|
|
||||||
def flick(self, direction):
|
|
||||||
if (direction == self.RIGHT):
|
|
||||||
self.setReverseBitValue(1,1)
|
|
||||||
self.setReverseBitValue(0,0)
|
|
||||||
elif(direction == self.LEFT):
|
|
||||||
self.setReverseBitValue(1,0)
|
|
||||||
self.setReverseBitValue(0,1)
|
|
||||||
|
|
||||||
def wing(self, direction):
|
|
||||||
if (direction == self.UP):
|
|
||||||
self.setReverseBitValue(3,1)
|
|
||||||
self.setReverseBitValue(2,0)
|
|
||||||
elif(direction == self.DOWN):
|
|
||||||
self.setReverseBitValue(3,0)
|
|
||||||
self.setReverseBitValue(2,1)
|
|
||||||
|
|
||||||
def getColors (self):
|
|
||||||
return self.getReverseBitValue(4), self.getReverseBitValue(5), self.getReverseBitValue(6)
|
|
||||||
|
|
||||||
def getHeart(self):
|
|
||||||
return self.getReverseBitValue(7)
|
|
||||||
|
|
||||||
def getWing(self):
|
|
||||||
return self.getReverseBitValue(2)
|
|
||||||
|
|
||||||
def getDirection(self):
|
|
||||||
return self.getReverseBitValue(1)
|
|
||||||
|
|
||||||
def send(self, inp):
|
|
||||||
try:
|
|
||||||
self.dev.handle.controlMsg(0x21, 0x09, self.SETUP, 0x02, 0x01)
|
|
||||||
self.dev.handle.controlMsg(0x21, 0x09, self.MESS+(inp,), 0x02, 0x01)
|
|
||||||
except usb.USBError:
|
|
||||||
print "USB error!"
|
|
||||||
self.__init__(self.battery,buddy_product)
|
|
||||||
|
|
||||||
#self.dev.handle.controlMsg(0x21, 0x09, self.SETUP, 0x02, 0x01)
|
|
||||||
#self.dev.handle.controlMsg(0x22, 0x09, self.SETUP, 0x02, 0x01)
|
|
||||||
#self.dev.handle.controlMsg(0x21, 0x09, self.MESS+(inp,), 0x02, 0x01)
|
|
||||||
|
|
||||||
## USB class
|
|
||||||
class UsbDevice:
|
|
||||||
def __init__(self, vendor_id, product_id, skip):
|
|
||||||
busses = usb.busses()
|
|
||||||
self.handle = None
|
|
||||||
count = 0
|
|
||||||
for bus in busses:
|
|
||||||
devices = bus.devices
|
|
||||||
for dev in devices:
|
|
||||||
|
|
||||||
if dev.idVendor==vendor_id and dev.idProduct==product_id:
|
|
||||||
if count==skip:
|
|
||||||
print "iBuddy found! (vend: %s, prod: %s)" % (dev.idVendor, dev.idProduct)
|
|
||||||
self.dev = dev
|
|
||||||
|
|
||||||
self.conf = self.dev.configurations[0]
|
|
||||||
self.intf = self.conf.interfaces[0][0]
|
|
||||||
self.endpoints = []
|
|
||||||
for endpoint in self.intf.endpoints:
|
|
||||||
self.endpoints.append(endpoint)
|
|
||||||
print "(found endpoint)"
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
count=count+1
|
|
||||||
raise NoBuddyException()
|
|
||||||
|
|
||||||
def open(self):
|
|
||||||
if self.handle:
|
|
||||||
self.handle = None
|
|
||||||
self.handle = self.dev.open()
|
|
||||||
# we need to detach HID interface
|
|
||||||
try:
|
|
||||||
self.handle.detachKernelDriver(0)
|
|
||||||
self.handle.detachKernelDriver(1)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
self.handle.setConfiguration(self.conf)
|
|
||||||
self.handle.claimInterface(self.intf)
|
|
||||||
self.handle.setAltInterface(self.intf)
|
|
||||||
|
|
||||||
class NoBuddyException(Exception): pass
|
|
||||||
|
|
||||||
#######################################
|
|
||||||
# MAIN program
|
|
||||||
#######################################
|
|
||||||
|
|
||||||
# initialize device
|
|
||||||
print "Starting search..."
|
|
||||||
try:
|
|
||||||
buddy=BuddyDevice(0, int(usbproduct))
|
|
||||||
except NoBuddyException, e:
|
|
||||||
print "No iBuddy device found!"
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
buddy.resetMessage()
|
|
||||||
buddy.pumpMessage()
|
|
||||||
sleep(0.5)
|
|
||||||
buddy.setHeadColor(1,0,0)
|
|
||||||
buddy.pumpMessage()
|
|
||||||
sleep(0.5)
|
|
||||||
buddy.setHeadColor(0,1,0)
|
|
||||||
buddy.pumpMessage()
|
|
||||||
sleep(0.5)
|
|
||||||
buddy.setHeadColor(0,0,1)
|
|
||||||
buddy.pumpMessage()
|
|
||||||
sleep(0.5)
|
|
||||||
buddy.flick(BuddyDevice.LEFT)
|
|
||||||
buddy.pumpMessage()
|
|
||||||
sleep(0.5)
|
|
||||||
buddy.flick(BuddyDevice.RIGHT)
|
|
||||||
buddy.pumpMessage()
|
|
||||||
sleep(0.5)
|
|
||||||
buddy.flick(BuddyDevice.LEFT)
|
|
||||||
buddy.pumpMessage()
|
|
||||||
sleep(0.5)
|
|
||||||
buddy.flick(BuddyDevice.RIGHT)
|
|
||||||
buddy.pumpMessage()
|
|
||||||
sleep(0.1)
|
|
||||||
buddy.wing(BuddyDevice.UP)
|
|
||||||
buddy.pumpMessage()
|
|
||||||
sleep(0.1)
|
|
||||||
buddy.wing(BuddyDevice.DOWN)
|
|
||||||
buddy.pumpMessage()
|
|
||||||
sleep(0.1)
|
|
||||||
buddy.wing(BuddyDevice.UP)
|
|
||||||
buddy.pumpMessage()
|
|
||||||
sleep(0.1)
|
|
||||||
buddy.wing(BuddyDevice.DOWN)
|
|
||||||
buddy.pumpMessage()
|
|
||||||
sleep(0.1)
|
|
||||||
buddy.wing(BuddyDevice.UP)
|
|
||||||
buddy.pumpMessage()
|
|
||||||
sleep(0.1)
|
|
||||||
buddy.wing(BuddyDevice.DOWN)
|
|
||||||
buddy.pumpMessage()
|
|
||||||
buddy.setHeadColor(0,0,0)
|
|
||||||
buddy.pumpMessage()
|
|
||||||
246
pybuddylib.py
Normal file
246
pybuddylib.py
Normal file
@@ -0,0 +1,246 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# pybuddylib.py: simple library to control iBuddy USB device
|
||||||
|
# by ewall <e@ewall.org>, Sept 2010
|
||||||
|
#
|
||||||
|
# borrows code from http://code.google.com/p/pybuddy
|
||||||
|
# by Jose.Carlos.Luna@gmail.com and luis.peralta@gmail.com
|
||||||
|
# who got most of the code from http://cuntography.com/blog/?p=17
|
||||||
|
# which is based on http://scott.weston.id.au/software/pymissile/
|
||||||
|
|
||||||
|
import logging
|
||||||
|
from time import sleep
|
||||||
|
import usb
|
||||||
|
|
||||||
|
### Global Configuration
|
||||||
|
DEBUG = True
|
||||||
|
|
||||||
|
### Prepare Logging
|
||||||
|
log = logging.getLogger("pybuddy")
|
||||||
|
log.setLevel(logging.DEBUG)
|
||||||
|
console_handler = logging.StreamHandler()
|
||||||
|
if DEBUG:
|
||||||
|
console_handler.setLevel(logging.DEBUG)
|
||||||
|
else:
|
||||||
|
console_handler.setLevel(logging.ERROR)
|
||||||
|
log.addHandler(console_handler)
|
||||||
|
|
||||||
|
### iBuddy Device Class
|
||||||
|
class iBuddyDevice:
|
||||||
|
USB_VENDOR = 0x1130
|
||||||
|
USB_PRODUCT = int(0001)
|
||||||
|
BATTERY = 0
|
||||||
|
SETUP = (0x22, 0x09, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00)
|
||||||
|
MESS = (0x55, 0x53, 0x42, 0x43, 0x00, 0x40, 0x02)
|
||||||
|
|
||||||
|
WAITTIME = 0.1
|
||||||
|
|
||||||
|
LEFT = 0
|
||||||
|
RIGHT = 1
|
||||||
|
UP = 0
|
||||||
|
DOWN = 1
|
||||||
|
OFF = 0
|
||||||
|
ON = 1
|
||||||
|
|
||||||
|
CLEAR = 0xFF
|
||||||
|
command = CLEAR
|
||||||
|
|
||||||
|
# the following items deal with setup and control
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
try:
|
||||||
|
self.dev=UsbDevice(self.USB_VENDOR, self.USB_PRODUCT, self.BATTERY)
|
||||||
|
self.dev.open()
|
||||||
|
self.dev.handle.reset()
|
||||||
|
self.resetCmd()
|
||||||
|
self.doCmd()
|
||||||
|
except NoBuddyException, e:
|
||||||
|
raise NoBuddyException()
|
||||||
|
|
||||||
|
def __send(self, inp):
|
||||||
|
""" send your command to the device """
|
||||||
|
try:
|
||||||
|
self.dev.handle.controlMsg(0x21, 0x09, self.SETUP, 0x02, 0x01)
|
||||||
|
self.dev.handle.controlMsg(0x21, 0x09, self.MESS+(inp,), 0x02, 0x01)
|
||||||
|
except usb.USBError:
|
||||||
|
if DEBUG:
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
self.__init__()
|
||||||
|
|
||||||
|
def doCmd(self, seconds=WAITTIME):
|
||||||
|
""" send the command specified by the current command """
|
||||||
|
self.__send(self.command)
|
||||||
|
sleep(seconds)
|
||||||
|
|
||||||
|
# the following items operate on the command to be sent next
|
||||||
|
|
||||||
|
def resetCmd(self):
|
||||||
|
""" reset command to default (must pump to take effect) """
|
||||||
|
self.command = self.CLEAR
|
||||||
|
|
||||||
|
def setReverseBitValue(self,num,value):
|
||||||
|
""" commands are sent as disabled bits """
|
||||||
|
if (value==1):
|
||||||
|
temp = 0xFF - (1<<num)
|
||||||
|
self.command = self.command & temp
|
||||||
|
elif (value==0):
|
||||||
|
temp = 1 << num
|
||||||
|
self.command = self.command | temp
|
||||||
|
|
||||||
|
def getReverseBitValue(self,num):
|
||||||
|
""" what was that bit set to again? """
|
||||||
|
temp = self.command
|
||||||
|
temp = temp >> num
|
||||||
|
res = not(temp&1)
|
||||||
|
return res
|
||||||
|
|
||||||
|
def setHeadColors(self, red, green, blue):
|
||||||
|
""" colors as (red, green, blue) can be on (1) or off (0) """
|
||||||
|
self.setReverseBitValue(4,red)
|
||||||
|
self.setReverseBitValue(5,green)
|
||||||
|
self.setReverseBitValue(6,blue)
|
||||||
|
self.setReverseBitValue(2,1)
|
||||||
|
|
||||||
|
def getHeadColors (self):
|
||||||
|
""" returns color status as tuple representing (red, green, blue) as on (1) or off (0) """
|
||||||
|
return self.getReverseBitValue(4), self.getReverseBitValue(5), self.getReverseBitValue(6)
|
||||||
|
|
||||||
|
def setHeart(self, status):
|
||||||
|
""" heart-light can be on (1) or off (0) """
|
||||||
|
self.setReverseBitValue(7,status)
|
||||||
|
|
||||||
|
def getHeart(self):
|
||||||
|
""" returns heart-light status of on (1) or off (0) """
|
||||||
|
return self.getReverseBitValue(7)
|
||||||
|
|
||||||
|
def setWing(self, direction):
|
||||||
|
""" move the wings iBuddyDevice.UP (0) or iBuddyDevice.DOWN (1) """
|
||||||
|
if (direction == self.UP):
|
||||||
|
self.setReverseBitValue(3,1)
|
||||||
|
self.setReverseBitValue(2,0)
|
||||||
|
elif(direction == self.DOWN):
|
||||||
|
self.setReverseBitValue(3,0)
|
||||||
|
|
||||||
|
def getWing(self):
|
||||||
|
""" returns wing status of iBuddyDevice.UP (0) or iBuddyDevice.DOWN (1) """
|
||||||
|
return self.getReverseBitValue(2)
|
||||||
|
|
||||||
|
def setSwivel(self, direction):
|
||||||
|
""" swivel the body iBuddyDevice.LEFT (0) or iBuddyDevice.RIGHT (1) """
|
||||||
|
if (direction == self.RIGHT):
|
||||||
|
self.setReverseBitValue(1,1)
|
||||||
|
self.setReverseBitValue(0,0)
|
||||||
|
elif(direction == self.LEFT):
|
||||||
|
self.setReverseBitValue(1,0)
|
||||||
|
self.setReverseBitValue(0,1)
|
||||||
|
|
||||||
|
def getSwivel(self):
|
||||||
|
""" returns current swivel direction as iBuddyDevice.LEFT (0) or iBuddyDevice.RIGHT (1) """
|
||||||
|
return self.getReverseBitValue(1)
|
||||||
|
|
||||||
|
# the following items are macros for specific behaviors
|
||||||
|
|
||||||
|
def doReset(self, seconds=WAITTIME):
|
||||||
|
self.resetCmd()
|
||||||
|
self.doCmd(seconds)
|
||||||
|
|
||||||
|
def doFlap(self, times=3, seconds=WAITTIME):
|
||||||
|
for i in range(times):
|
||||||
|
self.setWing(self.UP)
|
||||||
|
self.doCmd(seconds)
|
||||||
|
self.setWing(self.DOWN)
|
||||||
|
self.doCmd(seconds)
|
||||||
|
|
||||||
|
def doWiggle(self, times=2, seconds=WAITTIME):
|
||||||
|
for i in range(times):
|
||||||
|
self.setSwivel(self.LEFT)
|
||||||
|
self.doCmd(seconds)
|
||||||
|
self.setSwivel(self.RIGHT)
|
||||||
|
self.doCmd(seconds)
|
||||||
|
|
||||||
|
def doHeartbeat(self, times=3, seconds=WAITTIME):
|
||||||
|
for i in range(times):
|
||||||
|
self.setHeart(self.ON)
|
||||||
|
self.doCmd(seconds)
|
||||||
|
self.setHeart(self.OFF)
|
||||||
|
self.doCmd(seconds)
|
||||||
|
|
||||||
|
# TODO: macros for specific colors
|
||||||
|
|
||||||
|
|
||||||
|
### General USB Device Class
|
||||||
|
class UsbDevice:
|
||||||
|
# TODO: improve on this device search
|
||||||
|
def __init__(self, vendor_id, product_id, skip):
|
||||||
|
busses = usb.busses()
|
||||||
|
self.handle = None
|
||||||
|
count = 0
|
||||||
|
for bus in busses:
|
||||||
|
devices = bus.devices
|
||||||
|
for dev in devices:
|
||||||
|
|
||||||
|
if dev.idVendor==vendor_id and dev.idProduct==product_id:
|
||||||
|
if count==skip:
|
||||||
|
log.info("iBuddy device found (vend: %s, prod: %s)." % (dev.idVendor, dev.idProduct))
|
||||||
|
self.dev = dev
|
||||||
|
|
||||||
|
self.conf = self.dev.configurations[0]
|
||||||
|
self.intf = self.conf.interfaces[0][0]
|
||||||
|
self.endpoints = []
|
||||||
|
for endpoint in self.intf.endpoints:
|
||||||
|
self.endpoints.append(endpoint)
|
||||||
|
log.info("Endpoint found.")
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
count=count+1
|
||||||
|
raise NoBuddyException()
|
||||||
|
|
||||||
|
def open(self):
|
||||||
|
# TODO: should the HID driver detachment be optional?
|
||||||
|
self.handle = self.dev.open()
|
||||||
|
|
||||||
|
# we need to detach HID interface
|
||||||
|
try:
|
||||||
|
self.handle.detachKernelDriver(0)
|
||||||
|
self.handle.detachKernelDriver(1)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
self.handle.setConfiguration(self.conf)
|
||||||
|
self.handle.claimInterface(self.intf)
|
||||||
|
self.handle.setAltInterface(self.intf)
|
||||||
|
|
||||||
|
## Custom Exceptions
|
||||||
|
class NoBuddyException(usb.USBError):
|
||||||
|
""" indicates errors communicating with iBuddy USB device """
|
||||||
|
#def __init__(self, *args):
|
||||||
|
# Exception._ _init_ _(self, *args)
|
||||||
|
# self.wrapped_exc = sys.exc_info()
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
### Main Program
|
||||||
|
if __name__ == '__main__':
|
||||||
|
|
||||||
|
log.info("Starting search...")
|
||||||
|
try:
|
||||||
|
buddy = iBuddyDevice()
|
||||||
|
except NoBuddyException, e:
|
||||||
|
log.exception("No iBuddy device found!")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# sample commands and macros
|
||||||
|
buddy.setHeadColors(1,0,0)
|
||||||
|
buddy.doCmd(1)
|
||||||
|
buddy.setHeadColors(0,1,0)
|
||||||
|
buddy.doCmd(1)
|
||||||
|
buddy.setHeadColors(0,0,1)
|
||||||
|
buddy.doCmd(1)
|
||||||
|
buddy.doFlap()
|
||||||
|
sleep(1)
|
||||||
|
buddy.doWiggle()
|
||||||
|
sleep(1)
|
||||||
|
buddy.doHeartbeat()
|
||||||
|
sleep(1)
|
||||||
|
buddy.doReset()
|
||||||
Reference in New Issue
Block a user