changeset 112:afbdae5e1359

dmx light output is now via a separate process which light8 talks to. dmx light output is now via a separate process which light8 talks to. other programs can also submit dmx to the server
author drewp
date Wed, 11 Jun 2003 09:36:35 +0000
parents 0c619695d6c6
children b6ccc325f1ec
files light8/Lightboard.py light8/dmxserver.py light8/rsn.py
diffstat 3 files changed, 39 insertions(+), 148 deletions(-) [+]
line wrap: on
line diff
--- a/light8/Lightboard.py	Wed Jun 11 09:36:07 2003 +0000
+++ b/light8/Lightboard.py	Wed Jun 11 09:36:35 2003 +0000
@@ -1,8 +1,9 @@
-from __future__ import nested_scopes
+from __future__ import nested_scopes,division
 
 from Tix import *
 from signal import signal, SIGINT
 from time import time
+import xmlrpclib
 import sys, cPickle, random
 
 from uihelpers import *
@@ -22,9 +23,9 @@
         self.windowpos = windowpos
 
 class Lightboard:
-    def __init__(self, master, parportdmx, DUMMY):
+    def __init__(self, master, DUMMY):
         self.master = master
-        self.parportdmx = parportdmx
+
         self.DUMMY = DUMMY
         self.jostle_mode = 0
         self.lastline = None
@@ -48,7 +49,11 @@
         self.get_data()
         self.buildinterface()
         self.load()
-        print "Light 8.8: Enterring backgroundloop"
+
+        # get a connection to the dmx server
+        self.dmxserver=xmlrpclib.Server("http://localhost:8030")
+        
+        print "Light 8.8: Entering backgroundloop"
         self.backgroundloop()
         self.updatestagelevels()
         self.rec_file = open('light9.log', 'a')
@@ -294,7 +299,8 @@
             levels = [min(100, max(x + delta, 0)) for x in levels]
             # print "jostled", levels
 
-        self.parportdmx.sendlevels(levels)
+        self.dmxserver.outputlevels("light8-%s" %os.getpid(),[l/100 for l in levels])
+#        self.parportdmx.sendlevels(levels)
 
     def updatestagelevels(self):
         self.master.after(100, self.updatestagelevels)
--- a/light8/dmxserver.py	Wed Jun 11 09:36:07 2003 +0000
+++ b/light8/dmxserver.py	Wed Jun 11 09:36:35 2003 +0000
@@ -1,4 +1,3 @@
-#!/usr/bin/python
 """
 
 this is the only process to talk to the dmx hardware. other clients
@@ -17,170 +16,58 @@
 
 server is port 8030; xmlrpc method is called outputlevels(pid,levellist).
 
-todo:
-  save dmx on quit and restore on restart
-  if parport fails, run in dummy mode (and make an option for that too)
 """
 
 from __future__ import division
 from twisted.internet import reactor
 from twisted.web import xmlrpc, server
-import sys,time,os
-from optparse import OptionParser
+
+import sys
+sys.path.append("../light8")
 from io import ParportDMX
-from updatefreq import Updatefreq
 
 class XMLRPCServe(xmlrpc.XMLRPC):
-    def __init__(self,options):
-
-        xmlrpc.XMLRPC.__init__(self)
-        
-        self.clientlevels={} # clientID : list of levels
-        self.lastseen={} # clientID : time last seen
-        self.clientfreq={} # clientID : updatefreq
-        
+    def __init__(self):
+        self.clientlevels={} # clientPID : list of levels
         self.combinedlevels=[] # list of levels, after max'ing the clients
         self.clientschanged=1 # have clients sent anything since the last send?
-        self.options=options
-        self.lastupdate=0 # time of last dmx send
-        self.laststatsprint=0  # time
-
-        # desired seconds between sendlevels() calls
-        self.calldelay=1/options.updates_per_sec 
 
         print "starting parport connection"
         self.parportdmx=ParportDMX()
-        if os.environ.get('DMXDUMMY',0):
-            self.parportdmx.godummy()
-        else:
-            self.parportdmx.golive()
-            
+        self.parportdmx.golive()
 
-        self.updatefreq=Updatefreq() # freq of actual dmx sends
-        self.num_unshown_updates=None
-        self.lastshownlevels=None
         # start the loop
+        self.numupdates=0
         self.sendlevels()
 
-        # the other loop
-        self.purgeclients()
-        
-    def purgeclients(self):
-        
-        """forget about any clients who haven't sent levels in a while.
-        this runs in a loop"""
-
-        purge_age=10 # seconds
-        
-        reactor.callLater(1,self.purgeclients)
-
-        now=time.time()
-        cids=self.clientlevels.keys()
-        for cid in cids:
-            lastseen=self.lastseen[cid]
-            if lastseen<now-purge_age:
-                print ("forgetting client %s (no activity for %s sec)" %
-                       (cid,purge_age))
-                del self.clientlevels[cid]
-                del self.clientfreq[cid]
-                del self.lastseen[cid]
-        
     def sendlevels(self):
-        
-        """sends to dmx if levels have changed, or if we havent sent
-        in a while"""
-
-        reactor.callLater(self.calldelay,self.sendlevels)
-
+        reactor.callLater(.02,self.sendlevels)
         if self.clientschanged:
             # recalc levels
