From a89c772cd64c6790906734f7128947e0f453c7e3 Mon Sep 17 00:00:00 2001 From: rcoh Date: Wed, 15 Dec 2010 00:18:24 -0500 Subject: About halfway done with the Util cleanup. Some stuff left to do with scoping etc. --- .gitignore | 2 + LightInstallation.py | 14 ++-- Util.py | 140 -------------------------------------- behaviors/ColorChangerBehavior.py | 7 +- operationscore/PixelEvent.py | 3 +- operationscore/SmootCoreObject.py | 3 +- pixelcore/Pixel.py | 9 +-- pixelevents/DecayEvent.py | 5 +- renderers/IndoorRenderer.py | 16 ++--- util/ColorOps.py | 11 +++ util/Config.py | 53 +++++++++++++++ util/NetworkOps.py | 6 ++ util/PacketComposition.py | 59 ++++++++++++++++ util/TimeOps.py | 19 ++++++ util/__init__.py | 0 15 files changed, 181 insertions(+), 166 deletions(-) create mode 100644 .gitignore create mode 100644 util/ColorOps.py create mode 100644 util/Config.py create mode 100644 util/NetworkOps.py create mode 100644 util/PacketComposition.py create mode 100644 util/TimeOps.py create mode 100644 util/__init__.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c9b568f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.pyc +*.swp diff --git a/LightInstallation.py b/LightInstallation.py index e4adab7..5f12abf 100644 --- a/LightInstallation.py +++ b/LightInstallation.py @@ -3,11 +3,13 @@ from pixelcore.Screen import * from pixelcore.PixelStrip import * import pdb, sys, time, Util, thread from pygame.locals import * +import util.TimeOps as clock +import util.Config as configGetter #Python class to instantiate and drive a Screen through different patterns, #and effects. class LightInstallation: def __init__(self, configFileName): - self.timer = Util.Stopwatch() + self.timer = clock.Stopwatch() self.timer.start() self.inputs = {} #dict of inputs and their bound behaviors, keyed by InputId self.behaviors = {} @@ -22,7 +24,7 @@ class LightInstallation: Util.setComponentDict(self.componentDict) self.screen = Screen() Util.setScreen(self.screen) - config = Util.loadConfigFile(configFileName) + config = configGetter.loadConfigFile(configFileName) #read configs from xml rendererConfig = config.find('RendererConfiguration') pixelConfig = config.find('PixelConfiguration') @@ -75,7 +77,7 @@ class LightInstallation: for configItem in config.getchildren(): [module,className] = configItem.find('Class').text.split('.') exec('from ' + module+'.'+className + ' import *') - args = Util.generateArgDict(configItem.find('Args')) + 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 @@ -85,12 +87,12 @@ class LightInstallation: return True def mainLoop(self): #self.screen.allOn() - lastLoopTime = Util.time() + lastLoopTime = clock.time() refreshInterval = 30 runCount = 10000 while runCount > 0: runCount -= 1 - loopStart = Util.time() + loopStart = clock.time() responses = self.evaluateBehaviors() #inputs are all queued when they #happen, so we only need to run the behaviors self.timer.start() @@ -98,7 +100,7 @@ class LightInstallation: response != []] self.screen.timeStep() [r.render(self.screen) for r in self.renderers] - loopElapsed = Util.time()-loopStart + loopElapsed = clock.time()-loopStart sleepTime = max(0,refreshInterval-loopElapsed) self.timer.stop() #print self.timer.elapsed() diff --git a/Util.py b/Util.py index 07ce545..2973e33 100644 --- a/Util.py +++ b/Util.py @@ -6,15 +6,8 @@ from bisect import * import socket import random from pygame.locals import * -import time as clock from pixelevents.StepEvent import * -VERSION = 0x0001 -MAGIC = 0x4adc0104 -MOREMAGIC = 0xdeadbeef -DEEPMAGIC = 0xc001d00d -MAGICHASH = 0x69000420 -PORTOUT = 0x0108 classArgsMem = {} UNI = 0 colorByteMem = {} @@ -52,39 +45,6 @@ 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 time(): - return clock.time()*1000 -def randomColor(): - return [random.randint(0,255) for i in range(3)] -def chooseRandomColor(colorList): - return random.choice(colorList) -def loadParamRequirementDict(className): - if not className in classArgsMem: #WOO CACHING - classArgsMem[className] = fileToDict(CONFIG_PATH + className) - return classArgsMem[className] -def loadConfigFile(fileName): - try: - fileName = CONFIG_PATH + fileName - if '.params' in fileName: - return fileToDict(fileName) - if '.xml' in fileName: - config = ElementTree() - config.parse(fileName) - return config - except: - return None -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: - return {} - if fileText == '': - return {} - return eval(fileText) def find_le(a, x): 'Find rightmost value less than or equal to x' return bisect_right(a, x)-1 @@ -92,35 +52,6 @@ def find_le(a, x): def find_ge(a, x): 'Find leftmost value greater than x' return bisect_left(a, x) -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 multiplyColor(color, percent): - return safeColor([channel*(percent) for channel in color]) -#parses arguments into python objects if possible, otherwise leaves as strings -def generateArgDict(parentNode, recurse=False): - args = {} - for arg in parentNode.getchildren(): - key = arg.tag - if arg.getchildren() != []: - value = generateArgDict(arg, True) - else: - #convert into python if possible, otherwise don't - try: - value = eval(arg.text) - except (NameError,SyntaxError): - value = str(arg.text) - if key in args: #build of lists of like-elements - if type(args[key]) != type([]): - args[key] = [args[key]] - args[key].append(value) - else: - args[key]=value - #if we should be a list but we aren't: - if len(args.keys()) == 1 and recurse: - return args[args.keys()[0]] - return args #Given a dictionary of connections, returns their topological ordering -- (the #order in which they can be visited such that all parents have been visited #before their children. Returns the order or None if no such ordering exists @@ -149,83 +80,12 @@ def topologicalSort(adjacencyDict): def topoTest(): adj = {'a':['d','c'], 'b':['c'], 'c':['e'], 'd':['e'], 'e':[]} print topologicalOrdering(adj) -def getConnectedSocket(ip,port): - sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - print (ip, port) - sock.connect((ip, port)) - return sock -def composePixelStripData(pixelStrip): - packet = bytearray() - for light in pixelStrip: - color = light.state() - for channel in color: #skip the last value, its an - #alpha value - packet.append(struct.pack('B', channel)) - return packet -# packet = [0]*len(pixelStrip.pixels)*3 #preallocate for speed -# for i in range(len(pixelStrip.pixels)): -#color = pixelStrip.pixels[i].state() -#packet[i:i+2] = color -# return bytearray(packet) -def composePixelStripPacket(pixelStrip,port): - packet = bytearray() - data = composePixelStripData(pixelStrip) - 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) - return packet -def kinetHeader(): - header = bytearray() - header.extend(struct.pack('L', MAGIC)) - header.extend(struct.pack('H', VERSION)) - header.extend(struct.pack('H', PORTOUT)) - header.extend(struct.pack('L', 0)) - return header -def kinetPortOut(): - header = kinetHeader() - header.extend(struct.pack('L', UNI)) - return header -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'])) - payload.extend(struct.pack('H', argDict['startcode'])) - #pdb.set_trace() - return payload -def kinetPortOutPacket(payloadArgs): - packet = bytearray() - packet.extend(kinetPortOut()) - packet.extend(kinetPortOutPayload(payloadArgs)) - return packet def testXMLParse(fileName): #pdb.set_trace() config = ElementTree() config.parse(fileName) print generateArgDict(config.find('ChildElement')) print generateArgDict(config.find('Renderer')) -class Stopwatch: - def __init__(self): - self.running = False - self.startTime = -1 - self.stopTime = -1 - def start(self): - self.startTime = Util.time() - self.running = True - def elapsed(self): - if self.running: - return Util.time()-self.startTime - else: - return self.stopTime - self.startTime - def stop(self): - self.stopTime = Util.time() - self.running = False ##CONSTANTS## location = 'Location' diff --git a/behaviors/ColorChangerBehavior.py b/behaviors/ColorChangerBehavior.py index a3b1739..e1827eb 100644 --- a/behaviors/ColorChangerBehavior.py +++ b/behaviors/ColorChangerBehavior.py @@ -1,5 +1,5 @@ from operationscore.Behavior import * -import Util +import util.ColorOps as color import pdb class ColorChangerBehavior(Behavior): def processResponse(self, sensorInputs, recursiveInputs): @@ -7,9 +7,8 @@ class ColorChangerBehavior(Behavior): for sensory in sensorInputs: newDict = dict(sensory) #don't run into shallow copy issues if self['ColorList'] != None: - newDict['Color'] = Util.chooseRandomColor(self['ColorList']) #TODO: this doesn't work. + newDict['Color'] = color.chooseRandomColor(self['ColorList']) #TODO: this doesn't work. else: - newDict['Color'] = Util.randomColor() -#newDict['Color'] = (255,0,0) + newDict['Color'] = color.randomColor() ret.append(newDict) return (ret, recursiveInputs) diff --git a/operationscore/PixelEvent.py b/operationscore/PixelEvent.py index 66b6fdf..27e6e4a 100644 --- a/operationscore/PixelEvent.py +++ b/operationscore/PixelEvent.py @@ -2,6 +2,7 @@ #which should return a color, or None if the response is complete. Consider #requiring a generate event. from operationscore.SmootCoreObject import * +import util.ColorOps as color class PixelEvent(SmootCoreObject): def init(self): self.validateArgs('PixelEvent.params') @@ -11,7 +12,7 @@ class PixelEvent(SmootCoreObject): #Returns a new PixelEvent, but with a response scaled by c. def scale(self,c): newDict = dict(self.argDict) - newDict['Color'] = Util.multiplyColor(newDict['Color'], c) + newDict['Color'] = color.multiplyColor(newDict['Color'], c) return self.__class__(newDict) def state(self,timeDelay): pass diff --git a/operationscore/SmootCoreObject.py b/operationscore/SmootCoreObject.py index 8514b3e..10df299 100644 --- a/operationscore/SmootCoreObject.py +++ b/operationscore/SmootCoreObject.py @@ -2,6 +2,7 @@ import Util import pdb import threading import thread +import util.Config as configGetter class SmootCoreObject(threading.Thread): def __init__(self, argDict, skipValidation = False): self.argDict = argDict @@ -29,7 +30,7 @@ class SmootCoreObject(threading.Thread): def __getiter__(self): return self.argDict.__getiter__() def validateArgs(self, argFileName): - self.validateArgDict(Util.loadParamRequirementDict(argFileName))#util + self.validateArgDict(configGetter.loadParamRequirementDict(argFileName))#util #caches for us, woo! def validateArgDict(self, validationDict): for item in validationDict: diff --git a/pixelcore/Pixel.py b/pixelcore/Pixel.py index ba87dff..f66d0bb 100644 --- a/pixelcore/Pixel.py +++ b/pixelcore/Pixel.py @@ -1,6 +1,7 @@ -import Util +import util.ColorOps as color import pdb from pixelevents.StepEvent import * +import util.TimeOps as clock #Pixel keeps a queue of events (PixelEvent objects) (actually a dictionary #keyed by event time). Every time is state is #requested, it processes all the members of its queue. If a member returns none, @@ -24,7 +25,7 @@ class Pixel: #arg #Add a pixelEvent to the list of active events def processInput(self,pixelEvent,zindex): #consider migrating arg to dict - self.events[Util.time()] = (zindex, pixelEvent) + self.events[clock.time()] = (zindex, pixelEvent) def clearAllEvents(self): self.events = {} #Combines all PixelEvents currently active and computes the current color of @@ -37,13 +38,13 @@ class Pixel: if len(self.events) == 0: return (0,0,0) deadEvents = [] - currentTime = Util.time() + currentTime = clock.time() resultingColor = (0,0,0) for eventTime in self.events: #TODO: right color weighting code (zindex,event) = self.events[eventTime] eventResult = event.state(currentTime-eventTime) if eventResult != None: - resultingColor = Util.combineColors(eventResult, resultingColor) + resultingColor = color.combineColors(eventResult, resultingColor) else: deadEvents.append(eventTime) [self.events.pop(event) for event in deadEvents] diff --git a/pixelevents/DecayEvent.py b/pixelevents/DecayEvent.py index 9a7c600..0b4c820 100644 --- a/pixelevents/DecayEvent.py +++ b/pixelevents/DecayEvent.py @@ -1,5 +1,6 @@ from operationscore.PixelEvent import * -import Util, math +import math +from util.ColorOps import * class DecayEvent(PixelEvent): def initEvent(self): self['Coefficient'] = abs(self['Coefficient']) @@ -8,7 +9,7 @@ class DecayEvent(PixelEvent): decay = math.exp(timeDelay*-1*self['Coefficient']) if self['DecayType'] == 'Proportional': decay = float(self['Coefficient']) / timeDelay - color = Util.multiplyColor(self['Color'], decay) + color = multiplyColor(self['Color'], decay) return color if sum(color) > 5 else None @staticmethod def generate(decayType, coefficient, color): diff --git a/renderers/IndoorRenderer.py b/renderers/IndoorRenderer.py index efe2b3a..2eac162 100644 --- a/renderers/IndoorRenderer.py +++ b/renderers/IndoorRenderer.py @@ -1,15 +1,15 @@ from operationscore.Renderer import * -import socket, Util -import pdb -kinetPort = 6038 +import util.PacketComposition as composer +import util.NetworkOps as network +import socket,pdb +port = 6038 +#Renderer for a Specific Light System. class IndoorRenderer(Renderer): def initRenderer(self): - #pdb.set_trace() self.stripLocations = {} #Dict that stores info necessary to render to #strips - self.sockets = {} #dict of (IP,port)->Socket + self.sockets = {} #dict of (IP)->Socket #a strip -# g self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) powerSupplies = self.argDict['PowerSupply'] if not type(powerSupplies) == type([]): powerSupplies = [powerSupplies] @@ -25,7 +25,7 @@ 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] = Util.getConnectedSocket(ip,kinetPort) - packet = Util.composePixelStripPacket(pixelStrip, port) + self.sockets[ip] = network.getConnectedSocket(ip,port) + packet = composer.composePixelStripPacket(pixelStrip, port) self.sockets[ip].send(packet, 0x00) diff --git a/util/ColorOps.py b/util/ColorOps.py new file mode 100644 index 0000000..b0d64a7 --- /dev/null +++ b/util/ColorOps.py @@ -0,0 +1,11 @@ +import random +def randomColor(): + return [random.randint(0,255) for i in range(3)] +def chooseRandomColor(colorList): + return random.choice(colorList) +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 multiplyColor(color, percent): + return safeColor([channel*(percent) for channel in color]) diff --git a/util/Config.py b/util/Config.py new file mode 100644 index 0000000..4cf2ed5 --- /dev/null +++ b/util/Config.py @@ -0,0 +1,53 @@ +from xml.etree.ElementTree import ElementTree +classArgsMem = {} +CONFIG_PATH = 'config/' +def loadParamRequirementDict(className): + if not className in classArgsMem: #WOO CACHING + classArgsMem[className] = fileToDict(CONFIG_PATH + className) + return classArgsMem[className] +def loadConfigFile(fileName): #TODO: error handling etc. + try: + fileName = CONFIG_PATH + fileName + if '.params' in fileName: + return fileToDict(fileName) + if '.xml' in fileName: + config = ElementTree() + config.parse(fileName) + return config + except: + return None +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: + return {} + if fileText == '': + return {} + return eval(fileText) +#parses arguments into python objects if possible, otherwise leaves as strings +def generateArgDict(parentNode, recurse=False): + args = {} + for arg in parentNode.getchildren(): + key = arg.tag + if arg.getchildren() != []: + value = generateArgDict(arg, True) + else: + #convert into python if possible, otherwise don't + try: + value = eval(arg.text) + except (NameError,SyntaxError): + value = str(arg.text) + if key in args: #build of lists of like-elements + if type(args[key]) != type([]): + args[key] = [args[key]] + args[key].append(value) + else: + args[key]=value + #if we should be a list but we aren't: + if len(args.keys()) == 1 and recurse: + return args[args.keys()[0]] + return args diff --git a/util/NetworkOps.py b/util/NetworkOps.py new file mode 100644 index 0000000..a247090 --- /dev/null +++ b/util/NetworkOps.py @@ -0,0 +1,6 @@ +import socket +def getConnectedSocket(ip,port): + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + print (ip, port) + sock.connect((ip, port)) + return sock diff --git a/util/PacketComposition.py b/util/PacketComposition.py new file mode 100644 index 0000000..5133459 --- /dev/null +++ b/util/PacketComposition.py @@ -0,0 +1,59 @@ +import struct +VERSION = 0x0001 +MAGIC = 0x4adc0104 +MOREMAGIC = 0xdeadbeef +DEEPMAGIC = 0xc001d00d +MAGICHASH = 0x69000420 +PORTOUT = 0x0108 +UNI = 0 +kinetDict = {'flags': 0, 'startcode': 0, 'pad':0} +def composePixelStripData(pixelStrip): + packet = bytearray() + for light in pixelStrip: + color = light.state() + for channel in color: #skip the last value, its an + #alpha value + packet.append(struct.pack('B', channel)) + return packet +# packet = [0]*len(pixelStrip.pixels)*3 #preallocate for speed +# for i in range(len(pixelStrip.pixels)): +#color = pixelStrip.pixels[i].state() +#packet[i:i+2] = color +# return bytearray(packet) +def composePixelStripPacket(pixelStrip,port): + packet = bytearray() + data = composePixelStripData(pixelStrip) + 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) + return packet +def kinetHeader(): + header = bytearray() + header.extend(struct.pack('L', MAGIC)) + header.extend(struct.pack('H', VERSION)) + header.extend(struct.pack('H', PORTOUT)) + header.extend(struct.pack('L', 0)) + return header +def kinetPortOut(): + header = kinetHeader() + header.extend(struct.pack('L', UNI)) + return header +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'])) + payload.extend(struct.pack('H', argDict['startcode'])) + #pdb.set_trace() + return payload +def kinetPortOutPacket(payloadArgs): + packet = bytearray() + packet.extend(kinetPortOut()) + packet.extend(kinetPortOutPayload(payloadArgs)) + return packet diff --git a/util/TimeOps.py b/util/TimeOps.py new file mode 100644 index 0000000..dcd5038 --- /dev/null +++ b/util/TimeOps.py @@ -0,0 +1,19 @@ +import time as clock +def time(): + return clock.time()*1000 #all times in MS +class Stopwatch: + def __init__(self): + self.running = False + self.startTime = -1 + self.stopTime = -1 + def start(self): + self.startTime = time() + self.running = True + def elapsed(self): + if self.running: + return time()-self.startTime + else: + return self.stopTime - self.startTime + def stop(self): + self.stopTime = time() + self.running = False diff --git a/util/__init__.py b/util/__init__.py new file mode 100644 index 0000000..e69de29 -- cgit v1.2.3