diff options
34 files changed, 360 insertions, 173 deletions
diff --git a/LightInstallation.py b/LightInstallation.py index 168983b..db7b808 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,40 @@ 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 *') - args = configGetter.generateArgDict(configItem.find('Args')) + 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 Exception as inst: + pdb.set_trace() + main_log.error('Error importing ' + module+'.'+'.className. Component not\ + initialized.') + continue #TODO: verify functions as expected + args = configGetter.pullArgsFromItem(configItem) 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 @@ -100,7 +121,7 @@ class LightInstallation: #self.screen.allOn() lastLoopTime = clock.time() refreshInterval = 30 - runCount = 150 + runCount = 3000 while runCount > 0: runCount -= 1 loopStart = clock.time() @@ -149,11 +170,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/ResponseMover.py b/ResponseMover.py new file mode 100644 index 0000000..718400d --- /dev/null +++ b/ResponseMover.py @@ -0,0 +1,15 @@ +from operationscore.Behavior import * +import util.ComponentRegistry as compReg +#ResponseMover is a scaffold for behaviors that spawn 'walkers' which act autonomously on input. +#Add a recursive hook to control the movement. +class ResponseMover(Behavior): + def processResponse(self, sensorInputs, recursiveInputs): + newResponses = sensorInputs + ret = [] + ret += newResponses + for recurInput in recursiveInputs: + outDict = dict(recurInput) + ret.append(outDict) + ret += newResponses + return (ret, ret) + diff --git a/behaviors/Accelerate.xml b/behaviors/Accelerate.xml new file mode 100644 index 0000000..2a3d7ac --- /dev/null +++ b/behaviors/Accelerate.xml @@ -0,0 +1,8 @@ +<Behavior> + <Class>behaviors.ModifyParam</Class> + <Args> + <ParamType>Sensor</ParamType> + <ParamName>StepSize</ParamName> + <ParamOp>{val}*1.05</ParamOp> + </Args> +</Behavior> 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/behaviors/LoopAndDie.xml b/behaviors/LoopAndDie.xml new file mode 100644 index 0000000..af26562 --- /dev/null +++ b/behaviors/LoopAndDie.xml @@ -0,0 +1,6 @@ +<Behavior> + <Class>behaviors.RecursiveDecay</Class> + <Args> + <InitialResponseCount>70</InitialResponseCount> + </Args> +</Behavior> diff --git a/behaviors/PixelDecay.xml b/behaviors/PixelDecay.xml new file mode 100644 index 0000000..f9eee0d --- /dev/null +++ b/behaviors/PixelDecay.xml @@ -0,0 +1,9 @@ +<Behavior> + <Class>behaviors.DecayBehavior</Class> + <Args> + <DecayType>Exponential</DecayType> + <Coefficient>.01</Coefficient> + <z-index>0</z-index> + <RenderToScreen>False</RenderToScreen> + </Args> +</Behavior> diff --git a/behaviors/RandomColor.xml b/behaviors/RandomColor.xml new file mode 100644 index 0000000..afac09c --- /dev/null +++ b/behaviors/RandomColor.xml @@ -0,0 +1,8 @@ +<Behavior> + <Class>behaviors.ColorChangerBehavior</Class> + <Args> + <Id>colorchange</Id> + <z-index>0</z-index> + <RenderToScreen>False</RenderToScreen> + </Args> +</Behavior> diff --git a/behaviors/RandomWalk.py b/behaviors/RandomWalk.py new file mode 100644 index 0000000..8254430 --- /dev/null +++ b/behaviors/RandomWalk.py @@ -0,0 +1,5 @@ +from operationscore.Behavior import * +import util.ComponentRegistry as compReg +class RandomWalk(Behavior): + def processResponse(self, sensors, recursives): + diff --git a/behaviors/RunningBehavior.xml b/behaviors/RunningBehavior.xml new file mode 100644 index 0000000..2a7bf37 --- /dev/null +++ b/behaviors/RunningBehavior.xml @@ -0,0 +1,8 @@ +<Behavior> + <Class>behaviors.RunningBehavior</Class> + <Args> + <Id>running</Id> + <StepSize>1</StepSize> + <RenderToScreen>False</RenderToScreen> + </Args> +</Behavior> diff --git a/config/Outdoor.xml b/config/Outdoor.xml index 67958d7..9ca33e9 100644 --- a/config/Outdoor.xml +++ b/config/Outdoor.xml @@ -28,29 +28,10 @@ </PixelMapperConfiguration> <RendererConfiguration> <Renderer> - <Class>renderers.PygameRenderer</Class> - <Args> - <Id>pygamerender</Id> - <displaySize>(1300,50)</displaySize> - </Args> + <InheritsFrom>renderers/SixStripUDP.xml</InheritsFrom> </Renderer> <Renderer> - <Class>renderers.IndoorRenderer</Class> - <Args> - <Id>indoorRenderer</Id> - <PowerSupply> - <IP>10.31.255.233</IP> - <PortMapping>{'strip1':1, 'strip2':2}</PortMapping> - </PowerSupply> - <PowerSupply> - <IP>10.32.97.17</IP> - <PortMapping>{'strip3':1, 'strip4':2}</PortMapping> - </PowerSupply> - <PowerSupply> - <IP>10.32.96.211</IP> - <PortMapping>{'strip5':1, 'strip6':2}</PortMapping> - </PowerSupply> - </Args> + <InheritsFrom>renderers/Pygame.xml</InheritsFrom> </Renderer> </RendererConfiguration> <InputConfiguration> @@ -61,20 +42,13 @@ <RefreshInterval>100</RefreshInterval> </Args> </InputElement> - <InputElement> - <Class>inputs.PygameInput</Class> - <Args> - <Id>followmouse</Id> - <RefreshInterval>50</RefreshInterval> - <FollowMouse>True</FollowMouse> - </Args> + <InputElement Id="followmouse"> + <InheritsFrom>inputs/MouseFollower.xml</InheritsFrom> </InputElement> <InputElement> - <Class>inputs.UDPInput</Class> + <Class>inputs.RandomLocs</Class> <Args> - <Id>UDP</Id> - <Port>6038</Port> - <RefreshInterval>100</RefreshInterval> + <Id>randomLoc</Id> </Args> </InputElement> </InputConfiguration> @@ -85,35 +59,13 @@ <Id>echo</Id> <z-index>0</z-index> <RenderToScreen>False</RenderToScreen> - <Inputs> - </Inputs> </Args> </Behavior> - <Behavior> - <Class>behaviors.ColorChangerBehavior</Class> - <Args> - <Id>colorchange</Id> - <z-index>0</z-index> - <RenderToScreen>False</RenderToScreen> - <!--<ColorList> - <Color>(255,0,0)</Color> - </ColorList>--> - <Inputs> - <Id>pygame</Id> - </Inputs> - </Args> + <Behavior Id="colorchange"> + <InheritsFrom>behaviors/RandomColor.xml</InheritsFrom> </Behavior> - <Behavior> - <Class>behaviors.DecayBehavior</Class> - <Args> - <Id>decay</Id> - <DecayType>Exponential</DecayType> - <Coefficient>.01</Coefficient> - <z-index>0</z-index> - <RenderToScreen>False</RenderToScreen> - <Inputs> - </Inputs> - </Args> + <Behavior Id="decay"> + <InheritsFrom>behaviors/PixelDecay.xml</InheritsFrom> </Behavior> <Behavior> <Class>behaviors.DebugBehavior</Class> @@ -131,12 +83,8 @@ <Id>pixelsleft</Id> </Args> </Behavior> - <Behavior> - <Class>behaviors.RecursiveDecay</Class> - <Args> - <Id>recursivedecay</Id> - <InitialResponseCount>70</InitialResponseCount> - </Args> + <Behavior Id="recursivedecay"> + <InheritsFrom>behaviors/LoopAndDie.xml</InheritsFrom> </Behavior> <Behavior> <Class>behaviors.BehaviorChain</Class> @@ -144,6 +92,7 @@ <Id>runcolordecay</Id> <Inputs> <Id>pygame</Id> + <Id>randomLoc</Id> </Inputs> <ChainedBehaviors> <Id>colorchange</Id> @@ -155,14 +104,8 @@ <Mapper>gaussmap</Mapper> </Args> </Behavior> - <Behavior> - <Class>behaviors.ModifyParam</Class> - <Args> - <Id>accelerate</Id> - <ParamType>Sensor</ParamType> - <ParamName>StepSize</ParamName> - <ParamOp>{val}*1.05</ParamOp> - </Args> + <Behavior Id="accelerate"> + <InheritsFrom>behaviors/Accelerate.xml</InheritsFrom> </Behavior> <Behavior> <Class>behaviors.BehaviorChain</Class> @@ -184,22 +127,13 @@ <ChainedBehaviors> <Id>echo</Id> <Id>pixelsleft</Id> - <Id>colorchange</Id> <Id>decay</Id> </ChainedBehaviors> <RenderToScreen>False</RenderToScreen> </Args> </Behavior> - <Behavior> - <Class>behaviors.RunningBehavior</Class> - <Args> - <Id>running</Id> - <Inputs> - <Id>pygame</Id> - </Inputs> - <StepSize>1</StepSize> - <RenderToScreen>False</RenderToScreen> - </Args> + <Behavior Id="running"> + <InheritsFrom>behaviors/RunningBehavior.xml</InheritsFrom> </Behavior> </BehaviorConfiguration> </LightInstallation> 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 @@ +<InputElement> + <Class>inputs.PygameInput</Class> + <Args> + <Id>followmouse</Id> + <RefreshInterval>50</RefreshInterval> + <FollowMouse>True</FollowMouse> + </Args> +</InputElement> diff --git a/inputs/RandomLocs.py b/inputs/RandomLocs.py new file mode 100644 index 0000000..d1ce1c7 --- /dev/null +++ b/inputs/RandomLocs.py @@ -0,0 +1,13 @@ +import util.TimeOps as clock +import random +import util.Geo as Geo +import util.Strings as Strings +from operationscore.Input import * +class RandomLocs(Input): + def inputInit(self): + self['LastEvent'] = clock.time() + def sensingLoop(self): #TODO: move to params + currentTime = clock.time() + if currentTime - self['LastEvent'] > 2000: + self.respond({Strings.LOCATION: Geo.randomLoc((50,50))}) + self['LastEvent'] = currentTime 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/layouts/50PixelStrip.xml b/layouts/50PixelStrip.xml new file mode 100644 index 0000000..beabb97 --- /dev/null +++ b/layouts/50PixelStrip.xml @@ -0,0 +1,8 @@ +<PixelStrip> + <Class>layouts.LineLayout</Class> + <Args> + <pixelToPixelSpacing>4</pixelToPixelSpacing> + <spacing>4</spacing> + <numPixels>50</numPixels> + </Args> +</PixelStrip> diff --git a/layouts/BasicSixStrip.xml b/layouts/BasicSixStrip.xml index 38c50d4..0d2d277 100644 --- a/layouts/BasicSixStrip.xml +++ b/layouts/BasicSixStrip.xml @@ -1,61 +1,43 @@ <PixelConfiguration> <PixelStrip> - <Class>layouts.LineLayout</Class> - <Args> + <InheritsFrom>layouts/50PixelStrip.xml</InheritsFrom> + <Args OverrideBehavior="Merge"> <Id>strip1</Id> - <pixelToPixelSpacing>4</pixelToPixelSpacing> - <spacing>4</spacing> - <numPixels>50</numPixels> <originLocation>(10,20)</originLocation> </Args> </PixelStrip> <PixelStrip> - <Class>layouts.LineLayout</Class> - <Args> + <InheritsFrom>layouts/50PixelStrip.xml</InheritsFrom> + <Args OverrideBehavior="Merge"> <Id>strip2</Id> - <pixelToPixelSpacing>4</pixelToPixelSpacing> - <spacing>4</spacing> - <numPixels>50</numPixels> <originLocation>(10,24)</originLocation> </Args> </PixelStrip> <PixelStrip> - <Class>layouts.LineLayout</Class> - <Args> + <InheritsFrom>layouts/50PixelStrip.xml</InheritsFrom> + <Args OverrideBehavior="Merge"> <Id>strip3</Id> - <pixelToPixelSpacing>4</pixelToPixelSpacing> - <spacing>4</spacing> - <numPixels>50</numPixels> <originLocation>(10,28)</originLocation> </Args> </PixelStrip> <PixelStrip> - <Class>layouts.LineLayout</Class> - <Args> + <InheritsFrom>layouts/50PixelStrip.xml</InheritsFrom> + <Args OverrideBehavior="Merge"> <Id>strip4</Id> - <pixelToPixelSpacing>4</pixelToPixelSpacing> - <spacing>4</spacing> - <numPixels>50</numPixels> <originLocation>(10,32)</originLocation> </Args> </PixelStrip> <PixelStrip> - <Class>layouts.LineLayout</Class> - <Args> + <InheritsFrom>layouts/50PixelStrip.xml</InheritsFrom> + <Args OverrideBehavior="Merge"> <Id>strip5</Id> - <pixelToPixelSpacing>4</pixelToPixelSpacing> - <spacing>4</spacing> - <numPixels>50</numPixels> <originLocation>(10,36)</originLocation> </Args> </PixelStrip> <PixelStrip> - <Class>layouts.LineLayout</Class> - <Args> + <InheritsFrom>layouts/50PixelStrip.xml</InheritsFrom> + <Args OverrideBehavior="Merge"> <Id>strip6</Id> - <pixelToPixelSpacing>4</pixelToPixelSpacing> - <spacing>4</spacing> - <numPixels>50</numPixels> <originLocation>(10,40)</originLocation> </Args> </PixelStrip> diff --git a/operationscore/Input.py b/operationscore/Input.py index 6b56cd5..3dd74cf 100644 --- a/operationscore/Input.py +++ b/operationscore/Input.py @@ -1,5 +1,5 @@ import threading,time -from operationscore.SmootCoreObject import * +from logger import main_log, exception_log from operationscore.ThreadedSmootCoreObject import ThreadedSmootCoreObject #Abstract class for inputs. Inheriting classes should call "respond" to raise #their event. Inheriting classes MUST define sensingLoop. Called at the @@ -34,7 +34,11 @@ class Input(ThreadedSmootCoreObject): 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 7e3c8bd..291519a 100644 --- a/operationscore/SmootCoreObject.py +++ b/operationscore/SmootCoreObject.py @@ -18,7 +18,7 @@ class SmootCoreObject(object): 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/pixelmappers/SimpleMapper.py b/pixelmappers/SimpleMapper.py index bc51cf9..5d4dceb 100644 --- a/pixelmappers/SimpleMapper.py +++ b/pixelmappers/SimpleMapper.py @@ -23,7 +23,7 @@ class SimpleMapper(PixelMapper): #optimizations possible. This might be slow in the long run if pixelValid: ret.append((pixel, 1)) - except: + except Exception as exp: raise Exception('Bad event condition') return ret diff --git a/renderers/IndoorRenderer.py b/renderers/IndoorRenderer.py index c13d11f..0ee566a 100644 --- a/renderers/IndoorRenderer.py +++ b/renderers/IndoorRenderer.py @@ -2,7 +2,7 @@ from operationscore.Renderer import * import util.PacketComposition as composer import util.NetworkOps as network import socket,pdb -port = 6038 +sock_port = 6038 #Renderer for a Specific Light System. class IndoorRenderer(Renderer): def initRenderer(self): @@ -26,9 +26,10 @@ class IndoorRenderer(Renderer): (ip, port) = self.stripLocations[stripId] if not ip in self.sockets: #do we have a socket to this #strip? if not, spin off a new one - self.sockets[ip] = network.getConnectedSocket(ip,port) + self.sockets[ip] = network.getConnectedSocket(ip,sock_port) packet = composer.composePixelStripPacket(pixelStrip, port) self.sockets[ip].send(packet, 0x00) - except: - pass #Rendering error. Log it. LOG + #pdb.set_trace() + except Exception as inst: + print inst diff --git a/renderers/Pygame.xml b/renderers/Pygame.xml new file mode 100644 index 0000000..e37739d --- /dev/null +++ b/renderers/Pygame.xml @@ -0,0 +1,7 @@ +<Renderer> + <Class>renderers.PygameRenderer</Class> + <Args> + <Id>pygamerender</Id> + <displaySize>(1300,50)</displaySize> + </Args> +</Renderer> diff --git a/renderers/SixStripUDP.xml b/renderers/SixStripUDP.xml new file mode 100644 index 0000000..f3c9e75 --- /dev/null +++ b/renderers/SixStripUDP.xml @@ -0,0 +1,18 @@ +<Renderer> + <Class>renderers.IndoorRenderer</Class> + <Args> + <Id>indoorRenderer</Id> + <PowerSupply> + <IP>10.31.255.233</IP> + <PortMapping>{'strip1':1, 'strip2':2}</PortMapping> + </PowerSupply> + <PowerSupply> + <IP>10.32.97.17</IP> + <PortMapping>{'strip3':1, 'strip4':2}</PortMapping> + </PowerSupply> + <PowerSupply> + <IP>10.32.96.211</IP> + <PortMapping>{'strip5':1, 'strip6':2}</PortMapping> + </PowerSupply> + </Args> +</Renderer> 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 @@ +<RendererConfiguration> + <Renderer> + <Class>renderers.IndoorRenderer</Class> + <Args> + <Id>indoorRenderer</Id> + <PowerSupply> + <IP>10.31.255.233</IP> + <PortMapping>{'strip1':1, 'strip2':2}</PortMapping> + </PowerSupply> + <PowerSupply> + <IP>10.32.97.17</IP> + <PortMapping>{'strip3':1, 'strip4':2}</PortMapping> + </PowerSupply> + <PowerSupply> + <IP>10.32.96.211</IP> + <PortMapping>{'strip5':1, 'strip6':2}</PortMapping> + </PowerSupply> + </Args> + </Renderer> + <Renderer> + <Class>renderers.PygameRenderer</Class> + <Args> + <Id>pygamerender</Id> + <displaySize>(1300,50)</displaySize> + </Args> + </Renderer> +</RendererConfiguration> diff --git a/tests/testdata/compositeTESTout.xml b/tests/testdata/compositeTESTout.xml index 435b75a..a306190 100644 --- a/tests/testdata/compositeTESTout.xml +++ b/tests/testdata/compositeTESTout.xml @@ -1,11 +1,11 @@ <Override> <A> - <override>overide parameter</override> + <blah>test</blah> + <foo>bar</foo> +<override>overide parameter</override> </A> -<B OverrideBehavior="Merge"> - <this>taht</this> - <that>this</that> -<SomeNewParam>blah</SomeNewParam> +<B OverrideBehavior="Replace"> + <SomeNewParam>blah</SomeNewParam> </B> <A> <someparam>appenedA</someparam> diff --git a/tests/testdata/compositeTRUTH.xml b/tests/testdata/compositeTRUTH.xml index 435b75a..a306190 100644 --- a/tests/testdata/compositeTRUTH.xml +++ b/tests/testdata/compositeTRUTH.xml @@ -1,11 +1,11 @@ <Override> <A> - <override>overide parameter</override> + <blah>test</blah> + <foo>bar</foo> +<override>overide parameter</override> </A> -<B OverrideBehavior="Merge"> - <this>taht</this> - <that>this</that> -<SomeNewParam>blah</SomeNewParam> +<B OverrideBehavior="Replace"> + <SomeNewParam>blah</SomeNewParam> </B> <A> <someparam>appenedA</someparam> diff --git a/tests/testdata/inheritanceTEST.xml b/tests/testdata/inheritanceTEST.xml index c2efd71..d90e9af 100644 --- a/tests/testdata/inheritanceTEST.xml +++ b/tests/testdata/inheritanceTEST.xml @@ -1,3 +1,22 @@ <A> - <InheritsFrom>tests/testdata/aParent.xml</InheritsFrom> + <B> + <SubB> + <SubSubB> + <A> + <InheritsFrom>tests/testdata/aParent.xml</InheritsFrom> + </A> + </SubSubB> + </SubB> + <A> + <InheritsFrom>tests/testdata/aParent.xml</InheritsFrom> + </A> + </B> </A> + +<!-- +<Parent> + <A> + <InheritsFrom>tests/testdata/aParent.xml</InheritsFrom> + </A> +</Parent> +--> diff --git a/tests/testdata/inheritanceTESTout.xml b/tests/testdata/inheritanceTESTout.xml index ffa6667..e8fb228 100644 --- a/tests/testdata/inheritanceTESTout.xml +++ b/tests/testdata/inheritanceTESTout.xml @@ -1,4 +1,16 @@ <A> - <param1>1</param1> + <B> + <SubB> + <SubSubB> + <A> + <param1>1</param1> <param2>2</param2> +</A> + </SubSubB> + </SubB> + <A> + <param1>1</param1> + <param2>2</param2> +</A> + </B> </A>
\ No newline at end of file diff --git a/tests/testdata/inheritanceTRUTH.xml b/tests/testdata/inheritanceTRUTH.xml index ffa6667..e8fb228 100644 --- a/tests/testdata/inheritanceTRUTH.xml +++ b/tests/testdata/inheritanceTRUTH.xml @@ -1,4 +1,16 @@ <A> - <param1>1</param1> + <B> + <SubB> + <SubSubB> + <A> + <param1>1</param1> <param2>2</param2> +</A> + </SubSubB> + </SubB> + <A> + <param1>1</param1> + <param2>2</param2> +</A> + </B> </A>
\ No newline at end of file diff --git a/tests/testdata/override.xml b/tests/testdata/override.xml index 1108fb0..722554a 100644 --- a/tests/testdata/override.xml +++ b/tests/testdata/override.xml @@ -2,7 +2,7 @@ <A> <override>overide parameter</override> </A> -<B OverrideBehavior="Merge"> +<B OverrideBehavior="Replace"> <SomeNewParam>blah</SomeNewParam> </B> <APPEND> diff --git a/util/Config.py b/util/Config.py index 33e6fee..4c1eb1e 100644 --- a/util/Config.py +++ b/util/Config.py @@ -1,25 +1,29 @@ from xml.etree.ElementTree import * +import sys import xml import pdb import util.Strings as Strings +import util.Search as Search +from logger import main_log, exception_log classArgsMem = {} CONFIG_PATH = 'config/' +DEFAULT_OVERRIDE_MODE = 'Merge' def loadParamRequirementDict(className): if not className in classArgsMem: #WOO CACHING classArgsMem[className] = fileToDict(CONFIG_PATH + 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: - config = ElementTree() #use .fromstring, and resolve xincludes + config = ElementTree() config.parse(fileName) - config = ElementTree(resolveConfigInheritance(config.getroot())) + resolveDocumentInheritances(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 @@ -28,9 +32,15 @@ def getElement(el): return el elif el.__class__ == ElementTree: return el.getroot() +#XML tree composition. Returns the resulting tree, but happens in-place in the overriding tree. 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 #TODO: this will probably cause a bug since it isn't in-place on + #overridingTree parentTree = getElement(parentTree) overridingTree = getElement(overridingTree) parentItems = parentTree.getchildren() @@ -44,13 +54,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' + mode = DEFAULT_OVERRIDE_MODE 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,16 +79,31 @@ 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 pullArgsFromItem(parentNode): + attribArgs = {} + for arg in parentNode.attrib: #automatically pull attributes into the argdict + attribArgs[arg] = parentNode.attrib[arg] + argNode = parentNode.find('Args') + args = generateArgDict(argNode) + for key in attribArgs: + args[key] = attribArgs[key] + return args def generateArgDict(parentNode, recurse=False): args = {} for arg in parentNode.getchildren(): @@ -100,11 +126,19 @@ def generateArgDict(parentNode, recurse=False): if len(args.keys()) == 1 and recurse: return args[args.keys()[0]] return args - -def resolveConfigInheritance(el): +#In place resolution of document inheritances. Doesn't return anything. +def resolveDocumentInheritances(el): + abstractMembers = Search.parental_tree_search(el, '.getchildren()', '.tag==\'InheritsFrom\'') + for subel in abstractMembers: + subel = resolveInheritance(subel) +#In place resolution of inheritence. Doesn't return anything. +def resolveInheritance(el): parentClass = el.find('InheritsFrom') if parentClass != None: parentTree = loadConfigFile(parentClass.text) - el = compositeXMLTrees(el, parentTree) + 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(parentTree, el) el.remove(parentClass) #get rid of the inheritance flag - return el diff --git a/util/Geo.py b/util/Geo.py index 885c585..a9243de 100644 --- a/util/Geo.py +++ b/util/Geo.py @@ -1,6 +1,7 @@ #Geometry code import math from bisect import * +import random def pointWithinBoundingBox(point, bb): #this could be in 4 lines, but I'm lazy. return sum([(point[i % 2] <= bb[i]) == (i>1) for i in range(4)]) == 4 print pointWithinBoundingBox((118,21), (10,8,298,42)) @@ -13,3 +14,8 @@ def gaussian(x,height,center,width): return a*math.exp(-((x-b)**2)/(2*c**2)) def dist(l1, l2): return math.sqrt(sum([(l1[i]-l2[i])**2 for i in range(len(l1))])) +def randomLoc(boundingBox): #TODO: make less shitty + loc = [] + loc.append(random.randint(0, boundingBox[0])) + loc.append(random.randint(0, boundingBox[1])) + return tuple(loc) diff --git a/util/NetworkOps.py b/util/NetworkOps.py index 0404975..6c50c6d 100644 --- a/util/NetworkOps.py +++ b/util/NetworkOps.py @@ -1,8 +1,11 @@ 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' - return sock + return sock + except Exception as inst: + main_log.error('Network down. All network based renderers and sensors will not function.', + inst) + print (ip, port) diff --git a/util/PacketComposition.py b/util/PacketComposition.py index 2563c61..73eefff 100644 --- a/util/PacketComposition.py +++ b/util/PacketComposition.py @@ -6,6 +6,7 @@ DEEPMAGIC = 0xc001d00d MAGICHASH = 0x69000420 PORTOUT = 0x0108 UNI = 0 +import pdb kinetDict = {'flags': 0, 'startcode': 0, 'pad':0} def composePixelStripData(pixelStrip): packet = bytearray() @@ -44,7 +45,6 @@ def kinetPortOut(): def kinetPortOutPayload(argDict): payload = bytearray() payload.extend(struct.pack('B', argDict['port'])) - #payload.append(0x00) #somepadding? lolwtf. payload.extend(struct.pack('H', argDict['flags'])) #payload.append(0x00) #somepadding? lolwtf. payload.extend(struct.pack('H', argDict['len'])) diff --git a/util/Search.py b/util/Search.py index 25882da..f7e4b81 100644 --- a/util/Search.py +++ b/util/Search.py @@ -6,3 +6,17 @@ def find_le(a, x): def find_ge(a, x): 'Find leftmost value greater than x' return bisect_left(a, x) +#returns parents of nodes that meed a given condition +def parental_tree_search(root, childrenstr, conditionstr): + ret = [] + queue = [root] + while queue: + current = queue.pop() + children = eval('current'+childrenstr) + for child in children: + if eval('child'+conditionstr): + ret.append(current) + #we know have a tree, so there are no back-edges etc, so no checking of that kind is + #necessary + queue += children + return ret |