diff --git a/LJ.conf b/LJ.conf
index 5b2ebba..73181d1 100644
--- a/LJ.conf
+++ b/LJ.conf
@@ -1,8 +1,8 @@
[General]
-lasernumber = 4
+lasernumber = 1
debug = 0
ljayserverip = 0.0.0.0
-wwwip = 192.168.2.44
+wwwip = 127.0.0.1
nozoscip = 127.0.0.1
bhoroscip = 127.0.0.1
autostart = artnet
@@ -12,7 +12,7 @@ wsport = 9001
[laser0]
color = -1
type = DS1000
-ip = 192.168.2.3
+ip = 127.0.0.1
kpps = 25000
centerx = 0
centery = 0
@@ -21,7 +21,7 @@ zoomy = 50.0
sizex = 32000
sizey = 32000
finangle = 0.0
-swapx = -1
+swapx = 1
swapy = -1
lsteps = [ (1.0, 8),(0.25, 3), (0.75, 3), (1.0, 10)]
warpdest = [[-1500., 1500.],
@@ -36,8 +36,8 @@ ip = 192.168.2.5
kpps = 25000
centerx = 0
centery = 0
-zoomx = 80.0
-zoomy = 80.0
+zoomx = 50.0
+zoomy = 50.0
sizex = 32000
sizey = 32000
finangle = 0.0
@@ -45,9 +45,9 @@ swapx = -1
swapy = -1
lsteps = [ (1.0, 2),(0.25, 1), (0.75, 1), (1.0, 5)]
warpdest = [[-1500., 1500.],
- [ 1500., 1500.],
- [ 1500.,-1500.],
- [-1500.,-1500.]]
+ [ 1500., 1500.],
+ [ 1500.,-1500.],
+ [-1500.,-1500.]]
[laser2]
color = -1
@@ -65,14 +65,14 @@ swapx = -1
swapy = -1
lsteps = [(1.0, 8),(0.25, 3), (0.75, 3), (1.0, 10)]
warpdest = [[-1500., 1500.],
- [ 1500., 1500.],
- [ 1500.,-1500.],
- [-1500.,-1500.]]
+ [ 1500., 1500.],
+ [ 1500.,-1500.],
+ [-1500.,-1500.]]
[laser3]
color = -1
type = LUKE400
-ip = 192.168.2.4
+ip = 192.168.1.5
kpps = 25000
centerx = 0
centery = 0
@@ -81,34 +81,19 @@ zoomy = 50.0
sizex = 32000
sizey = 32000
finangle = 0.0
-swapx = 1
-swapy = 1
+swapx = -1
+swapy = -1
lsteps = [(1.0, 8),(0.25, 3), (0.75, 3), (1.0, 10)]
warpdest = [[-1500., 1500.],
- [ 1500., 1500.],
- [ 1500.,-1500.],
- [-1500.,-1500.]]
+ [ 1500., 1500.],
+ [ 1500.,-1500.],
+ [-1500.,-1500.]]
[plugins]
plugins = {
"aurora": {"OSC": 8090, "command": "python3 plugins/aurora/aurora.py", "display": True},
- "nozoid": {"OSC": 8003, "command": "python3 plugins/audio/nozoids3.py", "display": True},
- "glyph": {"OSC": 8004, "command": "python3 plugins/laserglyph.py", "display": True},
- "planet": {"OSC": 8005, "command": "python3 plugins/planetarium/main.py", "display": True},
- "words": {"OSC": 8006, "command": "python3 plugins/livewords3.py", "display": True},
- "cycl": {"OSC": 8007, "command": "python3 plugins/textcycl.py", "display": True},
- "simu": {"OSC": 8008, "command": "python plugins/pysimu.py", "display": False},
"artnet": {"OSC": 8009, "command": "python3 libs3/artnet.py", "display": False},
- "trckr": {"OSC": 8017, "command": "python3 plugins/trckr.py", "display": False},
- "maxw": {"OSC": 8012, "command": "python3 plugins/maxwell.py", "display": True},
"square": {"OSC": 8013, "command": "python3 plugins/square.py", "display": True},
- "custom1": {"OSC": 8014, "command": "python3 plugins/custom1.py", "display": True},
- "mitraille": {"OSC": 8015, "command": "python3 plugins/audio/mitraille.py", "display": True},
- "livecode": {"OSC": 8016, "command": "python3 plugins/livecoding.py", "display": True},
- "ljpong": {"OSC": 8020, "command": "python plugins/games/ljpong/main.py", "display": True},
- "ljwars": {"OSC": 8021, "command": "python plugins/games/ljsw/main.py", "display": True},
- "audiogen": {"OSC": 8030, "command": "python3 plugins/audio/audiogen.py", "display": False},
- "midigen": {"OSC": 8031, "command": "python3 plugins/audio/midigen.py", "display": False},
- "viewgen": {"OSC": 8032, "command": "python3 plugins/audio/viewgen.py", "display": True}
+ "custom1": {"OSC": 8014, "command": "python3 plugins/custom1.py", "display": True}
}
diff --git a/LJ_template.conf b/LJ_template.conf
deleted file mode 100644
index 002fe4c..0000000
--- a/LJ_template.conf
+++ /dev/null
@@ -1,114 +0,0 @@
-[General]
-lasernumber = 1
-debug = 0
-ljayserverip = 0.0.0.0
-wwwip = 192.168.2.43
-nozoscip = 127.0.0.1
-bhoroscip = 127.0.0.1
-autostart = artnet
-wstype = ws
-wsport = 9001
-
-[laser0]
-color = -1
-type = DS1000
-ip = 192.168.2.3
-kpps = 25000
-centerx = 0
-centery = 0
-zoomx = 50.0
-zoomy = 50.0
-sizex = 32000
-sizey = 32000
-finangle = 0.0
-swapx = 1
-swapy = -1
-lsteps = [ (1.0, 8),(0.25, 3), (0.75, 3), (1.0, 10)]
-warpdest = [[-1500., 1500.],
- [ 1500., 1500.],
- [ 1500.,-1500.],
- [-1500.,-1500.]]
-
-[laser1]
-color = -1
-type = LOCAL
-ip = 192.168.2.5
-kpps = 25000
-centerx = 0
-centery = 0
-zoomx = 50.0
-zoomy = 50.0
-sizex = 32000
-sizey = 32000
-finangle = 0.0
-swapx = -1
-swapy = -1
-lsteps = [ (1.0, 2),(0.25, 1), (0.75, 1), (1.0, 5)]
-warpdest = [[-1500., 1500.],
- [ 1500., 1500.],
- [ 1500.,-1500.],
- [-1500.,-1500.]]
-
-[laser2]
-color = -1
-type = LUKE400
-ip = 192.168.2.6
-kpps = 25000
-centerx = 0
-centery = 0
-zoomx = 50.0
-zoomy = 50.0
-sizex = 32000
-sizey = 32000
-finangle = 0.0
-swapx = -1
-swapy = -1
-lsteps = [(1.0, 8),(0.25, 3), (0.75, 3), (1.0, 10)]
-warpdest = [[-1500., 1500.],
- [ 1500., 1500.],
- [ 1500.,-1500.],
- [-1500.,-1500.]]
-
-[laser3]
-color = -1
-type = LUKE400
-ip = 192.168.1.5
-kpps = 25000
-centerx = 0
-centery = 0
-zoomx = 50.0
-zoomy = 50.0
-sizex = 32000
-sizey = 32000
-finangle = 0.0
-swapx = -1
-swapy = -1
-lsteps = [(1.0, 8),(0.25, 3), (0.75, 3), (1.0, 10)]
-warpdest = [[-1500., 1500.],
- [ 1500., 1500.],
- [ 1500.,-1500.],
- [-1500.,-1500.]]
-
-[plugins]
-plugins = {
- "aurora": {"OSC": 8090, "command": "python3 plugins/aurora/aurora.py", "display": True},
- "nozoid": {"OSC": 8003, "command": "python3 plugins/audio/nozoids3.py", "display": True},
- "glyph": {"OSC": 8004, "command": "python3 plugins/laserglyph.py", "display": True},
- "planet": {"OSC": 8005, "command": "python3 plugins/planetarium/main.py", "display": True},
- "words": {"OSC": 8006, "command": "python3 plugins/livewords3.py", "display": True},
- "cycl": {"OSC": 8007, "command": "python3 plugins/textcycl.py", "display": True},
- "simu": {"OSC": 8008, "command": "python plugins/pysimu.py", "display": False},
- "artnet": {"OSC": 8009, "command": "python3 libs3/artnet.py", "display": False},
- "trckr": {"OSC": 8017, "command": "python3 plugins/trckr.py", "display": False},
- "maxw": {"OSC": 8012, "command": "python3 plugins/maxwell.py", "display": True},
- "square": {"OSC": 8013, "command": "python3 plugins/square.py", "display": True},
- "custom1": {"OSC": 8014, "command": "python3 plugins/custom1.py", "display": True},
- "mitraille": {"OSC": 8015, "command": "python3 plugins/audio/mitraille.py", "display": True},
- "livecode": {"OSC": 8016, "command": "python3 plugins/livecoding.py", "display": True},
- "ljpong": {"OSC": 8020, "command": "python plugins/games/ljpong/main.py", "display": True},
- "ljwars": {"OSC": 8021, "command": "python plugins/games/ljsw/main.py", "display": True},
- "audiogen": {"OSC": 8030, "command": "python3 plugins/audio/audiogen.py", "display": False},
- "midigen": {"OSC": 8031, "command": "python3 plugins/audio/midigen.py", "display": False},
- "viewgen": {"OSC": 8032, "command": "python3 plugins/audio/viewgen.py", "display": True}
- }
-
diff --git a/Pd/.DS_Store b/Pd/.DS_Store
new file mode 100644
index 0000000..31a0d67
Binary files /dev/null and b/Pd/.DS_Store differ
diff --git a/Pd/LJsender.pd b/Pd/LJsender.pd
new file mode 100644
index 0000000..82c3bd3
--- /dev/null
+++ b/Pd/LJsender.pd
@@ -0,0 +1,23 @@
+#N canvas 468 143 709 527 10;
+#X msg 60 237 disconnect;
+#X floatatom 27 294 0 0 0 0 - - -;
+#X text 22 315 Outlet is nonzero if connection is open \, zero otherwise.
+;
+#X msg 37 60 send mytext trololo;
+#X obj 28 267 netsend 1;
+#X msg 51 125 send /pl/0/0 (150 2300 65280) (170 170 65280) (230 170
+65280) (210 230 65280) (150 230 65280);
+#X text 258 29 LJ Sender;
+#X msg 46 84 send /pl/0/0 150 2300 65280 170 170 65280 230 170 65280
+210 230 65280 150 230 65280;
+#X msg 26 39 connect 127.0.0.1 8083;
+#X msg 58 165 send /pl/0/0 [(150.0:230.0:65280) (170.0:170.0:65280)
+(230.0:170.0:65280) (210.0:230.0:65280) (150.0:230.0:65280)];
+#X text 444 174 <- le mieux;
+#X connect 0 0 4 0;
+#X connect 3 0 4 0;
+#X connect 4 0 1 0;
+#X connect 5 0 4 0;
+#X connect 7 0 4 0;
+#X connect 8 0 4 0;
+#X connect 9 0 4 0;
diff --git a/Pd/ljpd.py b/Pd/ljpd.py
new file mode 100644
index 0000000..67c97d1
--- /dev/null
+++ b/Pd/ljpd.py
@@ -0,0 +1,106 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+# -*- mode: Python -*-
+
+'''
+
+LJPD
+
+Udp server to redis
+v0.1b
+
+'''
+import traceback, time
+import argparse
+import socket
+import _thread
+import redis
+
+
+print()
+print ("LJPD")
+print ("Arguments parsing if needed...")
+argsparser = argparse.ArgumentParser(description="dumpUDP v0.1b help mode")
+argsparser.add_argument("-i","--IP",help="IP to bind to (0.0.0.0 by default)", type=str)
+argsparser.add_argument("-p","--port",help="UDP port to bind to (9000 by default)", type=str)
+argsparser.add_argument("-l","--lj",help="LJ IP address (127.0.0.1 by default)", type=str)
+
+
+args = argsparser.parse_args()
+
+# LJ server IP name
+if args.IP:
+ ljIP = lj.IP
+else:
+ ljIP = "127.0.0.1"
+
+# Server
+if args.IP:
+ serverIP = args.IP
+else:
+ serverIP = "0.0.0.0"
+
+# ORCA destination device
+if args.port:
+ UDPORT = int(args.port)
+else:
+ UDPORT = 8083
+
+print("Connecting to Redis...")
+
+r = redis.StrictRedis(host= ljIP, port=6379, db=0)
+
+def GetTime():
+ return time.strftime("%a, %d %b %Y %H:%M:%S", time.localtime())
+
+
+def udp_thread():
+
+ while True:
+
+ payload, client_address = sock.recvfrom(1024)
+ udpath = payload.decode('utf_8')
+ print(GetTime(),"From", str(client_address),"got", udpath )
+ #r.set('/pl/0/0', "/pl/"+str(clientnumber)+"/")
+ #print(udpath[0:1], " ",udpath[1:2], " ",udpath[2:3], " ",udpath[3:4], " " )
+
+
+ # Reply to client
+ bytesToSend = str.encode("ACK :"+str(payload))
+ serverAddressPort = (client_address, UDPORT)
+ bufferSize = 1024
+ #sock.sendto(bytesToSend, serverAddressPort)
+ sock.sendto(bytesToSend, client_address)
+
+
+ time.sleep(0.005)
+
+
+
+def Start(serverIP, UDPORT):
+ global sock
+
+ sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ server = ( serverIP,UDPORT)
+ sock.bind(server)
+ _thread.start_new_thread(udp_thread, ())
+
+
+
+# Launch server in another thread.
+print("Launching UDP Server", serverIP,':', UDPORT)
+Start(serverIP, UDPORT)
+
+
+# Do something else
+try:
+
+ while True:
+ time.sleep(0.005)
+
+except Exception:
+ traceback.print_exc()
+
+finally:
+ print("")
+ print("ljpd stopped.")
\ No newline at end of file
diff --git a/README.md b/README.md
index e43eebb..3618c65 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-LJ v0.8.2
+LJ v0.8.2 'fireandforget'
By Sam Neurohack, Loloster, Cocoa
@@ -7,17 +7,26 @@ LICENCE : CC BY
![LJ](https://www.teamlaser.fr/lj/images/lj2.png)
-A software laser framework with GUI, for up to 4 lasers live actions with ethedreams DACs. Think creative like Laser "battles", planetarium, sharing available lasers in demoparties for competition, ...
-
+LJ is like a video projector where you fire images and forget. Lasers are dangerous : you can really fire real world objects.
+
+A software laser framework with webGUI, for up to 4 lasers live actions with ethedreams DACs. Think creative like Laser "battles", planetarium, sharing available lasers in demoparties for competition,...
LJ has 5 main components :
-- "Plugins" are points generators (to one or more lasers). Lot examples comes with LJ : planetarium, 3D anaglyph animations,... See plugins directory.
+- "Plugins" are "frames" generators to one or more lasers. Frames goes to different possible frames inputs of the "manager". With laser one frame = one polyline, like in LOGO. Lot examples comes with LJ : planetarium, 3D anaglyph animations,... See plugins directory.
- A "tracer" per etherdream/laser that take its given point list, correct geometry, recompute in laser controller coordinates, send it to its controller and report its status to the "manager".
-- A "manager" that talk to all tracers (which client number point lists to draw, new geometry correction,...), handle IOs (webui functions, OSC commands,...) and plugins.
+- A "manager" that talk to all tracers (which point lists to draw, new geometry correction,...), handle IOs (webui functions, OSC commands,...) and plugins.
- A web GUI in html, css, and vanilla js. This UI can be used in a tablet, computer, whatever. LJ does not come with an html server but absolutely can . This GUI has a (currently slow) simulator, but one can also use an etherdream/laser emulator (see nannou simulator below) to work without physical lasers !!
- A network available database (redis). "Plugins" can send directly their pointlists to redis. Each "tracer" is instructed to get one of the avalaible pointlist in redis.
+"Frames" (actually polylines) inputs are :
+
+- OSC (port 8002)
+- Websocket (port 9001)
+- Cli pipe (see clitools)
+- Redis keys
+
+
Important : for best performance LJ is meant to run in a dedicated computer especially with multiple lasers and highly multitasked load : if you watch video, use live webcam face recognition, webui simulator,... and run LJ on the same computer, well you need a bunch of cores. If you don't, spread the load : you can use webui on a tablet, the livecam on a phone, run pointlists generators on another computer,...
#
@@ -384,6 +393,8 @@ python3 talk3.py -i etherdreamIP
- Switch to simu page. If you don't see anything : check redis server or your points in redis doesn't respect pointlist formatting (see command reference).
+- Check Leds : for each IRL lasers the two sets of must be green at startup and laser should display their number or the pointlist you want.
+
- If talk3 works but you don't see your points : click on the Grid icon in Align page. This will override your pointlist and display squares. If Grid works : recomputed points by tracers are "bad" with given values in LJ.conf.
"Bad points" ?
@@ -444,8 +455,6 @@ lsteps is a string like "[ (1.0, 8),(0.25, 3), (0.75, 3), (1.0, 10)]"
/scene/scenenumber/start 0 or 1 : tell all tracers to use given scene
-/regen : regen webui index html page.
-
/scim : change webui simulated laser.
diff --git a/clitools/exports/toUDP.py b/clitools/exports/toUDP.py
new file mode 100644
index 0000000..64787db
--- /dev/null
+++ b/clitools/exports/toUDP.py
@@ -0,0 +1,84 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+# -*- mode: Python -*-
+
+
+'''
+
+toUDP
+v0.1.0
+
+A basic exporter
+
+LICENCE : CC
+
+by cocoa
+
+
+'''
+from __future__ import print_function
+import sys
+import os
+import argparse
+import time
+import socket
+import ast
+
+argsparser = argparse.ArgumentParser(description="toUDP v0.1b help mode")
+argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose output")
+argsparser.add_argument("-i","--ip",help="IP to bind to (0.0.0.0 by default)",default="0.0.0.0",type=str)
+argsparser.add_argument("-p","--port",help="UDP port to bind to (9000 by default)",default="9003",type=str)
+args = argsparser.parse_args()
+
+verbose = args.verbose
+ip = args.ip
+port = int(args.port)
+verbose = args.verbose
+
+
+name = "exports::toUDP"
+
+def debug(*args, **kwargs):
+ if( verbose == False ):
+ return
+ print(*args, file=sys.stderr, **kwargs)
+
+def ClientStart(ip, port):
+ global sockclient
+
+ sockclient = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
+
+def ClientSend(msgFromClient):
+
+ bytesToSend = str.encode(str(msgFromClient))
+ serverAddressPort = (ip, port)
+ bufferSize = 1024
+
+ # Send to server using created UDP socket
+ sockclient.sendto(bytesToSend, serverAddressPort)
+
+ '''
+ # If reply :
+ msgFromServer = sockclient.recvfrom(bufferSize)
+
+ msg = "Message from Server {}".format(msgFromServer[0])
+ print(msg)
+ '''
+
+try:
+
+ ClientStart(ip, port)
+ while True:
+
+ line = sys.stdin.readline()
+ if line == "":
+ time.sleep(0.01)
+ line = line.rstrip('\n')
+ #pointsList = ast.literal_eval(line)
+ debug(name,": "+line)
+ ClientSend(line)
+
+
+except EOFError:
+ debug("break")# no more information
+
diff --git a/clitools/filters/kaleidoscope.py b/clitools/filters/kaleidoscope.py
index 0495f23..5ca4396 100755
--- a/clitools/filters/kaleidoscope.py
+++ b/clitools/filters/kaleidoscope.py
@@ -163,6 +163,7 @@ try:
# Do the filter
result = kaleidoscope( pointsList )
print( result, flush=True )
+
looptime = time.time() - start
# debug(name+" looptime:"+str(looptime))
if( looptime < optimal_looptime ):
diff --git a/clitools/generators/fromOSC.py b/clitools/generators/fromOSC.py
new file mode 100644
index 0000000..d8005c5
--- /dev/null
+++ b/clitools/generators/fromOSC.py
@@ -0,0 +1,126 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+# -*- mode: Python -*-
+
+'''
+Forward /pl pointlist to cli
+
+input OSC in END points format : (x,y,color)
+output CLI in CLI points format : [x,y,color]
+
+/pl "[(150.0, 230.0, 255), (170.0, 170.0, 255), (230.0, 170.0, 255), (210.0, 230.0, 255), (150.0, 230.0, 255)]"
+
+v0.1.0
+
+LICENCE : CC
+
+by Cocoa, Sam Neurohack
+
+'''
+from __future__ import print_function
+from OSC3 import OSCServer, OSCClient, OSCMessage
+import sys
+from time import sleep
+import argparse
+import ast
+
+argsparser = argparse.ArgumentParser(description="fromOSC generator")
+argsparser.add_argument("-i","--ip",help="IP to bind to (0.0.0.0 by default)",default="0.0.0.0",type=str)
+argsparser.add_argument("-p","--port",help="OSC port to bind to (9002 by default)",default=9002,type=str)
+argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose output")
+args = argsparser.parse_args()
+
+verbose = args.verbose
+ip = args.ip
+port = int(args.port)
+
+def debug(*args, **kwargs):
+ if( verbose == False ):
+ return
+ print(*args, file=sys.stderr, **kwargs)
+
+oscserver = OSCServer( (ip, port) )
+oscserver.timeout = 0
+run = True
+
+# this method of reporting timeouts only works by convention
+# that before calling handle_request() field .timed_out is
+# set to False
+def handle_timeout(self):
+ self.timed_out = True
+
+# funny python's way to add a method to an instance of a class
+import types
+oscserver.handle_timeout = types.MethodType(handle_timeout, oscserver)
+
+# RAW OSC Frame available ?
+def OSC_frame():
+ # clear timed_out flag
+ oscserver.timed_out = False
+ # handle all pending requests then return
+ while not oscserver.timed_out:
+ oscserver.handle_request()
+
+
+# default handler
+def OSChandler(oscpath, tags, args, source):
+
+ oscaddress = ''.join(oscpath.split("/"))
+ debug("fromOSC Default OSC Handler got oscpath", oscpath, "from" + str(source[0]), ":", args)
+ #print("OSC address", path)
+ #print("find.. /bhoreal ?", path.find('/bhoreal'))
+
+ if oscpath == "/pl" and len(args)==1:
+
+ debug("correct OSC type :'/pl")
+
+ if validate(args[0]) == True:
+
+ debug("new pl : ", args[0])
+ line = args[0].replace("(",'[')
+ line = line.replace(")",']')
+ line = "[{}]".format(line)
+ print(line, flush=True);
+
+ else:
+ debug("Bad pointlist -> msg trapped.")
+
+ else:
+ debug("BAD OSC Message : " + oscpath +" " +args[0])
+
+
+oscserver.addMsgHandler( "default", OSChandler )
+
+
+def validate(pointlist):
+
+ state = True
+
+ if len(pointlist)<9:
+ debug("Not enough characters :", pointlist)
+ state = False
+
+ if pointlist.find("(") == -1:
+ debug("Bad format : use () not [] for points", pointlist)
+ state = False
+
+ try:
+ pl = bytes(pointlist, 'ascii')
+ check = ast.literal_eval(pl.decode('ascii'))
+
+ except:
+ debug("BAD POINTLIST :", pointlist)
+ state = False
+
+ return state
+
+
+# simulate a "game engine"
+while run:
+ # do the game stuff:
+ sleep(0.01)
+ # call user script
+ OSC_frame()
+
+oscserver.close()
+
diff --git a/clitools/generators/fromUDP.py b/clitools/generators/fromUDP.py
new file mode 100644
index 0000000..5f6e5e9
--- /dev/null
+++ b/clitools/generators/fromUDP.py
@@ -0,0 +1,84 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+# -*- mode: Python -*-
+
+'''
+
+fromUDP
+
+Udp server to cli
+v0.1b
+
+'''
+from __future__ import print_function
+import traceback, time
+import argparse
+import socket
+import _thread
+import sys
+
+name="generator::fromUDP"
+
+
+def debug(*args, **kwargs):
+ if( verbose == False ):
+ return
+ print(*args, file=sys.stderr, **kwargs)
+
+
+argsparser = argparse.ArgumentParser(description="fromUDP v0.1b help mode")
+argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose output")
+argsparser.add_argument("-i","--ip",help="IP to bind to (0.0.0.0 by default)",default="0.0.0.0",type=str)
+argsparser.add_argument("-p","--port",help="UDP port to bind to (9000 by default)",default=9000,type=str)
+args = argsparser.parse_args()
+
+verbose = args.verbose
+ip = args.ip
+port = int(args.port)
+verbose = args.verbose
+
+
+
+def udp_thread():
+
+ while True:
+
+ payload, client_address = sock.recvfrom(1024)
+ udpath = payload.decode('utf_8')
+ debug(udpath[0:])
+ print(udpath[0:], flush=True);
+
+ '''
+ # Reply to client
+ bytesToSend = str.encode("ACK :"+str(payload))
+ serverAddressPort = (client_address, port)
+ bufferSize = 1024
+ #sock.sendto(bytesToSend, serverAddressPort)
+ sock.sendto(bytesToSend, client_address)
+ '''
+
+def StartUDP(serverIP, UDPORT):
+ global sock
+
+ sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ server = ( serverIP,UDPORT)
+ sock.bind(server)
+ _thread.start_new_thread(udp_thread, ())
+
+
+StartUDP(ip, port)
+
+
+# Do something else
+try:
+
+ while True:
+ time.sleep(0.005)
+
+except Exception:
+ traceback.print_exc()
+
+
+
+
+
diff --git a/ethertools/receivebroadcast.py b/ethertools/receivebroadcast.py
new file mode 100644
index 0000000..ec73293
--- /dev/null
+++ b/ethertools/receivebroadcast.py
@@ -0,0 +1,22 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+# -*- mode: Python -*-
+
+# or tcpdump -i eth1 port 54545 -XX
+
+import socket
+
+
+def find_LJ():
+ """Listen for broadcast packets."""
+
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ s.bind(("0.0.0.0", 54545))
+
+ while True:
+ data, addr = s.recvfrom(1024)
+ print(" %s " % (data, ))
+ print("Packet from %s: " % (addr, ))
+
+
+find_LJ()
\ No newline at end of file
diff --git a/libs3/OSCom.py b/libs3/OSCom.py
index 4bf607b..a297f4b 100644
--- a/libs3/OSCom.py
+++ b/libs3/OSCom.py
@@ -70,12 +70,9 @@ def OSCframe():
oscserver.handle_request()
-
-
# OSC server Thread : handler, dacs reports and simulator points sender to UI.
def osc_thread():
-
#print("osc Thread launched")
try:
while True:
@@ -92,8 +89,6 @@ def osc_thread():
print("\n")
-
-
# Properly close the system. Todo
def Stop():
oscserver.close()
diff --git a/libs3/commands.py b/libs3/commands.py
index abbfd98..e80363b 100644
--- a/libs3/commands.py
+++ b/libs3/commands.py
@@ -398,6 +398,16 @@ def handler(oscpath, args):
print()
DAChecks()
print("Done.")
+
+
+ if oscpath[2] == "reset":
+ import shutil
+ print()
+ shutil.copyfile(gstt.ljpath+'/templates/LJ_template.conf', gstt.ljpath+'/LJ.conf')
+ print("templates/LJ_template.conf copied to LJ.conf.")
+ print("** RESTART LJ **")
+ #LJautokill()
+
if oscpath[2] == "restart":
print()
@@ -597,7 +607,7 @@ def UpdateAllwww():
Updatepage(gstt.ljpath+"/www/LJ.js")
Updatepage(gstt.ljpath+"/www/trckr/trckrcam1.html")
Updatepage(gstt.ljpath+"/www/simu.html")
- Updatepage(gstt.ljpath+"/www/align.html")
+ Updatepage(gstt.ljpath+"/www/settings.html")
Updatepage(gstt.ljpath+"/www/auralls.html")
Updatepage(gstt.ljpath+"/www/index.html")
diff --git a/libs3/lj23layers.py b/libs3/lj23layers.py
index f766121..a6488f3 100644
--- a/libs3/lj23layers.py
+++ b/libs3/lj23layers.py
@@ -1012,8 +1012,4 @@ def TextRGB(message, zpos, c, layer, xpos, ypos, resize, rotx, roty, rotz):
Text(message, zpos, int('0x%02x%02x%02x' % (red,green,blue),0), layer, xpos, ypos, resize, rotx, roty, rotz)
-
-
-
-
\ No newline at end of file
diff --git a/libs3/plugins.py b/libs3/plugins.py
index bfa4eb1..392bd1c 100644
--- a/libs3/plugins.py
+++ b/libs3/plugins.py
@@ -15,7 +15,7 @@ from libs3 import gstt
import os
import subprocess
import sys
-
+from socket import *
def Init(wserver):
global WSserver
@@ -177,6 +177,14 @@ def OSCsend(name, oscaddress, oscargs =''):
#PluginStart(name)
return False
+def sendbroadcast():
+
+ if gstt.debug > 0:
+ print("Sending broadcast")
+ cs = socket(AF_INET, SOCK_DGRAM)
+ cs.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
+ cs.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
+ cs.sendto("LJ 0.8".encode(), ("255.255.255.255", 54545))
# for each plugin will automatically add /pluginame before oscpath to send like /aurora/scim 1, if oscpath = "/scim 1"
diff --git a/libs3/tracer3.py b/libs3/tracer3.py
index 02ffa1e..85400c2 100644
--- a/libs3/tracer3.py
+++ b/libs3/tracer3.py
@@ -23,44 +23,44 @@ This tracer include an enhanced version (support for several lasers) of the ethe
- Drawing things :
-/pl/Scene/lasernumber [(x,y,color),(x1,y1,color),...] The live list of drawn pygame points. Tracer continously ask redis for key /clientkey+lasernumber
+/pl/Scene/lasernumber [(x,y,color),(x1,y1,color),...] The live list of drawn pygame points. Tracer continously ask redis for key /clientkey+lasernumber
/resampler/lasernumber [(1.0,8), (0.25,3),(0.75,3),(1.0,10)] : a string for resampling rules.
the first tuple (1.0,8) is for short line < 4000 in etherdream space
(0.25,3),(0.75,3),(1.0,10) for long line > 4000
i.e (0.25,3) means go at 25% position on the line, send 3 times this position to etherdream
-/clientkey "/pl/SceneNumber/" What Scene to retrieve from redis
+/clientkey "/pl/SceneNumber/" What Scene to retrieve from redis
/EDH/lasernumber
- Tracer control :
-/order 0-8 Set redis key with new value then issue the order number
+/order 0-8 Set redis key with new value then issue the order number
0 : Draw Normal point list
- 1 : Get the new EDH = reread redis key /EDH/lasernumber
+ 1 : Get the new EDH = reread redis key /EDH/lasernumber
2 : Draw BLACK point list
3 : Draw GRID point list
4 : Resampler Change (longs and shorts lsteps)
- 5 : Client Key Change = reread redis key /clientkey
- 6 : Max Intensity Change = reread redis key /intensity
- 7 : kpps change = reread redis key /kpps
- 8 : color balance change = reread redis keys /red /green /blue
+ 5 : Client Key Change = reread redis key /clientkey
+ 6 : Max Intensity Change = reread redis key /intensity
+ 7 : kpps change = reread redis key /kpps
+ 8 : color balance change = reread redis keys /red /green /blue
- Managing Etherdream DACs :
Discrete drawing values
-/kpps 0- DAC output speed to laser, then order 7. Depends of actual angle
-/intensity 0-255 Laser output power, then order 6 (for alignement,...)
-/red 0-100 % of full red, then order 8
-/green 0-100 % of full green, then order 8
-/blue 0-100 % of full blue, then order 8
+/kpps 0- DAC output speed to laser, then order 7. Depends of actual angle
+/intensity 0-255 Laser output power, then order 6 (for alignement,...)
+/red 0-100 % of full red, then order 8
+/green 0-100 % of full green, then order 8
+/blue 0-100 % of full blue, then order 8
DAC status report
-/lstt/lasernumber etherdream last_status.playback_state (0: idle 1: prepare 2: playing)
-/cap/lasernumber number of empty points sent to fill etherdream buffer (up to 1799)
-/lack/lasernumber "a": ACK "F": Full "I": invalid. 64 or 35 for no connection.
+/lstt/lasernumber etherdream last_status.playback_state (0: idle 1: prepare 2: playing)
+/cap/lasernumber number of empty points sent to fill etherdream buffer (up to 1799)
+/lack/lasernumber "a": ACK "F": Full "I": invalid. 64 or 35 for no connection.
Geometric corrections
@@ -223,7 +223,7 @@ class DAC(object):
while True:
- #pdb.set_trace()
+ #pdb.set_trace()
for indexpoint,currentpoint in enumerate(self.pl):
#print indexpoint, currentpoint
xyc = [currentpoint[0],currentpoint[1],currentpoint[2]]
@@ -335,7 +335,7 @@ class DAC(object):
# ipconn state is -1 at startup (see gstt) and modified here
r.set('/lack/'+str(self.mylaser), self.connstatus)
- gstt.lstt_ipconn[self.mylaser] = self.connstatus
+ gstt.lstt_ipconn[self.mylaser] = self.connstatus
self.buf = b''
# Upper case PL is the Point List number
@@ -349,7 +349,7 @@ class DAC(object):
if r.get('/EDH/'+str(self.mylaser)) == None:
#print("Laser",self.mylaser,"NO EDH !! Computing one...")
homographyp.newEDH(self.mylaser)
- else:
+ else:
gstt.EDH[self.mylaser] = np.array(ast.literal_eval(r.get('/EDH/'+str(self.mylaser)).decode('ascii')))
#print("Laser",self.mylaser,"found its EDH in redis")
@@ -447,9 +447,17 @@ class DAC(object):
if order == 0:
# USER point list
- self.pl = ast.literal_eval(r.get(self.clientkey+str(self.mylaser)).decode('ascii'))
+
+ #self.pl = ast.literal_eval(r.get(self.clientkey+str(self.mylaser)).decode('ascii'))
#print("Tracer : laser", self.mylaser, " order 0 : pl : ",len(self.pl))
+ try:
+ self.pl = ast.literal_eval(r.get(self.clientkey+str(self.mylaser)).decode('ascii'))
+
+ except SyntaxError:
+ print("BAD POINTLIST on Tracer : laser", self.mylaser, " order 0 : pl :",self.pl)
+ self.pl = grid_points
+
else:
# Get the new EDH
@@ -524,13 +532,13 @@ class DAC(object):
time.sleep(0.001)
cap += 150
-# print("Writing %d points" % (cap, ))
+ #print("Writing %d points" % (cap, ))
#t0 = time.time()
#if self.mylaser == 2:
- # print(points)
+ # print(points)
self.write(points)
#t1 = time.time()
-# print("Took %f" % (t1 - t0, )
+ #print("Took %f" % (t1 - t0, )
if not started:
print("Tracer", self.mylaser, "starting with", gstt.kpps[self.mylaser],"kpps")
@@ -571,7 +579,7 @@ def find_dac():
order = r.get('/order')
neworder = order & ~(1<< self.mylaser*2)
neworder = neworder & ~(1<< 1+ self.mylaser*2)
- r.set('/order', str(neworder))
+ r.set('/order', str(neworder))
else:
# Laser bit 0 = 1
diff --git a/main.py b/main.py
index acaefe9..08dbd47 100755
--- a/main.py
+++ b/main.py
@@ -36,35 +36,32 @@ print("")
import redis
import os
ljpath = r'%s' % os.getcwd().replace('\\','/')
-
-
import sys
#sys.path.append('libs3/')
-
from libs3 import gstt, settings
-gstt.ljpath= ljpath
+gstt.ljpath = ljpath
log.info("Reading " + gstt.ConfigName + " setup file...")
settings.Read()
# Arguments may alter .conf file so import settings first then cli
from libs3 import cli
-
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 homographyp, commands, font1
-
#import subprocess
-
import os
#import midi
-
from libs3 import OSC3
from websocket_server import WebsocketServer
#import socket
@@ -264,14 +261,16 @@ def osc_thread():
#print("Sending simu frame from",'/pl/'+str(gstt.SceneNumber)+'/'+str(gstt.Laser))
#print(r.get('/pl/'+str(gstt.SceneNumber)+'/'+str(gstt.Laser)))
- sendWSall("/simul" +" "+ str(r.get('/pl/'+str(gstt.SceneNumber)+'/'+str(gstt.Laser)).decode('ascii')))
+ sendWSall("/simul" +" "+ str(r.get('/po/'+str(gstt.SceneNumber)+'/'+str(gstt.Laser)).decode('ascii')))
+ if random.randint(0,100)>95:
+ plugins.sendbroadcast()
except Exception as e:
import sys, traceback
- print('\n---------------------')
- print('Exception: %s' % e)
- print('- - - - - - - - - - -')
+ print('\n--------------------------')
+ print('OSC Thread Exception: %s' % e)
+ print('- - - - - - - - - - - - - - ')
traceback.print_tb(sys.exc_info()[2])
print("\n")
diff --git a/plugins/aurora/aurora.py b/plugins/aurora/aurora.py
index 303baa0..5bdbe60 100644
--- a/plugins/aurora/aurora.py
+++ b/plugins/aurora/aurora.py
@@ -181,7 +181,7 @@ log.infog("Aurora v0.1b")
OSCinPort = 8090
ljscene = 0
-StartFXs = ["anim.Maxwell","anim.Starfield","anim.Starfield", "anim.Word"]
+StartFXs = ["anim.Starfield","anim.Starfield","anim.Starfield", "anim.Word"]
# Useful variables init.
white = lj.rgb2int(255,255,255)
@@ -1125,9 +1125,9 @@ def AllFX():
dots = eval(LAY['FX']+"(LAY)")
if LAY['FX'] != "Zero" or lent(dots) != 0:
#print(dots, LAY['color'])
- for cc in range(15):
- ccmidi[cc] = int(lj.fromKey("/midi/cc/1/"+str(cc)))
- #print(ccmidi)
+ #for cc in range(15):
+ # ccmidi[cc] = int(lj.fromKey("/midi/cc/1/"+str(cc)))
+ # #print(ccmidi)
lj.rPolyLineOneColor(dots, c = LAY['color'], layer = l, closed = LAY['closed'], xpos = LAY['Xcoord'] + LAY['stepvals'][LAY['step']] - (LAY['lineSize']/2), ypos = Layer[l]['Ycoord'], resize = LAY['scale'] * audioR, rotx = LAY['Xrotdirec'], roty = LAY['Yrotdirec'], rotz = LAY['Zrotdirec'])
#lj.rPolyLineOneColor(dots, c = LAY['color'], layer = l, closed = LAY['closed'], xpos = LAY['Xcoord'] - (ccmidi[0]-64)*4 - (LAY['lineSize']/2), ypos = Layer[l]['Ycoord'] + (ccmidi[1]-64)*4, resize = LAY['scale'] * audioR * (ccmidi[2])/50, rotx = LAY['Xrotdirec']+(ccmidi[3]*3), roty = LAY['Yrotdirec']+(ccmidi[3]*3), rotz = LAY['Zrotdirec']+(ccmidi[3]*3))
else:
diff --git a/www/align.html b/www/align.html
deleted file mode 100644
index 6a6d427..0000000
--- a/www/align.html
+++ /dev/null
@@ -1,937 +0,0 @@
-
-
-
- Align Rack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- /TL Align
-
-
-
-
-
-
-
- Align Rack
-
-
- /team/laser
-
-
-
- Stt
-
-
-
-
-
-
- Ack
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Scene
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
kPPS
-
Buffer
-
-
-
-
-
-
-
-
-
Angle
-
Offset X
-
Offset Y
-
-
-
-
-
-
-
-
-
-
-
-
Intens
-
Scale X
-
Scale X
-
-
-
-
-
-
-
-
-
-
-
-
Red
-
Green
-
Blue
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
kPPS
-
Buffer
-
-
-
-
-
-
-
-
-
Angle
-
Offset X
-
Offset Y
-
-
-
-
-
-
-
-
-
-
-
-
Intens
-
Scale X
-
Scale X
-
-
-
-
-
-
-
-
-
-
-
-
Red
-
Green
-
Blue
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
kPPS
-
Buffer
-
-
-
-
-
-
-
-
-
Angle
-
Offset X
-
Offset Y
-
-
-
-
-
-
-
-
-
-
-
-
Intens
-
Scale X
-
Scale X
-
-
-
-
-
-
-
-
-
-
-
-
Red
-
Green
-
Blue
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
kPPS
-
Buffer
-
-
-
-
-
-
-
-
-
Angle
-
Offset X
-
Offset Y
-
-
-
-
-
-
-
-
-
-
-
-
Intens
-
Scale X
-
Scale X
-
-
-
-
-
-
-
-
-
-
-
-
Red
-
Green
-
Blue
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/www/auralls.html b/www/auralls.html
index 866ed23..daf2a20 100644
--- a/www/auralls.html
+++ b/www/auralls.html
@@ -59,10 +59,10 @@
-
+
@@ -93,8 +93,8 @@
-
diff --git a/www/index.html b/www/index.html
index ddde89a..e843eae 100644
--- a/www/index.html
+++ b/www/index.html
@@ -101,15 +101,15 @@
-
+
- Align
+ Settings
@@ -117,7 +117,7 @@
- Align
+ Settings
diff --git a/www/simu.html b/www/simu.html
index e3b1320..68885af 100644
--- a/www/simu.html
+++ b/www/simu.html
@@ -56,10 +56,10 @@
-
+
@@ -90,8 +90,8 @@
-
- rstrt LJ
+
+ reset
diff --git a/www/trckr/trckr.html b/www/trckr/trckr.html
deleted file mode 100644
index 1cc933c..0000000
--- a/www/trckr/trckr.html
+++ /dev/null
@@ -1,680 +0,0 @@
-
-
-
-
LASERCam 1
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- /TL RGY 1
-
-
-
-
-
-
-
- LASERcam 1 : Allow to use your webcam + start
-
-
- /team/laser
-
-
-
-
-
-
-
-
-
-
-
-
-
- Colors
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
To try it out:
-
- - Allow the page to use your webcamera
- - Make sure that your face is clearly visible in the video, and click start
- - See the model fitted to your face
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/www/trckr/trckrcam1.html b/www/trckr/trckrcam1.html
index f94f0b5..4e2056e 100644
--- a/www/trckr/trckrcam1.html
+++ b/www/trckr/trckrcam1.html
@@ -93,10 +93,10 @@
-
+
@@ -127,8 +127,8 @@
-
- rstrt LJ
+
+ Reset