#!/usr/bin/env python # # pybuddylib.py: simple library to control iBuddy USB device # by ewall , 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 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()