#!/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/ # # TODO: - Why does libusb require sudo/root on Linux? # - Why does libusb-win32 error on Windoze? # import logging from time import sleep from sys import exit 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) ### General USB Device 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: log.info("USB 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("USB 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) ### iBuddy Device Class class iBuddyDevice: USB_VENDOR = 0x1130 USB_PRODUCT = int(0x0001) 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 BLUE = (0,0,1) GREEN = (0,1,0) LTBLUE = (0,1,1) PURPLE = (1,0,1) RED = (1,0,0) WHITE = (1,1,1) YELLOW = (1,1,0) 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: self.__init__() #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) self.setReverseBitValue(2,1) 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): """ reset to default positions/off, run command immediately """ self.resetCmd() self.doCmd(seconds) def doFlap(self, times=3, seconds=0.2): """ flap wings X times with Y seconds pause in between, run command immediately """ for i in range(times): self.setWing(self.UP) self.doCmd(seconds) self.setWing(self.DOWN) self.doCmd(seconds) def doWiggle(self, times=3, seconds=0.2): """ wiggle back and forth X times with Y seconds pauses, run command immediately """ 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=0.3): """ blink heart X times with Y seconds' pause in betwee, run command immediately """ for i in range(times): self.setHeart(self.ON) self.doCmd(seconds) self.setHeart(self.OFF) self.doCmd(seconds) def doColorRGB(self, r, g, b, seconds=WAITTIME): """ set head color by red/green/blue values 0 or 1, run command immediately """ self.setHeadColors(r, g, b) self.doCmd(seconds) def doColorName(self, rgb, seconds=WAITTIME): """ set head color with color name tuples, run command immediately """ self.setHeadColors(*rgb) self.doCmd(seconds) ## 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__': # find iBuddy device log.info("Starting search...") try: buddy = iBuddyDevice() except NoBuddyException, e: log.exception("No iBuddy device found!") exit(1) # demo command macros buddy.doColorName(iBuddyDevice.PURPLE, 0.5) buddy.doColorName(iBuddyDevice.BLUE, 0.5) buddy.doColorName(iBuddyDevice.LTBLUE, 0.5) buddy.doColorName(iBuddyDevice.YELLOW, 0.5) buddy.doColorName(iBuddyDevice.GREEN, 0.5) buddy.doColorName(iBuddyDevice.RED, 0.5) buddy.doColorName(iBuddyDevice.WHITE, 0.5) buddy.doFlap() sleep(1) buddy.doWiggle() sleep(1) buddy.doHeartbeat() sleep(1) buddy.doReset()