diff --git a/LJ.conf b/LJ.conf index 598df2f..af428a1 100644 --- a/LJ.conf +++ b/LJ.conf @@ -2,7 +2,7 @@ lasernumber = 1 debug = 0 rediserverip = 0.0.0.0 -wwwip = 192.168.1.14 +wwwip = 127.0.0.1 nozoscip = 127.0.0.1 oscserverip = 127.0.0.1 autostart = artnet @@ -10,22 +10,23 @@ wstype = ws wsport = 9001 [laser0] +dac_family = extern_cmd +cmd = ./tracers/lj_rust/lj_rust ./tracers/lj_rust/settings.toml color = -1 -type = LOCAL -dac_family = etherdream -ip = 127.0.0.1 -kpps = 10000 -centerx = 7.0 -centery = 61.0 -zoomx = 312.0 -zoomy = 1039.0 -sizex = 32000.0 -sizey = 32000.0 -finangle = -0.02263757042605427 +type = DS1000 +ip = 192.168.1.35 +kpps = 25000 intens = 255.0 red = 100 green = 100 blue = 100 +centerx = -21504.0 +centery = 21504.0 +zoomx = 8.90625 +zoomy = 20.671875 +sizex = 32000.0 +sizey = 32000.0 +finangle = 0.0 swapx = -1 swapy = -1 lsteps = [ (1.0, 8),(0.25, 3), (0.75, 3), (1.0, 10)] diff --git a/configure.py b/configure.py old mode 100644 new mode 100755 diff --git a/libs3/commands.py b/libs3/commands.py index 3437fd3..7a1b924 100644 --- a/libs3/commands.py +++ b/libs3/commands.py @@ -14,13 +14,13 @@ Commands reference. Use commands from websocket (webUI) or OSC, do not set value DAChecks() UpdateAllwww() -/forwardui "htmlid args" +/forwardui "htmlid args" /scale/X/lasernumber value (0-200) /scale/Y/lasernumber value (0-200) /client or note on < 8 : change client displayed for Current Laser -23 < /noteon < 32 : PL number displayed on webUI simulator +23 < /noteon < 32 : PL number displayed on webUI simulator /grid/lasernumber value (0 or 1) : switch given laser with grid display on or off @@ -34,15 +34,15 @@ Live change of kpps is not implemented in newdac.py. Change will effect next sta /angle/lasernumber value : angle correction for given laser by value (0-360) -/intens/lasernumber value : increase/decrease intensity for given laser by value +/intens/lasernumber value : increase/decrease intensity for given laser by value /resampler/lasernumber lsteps : change resampling strategy (glitch art) for given laser lsteps is a string like "[ (1.0, 8),(0.25, 3), (0.75, 3), (1.0, 10)]" - -/mouse/lasernumber value (0 or 1) -/swap/X/lasernumber value (0 or 1) -/swap/Y/lasernumber value (0 or 1) +/mouse/lasernumber value (0 or 1) + +/swap/X/lasernumber value (0 or 1) +/swap/Y/lasernumber value (0 or 1) /loffset/X/lasernumber value : change X offset of given laser to value (-32000/32000) /loffset/Y/lasernumber value : change Y offset of given laser to value (-32000/32000) @@ -50,10 +50,10 @@ lsteps is a string like "[ (1.0, 8),(0.25, 3), (0.75, 3), (1.0, 10)]" /order value : instruct tracer what to do. 0 : display user pointlist with current client key. See below for client key. -1 : pull in redis a new correction matrix (EDH) -2 : display black +1 : pull in redis a new correction matrix (EDH) +2 : display black 3 : display grid -4 : resampler +4 : resampler 5 : pull in redis a new client key 6 : Max Intensity Change = reread redis key /intensity 7 : kpps change = reread redis key /kpps @@ -74,12 +74,12 @@ lsteps is a string like "[ (1.0, 8),(0.25, 3), (0.75, 3), (1.0, 10)]" Example : client 0 send 2 point lists one for laser 0 and one for laser 1 by sending in redis : /pl/0/0 and /pl/0/1 -The "client key" when client 0 is selected to be displayed by lasers is "/pl/0/". -Each tracer pull its pointlist by using the current client key "/pl/0/" +The "client key" when client 0 is selected to be displayed by lasers is "/pl/0/". +Each tracer pull its pointlist by using the current client key "/pl/0/" and add its laser number at startup : /pl0/0 ant /pl/0/1 -"Client" is a concept. Imagine in a demoparty there is 4 lasers. -John and Paul want to draw on all lasers. +"Client" is a concept. Imagine in a demoparty there is 4 lasers. +John and Paul want to draw on all lasers. Let's give John client 0, he will send points to /pl/0/0, /pl/0/1, /pl/0/2 and /pl/0/3. Paul is client 1, so he will use /pl/1/0, /pl/1/1, /pl/1/2 and /pl/1/3. @@ -87,7 +87,7 @@ Paul is client 1, so he will use /pl/1/0, /pl/1/1, /pl/1/2 and /pl/1/3. Both can send their pointlists to redis server. When John get the lasers switch to client 0, when it's Paul turn switch to client 1. -But say Bob and Lisa needs only 2 lasers each. Give them client 2. +But say Bob and Lisa needs only 2 lasers each. Give them client 2. Bob could use /pl/2/0 and /pl/2/1 and Lisa could use /pl/2/2 and /pl/2/3. @@ -96,17 +96,18 @@ Bob could use /pl/2/0 and /pl/2/1 and Lisa could use /pl/2/2 and /pl/2/3. import types, time, socket, math from libs3 import gstt import redis -from libs3 import OSC3 +from libs3 import OSC3 from libs3 import settings, plugins, homographyp,log r = redis.StrictRedis(host=gstt.RediServerIP , port=6379, db=0) #r = redis.StrictRedis(host=gstt.RediServerIP , port=6379, db=0, password='-+F816Y+-') +workers = [] GenericCommands = ["start", "align", "ljclient", "scene", "addest", "deldest", "dest", "clientnumber", "vcvrack", "fft", "mitraille", "faceosc", "midigen", "viewgen", "audiogen", "noteon", "cc", "ljpong", "ljwars", "mouse", "emergency", "simu", "status", "run", "nozoid", "planet", "live", "words", "ai", "bank0", "pose", "lj", "cycl", "glyph", "pong", "maxw", "custom1", "square", "regen", "trckr", "aurora", "line1", "ForwardUI", "settings", "debug", "pl", "plugins"] - + def UserOn(laser): print("User for laser ", laser) @@ -130,7 +131,7 @@ def BlackOn(laser): plugins.sendWSall("/status Black on laser " + str(laser)) sendOSCUI('/black/'+str(laser),1) r.set('/order/'+str(laser), 2) - + def GridOn(laser): @@ -164,7 +165,7 @@ def LasClientChange(clientnumber): r.set('/order/'+str(laserid), 5) else: print("ERROR : Maximum number of scenes is set to ", gstt.MaxScenes) - + def SceneChange(newscene): @@ -190,7 +191,7 @@ def NoteOn(note): # Change laser client if note < 8: LasClientChange(note) - + # Change PL displayed on webui if note > 23 and note < 32: if note - 24 > gstt.LaserNumber -1: @@ -198,8 +199,8 @@ def NoteOn(note): plugins.sendWSall("/redstatus No Laser"+str(note-24)) plugins.sendWSall("/laser "+str(gstt.LaserNumber-1)) plugins.SendAll("/laser "+str(gstt.LaserNumber-1)) - - else: + + else: gstt.Laser = note -24 print("Current Laser switched to", gstt.Laser) plugins.sendWSall("/status Laser " + str(gstt.Laser)) @@ -209,7 +210,7 @@ def NoteOn(note): plugins.sendWSall("/loffset/Y/" + str(gstt.Laser) +" " +str(gstt.centerY[gstt.Laser])) plugins.sendWSall("/scale/X/" + str(gstt.Laser) +" " + str(gstt.zoomX[gstt.Laser])) plugins.sendWSall("/scale/Y/" + str(gstt.Laser) +" " +str(gstt.zoomY[gstt.Laser])) - + def Scim(path, tags, args, source): @@ -223,7 +224,7 @@ def Scim(path, tags, args, source): plugins.sendWSall("/redstatus No Laser"+str(note-24)) plugins.sendWSall("/laser "+str(gstt.LaserNumber-1)) - else: + else: gstt.Laser = laser -24 plugins.sendWSall("/status Laser " + str(gstt.Laser)) print("Current Laser switched to", gstt.Laser) @@ -232,15 +233,15 @@ def Scim(path, tags, args, source): def Line1(path, tags, args, source): line1 = args[0] - print("OSC /line1", line1) + print("OSC /line1", line1) plugins.sendWSall("/line1 " +"Fx "+line1) -# forward +# forward def ForwardUI(path, tags, args, source): line = args[0] - print("OSC /forwardui to WebUI :", line) + print("OSC /forwardui to WebUI :", line) print('from path', path, 'args', args) plugins.sendWSall(line) sendOSCUI('/status',line) @@ -264,12 +265,12 @@ def handler(oscpath, args): # 2 incoming cases : generic or specific for a given lasernumber : - + # # Generic : Commands without a laser number # - if oscpath[1] in GenericCommands: + if oscpath[1] in GenericCommands: if gstt.debug > 0: print("GenericCommand :", oscpath[1], "with args", args) @@ -286,7 +287,7 @@ def handler(oscpath, args): r.set("/"+oscpath[1]+"/"+oscpath[2]+"/"+oscpath[3], args[0]) - if oscpath[0] == "pl" : + if oscpath[0] == "pl" : r.set(oscpath, args[0]) @@ -314,7 +315,7 @@ def handler(oscpath, args): if gstt.debug >0: print(("/" + args[0] + "/start 1")) print(("/status got pong from "+ args[0] +".")) - + plugins.sendWSall("/" + args[0] + "/start 1") #plugins.sendWSall("/status got pong from "+ args[0] +".") @@ -333,25 +334,25 @@ def handler(oscpath, args): elif oscpath[1] == "mouse": Mouse(int(args[0]),int(args[1]),int(args[2]),int(args[3])) - - # /emergency value (0 or 1) + + # /emergency value (0 or 1) elif oscpath[1] == "emergency": - + if args[0] == "1": - + for laser in range(gstt.lasernumber): print("Black requested for laser ", laser) BlackOn(laser) print("EMERGENCY MODE") - plugins.sendWSall("/status EMERGENCY MODE") + plugins.sendWSall("/status EMERGENCY MODE") else: for laser in range(gstt.lasernumber): print("Back to normal for laser ", laser) UserOn(laser) - # Plugins commands : + # Plugins commands : elif oscpath[1] == "plugins": # /plugins/start pluginame if oscpath[2] == "start": @@ -373,9 +374,9 @@ def handler(oscpath, args): print("Restarting plugin :",args[0]) print() plugins.Restart(args[0]) - - - # Settings commands : + + + # Settings commands : elif oscpath[1] == "settings": if oscpath[2] == "lasers": print() @@ -420,7 +421,7 @@ def handler(oscpath, args): print("** RESTART LJ **") #LJautokill() - + if oscpath[2] == "restart": print() print("Restarting", args[0], "...") @@ -457,25 +458,25 @@ def handler(oscpath, args): else: laser = int(oscpath[3]) - + #print "args[0] :",args[0]," ", type(args[0]) - # /black/lasernumber value (0 or 1) + # /black/lasernumber value (0 or 1) if oscpath[1] == "black": - + if args[0] == "1": print("Black requested for laser ", laser) - BlackOn(laser) + BlackOn(laser) else: print("User mode for laser ", laser) UserOn(laser) - - # /grid/lasernumber value (0 or 1) + + # /grid/lasernumber value (0 or 1) if oscpath[1] == "grid": - + if args[0] == "1": print("Grid requested for laser ", laser) - GridOn(laser) + GridOn(laser) else: print("No grid for laser ", laser) UserOn(laser) @@ -485,7 +486,7 @@ def handler(oscpath, args): print("New IP for laser ", laser) gstt.lasersIPS[laser]= args[0] settings.Write() - + # /kpps/lasernumber value # Live change of kpps is not implemented in newdac.py. Change will effect next startup. if oscpath[1] == "kpps": @@ -495,59 +496,59 @@ def handler(oscpath, args): sendOSCUI('/kpps/' + str(laser), args[0]) r.set('/kpps/' + str(laser), str(args[0])) r.set('/order/'+str(laser), 7) - - # /angle/lasernumber value + + # /angle/lasernumber value if oscpath[1] == "angle": print("New Angle modification for laser ", oscpath[2], ":", float(args[0])) gstt.finANGLE[laser] = math.radians(float(args[0])) sendOSCUI('/angle/' + str(laser), gstt.finANGLE[laser]) NewEDH(laser) print("New angle", gstt.finANGLE[laser]) - - # /intens/lasernumber value + + # /intens/lasernumber value if oscpath[1] == "intens": print("LJ2 : New intensity requested for laser ", laser, ":", int(args[0])) plugins.sendWSall("/status Intensity " + str(args[0])) sendOSCUI('/intens/' + str(laser), args[0]) r.set('/intensity/' + str(laser), str(args[0])) r.set('/order/'+str(laser), 6) - - + + # /resampler/lasernumber lsteps # lsteps is a string like "[ (1.0, 8),(0.25, 3), (0.75, 3), (1.0, 10)]" if oscpath[1] == "resampler": #print"resampler with args", args Resampler(laser,args) - - - # /mouse/lasernumber value (0 or 1) + + + # /mouse/lasernumber value (0 or 1) if oscpath[1] == "mouse": - + if args[0] == "1": print("Mouse requested for laser ", oscpath[2]) gstt.Laser = oscpath[2] else: print("No mouse for laser ", oscpath[2]) - - - # /swap/X/lasernumber value (0 or 1) + + + # /swap/X/lasernumber value (0 or 1) if oscpath[1] == "swap" and oscpath[2] == "X": - + print("swapX was", gstt.swapX[laser]) if args[0] == "0": print("swap X -1 for laser ", laser) gstt.swapX[laser]= -1 NewEDH(laser) - + else: print("swap X 1 for laser ", laser) gstt.swapX[laser]= 1 NewEDH(laser) - - # /swap/Y/lasernumber value (0 or 1) + + # /swap/Y/lasernumber value (0 or 1) if oscpath[1] == "swap" and oscpath[2] == "Y": - + print("swapY was", gstt.swapX[laser]) if args[0] == "0": print("swap Y -1 for laser ", laser) @@ -557,7 +558,7 @@ def handler(oscpath, args): print("swap Y 1 for laser ", laser) gstt.swapY[laser]= 1 NewEDH(laser) - + # /loffset/X/lasernumber value if oscpath[1] == "loffset" and oscpath[2] == "X": @@ -565,7 +566,7 @@ def handler(oscpath, args): print("offset/X laser", laser, "modified to", args[0]) gstt.centerX[laser] = float(args[0]) NewEDH(laser) - + # /loffset/Y/lasernumber value if oscpath[1] == "loffset" and oscpath[2] == "Y": @@ -573,18 +574,18 @@ def handler(oscpath, args): print("offset/Y laser", laser, "modified to", args[0]) gstt.centerY[laser] = float(args[0]) NewEDH(laser) - - + + # /scale/X/lasernumber value if oscpath[1] == "scale" and oscpath[2] == "X": - + gstt.zoomX[laser] = float(args[0]) print("scale/X laser", laser , "modified to", gstt.zoomX[laser]) NewEDH(laser) - + # /scale/Y/lasernumber value if oscpath[1] == "scale" and oscpath[2] == "Y": - + gstt.zoomY[laser] = float(args[0]) print("scale/Y laser", laser, "modified to", gstt.zoomY[laser]) NewEDH(laser) @@ -592,22 +593,22 @@ def handler(oscpath, args): # OSC UI feedback def sendOSCUI(oscaddress,oscargs=''): - + if gstt.TouchOSCUI == True: oscmsg = OSC3.OSCMessage() oscmsg.setAddress(oscaddress) oscmsg.append(oscargs) - + oscui = OSC3.OSCClient() - oscui.connect((gstt.TouchOSCIP, 8001)) + oscui.connect((gstt.TouchOSCIP, 8001)) #print("main sending OSC UI message :", oscmsg, "to", gstt.TouchOSCIP, ":8001") if gstt.debug >0: print("main sending OSC UI message :", oscmsg, "to", gstt.TouchOSCIP, ":8001") - + try: oscui.sendto(oscmsg, (gstt.TouchOSCIP, 8001)) oscmsg.clearData() - + except: print ('Connection to OSC UI refused : died ?') pass @@ -639,7 +640,7 @@ def UpdateOSCUI(laserid): sendOSCUI("/swap/Y/" + str(laserid), 0) -# +# # Different useful codes for some commands # @@ -700,7 +701,7 @@ def isOpen(ip): time.sleep(1) finally: - + dacksock.close() return istate @@ -726,22 +727,27 @@ def LJautokill(): print('Shutdown order for tracer '+str(laser), 9) r.set('/order/'+str(laser), 9) + for (n,dac_worker) in enumerate(workers): + log.warn(f'Entering tracer{n} ...') + dac_worker.join() + lasernumber= gstt.LaserNumber -1 - log.warn("Ending tracer0...") - worker0.join() - if lasernumber >0: - log.warn("Ending tracer1...") - worker1.join() - if lasernumber >1: - log.warn("Ending tracer2...") - worker2.join() - if lasernumber >2: - log.warn("Ending tracer3...") - worker3.join() - + # log.warn("Ending tracer0...") + # worker0.join() + # if lasernumber >0: + # log.warn("Ending tracer1...") + # worker1.join() + # if lasernumber >1: + # log.warn("Ending tracer2...") + # worker2.join() + # if lasernumber >2: + # log.warn("Ending tracer3...") + # worker3.join() + + log.warn("Laser feedbacks resetting...") for laserid in range(0,lasernumber+1): - + r.set('/lack/'+str(laserid),64) r.set('/lstt/'+str(laserid),64) r.set('/cap/'+str(laserid),0) @@ -759,9 +765,9 @@ def DAChecks(): if isOpen(gstt.lasersIPS[dac]): print("DAC", dac, "at", gstt.lasersIPS[dac], ": UP") - gstt.dacs[gstt.dacnumber] = dac + gstt.dacs[gstt.dacnumber] = dac gstt.dacnumber +=1 - + else: print("DAC", dac, "at", gstt.lasersIPS[dac], ": DOWN") @@ -786,19 +792,19 @@ For reference values of EDH modifier if assign to keyboard keys (was alignp) gstt.zoomX[gstt.Laser] += 0.1 gstt.zoomY[gstt.Laser] -= 0.1 - + gstt.zoomY[gstt.Laser] += 0.1 - + gstt.sizeX[gstt.Laser] -= 50 - + gstt.sizeX[gstt.Laser] += 50 - + gstt.sizeY[gstt.Laser] -= 50 - + gstt.sizeY[gstt.Laser] += 50 - + gstt.finANGLE[gstt.Laser] -= 0.001 - + gstt.finANGLE[gstt.Laser] += 0.001 Code for bit analysis 2 bits / laser to encode order. @@ -813,7 +819,7 @@ Code for bit analysis 2 bits / laser to encode order. #order = r.get('/order') #neworder = order & ~(1<< laser*2) #neworder = neworder & ~(1<< 1+ laser*2) - #r.set('/order', str(neworder)) + #r.set('/order', str(neworder)) # Laser bit 0 = 0 and bit 1 = 1 : New EDH #order = r.get('/order') diff --git a/libs3/gstt.py b/libs3/gstt.py index 188e4c2..2840c1b 100644 --- a/libs3/gstt.py +++ b/libs3/gstt.py @@ -49,13 +49,13 @@ Laser = 0 # Can be changed with /noteon 24-31 simuPL = 1 -# gstt.laserIPS. +# gstt.laserIPS. lasersIPS = ['192.168.1.5','192.168.1.6','192.168.1.3','192.168.1.4'] maxdacs = 4 # Autodetected by DAChecks() in main3 : -# Store connected dacs. Maybe laser 1 in LJ.conf is not connected but Laser 2 is. +# Store connected dacs. Maybe laser 1 in LJ.conf is not connected but Laser 2 is. dacs = [-1, -1, -1, -1] # Actual number of connected DACs dacnumber = 0 @@ -63,8 +63,9 @@ dacnumber = 0 # gstt.kpps stores kpps for each laser. # ** Will be overridden by LJ.conf file values ** kpps = [25000,25000,25000,25000] -lasertype = ["LOCAL","LOCAL","LOCAL","LOCAL"] -dacfamily = ["etherdream","etherdream","etherdream","etherdream"] +lasertype = ["LOCAL","LOCAL","LOCAL","LOCAL"] +dacfamily = ["etherdream","etherdream","etherdream","etherdream"] +cmd = [None,None,None,None] intensity = [-1,-1,-1,-1] intens = [-1,-1,-1,-1] red = [100,100,100,100] @@ -74,17 +75,17 @@ blue = [100,100,100,100] # gstt.GridDisplay : if = 1 Curve points actually sent to PL are replaced by a grid GridDisplay = [0,0,0,0] -# Transformation Matrix for each laser +# Transformation Matrix for each laser EDH = [[], [], [], []] -# Etherdreams reports +# Etherdreams reports # ipconn is initial newdac to its etherdream lstt_ipconn = [[-1], [-1], [-1], [-1]] # dacstt is dac light engine state lstt_dacstt = [[-1], [-1], [-1], [-1]] -# store last dac answers : ACK, not ACK,... +# store last dac answers : ACK, not ACK,... lstt_dacanswers = [[-1], [-1], [-1], [-1]] -# store last number of points sent to etherdreams buffer +# store last number of points sent to etherdreams buffer lstt_points = [[0], [0], [0], [0]] swapX = [1,1,1,-1] @@ -93,7 +94,7 @@ swapY = [1,1,1,-1] lsteps = [[],[],[],[]] # For glitch art : change position and number of points added by tracer.py -# shortline is for distance with next point, shorter than 4000 (in etherdream coordinates) +# shortline is for distance with next point, shorter than 4000 (in etherdream coordinates) # i.e (0.25,3) means add 3 points at 25% on the line. stepshortline = [(1.0, 8)] stepslongline = [(0.25, 3), (0.75, 3), (1.0, 10)] @@ -114,7 +115,7 @@ knob = [0] * 33 cc[21]=60 viewer_distance = cc[21] * 8 -# fov (cc 22) +# fov (cc 22) cc[22]= 60 fov = 4 * cc[22] @@ -130,7 +131,7 @@ nozoport=8001 #nozosc.py sending port to LJay (main.py) nozuport=0 #linux serial usb port connecting nozoid devices ACM0 by default -angleX = 0 +angleX = 0 angleY = 0 angleZ = 0 diff --git a/libs3/settings.py b/libs3/settings.py index 8806330..cffc7f9 100644 --- a/libs3/settings.py +++ b/libs3/settings.py @@ -16,7 +16,7 @@ import ast import numpy as np -def Write(): +def Write(): config.set('General', 'lasernumber', str(gstt.LaserNumber)) config.set('General', 'rediserverip', str(gstt.RediServerIP)) @@ -51,8 +51,8 @@ def Write(): -def Read(): - +def Read(): + gstt.LaserNumber = config.getint('General', 'lasernumber') gstt.RediServerIP= config.get('General', 'rediserverip') gstt.wwwIP= config.get('General', 'wwwip') @@ -69,6 +69,8 @@ def Read(): gstt.lasersIPS[i]= config.get(laser, 'ip') gstt.lasertype[i]= config.get(laser, 'type') gstt.dacfamily[i] = config.get(laser, 'dac_family') + if gstt.dacfamily[i] == "extern_cmd": + gstt.cmd[i] = config.get(laser, 'cmd') gstt.kpps[i] = config.getint(laser, 'kpps') gstt.intens[i] = config.getfloat(laser, 'intens') gstt.red[i] = config.getint(laser, 'red') @@ -90,4 +92,3 @@ def Read(): config = configparser.ConfigParser() config.read(gstt.ConfigName) - diff --git a/main.py b/main.py index f37e951..ccd6a15 100755 --- a/main.py +++ b/main.py @@ -11,14 +11,14 @@ Laser server + webUI servers (ws + OSC) - get point list to draw : /pl/lasernumber - for report /lstt/lasernumber /lack/lasernumber /cap/lasernumber -- a nice ws debug tool : websocat -- a "plugin" is a generator that send points to LJ. Plugins if they have an open OSC port can be checked and restart if in the same computer. +- a nice ws debug tool : websocat +- a "plugin" is a generator that send points to LJ. Plugins if they have an open OSC port can be checked and restart if in the same computer. -All used ports: +All used ports: 8002 OSC incoming -9001 Websocket communication with WebGUI +9001 Websocket communication with WebGUI Plugins OSC Ports (see LJ.conf) ''' @@ -52,14 +52,14 @@ settings.Write() from multiprocessing import Process, set_start_method import random, ast from libs3 import plugins -#from libs3 import lasytracer as tracer -from libs3 import tracer3 as tracer -#from libs3 import niptracer3 as tracer +#from libs3 import lasytracer as tracer +from libs3 import tracer3 as tracer +#from libs3 import niptracer3 as tracer from libs3 import homographyp, commands, font1 #import subprocess import os #from libs3 import midi3 -from libs3 import OSC3 +from libs3 import OSC3 from websocket_server import WebsocketServer #import socket import types, _thread, time @@ -82,7 +82,6 @@ elif os_name == "Darwin": # macOS elif os_name == "Linux": print("Plateform: Linux") - def dac_process(number, pl): import sys @@ -90,6 +89,7 @@ def dac_process(number, pl): print("Starting dac process", number) + while True: try: d = tracer.DAC(number,pl) @@ -110,20 +110,20 @@ def dac_process(number, pl): except KeyboardInterrupt: sys.exit(0) - + # # Init variables # -debug = gstt.debug +debug = gstt.debug print("Debug :", debug) print("Start Scene number :",gstt.SceneNumber) print("Laser feedbacks resetting...") for laserid in range(0,gstt.LaserNumber): - + r.set('/lack/'+str(laserid),64) r.set('/lstt/'+str(laserid),64) r.set('/cap/'+str(laserid),0) @@ -156,13 +156,13 @@ import socket # oscserver oscserverIP = gstt.oscIPin -# OSC Server : accept OSC message on port 8002 +# OSC Server : accept OSC message on port 8002 #oscIPin = "192.168.1.10"s oscserverIPin = serverIP oscserverPORTin = 8002 # OSC Client : to send OSC message to an IP port 8001 -oscserverIPout = oscserverIP +oscserverIPout = oscserverIP oscserverPORTout = 8101 oscserver = OSC3.OSCServer( (oscserverIPin, oscserverPORTin) ) @@ -200,7 +200,7 @@ def handler(path, tags, args, source): commands.handler(oscpath,args) -# RAW OSC Frame available ? +# RAW OSC Frame available ? def osc_frame(): #print 'oscframe' # clear timed_out flag @@ -213,7 +213,7 @@ def PingAll(): if gstt.debug > 0: print("Pinging all plugins...") - + for plugin in list(gstt.plugins.keys()): if gstt.debug > 0: print("pinging", plugin) @@ -223,28 +223,28 @@ def PingAll(): ''' gstt.lasertype[i -gstt.sizeX[i] = -gstt.sizeY[i] = +gstt.sizeX[i] = +gstt.sizeY[i] = ''' ''' # OSC UI feedback def sendOSCUI(oscaddress,oscargs=''): - + if gstt.TouchOSCUI == True: oscmsg = OSC3.OSCMessage() oscmsg.setAddress(oscaddress) oscmsg.append(oscargs) - + oscui = OSC3.OSCClient() - oscui.connect((gstt.TouchOSCIP, 8001)) + oscui.connect((gstt.TouchOSCIP, 8001)) print("main sending OSC UI message :", oscmsg, "to", gstt.TouchOSCIP, ":8001") if gstt.debug >0: print("main sending OSC UI message :", oscmsg, "to", gstt.TouchOSCIP, ":8001") - + try: oscui.sendto(oscmsg, (gstt.TouchOSCIP, 8001)) oscmsg.clearData() - + except: print ('Connection to OSC UI refused : died ?') pass @@ -276,7 +276,7 @@ def osc_thread(): if lstt == "2": # Dac PLAYING (2) -> led is green (1) sendWSall("/lstt/" + str(laserid) + " 1") - + ackstate = {'61': 'ACK', '46': 'FULL', '49': "INVALID", '21': 'STOP', '64': "NOCONNECTION ?", '35': "NOCONNECTION ?" , '97': 'ACK', '70': 'FULL', '73': "INVALID", '33': 'STOP', '100': "NOCONNECTION", '48': "NOCONNECTION", 'a': 'ACK', 'F': 'FULL', 'I': "INVALID", '!': 'STOP', 'd': "NOCONNECTION", '0': "NOCONNECTION"} lack= r.get('/lack/'+str(laserid)).decode('ascii') @@ -293,13 +293,13 @@ def osc_thread(): if chr(int(lack)) == 'I': # Dac sent INVALID ("I") -> led is yellow (4) sendWSall("/lack/" + str(laserid)+" 4") #print lack - + if lack == "64" or lack =="35": # no connection to dac -> leds are red (6) - sendWSall("/lack/" + str(laserid) + " 6") - sendWSall("/lstt/" + str(laserid) + " 6") - #sendWSall("/lstt/" + str(laserid) + " 0") + sendWSall("/lack/" + str(laserid) + " 6") + sendWSall("/lstt/" + str(laserid) + " 6") + #sendWSall("/lstt/" + str(laserid) + " 0") sendWSall("/points/" + str(laserid) + " 6") - + else: # last number of points sent to etherdream buffer sendWSall("/points/" + str(laserid) + " " + str(r.get('/cap/'+str(laserid)).decode('ascii'))) @@ -322,17 +322,17 @@ def osc_thread(): # # Websocket part -# +# def get_Host_name_IP(): try: - host_name = socket.gethostname() + host_name = "localhost" #socket.gethostname() host_ip = socket.gethostbyname(host_name) print("Hostname : ", host_name) print("IP : ", host_ip) except: print("Unable to get Hostname and IP") return host_ip - + # Called for every WS client connecting (after handshake) def new_client(client, wserver): @@ -340,7 +340,7 @@ def new_client(client, wserver): sendWSall("/status Hello " + str(client['id'])) #commands.sendOSCUI("/status", "Hello " + str(client['id'])) - for laserid in range(0,gstt.LaserNumber): + for laserid in range(0,gstt.LaserNumber): sendWSall("/ip/" + str(laserid) + " " + str(gstt.lasersIPS[laserid])) sendWSall("/kpps/" + str(laserid)+ " " + str(gstt.kpps[laserid])) @@ -348,8 +348,8 @@ def new_client(client, wserver): sendWSall("/laser "+str(laserid)) #print("/laser "+str(laserid)) sendWSall("/lack/" + str(laserid) + " 6") - #print("/lack/" + str(laserid) + " 6") - sendWSall("/lstt/" + str(laserid) + " 6") + #print("/lack/" + str(laserid) + " 6") + sendWSall("/lstt/" + str(laserid) + " 6") #print("/lstt/" + str(laserid) + " 6") sendWSall("/points/" + str(laserid) + " 0") #print("/points/" + str(laserid) + " 0") @@ -379,25 +379,25 @@ def client_left(client, wserver): def message_received(client, wserver, message): #if len(message) > 200: - # message = message[:200]+'..' + # message = message[:200]+'..' #if gstt.debug >0: # print ("") # print("WS Client(%d) said: %s" % (client['id'], message)) - + oscpath = message.split(" ") #print "WS Client", client['id'], "said :", message, "splitted in an oscpath :", oscpath if gstt.debug > 0: print("WS Client", client['id'], "said :", message, "splitted in an oscpath :", oscpath) - + PingAll() message4plugin = False # WS received Message is for a plugin ? for plugin in list(gstt.plugins.keys()): - + if oscpath[0].find(plugin) != -1: - + message4plugin = True #print(oscpath) if plugins.Send(plugin, oscpath): @@ -411,13 +411,13 @@ def message_received(client, wserver, message): if len(oscpath) == 1: args[0] = "noargs" #print "noargs command" - + elif len(oscpath) > 1: - args[0] = str(oscpath[1]) + args[0] = str(oscpath[1]) #print "arg",oscpath[1] - + commands.handler(oscpath[0].split("/"),args) - + # if needed a loop back : WS Client -> server -> WS Client #sendWSall("ws"+message) @@ -431,7 +431,7 @@ def sendWSall(message): #if gstt.debug >0: #print("WS sending %s" % (message)) wserver.send_message_to_all(message) - + if gstt.TouchOSCUI == True: if message[:7] == '/status': print("Main WSall", message, message[:6]) @@ -440,8 +440,8 @@ def sendWSall(message): print("Main WSall", message, message[:6]) commands.sendOSCUI('/line1', message[6:]) - -''' + +''' print ("") log.info("Midi Configuration...") midi3.check() @@ -462,7 +462,7 @@ log.info("Creating startup point lists...") if r.set("/clientkey","/pl/"+str(gstt.SceneNumber)+"/")==True: print("sent clientkey : /pl/"+str(gstt.SceneNumber)+"/") - + #pdb.set_trace() for sceneid in range(0,gstt.MaxScenes+1): print("Scene "+ str(sceneid)) @@ -480,10 +480,32 @@ for sceneid in range(0,gstt.MaxScenes+1): r.set('/order/'+str(laserid), 0) +# +# For tracer as external command +# +import subprocess +import select +def spawn(cmd): + p = subprocess.Popen(cmd, + shell=True, + stdin=subprocess.DEVNULL, + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL) + return p # # Starts one DAC process per requested Laser # +import signal +import sys + +def signal_handler(sig, frame): + print('You pressed Ctrl+C!') + commands.LJautokill() + sys.exit(0) + +signal.signal(signal.SIGINT, signal_handler) + if __name__ == '__main__': # Bug in 3.8.4 MacOS default multiprocessing start method is spawn. Spawn doesn't work properly @@ -495,44 +517,55 @@ if __name__ == '__main__': commands.DAChecks() print("dacs", gstt.dacs) - else: + else: log.infog("Resquested DACs mode") - lasernumber = gstt.LaserNumber -1 + #lasernumber = gstt.LaserNumber -1 print("LaserNumber = ", gstt.LaserNumber) log.info("Starting "+str(gstt.LaserNumber) + " DACs process...") - - # Launch one process (a tracer3 instance) by laser - dac_worker0= Process(target=dac_process, args=(0,0,)) - dac_worker0.start() - commands.worker0 = dac_worker0 - print("Tracer 0 : name", dac_worker0.name , "pid", dac_worker0.pid ) - - if lasernumber >0: - dac_worker1= Process(target=dac_process, args=(1,0,)) - commands.worker1 = dac_worker1 - print("Tracer 1 : name", dac_worker1.name , "pid", dac_worker1.pid ) - dac_worker1.start() - - if lasernumber >1: - dac_worker2= Process(target=dac_process, args=(2,0,)) - dac_worker2.start() - commands.worker2 = dac_worker2 - print("Tracer 2 : name", dac_worker2.name , "pid", dac_worker2.pid ) - - if lasernumber >2: - dac_worker3= Process(target=dac_process, args=(3,0,)) - print("Tracer 3 : name", dac_worker3.name , "pid", dac_worker3.pid ) - commands.worker3 = dac_worker3 - dac_worker3.start() + + commands.workers = [] + for lasernumber in range(0,gstt.LaserNumber): + # Launch one process (a tracer3 instance) by laser + if gstt.dacfamily[lasernumber] == "extern_cmd": + dac_worker0 = spawn(gstt.cmd[lasernumber]) #Process(target=spawn, args=(gstt.cmd[0],)) + dac_worker0.name = f'ExternCmd{lasernumber}' + dac_worker0.join = dac_worker0.wait + else: + dac_worker0= Process(target=dac_process, args=(lasernumber,0,)) + dac_worker0.start() + + #commands.worker0 = dac_worker0 # ??? + commands.workers.append(dac_worker0) + print("Tracer 0 : name", dac_worker0.name , "pid", dac_worker0.pid ) + print("DAC Family:", gstt.dacfamily[lasernumber]); + + # if lasernumber >0: + + # dac_worker1= Process(target=dac_process, args=(1,0,)) + # commands.worker1 = dac_worker1 + # print("Tracer 1 : name", dac_worker1.name , "pid", dac_worker1.pid ) + # dac_worker1.start() + + # if lasernumber >1: + # dac_worker2= Process(target=dac_process, args=(2,0,)) + # dac_worker2.start() + # commands.worker2 = dac_worker2 + # print("Tracer 2 : name", dac_worker2.name , "pid", dac_worker2.pid ) + + # if lasernumber >2: + # dac_worker3= Process(target=dac_process, args=(3,0,)) + # print("Tracer 3 : name", dac_worker3.name , "pid", dac_worker3.pid ) + # commands.worker3 = dac_worker3 + # dac_worker3.start() print("") - + # # start WS and OSC servers # - + try: - + log.info("Starting servers...") hostIP= get_Host_name_IP() if hostIP != gstt.wwwIP: @@ -542,8 +575,8 @@ if __name__ == '__main__': print("python3 configure.py") log.err('Exiting...') #gstt.wwwIP = hostIP - commands.LJautokill() - sys.exit() + #commands.LJautokill() + #sys.exit() # Launch OSC thread listening to oscserver print("OSC server to receive messages (UI,...)") @@ -559,13 +592,13 @@ if __name__ == '__main__': #print() # Websocket listening port print("WebUI WS server...") - + #hostIP= get_Host_name_IP() if hostIP != gstt.wwwIP: log.err("wwwIP in config is not set to "+str(hostIP)) gstt.wwwIP = hostIP #commands.LJautokill() - + print("binded at", gstt.wwwIP, "port",str(gstt.wsPORT)) wserver = WebsocketServer(gstt.wsPORT,host= gstt.wwwIP) plugins.Init(wserver) @@ -575,43 +608,40 @@ if __name__ == '__main__': print("") log.info("Resetting all Homographies...") - for laserid in range(0,gstt.LaserNumber): + for laserid in range(0,gstt.LaserNumber): homographyp.newEDH(laserid) - + #midi3.check() # plugins autostart #print("") log.info("Plugins startup...") - + if gstt.autostart != "": - + for pluginname in gstt.autostart.split(","): print("Autostarting", pluginname, "...") plugins.Start(pluginname) - + print("") log.infog("LJ server running...") - + # websocket loop wserver.run_forever() - - + + except Exception: log.err("Exception") traceback.print_exc() - + # Gently stop on CTRL C - + finally: commands.LJautokill() ''' Some code previously used, for reference : - + random_points = [(300.0+random.randint(-100, 100), 200.0+random.randint(-100, 100), 0), (500.0+random.randint(-100, 100), 200.0+random.randint(-100, 100), 65280), (500.0+random.randint(-100, 100), 400.0+random.randint(-100, 100), 65280), (300.0+random.randint(-100, 100), 400.0+random.randint(-100, 100), 65280), (300.0+random.randint(-100, 100), 200.0+random.randint(-100, 100), 65280)] ''' - - -