From c581408f028d5b8ceadc53c68d7c1252fbe09e6d Mon Sep 17 00:00:00 2001 From: rcoh Date: Wed, 22 Dec 2010 14:27:33 -0500 Subject: About halfway done with support for pixel regions. Modified the component registry a bit. Added support for multiple pixel mappers (and along with that, default components). RCOH --- LightInstallation.py | 28 +++++++++++++++++----------- behaviors/BehaviorChain.py | 1 - behaviors/DebugBehavior.py | 1 - behaviors/DecayBehavior.py | 1 - behaviors/EchoBehavior.py | 1 - behaviors/ModifyParam.py | 1 - behaviors/RunningBehavior.py | 1 - config/Outdoor.xml | 9 ++++++--- inputs/PygameInput.py | 2 +- inputs/TCPInput.py | 1 - inputs/TCPInput_backup.py | 1 - inputs/UDPInput.py | 1 - operationscore/Behavior.py | 21 ++++++++++++++++----- operationscore/Input.py | 6 +----- operationscore/PixelAssembler.py | 1 - operationscore/PixelMapper.py | 1 - operationscore/SmootCoreObject.py | 2 +- pixelcore/PixelStrip.py | 1 - pixelcore/Screen.py | 14 ++++++++++---- pixelmappers/GaussianMapper.py | 1 - pixelmappers/SimpleMapper.py | 4 ++-- renderers/IndoorRenderer.py | 19 +++++++++++-------- util/ComponentRegistry.py | 36 +++++++++++++++++++++++++++++++----- util/Config.py | 4 ++-- util/NetworkOps.py | 6 ++++-- util/PacketComposition.py | 2 -- util/Strings.py | 1 + 27 files changed, 103 insertions(+), 64 deletions(-) diff --git a/LightInstallation.py b/LightInstallation.py index e6e5a26..48dee77 100644 --- a/LightInstallation.py +++ b/LightInstallation.py @@ -1,7 +1,7 @@ from xml.etree.ElementTree import ElementTree from pixelcore.Screen import * from pixelcore.PixelStrip import * -import pdb, sys, time, Util, thread +import pdb, sys, time, thread from pygame.locals import * import util.TimeOps as clock import util.Config as configGetter @@ -20,11 +20,8 @@ class LightInstallation: self.componentDict = {} self.inputBehaviorRegistry = {} #inputid -> behaviors listening to that #input - #give Util a pointer to our componentRegistry and screen so that everyone can use - #it - #Util.setComponentDict(self.componentDict) self.screen = Screen() - #Util.setScreen(self.screen) + compReg.initRegistry() compReg.registerComponent(self.screen, 'Screen') #TODO: move to constants file config = configGetter.loadConfigFile(configFileName) #read configs from xml @@ -33,25 +30,34 @@ class LightInstallation: inputConfig = config.find('InputConfiguration') behaviorConfig = config.find('BehaviorConfiguration') mapperConfig = config.find('PixelMapperConfiguration') + + installationConfig = config.find('InstallationConfiguration') #inits self.initializeScreen(pixelConfig) self.initializeRenderers(rendererConfig) self.initializeInputs(inputConfig) self.initializeBehaviors(behaviorConfig) self.initializeMapper(mapperConfig) - - self.screen.setMapper(self.mapper) #registration in dict self.registerComponents(self.renderers) self.registerComponents(self.inputs) self.registerComponents(self.behaviors) + self.registerComponents(self.mappers) + pdb.set_trace() + self.configureInstallation(installationConfig) #Done initializing. Lets start this thing! self.timer.stop() print 'Initialization done. Time: ', self.timer.elapsed(), 'ms' self.mainLoop() + def configureInstallation(self, installationConfig): + defaults = configGetter.generateArgDict(installationConfig.find('Defaults')) + for defaultSelection in defaults: + componentToMap = compReg.getComponent(defaults[defaultSelection]) + compReg.registerComponent(compReg.getComponent(defaults[defaultSelection]),\ + 'Default'+defaultSelection) + def initializeMapper(self, mapperConfig): - self.mapper = self.initializeComponent(mapperConfig)[0] #TODO: support - #multiple mappers + self.mappers = self.initializeComponent(mapperConfig) def initializeScreen(self, layoutConfig): pixelAssemblers = self.initializeComponent(layoutConfig) [self.addPixelStrip(l) for l in pixelAssemblers] @@ -72,7 +78,6 @@ class LightInstallation: cid = component['Id'] if cid == None: raise Exception('Components must have Ids!') - #self.componentDict[cid] = component compReg.registerComponent(component) def initializeComponent(self, config): components = [] @@ -141,7 +146,8 @@ class LightInstallation: try: [compReg.getComponent(b).addInput(responseDict) for b in boundBehaviorIds] except: - print 'Behaviors not initialized yet. WAIT!' + pass + #print 'Behaviors not initialized yet. WAIT!' def main(argv): print argv if len(argv) == 1: diff --git a/behaviors/BehaviorChain.py b/behaviors/BehaviorChain.py index 65f5c9d..98585c9 100644 --- a/behaviors/BehaviorChain.py +++ b/behaviors/BehaviorChain.py @@ -1,6 +1,5 @@ from operationscore.Behavior import * import util.ComponentRegistry as compReg -import Util import pdb class BehaviorChain(Behavior): def behaviorInit(self): diff --git a/behaviors/DebugBehavior.py b/behaviors/DebugBehavior.py index 4c8550a..a00346b 100644 --- a/behaviors/DebugBehavior.py +++ b/behaviors/DebugBehavior.py @@ -1,5 +1,4 @@ from operationscore.Behavior import * -import Util import pdb class DebugBehavior(Behavior): def processResponse(self, sensorInputs, recursiveInputs): diff --git a/behaviors/DecayBehavior.py b/behaviors/DecayBehavior.py index 56e1686..c1f6f92 100644 --- a/behaviors/DecayBehavior.py +++ b/behaviors/DecayBehavior.py @@ -1,7 +1,6 @@ from operationscore.Behavior import * from pixelevents.DecayEvent import * import util.Strings as Strings -import Util import pdb class DecayBehavior(Behavior): def processResponse(self, sensorInputs, recursiveInputs): diff --git a/behaviors/EchoBehavior.py b/behaviors/EchoBehavior.py index 002f8fb..be0ed14 100644 --- a/behaviors/EchoBehavior.py +++ b/behaviors/EchoBehavior.py @@ -1,6 +1,5 @@ from operationscore.Behavior import * import util.Strings as Strings -import Util import pdb class EchoBehavior(Behavior): def processResponse(self, sensorInputs, recursiveInputs): diff --git a/behaviors/ModifyParam.py b/behaviors/ModifyParam.py index 38b8cd5..3701013 100644 --- a/behaviors/ModifyParam.py +++ b/behaviors/ModifyParam.py @@ -1,5 +1,4 @@ from operationscore.Behavior import * -import Util import pdb #Class to perform a given operation on some element of an argDict. Designed to be used a recursive hook, but can serve sensor-based functions as well. Specify ParamType (Sensor or Recurse), ParamName, and ParamOp, (a valid python statement with the old value represented as {val}) class ModifyParam(Behavior): diff --git a/behaviors/RunningBehavior.py b/behaviors/RunningBehavior.py index 1969162..92db69b 100644 --- a/behaviors/RunningBehavior.py +++ b/behaviors/RunningBehavior.py @@ -2,7 +2,6 @@ from operationscore.Behavior import * import util.ComponentRegistry as compReg import util.Geo as Geo import pdb -import Util class RunningBehavior(Behavior): def processResponse(self, sensorInputs, recursiveInputs): newResponses = sensorInputs diff --git a/config/Outdoor.xml b/config/Outdoor.xml index 10274b2..a004c4e 100644 --- a/config/Outdoor.xml +++ b/config/Outdoor.xml @@ -1,5 +1,10 @@ + + + simplemap + + layouts.LineLayout @@ -62,15 +67,13 @@ - - pixelmappers.GaussianMapper diff --git a/inputs/PygameInput.py b/inputs/PygameInput.py index f69d0f5..6779a20 100644 --- a/inputs/PygameInput.py +++ b/inputs/PygameInput.py @@ -1,4 +1,4 @@ -import time, Util +import time import util.Strings as Strings from operationscore.Input import * import pygame diff --git a/inputs/TCPInput.py b/inputs/TCPInput.py index 9f62825..1517afa 100644 --- a/inputs/TCPInput.py +++ b/inputs/TCPInput.py @@ -1,4 +1,3 @@ -import Util import util.Strings as Strings from operationscore.Input import * import socket, json, time diff --git a/inputs/TCPInput_backup.py b/inputs/TCPInput_backup.py index 01b6a99..d2c4087 100644 --- a/inputs/TCPInput_backup.py +++ b/inputs/TCPInput_backup.py @@ -1,5 +1,4 @@ import SocketServer -import Util from operationscore.Input import * """ diff --git a/inputs/UDPInput.py b/inputs/UDPInput.py index 5b83792..7d5609e 100644 --- a/inputs/UDPInput.py +++ b/inputs/UDPInput.py @@ -1,4 +1,3 @@ -import Util from operationscore.Input import * import socket class UDPInput(Input): diff --git a/operationscore/Behavior.py b/operationscore/Behavior.py index 3bdf1ec..d48c1d5 100644 --- a/operationscore/Behavior.py +++ b/operationscore/Behavior.py @@ -33,14 +33,26 @@ class Behavior(SmootCoreObject): recursiveInputs) if type(output) != type([]): output = [output] - return (output, recursions) - except: + return self.addMapperToResponse((output, recursions)) #TODO: use a decorator for this? + except: #deal with behaviors that don't return a tuple. + responses = self.processResponse(sensorInputs, recursiveInputs) return (self.processResponse(sensorInputs, recursiveInputs),[]) def addInputs(self, sensorInputs): if type(sensorInputs) == type([]): [self.addInput(sensorInput) for sensorInput in sensorInputs] else: self.addInput(sensorInputs) + #private + def addMapperToResponse(self, responses): + if self['Mapper'] != None: + if type(responses) == type(tuple): + (out, recurs) = responses + return (self.addMapperToResponse(out), self.addMapperToResponse(recurs)) + if type(responses) == type([]): + for r in responses: + r['Mapper'] = self['Mapper'] + return responses + return responses def timeStep(self): #TODO: type checking. clean this up responses = self.processResponse(self.sensorResponseQueue, \ self.recursiveResponseQueue) @@ -54,8 +66,7 @@ class Behavior(SmootCoreObject): if type(outputs) != type([]): outputs = [outputs] try: - return outputs + return self.addMapperToResponse(outputs) #TODO: WTF is up with this? except: pass - #pdb.set_trace() - return outputs + return self.addMapperToResponse(outputs) diff --git a/operationscore/Input.py b/operationscore/Input.py index 2144678..62c4682 100644 --- a/operationscore/Input.py +++ b/operationscore/Input.py @@ -1,4 +1,4 @@ -import threading,time,Util +import threading,time from operationscore.SmootCoreObject import * #Abstract class for inputs. Inheriting classes should call "respond" to raise #their event. Inheriting classes MUST define sensingLoop. Called at the @@ -22,14 +22,10 @@ class Input(SmootCoreObject): self.daemon = True #This kills this thread when the main thread stops def respond(self, eventDict): #if eventDict != []: - #pdb.set_trace() self.parentScope.lock.acquire() self.parentScope.processResponse(self.argDict, eventDict) self.parentScope.lock.release() time.sleep(.001) - def newEvent(self, event): #Mostly just useful for grabbing events from the - #computer running the sim (key presses, clicks etc.) - self.eventQueue.append(event) def parentAlive(self): try: parentAlive = self.parentScope.alive() diff --git a/operationscore/PixelAssembler.py b/operationscore/PixelAssembler.py index c8563fb..6878f8a 100644 --- a/operationscore/PixelAssembler.py +++ b/operationscore/PixelAssembler.py @@ -1,6 +1,5 @@ from operationscore.SmootCoreObject import * import util.Geo as Geo -import Util import pdb class PixelAssembler(SmootCoreObject): def init(self): diff --git a/operationscore/PixelMapper.py b/operationscore/PixelMapper.py index bbbfcf4..e3f2515 100644 --- a/operationscore/PixelMapper.py +++ b/operationscore/PixelMapper.py @@ -1,5 +1,4 @@ from operationscore.SmootCoreObject import * -import Util import pdb class PixelMapper(SmootCoreObject): def init(self): diff --git a/operationscore/SmootCoreObject.py b/operationscore/SmootCoreObject.py index 10df299..9784aab 100644 --- a/operationscore/SmootCoreObject.py +++ b/operationscore/SmootCoreObject.py @@ -1,4 +1,3 @@ -import Util import pdb import threading import thread @@ -8,6 +7,7 @@ class SmootCoreObject(threading.Thread): self.argDict = argDict self.validateArgs(self.className()+'.params') self.lock = thread.allocate_lock() + threading.Thread.__init__(self) self.init() #call init of inheriting class # self.__setitem__ = self.argDict.__setitem__ # self.__getitem__ = self.argDict.__getitem__ diff --git a/pixelcore/PixelStrip.py b/pixelcore/PixelStrip.py index cfab948..fceff8e 100644 --- a/pixelcore/PixelStrip.py +++ b/pixelcore/PixelStrip.py @@ -4,7 +4,6 @@ import util.Geo as Geo from pixelevents.StepEvent import * import pygame import math -import Util import pdb #Python class representing a single Pixel strip (usually 50 Pixels) class PixelStrip: diff --git a/pixelcore/Screen.py b/pixelcore/Screen.py index a20cc72..da03ad2 100644 --- a/pixelcore/Screen.py +++ b/pixelcore/Screen.py @@ -1,7 +1,10 @@ from pixelcore.Pixel import * from pixelcore.PixelStrip import * from operationscore.PixelEvent import * +from operationscore.PixelMapper import * import util.Search as Search +import util.ComponentRegistry as compReg +import util.Strings as Strings import itertools #Class representing a collection of Pixels grouped into PixelStrips. Needs a #PixelMapper, currently set via setMapper by may be migrated into the argDict. @@ -29,8 +32,6 @@ class Screen: self.xPixelLocs = [p[0] for p in self.xSortedPixels] def render(self, surface): [lS.render(surface) for lS in self.pixelStrips] - def setMapper(self, mapper): - self.mapper = mapper def allOn(self): [lS.allOn(-1) for lS in self.pixelStrips] def __iter__(self): #the iterator of all our pixel strips chained togther @@ -70,8 +71,13 @@ class Screen: #[strip.respond(dict(responseInfo)) for strip in self.pixelStrips] if type(responseInfo) != type(dict()): pass - #pdb.set_trace() - pixelWeightList = self.mapper.mapEvent(responseInfo['Location'], self) + if 'Mapper' in responseInfo: + mapper = compReg.getComponent(responseInfo['Mapper']) + else: + mapper = compReg.getComponent(Strings.DEFAULT_MAPPER) + #if type(mapper) != type(PixelMapper): + # raise Exception('No default mapper specified.') + pixelWeightList = mapper.mapEvent(responseInfo['Location'], self) PixelEvent.addPixelEventIfMissing(responseInfo) for (pixel, weight) in pixelWeightList: pixel.processInput(responseInfo['PixelEvent'].scale(weight), 0) #TODO: z-index diff --git a/pixelmappers/GaussianMapper.py b/pixelmappers/GaussianMapper.py index e94235e..8755acf 100644 --- a/pixelmappers/GaussianMapper.py +++ b/pixelmappers/GaussianMapper.py @@ -1,6 +1,5 @@ from operationscore.PixelMapper import * import util.Geo as Geo -import Util class GaussianMapper(PixelMapper): def mappingFunction(self, eventLocation, screen): returnPixels = [] #TODO: consider preallocation and trimming diff --git a/pixelmappers/SimpleMapper.py b/pixelmappers/SimpleMapper.py index fdcf8b9..6b414ea 100644 --- a/pixelmappers/SimpleMapper.py +++ b/pixelmappers/SimpleMapper.py @@ -1,12 +1,12 @@ from operationscore.PixelMapper import * -import Util +import util.Geo as Geo class SimpleMapper(PixelMapper): def mappingFunction(self, eventLocation, screen): if type(eventLocation) == type(tuple()): bestDist = 10**10 #don't kill me, I'm lazy bestPixel = None for pixel in screen: - pixelDist = Util.dist(pixel.location, eventLocation) + pixelDist = Geo.dist(pixel.location, eventLocation) if pixelDist < bestDist: bestPixel = pixel bestDist = pixelDist diff --git a/renderers/IndoorRenderer.py b/renderers/IndoorRenderer.py index 2eac162..c13d11f 100644 --- a/renderers/IndoorRenderer.py +++ b/renderers/IndoorRenderer.py @@ -20,12 +20,15 @@ class IndoorRenderer(Renderer): self.stripLocations[stripId] = (ip, \ stripsInPowerSupply[stripId]) def render(self, lightSystem): - for pixelStrip in lightSystem.pixelStrips: - stripId = pixelStrip.argDict['Id'] - (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) - packet = composer.composePixelStripPacket(pixelStrip, port) - self.sockets[ip].send(packet, 0x00) + try: + for pixelStrip in lightSystem.pixelStrips: + stripId = pixelStrip.argDict['Id'] + (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) + packet = composer.composePixelStripPacket(pixelStrip, port) + self.sockets[ip].send(packet, 0x00) + except: + pass #Rendering error. Log it. LOG diff --git a/util/ComponentRegistry.py b/util/ComponentRegistry.py index f8fe00d..119ce18 100644 --- a/util/ComponentRegistry.py +++ b/util/ComponentRegistry.py @@ -1,17 +1,43 @@ import pdb +#component registry, a singleton +import thread +#class ComponentRegistry: +# def __init__(self): +# self.regDict = {} +# @staticmethod +# def getRegistry(self): +# if self.instance == None: +# self.instance = self.__class__() +# return self.instance +# def registerComponent(component, cid=None): +# if cid != None: +# globals()['Registry'][cid] = component +# else: +# try: +# cid = component['Id'] +# globals()['Registry'][cid] = component +# except: +# raise Exception('Must specify Id, component did not store it') +#def registerDefault( +def removeComponent(cid): + globals()['Registry'].pop(cid) +def getComponent(cid): + return globals()['Registry'][cid] #Registry of all components of the light system #TODO: pick a graceful failure behavior and implement it -registry = {} +def initRegistry(): + globals()['Registry'] = {} def registerComponent(component, cid=None): if cid != None: - registry[cid] = component + globals()['Registry'][cid] = component else: try: cid = component['Id'] - registry[cid] = component + globals()['Registry'][cid] = component except: raise Exception('Must specify Id, component did not store it') +#def registerDefault( def removeComponent(cid): - registry.pop(cid) + globals()['Registry'].pop(cid) def getComponent(cid): - return registry[cid] + return globals()['Registry'][cid] diff --git a/util/Config.py b/util/Config.py index 4cf2ed5..f80b7b2 100644 --- a/util/Config.py +++ b/util/Config.py @@ -6,7 +6,7 @@ def loadParamRequirementDict(className): classArgsMem[className] = fileToDict(CONFIG_PATH + className) return classArgsMem[className] def loadConfigFile(fileName): #TODO: error handling etc. - try: + #try: fileName = CONFIG_PATH + fileName if '.params' in fileName: return fileToDict(fileName) @@ -14,7 +14,7 @@ def loadConfigFile(fileName): #TODO: error handling etc. config = ElementTree() config.parse(fileName) return config - except: + #except: return None def fileToDict(fileName): fileText = '' diff --git a/util/NetworkOps.py b/util/NetworkOps.py index a247090..0404975 100644 --- a/util/NetworkOps.py +++ b/util/NetworkOps.py @@ -1,6 +1,8 @@ import socket def getConnectedSocket(ip,port): sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - print (ip, port) - sock.connect((ip, port)) + try: + sock.connect((ip, port)) + except: + print 'network down' return sock diff --git a/util/PacketComposition.py b/util/PacketComposition.py index 5133459..2563c61 100644 --- a/util/PacketComposition.py +++ b/util/PacketComposition.py @@ -26,7 +26,6 @@ def composePixelStripPacket(pixelStrip,port): subDict = dict(kinetDict) subDict['len'] = 38000 #I have no idea why this works. subDict['port'] = port - #pdb.set_trace() packet.extend(kinetPortOutPacket(subDict)) packet.append(0x0) packet.extend(data) @@ -50,7 +49,6 @@ def kinetPortOutPayload(argDict): #payload.append(0x00) #somepadding? lolwtf. payload.extend(struct.pack('H', argDict['len'])) payload.extend(struct.pack('H', argDict['startcode'])) - #pdb.set_trace() return payload def kinetPortOutPacket(payloadArgs): packet = bytearray() diff --git a/util/Strings.py b/util/Strings.py index 1331db4..81c34f2 100644 --- a/util/Strings.py +++ b/util/Strings.py @@ -1 +1,2 @@ LOCATION = 'Location' +DEFAULT_MAPPER = 'DefaultPixelMapper' -- cgit v1.2.3