From c8209d01f9ddf4c6670caee08073924cb33e447f Mon Sep 17 00:00:00 2001 From: rcoh Date: Wed, 29 Dec 2010 12:43:05 -0500 Subject: setting up some more behaviors to get inherited from --- LightInstallation.py | 49 +++++++++++++++++++++++++++++---------- behaviors/BehaviorChain.py | 8 ++++--- behaviors/DebugBehavior.py | 3 ++- config/Outdoor.xml | 46 ++---------------------------------- inputs/MouseFollower.xml | 8 +++++++ inputs/TCPInput.py | 5 ++-- operationscore/Input.py | 7 +++++- operationscore/SmootCoreObject.py | 2 +- pixelevents/DecayEvent.py | 2 +- renderers/SixStripUDPPygame.xml | 27 +++++++++++++++++++++ util/ColorOps.py | 8 +++++++ util/Config.py | 29 ++++++++++++++++++----- util/NetworkOps.py | 6 +++-- 13 files changed, 127 insertions(+), 73 deletions(-) create mode 100644 inputs/MouseFollower.xml create mode 100644 renderers/SixStripUDPPygame.xml diff --git a/LightInstallation.py b/LightInstallation.py index 07fa8fc..8b2d059 100644 --- a/LightInstallation.py +++ b/LightInstallation.py @@ -11,8 +11,7 @@ from logger import main_log #and effects. class LightInstallation: def __init__(self, configFileName): - main_log.critical("hi russell, i'm sending info to the log files") - main_log.critical("initializing based on file: " + str(configFileName)) + main_log.info("System Initialization began based on: " + str(configFileName)) self.timer = clock.Stopwatch() self.timer.start() self.inputs = {} #dict of inputs and their bound behaviors, keyed by InputId @@ -41,6 +40,7 @@ class LightInstallation: self.initializeInputs(inputConfig) self.initializeBehaviors(behaviorConfig) self.initializeMapper(mapperConfig) + main_log.info('All components initialized') #registration in dict self.registerComponents(self.renderers) self.registerComponents(self.inputs) @@ -49,7 +49,7 @@ class LightInstallation: self.configureInstallation(installationConfig) #Done initializing. Lets start this thing! self.timer.stop() - print 'Initialization done. Time: ', self.timer.elapsed(), 'ms' + #main_log.info('Initialization done. Time: ', self.timer.elapsed(), 'ms') self.mainLoop() def configureInstallation(self, installationConfig): defaults = configGetter.generateArgDict(installationConfig.find('Defaults')) @@ -57,6 +57,8 @@ class LightInstallation: componentToMap = compReg.getComponent(defaults[defaultSelection]) compReg.registerComponent(compReg.getComponent(defaults[defaultSelection]),\ 'Default'+defaultSelection) + main_log.debug('Default Set: ' + defaultSelection + 'set to ' +\ + defaults[defaultSelection]) def initializeMapper(self, mapperConfig): self.mappers = self.initializeComponent(mapperConfig) @@ -78,21 +80,43 @@ class LightInstallation: def registerComponents(self, components): for component in components: cid = component['Id'] - if cid == None: - raise Exception('Components must have Ids!') - compReg.registerComponent(component) + if cid == None: #TODO: determine if componenent is critical, and if so, die + main_log.error('Components must be registered with Ids. Component not registered') + else: + compReg.registerComponent(component) + main_log.debug(cid + ' registered') def initializeComponent(self, config): components = [] if config != None: config = configGetter.resolveConfigInheritance(config) for configItem in config.getchildren(): - [module,className] = configItem.find('Class').text.split('.') - exec('from ' + module+'.'+className + ' import *') + configItem = configGetter.resolveConfigInheritance(configItem) #resolve + #inheritences. TODO: migrate to a recursive inheritence resolver that gets run on + #file-parse + try: + [module,className] = configItem.find('Class').text.split('.') + except: + main_log.error('Module must have Class element') + main_log.warn('Module without class element. Module not initialized') + continue + try: + exec('from ' + module+'.'+className + ' import *') + main_log.debug(module +'.' +className + 'imported') + except: + main_log.error('Error importing ' + module+'.'+'.className. Component not\ + initialized.') + continue #TODO: verify functions as expected args = configGetter.generateArgDict(configItem.find('Args')) args['parentScope'] = self #TODO: we shouldn't give away scope #like this, find another way. - components.append(eval(className+'(args)')) #TODO: doesn't error + try: + components.append(eval(className+'(args)')) #TODO: doesn't error + main_log.debug(className + 'initialized with args ' + str(args)) #right + except Exception as inst: + main_log.error('Failure while initializing ' + className + ' with ' + str(args)) + #main_log.error(inst) TODO: exception logging + return components def alive(self): return True @@ -149,11 +173,12 @@ class LightInstallation: pass #print 'Behaviors not initialized yet. WAIT!' def main(argv): - print argv if len(argv) == 1: l = LightInstallation('LightInstallationConfig.xml') else: l = LightInstallation(argv[1]) if __name__ == "__main__": - main(sys.argv) - + try: + main(sys.argv) + except KeyboardInterrupt: + main_log.info('Terminated by keyboard.') diff --git a/behaviors/BehaviorChain.py b/behaviors/BehaviorChain.py index 98585c9..ce161f9 100644 --- a/behaviors/BehaviorChain.py +++ b/behaviors/BehaviorChain.py @@ -1,5 +1,6 @@ from operationscore.Behavior import * import util.ComponentRegistry as compReg +import logging as main_log import pdb class BehaviorChain(Behavior): def behaviorInit(self): @@ -20,11 +21,12 @@ class BehaviorChain(Behavior): if behaviorId in self.hooks: #process recursive hook if there is one hookBehavior = compReg.getComponent(self.hooks[behaviorId]) -#we feed its recurrence in as input to the behavior. + #we feed its recurrence in as input to the behavior. (recurrence, hookRecurrence) = \ hookBehavior.immediateProcessInput(recurrence, \ []) if hookRecurrence != []: - print 'Hook recurrences are not currently supported. Implement it yourself or bug russell' - self.feedback[behaviorId] = recurrence + main_log.warn('Hook recurrences are not currently supported. Implement it\ + yourself or bug russell') + self.feedback[behaviorId] = recurrence return response diff --git a/behaviors/DebugBehavior.py b/behaviors/DebugBehavior.py index a00346b..2f8db80 100644 --- a/behaviors/DebugBehavior.py +++ b/behaviors/DebugBehavior.py @@ -1,7 +1,8 @@ from operationscore.Behavior import * +from logger import main_log import pdb class DebugBehavior(Behavior): def processResponse(self, sensorInputs, recursiveInputs): if sensorInputs != []: - print 'Sensor Inputs: ', sensorInputs + main_log.debug('Sensor Inputs: ', sensorInputs) return [] diff --git a/config/Outdoor.xml b/config/Outdoor.xml index b34e18a..8ba7962 100644 --- a/config/Outdoor.xml +++ b/config/Outdoor.xml @@ -26,31 +26,7 @@ - - renderers.PygameRenderer - - pygamerender - (1300,50) - - - - renderers.IndoorRenderer - - indoorRenderer - - 10.31.255.233 - {'strip1':1, 'strip2':2} - - - 10.32.97.17 - {'strip3':1, 'strip4':2} - - - 10.32.96.211 - {'strip5':1, 'strip6':2} - - - + renderers/SixStripUDPPygame.xml @@ -61,20 +37,7 @@ - inputs.PygameInput - - followmouse - 50 - True - - - - inputs.UDPInput - - UDP - 6038 - 100 - + inputs/MouseFollower.xml @@ -84,8 +47,6 @@ echo 0 False - - @@ -110,8 +71,6 @@ .01 0 False - - @@ -183,7 +142,6 @@ echo pixelsleft - colorchange decay True diff --git a/inputs/MouseFollower.xml b/inputs/MouseFollower.xml new file mode 100644 index 0000000..7d7963d --- /dev/null +++ b/inputs/MouseFollower.xml @@ -0,0 +1,8 @@ + + inputs.PygameInput + + followmouse + 50 + True + + diff --git a/inputs/TCPInput.py b/inputs/TCPInput.py index 1517afa..197045f 100644 --- a/inputs/TCPInput.py +++ b/inputs/TCPInput.py @@ -1,6 +1,7 @@ import util.Strings as Strings from operationscore.Input import * import socket, json, time +import logging as main_log class TCPInput(Input): def inputInit(self): self.HOST = '' # Symbolic name meaning all available interfaces @@ -16,9 +17,9 @@ class TCPInput(Input): def sensingLoop(self): data = self.conn.recv(self.BUFFER_SIZE) - print data + main_log.debug('Incoming data', data) if not data or 'end' in data: # data end, close socket - print 'END!!' + main_log.debug('End in data') self.IS_RESPONDING = 0 self.sock.close() diff --git a/operationscore/Input.py b/operationscore/Input.py index 62c4682..9e8841a 100644 --- a/operationscore/Input.py +++ b/operationscore/Input.py @@ -1,5 +1,6 @@ import threading,time from operationscore.SmootCoreObject import * +from logger import main_log, exception_log #Abstract class for inputs. Inheriting classes should call "respond" to raise #their event. Inheriting classes MUST define sensingLoop. Called at the #interval specified in RefreshInterval while the input is active. For example, if you are writing @@ -33,7 +34,11 @@ class Input(SmootCoreObject): except: return False def run(self): - while self.parentAlive(): + while 1: + try: + die = self.parentAlive() + except: + break time.sleep(self.argDict['RefreshInterval']/float(1000)) self.acquireLock() self.sensingLoop() diff --git a/operationscore/SmootCoreObject.py b/operationscore/SmootCoreObject.py index 9784aab..26b3fc2 100644 --- a/operationscore/SmootCoreObject.py +++ b/operationscore/SmootCoreObject.py @@ -19,7 +19,7 @@ class SmootCoreObject(threading.Thread): def releaseLock(self): self.lock.release() def className(self): - return str(self.__class__).split('.')[-1] #TODO: this doesn't work. + return self.__class__.__name__ def __setitem__(self,k, item): self.argDict[k] = item def __getitem__(self, item): diff --git a/pixelevents/DecayEvent.py b/pixelevents/DecayEvent.py index 0b4c820..7c1504a 100644 --- a/pixelevents/DecayEvent.py +++ b/pixelevents/DecayEvent.py @@ -4,7 +4,7 @@ from util.ColorOps import * class DecayEvent(PixelEvent): def initEvent(self): self['Coefficient'] = abs(self['Coefficient']) - def state(self,timeDelay): + def state(self,timeDelay): #TODO: make this fast. if self['DecayType'] == 'Exponential': decay = math.exp(timeDelay*-1*self['Coefficient']) if self['DecayType'] == 'Proportional': diff --git a/renderers/SixStripUDPPygame.xml b/renderers/SixStripUDPPygame.xml new file mode 100644 index 0000000..9a5dfa8 --- /dev/null +++ b/renderers/SixStripUDPPygame.xml @@ -0,0 +1,27 @@ + + + renderers.IndoorRenderer + + indoorRenderer + + 10.31.255.233 + {'strip1':1, 'strip2':2} + + + 10.32.97.17 + {'strip3':1, 'strip4':2} + + + 10.32.96.211 + {'strip5':1, 'strip6':2} + + + + + renderers.PygameRenderer + + pygamerender + (1300,50) + + + diff --git a/util/ColorOps.py b/util/ColorOps.py index b0d64a7..88a58a7 100644 --- a/util/ColorOps.py +++ b/util/ColorOps.py @@ -7,5 +7,13 @@ def safeColor(c): return [min(channel,255) for channel in c] def combineColors(c1,c2): return safeColor([c1[i]+c2[i] for i in range(min(len(c1),len(c2)))]) +def fastMultiply(color, percent, acc=100): + percent = int(percent*acc) + color = colorToInt(color) + color = [channel*percent for channel in color] + +def colorToInt(color): + return [int(channel) for channel in color] def multiplyColor(color, percent): + return safeColor([channel*(percent) for channel in color]) diff --git a/util/Config.py b/util/Config.py index 33e6fee..040e9b0 100644 --- a/util/Config.py +++ b/util/Config.py @@ -1,7 +1,9 @@ from xml.etree.ElementTree import * +import sys import xml import pdb import util.Strings as Strings +from logger import main_log, exception_log classArgsMem = {} CONFIG_PATH = 'config/' def loadParamRequirementDict(className): @@ -10,8 +12,7 @@ def loadParamRequirementDict(className): return classArgsMem[className] #Loads a config file. If its an xml file, inheritances are automatically resolved. def loadConfigFile(fileName): #TODO: error handling etc. - #try: - #fileName = CONFIG_PATH + fileName + try: if '.params' in fileName: return fileToDict(fileName) if '.xml' in fileName: @@ -19,7 +20,8 @@ def loadConfigFile(fileName): #TODO: error handling etc. config.parse(fileName) config = ElementTree(resolveConfigInheritance(config.getroot())) return config - #except: + except Exception as inst: + main_log.error('Error loading config file ' + fileName)#, inst) TODO: log exception too return None #Takes an Element or an ElementTree. If it is a tree, it returns its root. Otherwise, just returns #it @@ -31,6 +33,10 @@ def getElement(el): def compositeXMLTrees(parentTree, overridingTree): #TODO: break up into sub-methods, change it to #use .find() #type checking -- convert ElementTrees to their root elements + if parentTree == None: + return overridingTree + if overridingTree == None: + return parentTree parentTree = getElement(parentTree) overridingTree = getElement(overridingTree) parentItems = parentTree.getchildren() @@ -44,13 +50,14 @@ def compositeXMLTrees(parentTree, overridingTree): #TODO: break up into sub-meth #do we merge or replace? intersectingElements = findElementsByTag(item.tag, overrideItems) if len(intersectingElements) > 1: - print 'ABUSE!' + main_log.warn('ABUSE! Override of multiple items isn\'t well defined. Don\'t do\ + it!') interEl = intersectingElements[0] mode = 'Replace' if Strings.OVERRIDE_BEHAVIOR in interEl.attrib: mode = interEl.attrib[Strings.OVERRIDE_BEHAVIOR] if mode != 'Replace' and mode != 'Merge': - print 'Bad Mode. Choosing to replace.' + main_log.warn('Bad Override Mode. Choosing to replace.') mode = 'Replace' if mode == 'Replace': pass #we don't need to do anything @@ -68,14 +75,20 @@ def findElementsByTag(tag, eList): def fileToDict(fileName): fileText = '' try: - print 'File Read' with open(fileName) as f: for line in f: fileText += line.rstrip('\n').lstrip('\t') + ' ' except IOError: + exception_log.exception('Failure reading ' + fileName) return {} if fileText == '': return {} + try: + resultDict = eval(fileText) + main_log.info(fileName + ' read and parsed') + return resultDict + except: + exception_log.info(fileName + ' is not a well formed python dict. Parsing failed') return eval(fileText) #parses arguments into python objects if possible, otherwise leaves as strings def generateArgDict(parentNode, recurse=False): @@ -105,6 +118,10 @@ def resolveConfigInheritance(el): parentClass = el.find('InheritsFrom') if parentClass != None: parentTree = loadConfigFile(parentClass.text) + if parentTree == None: + main_log.warn('Inheritance Failed. ' + parentClass.text + 'does not exist') + main_log.error('Inheritance Failed. ' + parentClass.text + 'does not exist') + return el el = compositeXMLTrees(el, parentTree) el.remove(parentClass) #get rid of the inheritance flag return el diff --git a/util/NetworkOps.py b/util/NetworkOps.py index 0404975..2fa531e 100644 --- a/util/NetworkOps.py +++ b/util/NetworkOps.py @@ -1,8 +1,10 @@ import socket +from logger import main_log, exception_log def getConnectedSocket(ip,port): sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: sock.connect((ip, port)) - except: - print 'network down' + except Exception as inst: + main_log.error('Network down. All network based renderers and sensors will not function.', + inst) return sock -- cgit v1.2.3