+            self.combinedlevels=[]
+            for chan in range(0,self.parportdmx.dimmers):
+                x=0
+                for clientlist in self.clientlevels.values():
+                    if len(clientlist)>chan:
+                        x=max(x,clientlist[chan])
+                self.combinedlevels.append(x)
 
-            self.calclevels()
-         
-            if (self.num_unshown_updates is None or # first time
-                self.options.fast_updates or # show always
-                (self.combinedlevels!=self.lastshownlevels and # changed
-                 self.num_unshown_updates>5)): # not too frequent
-                self.num_unshown_updates=0
-                self.printlevels()
-                self.lastshownlevels=self.combinedlevels[:]
-            else:
-                self.num_unshown_updates+=1
-
-        if time.time()>self.laststatsprint+2:
-            self.laststatsprint=time.time()
-            self.printstats()
-
-        if self.clientschanged or time.time()>self.lastupdate+1:
-            self.lastupdate=time.time()
-            self.sendlevels_dmx()
-
-        self.clientschanged=0 # clear the flag
+        self.numupdates=self.numupdates+1
+        if (self.numupdates%200)==0:
+            print self.combinedlevels
+            
+        # now send combinedlevels (they'll get divided by 100)
+        self.parportdmx.sendlevels([l*100 for l in self.combinedlevels]) 
         
-    def calclevels(self):
-        """combine all the known client levels into self.combinedlevels"""
-        self.combinedlevels=[]
-        for chan in range(0,self.parportdmx.dimmers):
-            x=0
-            for clientlist in self.clientlevels.values():
-                if len(clientlist)>chan:
-                    # clamp client levels to 0..1
-                    cl=max(0,min(1,clientlist[chan]))
-                    x=max(x,cl)
-            self.combinedlevels.append(x)
-
-    def printlevels(self):
-        """write all the levels to stdout"""
-        print "Levels:","".join(["% 2d "%(x*100) for
-                                 x in self.combinedlevels])
-    
-    def printstats(self):
-        """print the clock, freq, etc, with a \r at the end"""
-
-        sys.stdout.write("dmxserver up at %s, [polls %s] "%
-                         (time.strftime("%H:%M:%S"),
-                          str(self.updatefreq),
-                          ))
-        for cid,freq in self.clientfreq.items():
-            sys.stdout.write("[%s %s] " % (cid,str(freq)))
-        sys.stdout.write("\r")
-        sys.stdout.flush()
-
-    def sendlevels_dmx(self):
-        """output self.combinedlevels to dmx, and keep the updates/sec stats"""
-        # they'll get divided by 100
-        if self.parportdmx:
-            self.parportdmx.sendlevels([l*100 for l in self.combinedlevels])
-        self.updatefreq.update()
-    
     def xmlrpc_echo(self,x):
         return x
     
-    def xmlrpc_outputlevels(self,cid,levellist):
-        """send a unique id for your client (name+pid maybe), then
-        the variable-length dmx levellist (scaled 0..1)"""
-        if levellist!=self.clientlevels.get(cid,None):
-            self.clientlevels[cid]=levellist
-            self.clientschanged=1
-            if cid not in self.lastseen:
-                print "hello new client %s" % cid
-                self.clientfreq[cid]=Updatefreq()
-                
-        self.lastseen[cid]=time.time()
-        self.clientfreq[cid].update()
+    def xmlrpc_outputlevels(self,pid,levellist):
+        self.clientlevels[pid]=levellist
+        self.clientschanged=1
         return "ok"
 
-parser=OptionParser()
-parser.add_option("-f","--fast-updates",action='store_true',
-                  help=('display all dmx output to stdout instead '
-                        'of the usual reduced output'))
-parser.add_option("-r","--updates-per-sec",type='float',default=20,
-                  help=('dmx output frequency'))
-(options,songfiles)=parser.parse_args()
-
-print options
-
-print "starting xmlrpc server on port 8030"
-reactor.listenTCP(8030,server.Site(XMLRPCServe(options)))
+print "starting server on 8030"
+reactor.listenTCP(8030,server.Site(XMLRPCServe()))
 reactor.run()
 
--- a/light8/rsn.py	Wed Jun 11 09:36:07 2003 +0000
+++ b/light8/rsn.py	Wed Jun 11 09:36:35 2003 +0000
@@ -3,7 +3,7 @@
 
 from Tix import *
 from signal import signal, SIGINT
-import io
+import xmlrpclib
 from uihelpers import *
 from Fader import Fader
 from Lightboard import Lightboard
@@ -23,15 +23,13 @@
 root.tk_focusFollowsMouse()
 
 
-parportdmx = io.ParportDMX()
-
 if not DUMMY:
     # this turns the parportdmx from dummy to live
     print "Light 8.8: Preparing DMX interface..."
     parportdmx.golive()
 
 print "Light 8.8: And this...is Mr. Lightboard"
-mr_lightboard = Lightboard(root,parportdmx,DUMMY)
+mr_lightboard = Lightboard(root,DUMMY)
 # root.tk_setPalette('gray40')
 
 signal(SIGINT, mr_lightboard.quit)