aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--LightInstallation.py51
-rw-r--r--Util.py232
-rw-r--r--behaviors/AllPixelsLeft.py11
-rw-r--r--behaviors/BehaviorChain.py6
-rw-r--r--behaviors/ColorChangerBehavior.py7
-rw-r--r--behaviors/DebugBehavior.py1
-rw-r--r--behaviors/DecayBehavior.py4
-rw-r--r--behaviors/EchoBehavior.py4
-rw-r--r--behaviors/ModifyParam.py1
-rw-r--r--behaviors/RunningBehavior.py9
-rw-r--r--config/Outdoor.xml19
-rw-r--r--inputs/PygameInput.py9
-rw-r--r--inputs/TCPInput.py4
-rw-r--r--inputs/TCPInput_backup.py1
-rw-r--r--inputs/UDPInput.py1
-rw-r--r--operationscore/Behavior.py21
-rw-r--r--operationscore/Input.py6
-rw-r--r--operationscore/PixelAssembler.py4
-rw-r--r--operationscore/PixelEvent.py11
-rw-r--r--operationscore/PixelMapper.py1
-rw-r--r--operationscore/SmootCoreObject.py5
-rw-r--r--pixelcore/Pixel.py9
-rw-r--r--pixelcore/PixelStrip.py7
-rw-r--r--pixelcore/Screen.py22
-rw-r--r--pixelevents/DecayEvent.py5
-rw-r--r--pixelmappers/GaussianMapper.py6
-rw-r--r--pixelmappers/SimpleMapper.py35
-rw-r--r--renderers/IndoorRenderer.py31
-rw-r--r--util/ColorOps.py11
-rw-r--r--util/ComponentRegistry.py43
-rw-r--r--util/Config.py53
-rw-r--r--util/Geo.py15
-rw-r--r--util/NetworkOps.py8
-rw-r--r--util/PacketComposition.py57
-rw-r--r--util/Search.py8
-rw-r--r--util/Strings.py2
-rw-r--r--util/TimeOps.py19
-rw-r--r--util/__init__.py0
39 files changed, 402 insertions, 341 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..9d4e9cb
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+*.pyc
+*.swp
+*.swo
+*.pyo
diff --git a/LightInstallation.py b/LightInstallation.py
index 87aa629..5882806 100644
--- a/LightInstallation.py
+++ b/LightInstallation.py
@@ -1,8 +1,11 @@
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
+import util.ComponentRegistry as compReg
from logger import main_log
#Python class to instantiate and drive a Screen through different patterns,
#and effects.
@@ -10,7 +13,7 @@ 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))
- 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 = {}
@@ -20,38 +23,43 @@ 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)
- config = Util.loadConfigFile(configFileName)
+ compReg.initRegistry()
+ compReg.registerComponent(self.screen, 'Screen') #TODO: move to constants file
+ config = configGetter.loadConfigFile(configFileName)
#read configs from xml
rendererConfig = config.find('RendererConfiguration')
pixelConfig = config.find('PixelConfiguration')
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)
+ 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,14 +80,14 @@ 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 = []
if config != None:
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
@@ -89,12 +97,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()
@@ -102,7 +110,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()
@@ -124,9 +132,6 @@ class LightInstallation:
self.behaviors = self.initializeComponent(behaviorConfig)
for behavior in self.behaviors:
self.addBehavior(behavior)
- #TODO: we probably don't need this anymore :(
- def topologicalBehaviorSort(self):
- return Util.topologicalSort(self.behaviorDependencies)
#Does work needed to add a behavior: currently -- maps behavior inputs into
#the input behavior registry.
def addBehavior(self, behavior):
@@ -136,8 +141,12 @@ class LightInstallation:
def processResponse(self,inputDict, responseDict):
inputId = inputDict['Id']
boundBehaviorIds = self.inputBehaviorRegistry[inputId]
- [self.componentDict[b].addInput(responseDict) for b in boundBehaviorIds]
-
+ #TODO: fix this, it crashes because inputs get run before beahviors exist
+ try:
+ [compReg.getComponent(b).addInput(responseDict) for b in boundBehaviorIds]
+ except:
+ pass
+ #print 'Behaviors not initialized yet. WAIT!'
def main(argv):
print argv
if len(argv) == 1:
diff --git a/Util.py b/Util.py
deleted file mode 100644
index 07ce545..0000000
--- a/Util.py
+++ /dev/null
@@ -1,232 +0,0 @@
-import pdb
-from xml.etree.ElementTree import ElementTree
-import math,struct
-from bisect import *
-#import json # json.loads() to decode string; json.dumps() to encode data
-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 = {}
-CONFIG_PATH = 'config/'
-kinetDict = {'flags': 0, 'startcode': 0, 'pad':0}
-componentDict = {}
-#Only for rough estimates. Kindof lazy on specifics.
-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))
-def addLocations(l1,l2):
- return tuple([l1[i]+l2[i] for i in range(len(l1))])
-def setScreen(screen):
- globals()["screen"] = screen
-def getScreen():
- return screen
-def setComponentDict(componentDictRef):
- globals()["componentDict"] = componentDictRef
-def getComponentById(cid):
- if cid in componentDict:
- return componentDict[cid]
- else:
- return None
-def addPixelEventIfMissing(responseDict):
- if not 'PixelEvent' in responseDict:
- if 'Color' in responseDict:
- color = responseDict['Color']
- else:
- raise Exception('Need Color. Probably')
- responseDict['PixelEvent'] = StepEvent.generate(300, color)
-def gaussian(x,height,center,width):
- a=height
- b=center
- c=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
-
-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
-#(the graph contains a cycle).
-def topologicalSort(adjacencyDict):
- def dfsVisit(vertex):
- gray[vertex] = 1
- for child in adjacencyDict[vertex]:
- if not child in visited:
- if child in gray: #We have a cycle. No topological ordering
- #exists!
- raise Exception('Cycle!')
- dfsVisit(child)
- orderedList.insert(0, vertex)
- visited[vertex] = 1
- orderedList = []
- visited = {}
- gray = {}
- for vertex in adjacencyDict:
- try:
- if not vertex in visited:
- dfsVisit(vertex)
- except:
- return None #cycle
- return orderedList
-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/AllPixelsLeft.py b/behaviors/AllPixelsLeft.py
new file mode 100644
index 0000000..7f731e9
--- /dev/null
+++ b/behaviors/AllPixelsLeft.py
@@ -0,0 +1,11 @@
+from operationscore.Behavior import *
+import util.ComponentRegistry as compReg
+import pdb
+class AllPixelsLeft(Behavior):
+ def processResponse(self, sensorInputs, recursiveInputs):
+ for sensory in sensorInputs:
+ xLoc = sensory['Location'][0]
+ if type(xLoc) == type(tuple()):
+ pdb.set_trace()
+ sensory['Location'] = '[{x}<' + str(xLoc) + ']'
+ return (sensorInputs, recursiveInputs)
diff --git a/behaviors/BehaviorChain.py b/behaviors/BehaviorChain.py
index fe50573..98585c9 100644
--- a/behaviors/BehaviorChain.py
+++ b/behaviors/BehaviorChain.py
@@ -1,5 +1,5 @@
from operationscore.Behavior import *
-import Util
+import util.ComponentRegistry as compReg
import pdb
class BehaviorChain(Behavior):
def behaviorInit(self):
@@ -10,7 +10,7 @@ class BehaviorChain(Behavior):
def processResponse(self, sensorInputs, recursiveInputs):
response = sensorInputs
for behaviorId in self['ChainedBehaviors']:
- behavior = Util.getComponentById(behaviorId)
+ behavior = compReg.getComponent(behaviorId)
if behaviorId in self.feedback:
recurrence = self.feedback[behaviorId]
else:
@@ -19,7 +19,7 @@ class BehaviorChain(Behavior):
recurrence)
if behaviorId in self.hooks: #process recursive hook if there is one
- hookBehavior = Util.getComponentById(self.hooks[behaviorId])
+ hookBehavior = compReg.getComponent(self.hooks[behaviorId])
#we feed its recurrence in as input to the behavior.
(recurrence, hookRecurrence) = \
hookBehavior.immediateProcessInput(recurrence, \
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/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 edc833d..c1f6f92 100644
--- a/behaviors/DecayBehavior.py
+++ b/behaviors/DecayBehavior.py
@@ -1,13 +1,13 @@
from operationscore.Behavior import *
from pixelevents.DecayEvent import *
-import Util
+import util.Strings as Strings
import pdb
class DecayBehavior(Behavior):
def processResponse(self, sensorInputs, recursiveInputs):
ret = []
for sensory in sensorInputs:
outDict = {}
- outDict[Util.location] = sensory[Util.location]
+ outDict[Strings.LOCATION] = sensory[Strings.LOCATION]
outDict['PixelEvent'] = \
DecayEvent.generate(self['DecayType'],self['Coefficient'], sensory['Color'])
ret.append(outDict)
diff --git a/behaviors/EchoBehavior.py b/behaviors/EchoBehavior.py
index a11558a..be0ed14 100644
--- a/behaviors/EchoBehavior.py
+++ b/behaviors/EchoBehavior.py
@@ -1,12 +1,12 @@
from operationscore.Behavior import *
-import Util
+import util.Strings as Strings
import pdb
class EchoBehavior(Behavior):
def processResponse(self, sensorInputs, recursiveInputs):
ret = []
for sensory in sensorInputs:
outDict = {}
- outDict[Util.location] = sensory[Util.location]
+ outDict[Strings.LOCATION] = sensory[Strings.LOCATION]
outDict['Color'] = (255,0,0)
ret.append(outDict)
return ret
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 3d82d29..92db69b 100644
--- a/behaviors/RunningBehavior.py
+++ b/behaviors/RunningBehavior.py
@@ -1,6 +1,7 @@
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
@@ -12,10 +13,10 @@ class RunningBehavior(Behavior):
outDict['Dir'] = 1 #to the right
if not 'StepSize' in outDict:
outDict['StepSize'] = self['StepSize']
- outDict['Location']= Util.addLocations(outDict['Location'],
+ outDict['Location']= Geo.addLocations(outDict['Location'],
(outDict['StepSize']*outDict['Dir'],0))
- if not Util.pointWithinBoundingBox(outDict['Location'], \
- Util.getScreen().getSize()):
+ if not Geo.pointWithinBoundingBox(outDict['Location'], \
+ compReg.getComponent('Screen').getSize()):
outDict['Dir'] *= -1
ret.append(outDict)
ret += newResponses
diff --git a/config/Outdoor.xml b/config/Outdoor.xml
index 7f054f0..1cf00e4 100644
--- a/config/Outdoor.xml
+++ b/config/Outdoor.xml
@@ -1,5 +1,10 @@
<!---All configuration items contain a "Class" tag specifying the python class they represent, and an "Args" tag specifying the args to be passed in.-->
<LightInstallation>
+ <InstallationConfiguration>
+ <Defaults>
+ <PixelMapper>simplemap</PixelMapper>
+ </Defaults>
+ </InstallationConfiguration>
<PixelConfiguration>
<PixelStrip>
<Class>layouts.LineLayout</Class>
@@ -62,15 +67,13 @@
</Args>
</PixelStrip>
</PixelConfiguration>
- <!--<PixelMapperConfiguration>
+ <PixelMapperConfiguration>
<PixelMapper>
<Class>pixelmappers.SimpleMapper</Class>
<Args>
<Id>simplemap</Id>
</Args>
</PixelMapper>
- </PixelMapperConfiguration>-->
- <PixelMapperConfiguration>
<PixelMapper>
<Class>pixelmappers.GaussianMapper</Class>
<Args>
@@ -120,7 +123,7 @@
<Class>inputs.PygameInput</Class>
<Args>
<Id>followmouse</Id>
- <RefreshInterval>10</RefreshInterval>
+ <RefreshInterval>50</RefreshInterval>
<FollowMouse>True</FollowMouse>
</Args>
</InputElement>
@@ -181,6 +184,12 @@
</Args>
</Behavior>
<Behavior>
+ <Class>behaviors.AllPixelsLeft</Class>
+ <Args>
+ <Id>pixelsleft</Id>
+ </Args>
+ </Behavior>
+ <Behavior>
<Class>behaviors.RecursiveDecay</Class>
<Args>
<Id>recursivedecay</Id>
@@ -201,6 +210,7 @@
</ChainedBehaviors>
<RecursiveHooks>{'running':'acceleratedie'}</RecursiveHooks>
<RenderToScreen>True</RenderToScreen>
+ <Mapper>gaussmap</Mapper>
</Args>
</Behavior>
<Behavior>
@@ -231,6 +241,7 @@
</Inputs>
<ChainedBehaviors>
<Id>echo</Id>
+ <Id>pixelsleft</Id>
<Id>colorchange</Id>
<Id>decay</Id>
</ChainedBehaviors>
diff --git a/inputs/PygameInput.py b/inputs/PygameInput.py
index 1f438d6..6779a20 100644
--- a/inputs/PygameInput.py
+++ b/inputs/PygameInput.py
@@ -1,4 +1,5 @@
-import time, Util
+import time
+import util.Strings as Strings
from operationscore.Input import *
import pygame
from pygame.locals import *
@@ -8,13 +9,13 @@ class PygameInput(Input):
def sensingLoop(self):
#try:
if self['FollowMouse']:
- self.respond({Util.location: pygame.mouse.get_pos()})
+ self.respond({Strings.LOCATION: pygame.mouse.get_pos()})
return
for event in pygame.event.get():
if event.type is KEYDOWN:
- self.respond({Util.location: (5,5),'Key': event.key})
+ self.respond({Strings.LOCATION: (5,5),'Key': event.key})
if event.type is MOUSEBUTTONDOWN:
- self.respond({Util.location: pygame.mouse.get_pos()})
+ self.respond({Strings.LOCATION: pygame.mouse.get_pos()})
#except:
#raise Exception('Pygame not initialized. Pygame must be \
#initialized.')
diff --git a/inputs/TCPInput.py b/inputs/TCPInput.py
index acd6243..1517afa 100644
--- a/inputs/TCPInput.py
+++ b/inputs/TCPInput.py
@@ -1,4 +1,4 @@
-import Util
+import util.Strings as Strings
from operationscore.Input import *
import socket, json, time
class TCPInput(Input):
@@ -25,7 +25,7 @@ class TCPInput(Input):
if self.IS_RESPONDING == 1: # if 'responding', respond to the received data
dataDict = json.loads(data)
# socketDict = {'data':dataDict, 'address':self.address}
- socketDict = {Util.location: (100 * (1 - dataDict['x'] / 10), 25 * (1 + dataDict['y'] / 10))} # like PygameInput
+ socketDict = {Strings.LOCATION: (100 * (1 - dataDict['x'] / 10), 25 * (1 + dataDict['y'] / 10))} # like PygameInput
self.respond(socketDict)
else:
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 b6e35ac..6878f8a 100644
--- a/operationscore/PixelAssembler.py
+++ b/operationscore/PixelAssembler.py
@@ -1,5 +1,5 @@
from operationscore.SmootCoreObject import *
-import Util
+import util.Geo as Geo
import pdb
class PixelAssembler(SmootCoreObject):
def init(self):
@@ -17,7 +17,7 @@ class PixelAssembler(SmootCoreObject):
if newLocation == None:
raise Exception('Location cannot be null. layoutFunc not \
defined or improperly defined.')
- if Util.dist(newLocation, locations[-1]) > \
+ if Geo.dist(newLocation, locations[-1]) > \
self['pixelToPixelSpacing']:
raise Exception('Illegal pixel location. Distance \
between adjacent pixels must be less than \
diff --git a/operationscore/PixelEvent.py b/operationscore/PixelEvent.py
index 66b6fdf..e2b852a 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,8 +12,16 @@ 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
+ @staticmethod
+ def addPixelEventIfMissing(responseDict):
+ if not 'PixelEvent' in responseDict:
+ if 'Color' in responseDict:
+ color = responseDict['Color']
+ else:
+ raise Exception('Need Color. Probably')
+ responseDict['PixelEvent'] = StepEvent.generate(300, color)
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 8514b3e..9784aab 100644
--- a/operationscore/SmootCoreObject.py
+++ b/operationscore/SmootCoreObject.py
@@ -1,12 +1,13 @@
-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
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__
@@ -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/pixelcore/PixelStrip.py b/pixelcore/PixelStrip.py
index c82a87a..fceff8e 100644
--- a/pixelcore/PixelStrip.py
+++ b/pixelcore/PixelStrip.py
@@ -1,8 +1,9 @@
from pixelcore.Pixel import *
+import util.Strings as Strings
+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:
@@ -21,7 +22,7 @@ class PixelStrip:
[l.turnOnFor(time) for l in self.pixels] #TODO: add test-on method to
#pixels
def respond(self, responseInfo):
- location = responseInfo[Util.location]
+ location = responseInfo[Strings.LOCATION]
if not 'PixelEvent' in responseInfo:
if 'Color' in responseInfo:
color = responseInfo['Color']
@@ -32,7 +33,7 @@ class PixelStrip:
pixel.processInput(responseInfo['PixelEvent'], 0) #TODO: z-index
def getPixelNearest(self, location):
- dists = [(Util.dist(location, pixel.location), pixel) for pixel in self.pixels]
+ dists = [(Geo.dist(location, pixel.location), pixel) for pixel in self.pixels]
dists.sort()
return dists[0]
#just for now.
diff --git a/pixelcore/Screen.py b/pixelcore/Screen.py
index 92805a8..da03ad2 100644
--- a/pixelcore/Screen.py
+++ b/pixelcore/Screen.py
@@ -1,5 +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.
@@ -17,8 +22,8 @@ class Screen:
self.computeXSortedPixels()
#Returns (pixelIndex, pixel). Does a binary search.
def pixelsInRange(self, minX, maxX):
- minIndex = Util.find_ge(self.xPixelLocs, minX)
- maxIndex = Util.find_le(self.xPixelLocs, maxX)+1
+ minIndex = Search.find_ge(self.xPixelLocs, minX)
+ maxIndex = Search.find_le(self.xPixelLocs, maxX)+1
return self.xSortedPixels[minIndex:maxIndex]
def computeXSortedPixels(self):
for pixel in self:
@@ -27,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
@@ -68,9 +71,14 @@ 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)
- Util.addPixelEventIfMissing(responseInfo)
+ 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/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/pixelmappers/GaussianMapper.py b/pixelmappers/GaussianMapper.py
index 04bd447..8755acf 100644
--- a/pixelmappers/GaussianMapper.py
+++ b/pixelmappers/GaussianMapper.py
@@ -1,13 +1,13 @@
from operationscore.PixelMapper import *
-import Util
+import util.Geo as Geo
class GaussianMapper(PixelMapper):
def mappingFunction(self, eventLocation, screen):
returnPixels = [] #TODO: consider preallocation and trimming
[x,y] = eventLocation
for (x,pixel) in screen.pixelsInRange(x-self['CutoffDist'], \
x+self['CutoffDist']):
- pixelDist = Util.dist(pixel.location, eventLocation)
+ pixelDist = Geo.dist(pixel.location, eventLocation)
if pixelDist < self['CutoffDist']:
- w = Util.gaussian(pixelDist, self['Height'], 0, self['Width'])
+ w = Geo.gaussian(pixelDist, self['Height'], 0, self['Width'])
returnPixels.append((pixel, w))
return returnPixels
diff --git a/pixelmappers/SimpleMapper.py b/pixelmappers/SimpleMapper.py
index 7d730f1..bc51cf9 100644
--- a/pixelmappers/SimpleMapper.py
+++ b/pixelmappers/SimpleMapper.py
@@ -1,14 +1,29 @@
from operationscore.PixelMapper import *
-import Util
+import util.Geo as Geo
class SimpleMapper(PixelMapper):
def mappingFunction(self, eventLocation, screen):
- bestDist = 10**10 #don't kill me, I'm lazy
- bestPixel = None
- for pixel in screen:
- pixelDist = Util.dist(pixel.location, eventLocation)
- if pixelDist < bestDist:
- bestPixel = pixel
- bestDist = pixelDist
- return [(bestPixel,1)]
-
+ if type(eventLocation) == type(tuple()):
+ bestDist = 10**10 #don't kill me, I'm lazy
+ bestPixel = None
+ for pixel in screen:
+ pixelDist = Geo.dist(pixel.location, eventLocation)
+ if pixelDist < bestDist:
+ bestPixel = pixel
+ bestDist = pixelDist
+ return [(bestPixel,1)]
+ elif type(type(str)):
+ #[{x}>5,{y}<k]
+ #TODO: we should probably encapsulate this somewhere
+ ret = []
+ eventLocation = eventLocation.replace('{x}', 'pixel.location[0]')
+ eventLocation = eventLocation.replace('{y}', 'pixel.location[1]')
+ for pixel in screen:
+ try:
+ pixelValid = sum(eval(eventLocation)) == len(eval(eventLocation)) #TODO: some
+ #optimizations possible. This might be slow in the long run
+ if pixelValid:
+ ret.append((pixel, 1))
+ except:
+ raise Exception('Bad event condition')
+ return ret
diff --git a/renderers/IndoorRenderer.py b/renderers/IndoorRenderer.py
index efe2b3a..c13d11f 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]
@@ -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] = Util.getConnectedSocket(ip,kinetPort)
- packet = Util.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/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/ComponentRegistry.py b/util/ComponentRegistry.py
new file mode 100644
index 0000000..119ce18
--- /dev/null
+++ b/util/ComponentRegistry.py
@@ -0,0 +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
+def initRegistry():
+ globals()['Registry'] = {}
+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]
diff --git a/util/Config.py b/util/Config.py
new file mode 100644
index 0000000..f80b7b2
--- /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/Geo.py b/util/Geo.py
new file mode 100644
index 0000000..885c585
--- /dev/null
+++ b/util/Geo.py
@@ -0,0 +1,15 @@
+#Geometry code
+import math
+from bisect import *
+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))
+def addLocations(l1,l2):
+ return tuple([l1[i]+l2[i] for i in range(len(l1))])
+def gaussian(x,height,center,width):
+ a=height
+ b=center
+ c=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))]))
diff --git a/util/NetworkOps.py b/util/NetworkOps.py
new file mode 100644
index 0000000..0404975
--- /dev/null
+++ b/util/NetworkOps.py
@@ -0,0 +1,8 @@
+import socket
+def getConnectedSocket(ip,port):
+ sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ try:
+ sock.connect((ip, port))
+ except:
+ print 'network down'
+ return sock
diff --git a/util/PacketComposition.py b/util/PacketComposition.py
new file mode 100644
index 0000000..2563c61
--- /dev/null
+++ b/util/PacketComposition.py
@@ -0,0 +1,57 @@
+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
+ 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']))
+ return payload
+def kinetPortOutPacket(payloadArgs):
+ packet = bytearray()
+ packet.extend(kinetPortOut())
+ packet.extend(kinetPortOutPayload(payloadArgs))
+ return packet
diff --git a/util/Search.py b/util/Search.py
new file mode 100644
index 0000000..25882da
--- /dev/null
+++ b/util/Search.py
@@ -0,0 +1,8 @@
+from bisect import *
+def find_le(a, x):
+ 'Find rightmost value less than or equal to x'
+ return bisect_right(a, x)-1
+
+def find_ge(a, x):
+ 'Find leftmost value greater than x'
+ return bisect_left(a, x)
diff --git a/util/Strings.py b/util/Strings.py
new file mode 100644
index 0000000..81c34f2
--- /dev/null
+++ b/util/Strings.py
@@ -0,0 +1,2 @@
+LOCATION = 'Location'
+DEFAULT_MAPPER = 'DefaultPixelMapper'
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
--- /dev/null
+++ b/util/__init__.py