aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--LightInstallation.py11
-rw-r--r--Profile.py4
-rw-r--r--ResponseMover.py15
-rw-r--r--TestProfile.py34
-rw-r--r--behaviors/Accelerate.xml8
-rw-r--r--behaviors/LoopAndDie.xml6
-rw-r--r--behaviors/PixelDecay.xml9
-rw-r--r--behaviors/RandomColor.xml8
-rw-r--r--behaviors/RandomWalk.py5
-rw-r--r--behaviors/RunningBehavior.xml8
-rw-r--r--config/Outdoor.xml79
-rw-r--r--inputs/PygameInput.py2
-rw-r--r--inputs/RandomLocs.py13
-rw-r--r--layouts/50PixelStrip.xml8
-rw-r--r--layouts/BasicSixStrip.xml42
-rw-r--r--logger/loggingConfig.ini4
-rw-r--r--operationscore/Input.py4
-rw-r--r--operationscore/Renderer.py4
-rw-r--r--operationscore/SmootCoreObject.py3
-rw-r--r--operationscore/ThreadedSmootCoreObject.py14
-rw-r--r--pixelcore/Pixel.py21
-rw-r--r--pixelcore/Screen.py17
-rw-r--r--pixelevents/DecayEvent.py22
-rw-r--r--pixelmappers/GaussianMapper.py3
-rw-r--r--pixelmappers/SimpleMapper.py2
-rw-r--r--renderers/IndoorRenderer.py9
-rw-r--r--renderers/Pygame.xml7
-rw-r--r--renderers/SixStripUDP.xml18
-rw-r--r--tests/testdata/compositeTESTout.xml10
-rw-r--r--tests/testdata/compositeTRUTH.xml10
-rw-r--r--tests/testdata/inheritanceTEST.xml21
-rw-r--r--tests/testdata/inheritanceTESTout.xml14
-rw-r--r--tests/testdata/inheritanceTRUTH.xml14
-rw-r--r--tests/testdata/override.xml2
-rw-r--r--util/ColorOps.py24
-rw-r--r--util/Config.py33
-rw-r--r--util/Geo.py6
-rw-r--r--util/NetworkOps.py3
-rw-r--r--util/PacketComposition.py2
-rw-r--r--util/Search.py14
40 files changed, 381 insertions, 152 deletions
diff --git a/LightInstallation.py b/LightInstallation.py
index 8b2d059..db7b808 100644
--- a/LightInstallation.py
+++ b/LightInstallation.py
@@ -88,11 +88,7 @@ class LightInstallation:
def initializeComponent(self, config):
components = []
if config != None:
- config = configGetter.resolveConfigInheritance(config)
for configItem in config.getchildren():
- configItem = configGetter.resolveConfigInheritance(configItem) #resolve
- #inheritences. TODO: migrate to a recursive inheritence resolver that gets run on
- #file-parse
try:
[module,className] = configItem.find('Class').text.split('.')
except:
@@ -102,11 +98,12 @@ class LightInstallation:
try:
exec('from ' + module+'.'+className + ' import *')
main_log.debug(module +'.' +className + 'imported')
- except:
+ 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.generateArgDict(configItem.find('Args'))
+ args = configGetter.pullArgsFromItem(configItem)
args['parentScope'] = self #TODO: we shouldn't give away scope
#like this, find another way.
try:
@@ -124,7 +121,7 @@ class LightInstallation:
#self.screen.allOn()
lastLoopTime = clock.time()
refreshInterval = 30
- runCount = 10000
+ runCount = 3000
while runCount > 0:
runCount -= 1
loopStart = clock.time()
diff --git a/Profile.py b/Profile.py
new file mode 100644
index 0000000..45ccc35
--- /dev/null
+++ b/Profile.py
@@ -0,0 +1,4 @@
+import cProfile
+from LightInstallation import main
+command = """main(['', 'config/Outdoor.xml'])"""
+cProfile.runctx(command, globals(), locals(), filename="smootlight.profile")
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/TestProfile.py b/TestProfile.py
new file mode 100644
index 0000000..eccb884
--- /dev/null
+++ b/TestProfile.py
@@ -0,0 +1,34 @@
+import cProfile
+from LightInstallation import main
+numiter = 10000000
+def main1():
+ for i in xrange(0,numiter):
+ if 'abc' == 'def':
+ pass
+ if 'abc' == 'abc':
+ pass
+
+def main2():
+ for i in xrange(0,numiter):
+ if 1 == 2:
+ pass
+ if 1 == 1:
+ pass
+
+x = [1,2,3]
+a = []
+def abc1():
+ for i in xrange(0,numiter):
+ a = min(4, 255)
+ b = min(257, 255)
+
+def abc2():
+ for i in xrange(0,numiter):
+ a = 4 if 4 < 255 else 255
+ b = 257 if 257 < 255 else 255
+command = """abc1()"""
+cProfile.runctx(command, globals(), locals())
+
+command = """abc2()"""
+cProfile.runctx(command, globals(), locals())
+
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/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 65df4d0..9ca33e9 100644
--- a/config/Outdoor.xml
+++ b/config/Outdoor.xml
@@ -20,13 +20,19 @@
<Args>
<Id>gaussmap</Id>
<CutoffDist>20</CutoffDist>
- <Width>1</Width>
+ <MinWeight>0.01</MinWeight>
+ <Width>3</Width>
<Height>1</Height>
</Args>
</PixelMapper>
</PixelMapperConfiguration>
<RendererConfiguration>
- <InheritsFrom>renderers/SixStripUDPPygame.xml</InheritsFrom>
+ <Renderer>
+ <InheritsFrom>renderers/SixStripUDP.xml</InheritsFrom>
+ </Renderer>
+ <Renderer>
+ <InheritsFrom>renderers/Pygame.xml</InheritsFrom>
+ </Renderer>
</RendererConfiguration>
<InputConfiguration>
<InputElement>
@@ -36,9 +42,15 @@
<RefreshInterval>100</RefreshInterval>
</Args>
</InputElement>
- <InputElement>
+ <InputElement Id="followmouse">
<InheritsFrom>inputs/MouseFollower.xml</InheritsFrom>
</InputElement>
+ <InputElement>
+ <Class>inputs.RandomLocs</Class>
+ <Args>
+ <Id>randomLoc</Id>
+ </Args>
+ </InputElement>
</InputConfiguration>
<BehaviorConfiguration>
<Behavior>
@@ -49,29 +61,11 @@
<RenderToScreen>False</RenderToScreen>
</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>
- </Args>
+ <Behavior Id="decay">
+ <InheritsFrom>behaviors/PixelDecay.xml</InheritsFrom>
</Behavior>
<Behavior>
<Class>behaviors.DebugBehavior</Class>
@@ -89,12 +83,8 @@
<Id>pixelsleft</Id>
</Args>
</Behavior>
- <Behavior>
- <Class>behaviors.RecursiveDecay</Class>
- <Args>
- <Id>recursivedecay</Id>
- <InitialResponseCount>700</InitialResponseCount>
- </Args>
+ <Behavior Id="recursivedecay">
+ <InheritsFrom>behaviors/LoopAndDie.xml</InheritsFrom>
</Behavior>
<Behavior>
<Class>behaviors.BehaviorChain</Class>
@@ -102,6 +92,7 @@
<Id>runcolordecay</Id>
<Inputs>
<Id>pygame</Id>
+ <Id>randomLoc</Id>
</Inputs>
<ChainedBehaviors>
<Id>colorchange</Id>
@@ -110,17 +101,11 @@
</ChainedBehaviors>
<RecursiveHooks>{'running':'acceleratedie'}</RecursiveHooks>
<RenderToScreen>True</RenderToScreen>
- <!--<Mapper>gaussmap</Mapper>-->
+ <Mapper>gaussmap</Mapper>
</Args>
</Behavior>
- <Behavior>
- <Class>behaviors.ModifyParam</Class>
- <Args>
- <Id>accelerate</Id>
- <ParamType>Sensor</ParamType>
- <ParamName>StepSize</ParamName>
- <ParamOp>{val}*1.01</ParamOp>
- </Args>
+ <Behavior Id="accelerate">
+ <InheritsFrom>behaviors/Accelerate.xml</InheritsFrom>
</Behavior>
<Behavior>
<Class>behaviors.BehaviorChain</Class>
@@ -144,19 +129,11 @@
<Id>pixelsleft</Id>
<Id>decay</Id>
</ChainedBehaviors>
- <RenderToScreen>True</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>
+ <Behavior Id="running">
+ <InheritsFrom>behaviors/RunningBehavior.xml</InheritsFrom>
+ </Behavior>
</BehaviorConfiguration>
</LightInstallation>
diff --git a/inputs/PygameInput.py b/inputs/PygameInput.py
index 6779a20..a39c089 100644
--- a/inputs/PygameInput.py
+++ b/inputs/PygameInput.py
@@ -13,6 +13,8 @@ class PygameInput(Input):
return
for event in pygame.event.get():
if event.type is KEYDOWN:
+ if event.key == 301:
+ exit()
self.respond({Strings.LOCATION: (5,5),'Key': event.key})
if event.type is MOUSEBUTTONDOWN:
self.respond({Strings.LOCATION: pygame.mouse.get_pos()})
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/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/logger/loggingConfig.ini b/logger/loggingConfig.ini
index ee35749..6727c26 100644
--- a/logger/loggingConfig.ini
+++ b/logger/loggingConfig.ini
@@ -18,7 +18,7 @@ level = INFO
handlers = console
[logger_smoot_light]
-level = INFO
+level = DEBUG
handlers = file
qualname = smoot_light
propagate = 0
@@ -40,7 +40,7 @@ formatter = generic
[handler_file]
class = FileHandler
args = ('/var/log/smoot_light/main.log', 'a')
-level = INFO
+level = DEBUG
formatter = generic
[handler_exception]
diff --git a/operationscore/Input.py b/operationscore/Input.py
index 9e8841a..3dd74cf 100644
--- a/operationscore/Input.py
+++ b/operationscore/Input.py
@@ -1,6 +1,6 @@
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
#interval specified in RefreshInterval while the input is active. For example, if you are writing
@@ -8,7 +8,7 @@ from logger import main_log, exception_log
#Inheriting classes MAY define inputInit. This is called before the loop
#begins.
import pdb
-class Input(SmootCoreObject):
+class Input(ThreadedSmootCoreObject):
#Event scope is a function pointer the function that will get called when
#an Parent is raised.
def __init__(self, argDict):
diff --git a/operationscore/Renderer.py b/operationscore/Renderer.py
index 8e31f8b..88da606 100644
--- a/operationscore/Renderer.py
+++ b/operationscore/Renderer.py
@@ -3,8 +3,8 @@
#Inheriting classes may define initRenderer which is called after the dictionary
#is pulled from config.
#TODO: multithreaded-rendering
-from operationscore.SmootCoreObject import *
-class Renderer(SmootCoreObject):
+from operationscore.ThreadedSmootCoreObject import *
+class Renderer(ThreadedSmootCoreObject):
def init(self):
self.initRenderer()
threading.Thread.__init__(self)
diff --git a/operationscore/SmootCoreObject.py b/operationscore/SmootCoreObject.py
index 26b3fc2..291519a 100644
--- a/operationscore/SmootCoreObject.py
+++ b/operationscore/SmootCoreObject.py
@@ -2,12 +2,11 @@ import pdb
import threading
import thread
import util.Config as configGetter
-class SmootCoreObject(threading.Thread):
+class SmootCoreObject(object):
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__
diff --git a/operationscore/ThreadedSmootCoreObject.py b/operationscore/ThreadedSmootCoreObject.py
new file mode 100644
index 0000000..90611bc
--- /dev/null
+++ b/operationscore/ThreadedSmootCoreObject.py
@@ -0,0 +1,14 @@
+import pdb
+import threading
+import thread
+import util.Config as configGetter
+from operationscore.SmootCoreObject import SmootCoreObject
+class ThreadedSmootCoreObject(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__
diff --git a/pixelcore/Pixel.py b/pixelcore/Pixel.py
index f66d0bb..9f5cc85 100644
--- a/pixelcore/Pixel.py
+++ b/pixelcore/Pixel.py
@@ -1,7 +1,7 @@
import util.ColorOps as color
import pdb
from pixelevents.StepEvent import *
-import util.TimeOps as clock
+import util.TimeOps as timeops
#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,
@@ -10,12 +10,15 @@ import util.TimeOps as clock
class Pixel:
radius = 2
timeOff = -1
+
def __init__(self, location):
self.location = location
self.events = {}
self.memState = None
+
def turnOn(self):
self.turnOnFor(-1)
+
#Turn the light white for 'time' ms. Really only meant for testing. Use
#processInput instead. Also, you shouldn't use this anyway. You should be
#using the input method on the screen!
@@ -23,34 +26,42 @@ class Pixel:
event = StepEvent.generate(time, (255,255,255)) #TODO: Move color to
self.processInput(event, 0)
#arg
+
#Add a pixelEvent to the list of active events
def processInput(self,pixelEvent,zindex): #consider migrating arg to dict
- self.events[clock.time()] = (zindex, pixelEvent)
+ self.events[timeops.time()] = (zindex, pixelEvent)
+
def clearAllEvents(self):
self.events = {}
+
#Combines all PixelEvents currently active and computes the current color of
#the pixel.
def invalidateState(self):
self.memState = None
+
def state(self):
if self.memState != None:
return self.memState
- if len(self.events) == 0:
+ if self.events == []:
return (0,0,0)
deadEvents = []
- currentTime = clock.time()
+ currentTime = timeops.time()
resultingColor = (0,0,0)
+ colors = []
for eventTime in self.events: #TODO: right color weighting code
(zindex,event) = self.events[eventTime]
eventResult = event.state(currentTime-eventTime)
if eventResult != None:
- resultingColor = color.combineColors(eventResult, resultingColor)
+ colors.append(eventResult)
else:
deadEvents.append(eventTime)
+
+ resultingColor = color.combineColors(colors)
[self.events.pop(event) for event in deadEvents]
resultingColor = [int(round(c)) for c in resultingColor]
self.memState = tuple(resultingColor)
return tuple(resultingColor)
+
def __str__(self):
return 'Loc: ' + str(self.location)
diff --git a/pixelcore/Screen.py b/pixelcore/Screen.py
index da03ad2..b002896 100644
--- a/pixelcore/Screen.py
+++ b/pixelcore/Screen.py
@@ -6,6 +6,8 @@ import util.Search as Search
import util.ComponentRegistry as compReg
import util.Strings as Strings
import itertools
+import sys
+from logger import main_log
#Class representing a collection of Pixels grouped into PixelStrips. Needs a
#PixelMapper, currently set via setMapper by may be migrated into the argDict.
class Screen:
@@ -15,28 +17,35 @@ class Screen:
self.xSortedPixels = []
self.xPixelLocs = []
sizeValid = False
+
def addStrip(self, lS):
self.pixelStrips.append(lS)
self.sizeValid = False #keep track of whether or not our screen size has
#been invalidated by adding more pixels
self.computeXSortedPixels()
+
#Returns (pixelIndex, pixel). Does a binary search.
def pixelsInRange(self, minX, maxX):
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:
self.xSortedPixels.append((pixel.location[0], pixel))
self.xSortedPixels.sort()
self.xPixelLocs = [p[0] for p in self.xSortedPixels]
+
def render(self, surface):
[lS.render(surface) for lS in self.pixelStrips]
+
def allOn(self):
[lS.allOn(-1) for lS in self.pixelStrips]
+
def __iter__(self): #the iterator of all our pixel strips chained togther
return itertools.chain(*[strip.__iter__() for strip in \
self.pixelStrips]) #the * operator breaks the list into args
+
#increment time -- This processes all queued responses. Responses generated
#during this period are added to the queue that will be processed on the next
#time step.
@@ -46,14 +55,15 @@ class Screen:
for response in tempQueue:
self.processResponse(response)
[p.invalidateState() for p in self]
+
#public
def respond(self, responseInfo):
self.responseQueue.append(responseInfo)
+
def getSize(self):
if self.sizeValid:
return self.size
- (minX, minY, maxX, maxY) = (10**10,10**10,-10**10,-10*10) #TODO: don't
- #be lazy
+ (minX, minY, maxX, maxY) = (sys.maxint,sys.maxint,-sys.maxint,-sys.maxint)
for light in self:
(x,y) = light.location
@@ -65,6 +75,7 @@ class Screen:
self.size = (0,0, maxX, maxY)
self.sizeValid = True
return (0, 0, maxX+100, maxY+100) #TODO: cleaner
+
#private
def processResponse(self, responseInfo): #we need to make a new dict for
#each to prevent interference
@@ -78,6 +89,8 @@ class Screen:
#if type(mapper) != type(PixelMapper):
# raise Exception('No default mapper specified.')
pixelWeightList = mapper.mapEvent(responseInfo['Location'], self)
+ main_log.debug(str(len(pixelWeightList)))
+ main_log.debug(pixelWeightList)
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 7c1504a..c1166d6 100644
--- a/pixelevents/DecayEvent.py
+++ b/pixelevents/DecayEvent.py
@@ -3,14 +3,22 @@ import math
from util.ColorOps import *
class DecayEvent(PixelEvent):
def initEvent(self):
- self['Coefficient'] = abs(self['Coefficient'])
- def state(self,timeDelay): #TODO: make this fast.
+ self.coefficient = float(abs(self['Coefficient']))
if self['DecayType'] == 'Exponential':
- decay = math.exp(timeDelay*-1*self['Coefficient'])
- if self['DecayType'] == 'Proportional':
- decay = float(self['Coefficient']) / timeDelay
- color = multiplyColor(self['Color'], decay)
- return color if sum(color) > 5 else None
+ self.decayType = 1
+ else:
+ self.decayType = 2
+ self.color = self['Color']
+
+ #SUBVERTING DESIGN FOR THE SAKE OF EFFICIENCY -- RUSSELL COHEN (2011-01-03-23:18)
+ def state(self,timeDelay):
+ if self.decayType == 1:
+ decay = math.exp(timeDelay*-1*self.coefficient)
+ if self.decayType == 2:
+ decay = self.coefficient / timeDelay
+ color = multiplyColor(self.color, decay)
+ return color if (color[0] + color[1] + color[2]) > 5 else None
+
@staticmethod
def generate(decayType, coefficient, color):
args = {'DecayType': decayType, 'Coefficient':coefficient, 'Color':color}
diff --git a/pixelmappers/GaussianMapper.py b/pixelmappers/GaussianMapper.py
index 8755acf..8fdf16b 100644
--- a/pixelmappers/GaussianMapper.py
+++ b/pixelmappers/GaussianMapper.py
@@ -9,5 +9,6 @@ class GaussianMapper(PixelMapper):
pixelDist = Geo.dist(pixel.location, eventLocation)
if pixelDist < self['CutoffDist']:
w = Geo.gaussian(pixelDist, self['Height'], 0, self['Width'])
- returnPixels.append((pixel, w))
+ if w > self['MinWeight']:
+ returnPixels.append((pixel, w))
return returnPixels
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/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/ColorOps.py b/util/ColorOps.py
index f1d3741..143444f 100644
--- a/util/ColorOps.py
+++ b/util/ColorOps.py
@@ -5,16 +5,16 @@ def randomColor():
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 colorToInt(color):
- return [int(channel) for channel in color]
+ c[0] = c[0] if c[0] < 255 else 255
+ c[1] = c[1] if c[1] < 255 else 255
+ c[2] = c[2] if c[2] < 255 else 255
+ return c
+def combineColors(colors):
+ result = [0,0,0]
+ for c in colors:
+ result[0] += c[0]
+ result[1] += c[1]
+ result[2] += c[2]
+ return safeColor(result)
def multiplyColor(color, percent):
- return safeColor([fastMultiply(channel, percent, 1) for channel in color])
-
-def fastMultiply(value, mult, acc):
- if type(mult) == type(int(5)):
- return value*mult
- return int(value)*int(mult*10**acc)*10**(-acc)
-
+ return safeColor([channel*(percent) for channel in color])
diff --git a/util/Config.py b/util/Config.py
index 040e9b0..4c1eb1e 100644
--- a/util/Config.py
+++ b/util/Config.py
@@ -3,9 +3,11 @@ 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)
@@ -16,9 +18,9 @@ def loadConfigFile(fileName): #TODO: error handling etc.
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 Exception as inst:
main_log.error('Error loading config file ' + fileName)#, inst) TODO: log exception too
@@ -30,13 +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
+ 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()
@@ -53,7 +57,7 @@ def compositeXMLTrees(parentTree, overridingTree): #TODO: break up into sub-meth
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':
@@ -91,6 +95,15 @@ def fileToDict(fileName):
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():
@@ -113,8 +126,13 @@ 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)
@@ -122,6 +140,5 @@ def resolveConfigInheritance(el):
main_log.warn('Inheritance Failed. ' + parentClass.text + 'does not exist')
main_log.error('Inheritance Failed. ' + parentClass.text + 'does not exist')
return el
- el = compositeXMLTrees(el, parentTree)
+ el = 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 2fa531e..6c50c6d 100644
--- a/util/NetworkOps.py
+++ b/util/NetworkOps.py
@@ -4,7 +4,8 @@ def getConnectedSocket(ip,port):
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
sock.connect((ip, port))
+ return sock
except Exception as inst:
main_log.error('Network down. All network based renderers and sensors will not function.',
inst)
- return sock
+ 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