wip: heading to DAC modularity

This commit is contained in:
alban 2023-02-24 13:37:49 +01:00
parent 88998abde7
commit 1847c8ebef
10 changed files with 1197 additions and 194 deletions

2
.gitignore vendored
View File

@ -1,3 +1,5 @@
.*swp*
*__pycache__
www/config.js
.venv/
.idea

View File

@ -1,15 +1,16 @@
[General]
lasernumber = 1
debug = 1
debug = 2
ljayserverip = 0.0.0.0
wwwip = 127.0.0.1
nozoscip = 127.0.0.1
bhoroscip = 127.0.0.1
autostart = artnet
autostart =
wstype = ws
wsport = 9001
[laser0]
dac_family = helios
color = -1
type = DS1000
ip = 127.0.0.1

View File

@ -17,7 +17,7 @@ from /team/laser
#ConfigName = "setexample.conf"
ConfigName = "LJ.conf"
debug = 0
debug = 10
ljpath=''
anims= [[],[],[],[]]

View File

@ -151,8 +151,7 @@ def find_affine(points1,points2):
return H
def apply(H,points):
p = np.ones((len(points),3),'float64')
p = np.ones((len(points),2),'float64')
p[:,:2] = points
pp = np.dot(p,H.T)
pp[:,:2]/=pp[:,2].reshape(len(p),1)

BIN
libs3/libHeliosDacAPI.so Normal file

Binary file not shown.

94
libs3/tracer.py Normal file
View File

@ -0,0 +1,94 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# -*- mode: Python -*-
'''
Tracer v0.8.2
Etherdream DACs handler on network via Redis
LICENCE : CC
Sam Neurohack, pclf
One tracer process is launched per requested laser by LJ. Lasers parameters in LJ.conf.
Live I/O based on redis keys : inputs (Pointlists to draw,...) and outputs (DAC state, errors,..).
Keys are mostly read and set at each main loop.
* Redis keys reference *
- 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
/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
/EDH/lasernumber
- Tracer control :
/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
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
- 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
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.
Geometric corrections
Doctodo
'''
import socket
import time
import struct
# from gstt import debug
from libs3 import gstt, log
import math
from itertools import cycle
# from globalVars import *
import pdb
import ast
import redis
from .tracer_etherdream import TracerEtherdream
from .tracer_helios import TracerHelios
from libs3 import homographyp
import numpy as np
import binascii
r = redis.StrictRedis(host=gstt.LjayServerIP, port=6379, db=0)
def DAC(mylaser, point_list_number, dac_family="etherdream"):
print(f"# Starting DAC #{mylaser} PL#:{point_list_number} Family:'{dac_family}'")
if dac_family == "etherdream":
return TracerEtherdream(mylaser, point_list_number, redis=r, port=7765)
if dac_family == "helios":
return TracerHelios(mylaser, point_list_number, redis=r)

363
libs3/tracer_common.py Normal file
View File

@ -0,0 +1,363 @@
import ast
import math
import struct
import time
import numpy as np
import redis
from libs3 import gstt, log
def pack_point(laser, intensity, x, y, r, g, b, i=-1, u1=0, u2=0, flags=0):
"""Pack some color values into a struct dac_point."""
# print("Tracer", laser,":", r,g,b,"intensity", intensity, "i", i)
if r > intensity:
r = intensity
if g > intensity:
g = intensity
if b > intensity:
b = intensity
if max(r, g, b) == 0:
i = 0
else:
i = intensity
x = int(x)
y = int(y)
# print("Tracer ", laser, ": packing", x, y, r, g, b, "intensity", intensity, "i", i)
if x < -32767:
if gstt.debug > 1:
log.err("Tracer " + str(laser) + " : x coordinates " + str(x) + " was below -32767")
x = -32000
if x > 32767:
if gstt.debug > 1:
log.err("Tracer " + str(laser) + " : x coordinates " + str(x) + " was bigger than 32767")
x = 32000
if y < -32767:
if gstt.debug > 1:
log.err("Tracer " + str(laser) + " : y coordinates " + str(y) + " was below -32767")
y = -32000
if y > 32767:
if gstt.debug > 1:
log.err("Tracer " + str(laser) + " : y coordinates " + str(y) + " was bigger than 32767")
y = 32000
return struct.pack("<HhhHHHHHH", flags, x, y, r, g, b, i, u1, u2)
class ProtocolError(Exception):
"""Exception used when a protocol error is detected."""
pass
class Status(object):
"""Represents a status response from the DAC."""
def __init__(self, data):
"""Initialize from a chunk of data."""
self.protocol_version, self.le_state, self.playback_state, \
self.source, self.le_flags, self.playback_flags, \
self.source_flags, self.fullness, self.point_rate, \
self.point_count = \
struct.unpack("<BBBBHHHHII", data)
def dump(self, prefix=" - "):
"""Dump to a string."""
lines = [
""
"Host ",
"Light engine: state %d, flags 0x%x" %
(self.le_state, self.le_flags),
"Playback: state %d, flags 0x%x" %
(self.playback_state, self.playback_flags),
"Buffer: %d points" %
(self.fullness,),
"Playback: %d kpps, %d points played" %
(self.point_rate, self.point_count),
"Source: %d, flags 0x%x" %
(self.source, self.source_flags)
]
if gstt.debug == 2:
print()
for l in lines:
print(prefix + l)
class OnePointIterator( ):
def __init__(self, ref):
self.ref = ref
def __iter__(self):
return self
def __next__(self):
while True:
# pdb.set_trace()
for indexpoint, currentpoint in enumerate(self.ref.pl):
# We modify the point geometry according to warp settings
# print indexpoint, currentpoint
# xyc = [currentpoint[0], currentpoint[1], currentpoint[2]]
# self.ref.xyrgb = self.ref.get_warped_point(xyc)
x, y = self.ref.get_warped_point(currentpoint[0], currentpoint[1])
r, g, b = self.ref.int_to_rgb(currentpoint[2])
# We modify the point color based on channel specific r,g,b intensity settings
rgb = (round(r * self.ref.intred / 100), round(g * self.ref.intgreen / 100),
round(b * self.ref.intblue / 100))
# We compute the delta with previous position
delta_x, delta_y = x - self.ref.prev_x, y -self.ref.prev_y
# We compute the distance from previous postion
if math.hypot(delta_x, delta_y) < 4000:
# For glitch art : decrease lsteps
# l_steps = [ (1.0, 8)]
l_steps = gstt.stepshortline
else:
# For glitch art : decrease lsteps
# l_steps = [ (0.25, 3), (0.75, 3), (1.0, 10)]
l_steps = gstt.stepslongline
# We add intermediate points based on settings
for e in l_steps:
step = e[0]
for i in range(0, e[1]):
self.ref.xyrgb_step = (self.ref.prev_x + step * delta_x,
self.ref.prev_y + step * delta_y) + rgb # + self.ref.xyrgb_prev[2:]# + rgb
print(self.ref.xyrgb_step)
yield self.ref.xyrgb_step
self.ref.prev_x, self.ref.prev_y = x, y
self.ref.xyrgb_prev = [x, y]
class Tracer(object):
"""A connection to a DAC."""
laser_id: int
redis: object
point_list_number: list
pl: list
client_key: str # /pl/<laser_id> by default
black_points = [(278.0, 225.0, 0), (562.0, 279.0, 0), (401.0, 375.0, 0), (296.0, 454.0, 0), (298.0, 165.0, 0)]
grid_points = [(300.0, 200.0, 0), (500.0, 200.0, 65280), (500.0, 400.0, 65280), (300.0, 400.0, 65280),
(300.0, 200.0, 65280), (300.0, 200.0, 0), (200.0, 100.0, 0), (600.0, 100.0, 65280),
(600.0, 500.0, 65280), (200.0, 500.0, 65280), (200.0, 100.0, 65280)]
ackstate = {'61': 'ACK', '46': 'FULL', '49': "INVALID", '21': 'STOP', '64': "NO CONNECTION ?",
'35': "NO CONNECTION ?",
'97': 'ACK', '70': 'FULL', '73': "INVALID", '33': 'STOP', '100': "NOCONNECTION", '48': "NOCONNECTION",
'a': 'ACK', 'F': 'FULL', 'I': "INVALID", '!': 'STOP', 'd': "NO CONNECTION ?", '0': "NO CONNECTION ?"}
lstate = {'0': 'IDLE', '1': 'PREPARE', '2': "PLAYING", '3': 'STOP', '64': "NOCONNECTION ?"}
"""
status : the general status of the DAC, is it working or not?
ack_status : DAC specific, sent continuously by the DAC to track activity
"""
def int_to_rgb(self, c):
return ((c >> 16) & 0xFF) << 8, ((c >> 8) & 0xFF) << 8, (c & 0xFF) << 8
def get_status(self):
raise Exception("Please override the method")
def set_status(self, status: int):
raise Exception("Please override the method")
def get_warped_point(self, x, y ):
"""
A DAC specific point model, ex EtherPoint or HeliosPoint
:param xyc: x,y,color
:return:
"""
raise Exception("Please override the method")
# def get_ack_status(self):
# raise Exception("Please override the method")
#
# def set_ack_status(self, ack_status: int):
# raise Exception("Please override the method")
def GetPoints(self, capacity):
"""
Iterates points and sends them to OnePoint
:param capacity:
:return:
"""
iterator = OnePointIterator(self)
# i = list(next(iterator))
# d = [list(next(iterator)) for i in range(capacity)]
d = [list(next(iterator)) for i in range(capacity)]
return d
def prepare(self):
raise Exception("Please override the method")
def begin(self, n, kpps):
raise Exception("Please override the method")
def before_loop(self):
"""
Hook for DAC specific actions on each loop
:return:
"""
raise Exception("Please override the method")
def get_points_capacity(self):
"""
How much points can we send next to the DAC
:return: int
"""
raise Exception("Please override the method")
def convert_color(self, c):
"""
DAC specific color conversion
:param c:
:return:
"""
raise Exception("Please override the method")
def write(self, points):
"""
Actual sending to the DAC
:param points: a list of points "corrected" with geometry, color, intensity settings
:return:
"""
raise Exception("Please override the method")
def play_stream(self):
"""
Main loop common for every dac driver
:return:
"""
self.before_loop()
started = 0
while True:
self.redis.set('/lstate/' + str(self.laser_id), self.get_status())
# print("laser", self.laser_id, "Pb : ",self.last_status.playback_state)
order = int(self.redis.get('/order/' + str(self.laser_id)).decode('ascii'))
# print("tracer", str(self.laser_id),"order", order, type(order)
if order == 0:
""" 0 : The actual points sending to laser """
# USER point list /
# @todo si la clef est vide utiliser les points noirs ? -> syntax error -> black points.
try:
self.pl = ast.literal_eval(self.redis.get(self.clientkey + str(self.laser_id)).decode('ascii'))
except SyntaxError:
print("BAD POINTLIST on Tracer : laser", self.laser_id, " order 0 : pl : ", self.pl)
self.pl = self.black_points
# print("Tracer : laser", self.laser_id, " order 0 : pl : ",len(self.pl))
else:
if order == 1:
""" 1 : Get the new EDH / The zoom || trapezoidal / homography settings for the laser """
print("Tracer", self.laser_id, "new EDH ORDER in redis")
# gstt.EDH[self.laser_id] = np.array(
# ast.literal_eval(self.redis.get('/EDH/' + str(self.laser_id)).decode('ascii')))
# # Back to user point list
# self.redis.set('/order/' + str(self.laser_id), 0)
#
if order == 2:
""" 2 : Send a BLACK point list """
print("Tracer", self.laser_id, "BLACK ORDER in redis")
self.pl = self.black_points
if order == 3:
""" 3: Send a GRID point list"""
print("Tracer", self.laser_id, "GRID ORDER in redis")
self.pl = self.grid_points
if order == 4:
""" 4: Resampler Change, modify the automatic intermediary points settings """
self.resampler = ast.literal_eval(self.redis.get('/resampler/' + str(self.laser_id)).decode('ascii'))
print("Tracer", self.laser_id, " : resetting lsteps for", self.resampler)
gstt.stepshortline = self.resampler[0]
gstt.stepslongline[0] = self.resampler[1]
gstt.stepslongline[1] = self.resampler[2]
gstt.stepslongline[2] = self.resampler[3]
# Back to user point list order
self.redis.set('/order/' + str(self.laser_id), 0)
if order == 5:
""" 5: Client Key change, change the address to read points from in redis ex: /pl/0 => /pl/3"""
print("Tracer", self.laser_id, "new clientkey")
self.clientkey = self.redis.get('/clientkey')
# Back to user point list order
self.redis.set('/order/' + str(self.laser_id), 0)
if order == 6:
""" 6: change intensity """
# @todo check for helios vs etherdream
self.intensity = int(self.redis.get('/intensity/' + str(self.laser_id)).decode('ascii')) << 8
print("Tracer", self.laser_id, "new Intensity", self.intensity)
gstt.intensity[self.laser_id] = self.intensity
self.redis.set('/order/' + str(self.laser_id), "0")
if order == 7:
""" 7: kpps change"""
gstt.kpps[self.laser_id] = int(self.redis.get('/kpps/' + str(self.laser_id)).decode('ascii'))
print("Tracer", self.laser_id, "new kpps", gstt.kpps[self.laser_id])
self.update(0, gstt.kpps[self.laser_id])
self.redis.set('/order/' + str(self.laser_id), "0")
if order == 8:
""" 8: color balance change"""
self.intred = int(self.redis.get('/red/' + str(self.laser_id)).decode('ascii'))
self.intgreen = int(self.redis.get('/green/' + str(self.laser_id)).decode('ascii'))
self.intblue = int(self.redis.get('/blue/' + str(self.laser_id)).decode('ascii'))
print("Tracer", self.laser_id, "new color balance", self.intred, "% ", self.intgreen, "% ",
self.intblue, "% ")
self.redis.set('/order/' + str(self.laser_id), "0")
# if getattr(self, "last_status") :
# self.redis.set('/lstt/' + str(self.laser_id), self.last_status.playback_state)
# pdb.set_trace()
# How much room?
capacity = self.get_points_capacity()
self.redis.set('/cap/' + str(self.laser_id), capacity)
iterator = OnePointIterator(self)
points = [next(iterator) for i in range(capacity)]
# points = self.GetPoints(capacity)
# print("Writing %d points" % (cap, ))
# t0 = time.time()
# if self.laser_id == 2:
# print(points)
self.write(points)
# t1 = time.time()
# print("Took %f" % (t1 - t0, )
if not started:
print("Tracer", self.laser_id, "starting with", gstt.kpps[self.laser_id], "kpps")
self.begin(0, gstt.kpps[self.laser_id])
started = 1

400
libs3/tracer_etherdream.py Normal file
View File

@ -0,0 +1,400 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# -*- mode: Python -*-
'''
Tracer v0.8.2
Etherdream DACs handler on network via Redis
LICENCE : CC
Sam Neurohack, pclf
Includes live conversion in etherdream coordinates, geometric corrections, color balance change, intensity limitation, grid display,...
One tracer process is launched per requested laser by LJ. Lasers parameters in LJ.conf.
Live I/O based on redis keys : inputs (Pointlists to draw,...) and outputs (DAC state, errors,..).
Keys are mostly read and set at each main loop.
This tracer include an enhanced version (support for several lasers) of the etherdream python library from j4cDAC.
* Redis keys reference *
- 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
/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
/EDH/lasernumber
- Tracer control :
/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
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
- 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
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.
Geometric corrections
Doctodo
'''
import socket
import time
import struct
# from gstt import debug
from libs3 import gstt, log
import math
import ast
from libs3 import homographyp
import numpy as np
from .tracer_common import *
# @todo this needs normallization
ackstate = {'61': 'ACK', '46': 'FULL', '49': "INVALID", '21': 'STOP', '64': "NO CONNECTION ?",
'35': "NO CONNECTION ?",
'97': 'ACK', '70': 'FULL', '73': "INVALID", '33': 'STOP', '100': "NOCONNECTION", '48': "NOCONNECTION",
'a': 'ACK', 'F': 'FULL', 'I': "INVALID", '!': 'STOP', 'd': "NO CONNECTION ?", '0': "NO CONNECTION ?"}
black_points = [(278.0, 225.0, 0), (562.0, 279.0, 0), (401.0, 375.0, 0), (296.0, 454.0, 0), (298.0, 165.0, 0)]
grid_points = [(300.0, 200.0, 0), (500.0, 200.0, 65280), (500.0, 400.0, 65280), (300.0, 400.0, 65280),
(300.0, 200.0, 65280), (300.0, 200.0, 0), (200.0, 100.0, 0), (600.0, 100.0, 65280),
(600.0, 500.0, 65280), (200.0, 500.0, 65280), (200.0, 100.0, 65280)]
class TracerEtherdream(Tracer):
"""A connection to a DAC."""
# "Laser point List" Point generator
# each points is yielded : Getpoints() call n times OnePoint()
def __init__(self, mylaser, PL, redis, port=7765):
"""Connect to the DAC over TCP."""
socket.setdefaulttimeout(2)
self.redis = redis
self.mylaser = mylaser
self.clientkey = self.redis.get("/clientkey").decode('ascii')
# log.info("Tracer "+str(self.mylaser)+" connecting to "+ gstt.lasersIPS[mylaser])
# print("DAC", self.mylaser, "Handler process, connecting to", gstt.lasersIPS[mylaser] )
self.conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.connstatus = self.conn.connect_ex((gstt.lasersIPS[mylaser], port))
if self.connstatus == 35 or self.connstatus == 64:
log.err(
"Tracer " + str(self.mylaser) + " (" + gstt.lasersIPS[mylaser] + "): " + ackstate[str(self.connstatus)])
else:
print(
"Tracer " + str(self.mylaser) + " (" + gstt.lasersIPS[mylaser] + "): " + ackstate[str(self.connstatus)])
# ipconn state is -1 at startup (see gstt) and modified here
self.redis.set('/lack/' + str(self.mylaser), self.connstatus)
gstt.lstt_ipconn[self.mylaser] = self.connstatus
self.buf = b''
# Upper case PL is the Point List number
self.PL = PL
# Lower case pl is the actual point list coordinates
# pdb.set_trace()
self.pl = ast.literal_eval(self.redis.get(self.clientkey + str(self.mylaser)).decode('ascii'))
if self.redis.get('/EDH/' + str(self.mylaser)) == None:
# print("Laser",self.mylaser,"NO EDH !! Computing one...")
homographyp.newEDH(self.mylaser)
else:
gstt.EDH[self.mylaser] = np.array(ast.literal_eval(self.redis.get('/EDH/' + str(self.mylaser)).decode('ascii')))
# print("Laser",self.mylaser,"found its EDH in redis")
# print gstt.EDH[self.mylaser]
self.xyrgb = self.xyrgb_prev = (0, 0, 0, 0, 0)
self.intensity = 65280
self.intred = 100
self.intgreen = 100
self.intblue = 100
self.newstream = self.OnePoint()
self.prev_x = 0
self.prev_y = 0
if gstt.debug > 0:
print("Tracer", self.mylaser, "init asked for ckey", self.clientkey + str(self.mylaser))
if self.connstatus != 0:
# print(""
log.err("Connection ERROR " + str(self.connstatus) + " with laser " + str(mylaser) + " : " + str(
gstt.lasersIPS[mylaser]))
# print("first 10 points in PL",self.PL, self.GetPoints(10)
else:
print("Connection status for DAC " + str(self.mylaser) + " : " + str(self.connstatus))
# Reference points
# Read the "hello" message
first_status = self.readresp("?")
first_status.dump()
position = []
def before_loop(self):
# print("laser", self.laser_id, "Pb : ",self.last_status.playback_state)
# error if DAC is already playing state (from other source)
if self.last_status.playback_state == 2:
raise Exception("already playing?!")
# if idle go to prepare state
elif self.last_status.playback_state == 0:
self.prepare()
def get_points_capacity(self):
cap = 1799 - self.last_status.fullness
if cap < 100:
time.sleep(0.001)
cap += 150
return
def read(self, l):
"""Read exactly length bytes from the connection."""
while l > len(self.buf):
self.buf += self.conn.recv(4096)
obuf = self.buf
self.buf = obuf[l:]
return obuf[:l]
def readresp(self, cmd):
"""Read a response from the DAC."""
data = self.read(22)
response = data[0]
gstt.lstt_dacanswers[self.mylaser] = response
cmdR = chr(data[1])
status = Status(data[2:])
self.redis.set('/lack/' + str(self.mylaser), response)
if cmdR != cmd:
raise ProtocolError("expected resp for %r, got %r"
% (cmd, cmdR))
if response != ord('a'):
raise ProtocolError("expected ACK, got %r"
% (response,))
self.last_status = status
return status
def begin(self, lwm, rate):
cmd = struct.pack("<cHI", b'b', lwm, rate)
print("Tracer", str(self.mylaser), "begin with PL : ", str(self.PL))
self.conn.sendall(cmd)
return self.readresp("b")
def update(self, lwm, rate):
print(("update", lwm, rate))
cmd = struct.pack("<cHI", b'u', lwm, rate)
self.conn.sendall(cmd)
return self.readresp("u")
def encode_point(self, point):
return pack_point(self.mylaser, self.intensity, *point)
def get_capacity(self):
""" How much points can we send next / are free in etherdream's buffer?"""
cap = 1799 - self.last_status.fullness
return cap
def write(self, points):
epoints = list(map(self.encode_point, points))
cmd = struct.pack("<cH", b'd', len(epoints))
self.conn.sendall(cmd + b''.join(epoints))
return self.readresp('d')
def get_warped_point(self, x, y ):
# Etherpoint all transform in one matrix, with warp !!
# xy : x y
# gstt.EDH[self.mylaser]= np.array(ast.literal_eval(self.redis.get('/EDH/'+str(self.mylaser))))
position = homographyp.apply(gstt.EDH[self.laser_id], np.array([(x, y)]))
# print("etherdream point",position[0][0], position[0][1], ((c >> 16) & 0xFF) << 8, ((c >> 8) & 0xFF) << 8, (c & 0xFF) << 8)
return position[0][0], position[0][1]
def prepare(self):
self.conn.sendall(b'p')
return self.readresp('p')
def stop(self):
self.conn.sendall('s')
return self.readresp('s')
def estop(self):
self.conn.sendall("\xFF")
return self.readresp("\xFF")
def clear_estop(self):
self.conn.sendall("c")
return self.readresp("c")
def ping(self):
self.conn.sendall('?')
return self.readresp('?')
def play_stream(self):
# print("laser", self.mylaser, "Pb : ",self.last_status.playback_state)
# error if etherdream is already playing state (from other source)
if self.last_status.playback_state == 2:
raise Exception("already playing?!")
# if idle go to prepare state
elif self.last_status.playback_state == 0:
self.prepare()
started = 0
while True:
# print("laser", self.mylaser, "Pb : ",self.last_status.playback_state)
order = int(self.redis.get('/order/' + str(self.mylaser)).decode('ascii'))
# print("tracer", str(self.mylaser),"order", order, type(order)
if order == 0:
# USER point list
# self.pl = ast.literal_eval(self.redis.get(self.clientkey+str(self.mylaser)).decode('ascii'))
# print("Tracer : laser", self.mylaser, " order 0 : pl : ",len(self.pl))
# si la clef est vide utiliser les points noirs ? -> syntax error -> black points.
try:
# newpl = ""
# newpl = self.redis.get(self.clientkey+str(self.mylaser))
# self.pl = ast.literal_eval(newpl.decode('ascii'))
self.pl = ast.literal_eval(self.redis.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 = black_points
# print("Tracer : laser", self.mylaser, " order 0 : pl : ",len(self.pl))
else:
# Get the new EDH
if order == 1:
print("Tracer", self.mylaser, "new EDH ORDER in redis")
gstt.EDH[self.mylaser] = np.array(
ast.literal_eval(self.redis.get('/EDH/' + str(self.mylaser)).decode('ascii')))
# Back to user point list
self.redis.set('/order/' + str(self.mylaser), 0)
# BLACK point list
if order == 2:
print("Tracer", self.mylaser, "BLACK ORDER in redis")
self.pl = black_points
# GRID point list
if order == 3:
print("Tracer", self.mylaser, "GRID ORDER in redis")
self.pl = grid_points
# Resampler Change
if order == 4:
self.resampler = ast.literal_eval(self.redis.get('/resampler/' + str(self.mylaser)).decode('ascii'))
print("Tracer", self.mylaser, " : resetting lsteps for", self.resampler)
gstt.stepshortline = self.resampler[0]
gstt.stepslongline[0] = self.resampler[1]
gstt.stepslongline[1] = self.resampler[2]
gstt.stepslongline[2] = self.resampler[3]
# Back to user point list order
self.redis.set('/order/' + str(self.mylaser), 0)
# Client Key change
if order == 5:
print("Tracer", self.mylaser, "new clientkey")
self.clientkey = self.redis.get('/clientkey')
# Back to user point list order
self.redis.set('/order/' + str(self.mylaser), 0)
# Intensity change
if order == 6:
self.intensity = int(self.redis.get('/intensity/' + str(self.mylaser)).decode('ascii')) << 8
print("Tracer", self.mylaser, "new Intensity", self.intensity)
gstt.intensity[self.mylaser] = self.intensity
self.redis.set('/order/' + str(self.mylaser), "0")
# kpps change
if order == 7:
gstt.kpps[self.mylaser] = int(self.redis.get('/kpps/' + str(self.mylaser)).decode('ascii'))
print("Tracer", self.mylaser, "new kpps", gstt.kpps[self.mylaser])
self.update(0, gstt.kpps[self.mylaser])
self.redis.set('/order/' + str(self.mylaser), "0")
# color balance change
if order == 8:
self.intred = int(self.redis.get('/red/' + str(self.mylaser)).decode('ascii'))
self.intgreen = int(self.redis.get('/green/' + str(self.mylaser)).decode('ascii'))
self.intblue = int(self.redis.get('/blue/' + str(self.mylaser)).decode('ascii'))
print("Tracer", self.mylaser, "new color balance", self.intred, "% ", self.intgreen, "% ",
self.intblue, "% ")
self.redis.set('/order/' + str(self.mylaser), "0")
self.redis.set('/lstt/' + str(self.mylaser), self.last_status.playback_state)
# pdb.set_trace()
# How much room?
cap = 1799 - self.last_status.fullness
points = self.GetPoints(cap)
self.redis.set('/cap/' + str(self.mylaser), cap)
if cap < 100:
time.sleep(0.001)
cap += 150
# print("Writing %d points" % (cap, ))
# t0 = time.time()
# if self.mylaser == 2:
# print(points)
self.write(points)
# t1 = time.time()
# print("Took %f" % (t1 - t0, )
if not started:
print("Tracer", self.mylaser, "starting with", gstt.kpps[self.mylaser], "kpps")
self.begin(0, gstt.kpps[self.mylaser])
started = 1

148
libs3/tracer_helios.py Normal file
View File

@ -0,0 +1,148 @@
import ctypes
from libs3 import gstt
from libs3 import homographyp
from .tracer_common import Tracer, OnePointIterator, ProtocolError, Status
import numpy as np
from pathlib import Path
# Define point structure
class HeliosPoint(ctypes.Structure):
# _pack_=1
_fields_ = [('x', ctypes.c_uint16),
('y', ctypes.c_uint16),
('r', ctypes.c_uint8),
('g', ctypes.c_uint8),
('b', ctypes.c_uint8),
('i', ctypes.c_uint8)]
# Load and initialize library
so_path = Path(__file__).absolute().parent.joinpath("libHeliosDacAPI.so")
HeliosLib = ctypes.cdll.LoadLibrary(so_path)
numDevices = HeliosLib.OpenDevices()
print("Found ", numDevices, "Helios DACs")
class TracerHelios(Tracer):
"""A connection to a DAC."""
def __init__(self, laser_id, PL, redis):
self.redis = redis
self.laser_id = laser_id
self.PL = PL
self.pl = [[0,0,0]]
self.clientkey = self.redis.get("/clientkey").decode('ascii')
self.xyrgb = self.xyrgb_prev = (0, 0, 0, 0, 0)
self.intensity = 65280
self.intred = 100
self.intgreen = 100
self.intblue = 100
self.prev_x = 0
self.prev_y = 0
# self.newstream = OnePointIterator()
# "Laser point List" Point generator
# each points is yielded : Getpoints() call n times OnePoint()
pass
def get_points_capacity(self):
return 30000
# def GetPoints(self, capacity):
# a = [2,3]
# return a
def prepare(self):
return True
def begin(self, n, kpps):
return True
def get_status(self):
""" Return 0 if not ready (playing), 1 if ready to receive new frame,-1 if communication failed """
# va chercher dans le helios et renvoie la normalisée
status = HeliosLib.GetStatus(0)
if status == 0 :
return self.lstate["2"] # playing
if status == 1 :
return self.lstate["0"] # ready
if status == -1 :
return self.lstate["64"] # no connection
def set_status(self, status: int):
return
def before_loop(self):
return True
def write(self, points):
# status_attempts = 0
# j = 0
# while (status_attempts < 512 and HeliosLib.GetStatus(j) != 1):
# status_attempts += 1
# print("attempt {}".format(status_attempts))
# HeliosLib.WriteFrame(j, 3000, 0, ctypes.pointer(frames[i % 30]), 1000) # Send the frame
try :
points = [ *i for i in items ]
frames = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
frame_type = HeliosPoint * 1000
x = 0
y = 0
for i in range(30):
y = round(i * 0xFFF / 30)
frames[i] = frame_type()
for j in range(1000):
if (j < 500):
x = round(j * 0xFFF / 500)
else:
x = round(0xFFF - ((j - 500) * 0xFFF / 500))
frames[i][j] = HeliosPoint(int(x), int(y), 255, 255, 255, 255)
for i in range(150):
for j in range(numDevices):
statusAttempts = 0
# Make 512 attempts for DAC status to be ready. After that, just give up and try to write the frame anyway
while (statusAttempts < 512 and HeliosLib.GetStatus(j) != 1):
statusAttempts += 1
HeliosLib.WriteFrame(j, 30000, 0, ctypes.pointer(frames[i % 30]), 1000) # Send the frame
except Exception as exc :
print (exc)
def get_warped_point(self, x, y ):
# transform in one matrix, with warp !!
# Etherpoint all transform in one matrix, with warp !!
# position = homographyp.apply(gstt.EDH[self.laser_id], np.array([(x, y)]))
return x, y
# return position[0][0], position[0][1]
#
# # Create sample frames
# frames = [0 for x in range(30)]
# frameType = HeliosPoint * 1000
# x = 0
# y = 0
# for i in range(30):
# y = round(i * 0xFFF / 30)
# frames[i] = frameType()
# for j in range(1000):
# if (j < 500):
# x = round(j * 0xFFF / 500)
# else:
# x = round(0xFFF - ((j - 500) * 0xFFF / 500))
#
# frames[i][j] = HeliosPoint(int(x), int(y), 255, 255, 255, 255)
#
# # Play frames on DAC
# for i in range(150):
# for j in range(numDevices):
# statusAttempts = 0
# # Make 512 attempts for DAC status to be ready. After that, just give up and try to write the frame anyway
# while (statusAttempts < 512 and HeliosLib.GetStatus(j) != 1):
# statusAttempts += 1
# HeliosLib.WriteFrame(j, 30000, 0, ctypes.pointer(frames[i % 30]), 1000) # Send the frame
#
# HeliosLib.CloseDevices()

374
main.py
View File

@ -22,9 +22,10 @@ All used ports:
Plugins OSC Ports (see LJ.conf)
'''
#import pdb
# import pdb
from libs3 import log
print("")
print("")
log.infog("LJ Laser Server")
@ -35,11 +36,13 @@ print("")
import redis
import os
ljpath = r'%s' % os.getcwd().replace('\\','/')
ljpath = r'%s' % os.getcwd().replace('\\', '/')
import sys
#sys.path.append('libs3/')
# sys.path.append('libs3/')
from libs3 import gstt, settings
config = settings.config
gstt.ljpath = ljpath
log.info("Reading " + gstt.ConfigName + " setup file...")
@ -47,35 +50,31 @@ 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 lasytracer as tracer
from libs3 import tracer
from libs3 import homographyp, commands, font1
#import subprocess
# import subprocess
import os
#import midi
from libs3 import OSC3
# import midi
from libs3 import OSC3
from websocket_server import WebsocketServer
#import socket
# import socket
import types, _thread, time
r = redis.StrictRedis(host=gstt.LjayServerIP , port=6379, db=0)
r = redis.StrictRedis(host=gstt.LjayServerIP, port=6379, db=0)
# r = redis.StrictRedis(host=gstt.LjayServerIP , port=6379, db=0, password='-+F816Y+-')
args =[0,0]
args = [0, 0]
def dac_process(number, pl):
def dac_process(number, pl, dac_family):
import sys
from libs3 import gstt
@ -83,7 +82,7 @@ def dac_process(number, pl):
while True:
try:
d = tracer.DAC(number,pl)
d = tracer.DAC(number, pl, dac_family=dac_family)
d.play_stream()
except Exception as e:
@ -92,6 +91,7 @@ def dac_process(number, pl):
import traceback
if gstt.debug > 0:
# if True:
log.err('\n---------------------')
log.err('Exception: %s' % e)
log.err('- - - - - - - - - - -')
@ -101,14 +101,13 @@ def dac_process(number, pl):
except KeyboardInterrupt:
sys.exit(0)
#
# Servers init variables
#
print("Start Scene number :",gstt.SceneNumber)
print("Start Scene number :", gstt.SceneNumber)
print("WebUI connect to :", gstt.wwwIP)
@ -121,26 +120,25 @@ print("OSCserver IP :", oscserverIP)
nozoscIP = gstt.nozoscip
print("Nozosc IP :", nozoscIP)
debug = gstt.debug
# gstt.debug = 1
debug = gstt.debug
print("Debug :", debug)
# Websocket listening port
wsPORT = 9001
# oscserver
# OSC Server : accept OSC message on port 8002
#oscIPin = "192.168.1.10"s
# oscIPin = "192.168.1.10"s
oscserverIPin = serverIP
print("oscserverIPin", oscserverIPin)
oscserverPORTin = 8002
# OSC Client : to send OSC message to an IP port 8001
oscserverIPout = oscserverIP
oscserverIPout = oscserverIP
oscserverPORTout = 8001
'''
# Nozoid OSC Client : to send OSC message to Nozoid inport 8003
NozoscIPout = nozoscIP
@ -155,15 +153,15 @@ planetPORTout = plugins.Port("planet")
import socket
#retry = 1
#delay = 1
# retry = 1
# delay = 1
#
# OSC
#
oscserver = OSC3.OSCServer( (oscserverIPin, oscserverPORTin) )
oscserver = OSC3.OSCServer((oscserverIPin, oscserverPORTin))
oscserver.timeout = 0
OSCRunning = True
@ -171,110 +169,112 @@ OSCRunning = True
def handle_timeout(self):
self.timed_out = True
oscserver.handle_timeout = types.MethodType(handle_timeout, oscserver)
# OSC default path handler : send incoming OSC message to UI via websocket 9001
def handler(path, tags, args, source):
oscpath = path.split("/")
if gstt.debug > 0:
print("")
print("OSC handler in main said : path", path," oscpath ", oscpath," args", args)
print("OSC handler in main said : path", path, " oscpath ", oscpath, " args", args)
if oscpath[1] != "pong":
sendWSall(path + " " + str(args[0]))
commands.handler(oscpath,args)
commands.handler(oscpath, args)
# RAW OSC Frame available ?
def osc_frame():
#print 'oscframe'
# print 'oscframe'
# clear timed_out flag
oscserver.timed_out = False
# handle all pending requests then return
while not oscserver.timed_out:
oscserver.handle_request()
def PingAll():
def PingAll():
if gstt.debug > 0:
print("Pinging all plugins...")
for plugin in list(gstt.plugins.keys()):
if gstt.debug > 0:
print("pinging", plugin)
#sendWSall("/"+ plugin + "/start 0")
# sendWSall("/"+ plugin + "/start 0")
plugins.Ping(plugin)
# OSC server Thread : handler, dacs reports and simulator points sender to UI.
def osc_thread():
# while True:
try:
while True:
#while True:
try:
while True:
time.sleep(0.1)
osc_frame()
for laserid in range(0, gstt.LaserNumber): # Laser not used -> led is not lit
time.sleep(0.1)
osc_frame()
for laserid in range(0,gstt.LaserNumber): # Laser not used -> led is not lit
lstate = {'0': 'IDLE', '1': 'PREPARE', '2': "PLAYING", '64': "NOCONNECTION ?"}
lstt = r.get('/lstt/' + str(laserid)).decode('ascii')
# print ("laserid", laserid,"lstt",lstt, type(lstt))
if gstt.debug > 1:
print("DAC", laserid, "is in (lstt) :", lstt, lstate[str(lstt)])
if lstt == "0": # Dac IDLE state(0) -> led is blue (3)
sendWSall("/lstt/" + str(laserid) + " 3")
lstate = {'0': 'IDLE', '1': 'PREPARE', '2': "PLAYING", '64': "NOCONNECTION ?" }
lstt = r.get('/lstt/'+ str(laserid)).decode('ascii')
#print ("laserid", laserid,"lstt",lstt, type(lstt))
if gstt.debug >1:
print("DAC", laserid, "is in (lstt) :", lstt , lstate[str(lstt)])
if lstt == "0": # Dac IDLE state(0) -> led is blue (3)
sendWSall("/lstt/" + str(laserid) + " 3")
if lstt == "1": # Dac PREPARE state (1) -> led is cyan (2)
sendWSall("/lstt/" + str(laserid) + " 2")
if lstt == "1": # Dac PREPARE state (1) -> led is cyan (2)
sendWSall("/lstt/" + str(laserid) + " 2")
if lstt == "2": # Dac PLAYING (2) -> led is green (1)
sendWSall("/lstt/" + str(laserid) + " 1")
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')
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')
if gstt.debug > 1:
print("DAC", laserid, "answered (lack):", lack, chr(int(lack)), ackstate[str(lack)])
if gstt.debug >1:
print("DAC", laserid, "answered (lack):", lack, chr(int(lack)), ackstate[str(lack)])
if chr(int(lack)) == 'a': # Dac sent ACK ("a") -> led is green (1)
sendWSall("/lack/" + str(laserid) + " 1")
if chr(int(lack)) == 'a': # Dac sent ACK ("a") -> led is green (1)
sendWSall("/lack/" + str(laserid) +" 1")
if chr(int(lack)) == 'F': # Dac sent FULL ("F") -> led is orange (5)
sendWSall("/lack/" + str(laserid) + " 5")
if chr(int(lack)) == 'F': # Dac sent FULL ("F") -> led is orange (5)
sendWSall("/lack/" + str(laserid) +" 5")
if chr(int(lack)) == 'I': # Dac sent INVALID ("I") -> led is yellow (4)
sendWSall("/lack/" + str(laserid) + " 4")
# print lack
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("/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')))
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("/points/" + str(laserid) + " 6")
#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')))
if random.randint(0,100)>95:
plugins.sendbroadcast()
else:
# last number of points sent to etherdream buffer
sendWSall("/points/" + str(laserid) + " " + str(r.get('/cap/' + str(laserid)).decode('ascii')))
# 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')))
if random.randint(0, 100) > 95:
plugins.sendbroadcast()
except Exception as e:
import sys, traceback
print('\n--------------------------')
print('OSC Thread Exception: %s' % e)
print('- - - - - - - - - - - - - - ')
traceback.print_tb(sys.exc_info()[2])
print("\n")
except Exception as e:
import sys, traceback
print('\n--------------------------')
print('OSC Thread Exception: %s' % e)
print('- - - - - - - - - - - - - - ')
traceback.print_tb(sys.exc_info()[2])
print("\n")
#
# Websocket part
@ -282,33 +282,33 @@ def osc_thread():
# Called for every WS client connecting (after handshake)
def new_client(client, wserver):
print("New WS client connected and was given id %d" % client['id'])
sendWSall("/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]))
#sendWSall("/laser"+str(laserid)+"/start 1")
sendWSall("/laser "+str(laserid))
#print("/laser "+str(laserid))
sendWSall("/kpps/" + str(laserid) + " " + str(gstt.kpps[laserid]))
# sendWSall("/laser"+str(laserid)+"/start 1")
sendWSall("/laser " + str(laserid))
# print("/laser "+str(laserid))
sendWSall("/lack/" + str(laserid) + " 6")
#print("/lack/" + str(laserid) + " 6")
sendWSall("/lstt/" + str(laserid) + " 6")
#print("/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")
# print("/points/" + str(laserid) + " 0")
if gstt.swapX[laserid] == 1:
sendWSall("/swap/X/" + str(laserid)+ " 1")
sendWSall("/swap/X/" + str(laserid) + " 1")
else:
sendWSall("/swap/X/" + str(laserid)+ " 0")
sendWSall("/swap/X/" + str(laserid) + " 0")
if gstt.swapY[laserid] == 1:
sendWSall("/swap/Y/" + str(laserid)+ " 1")
sendWSall("/swap/Y/" + str(laserid) + " 1")
else:
sendWSall("/swap/Y/" + str(laserid)+ " 0")
sendWSall("/swap/Y/" + str(laserid) + " 0")
# Called for every WS client disconnecting
def client_left(client, wserver):
@ -317,53 +317,50 @@ def client_left(client, wserver):
# Called for each WS received message.
def message_received(client, wserver, message):
#if len(message) > 200:
# if len(message) > 200:
# message = message[:200]+'..'
#if gstt.debug >0:
# 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
# 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)
# print(oscpath)
if plugins.Send(plugin, oscpath):
print("plugins sent incoming WS correctly to", plugin)
else:
print("plugins detected", plugin, "offline.")
# WS received message is an LJ command
# WS received message is an LJ command
if message4plugin == False:
if len(oscpath) == 1:
args[0] = "noargs"
#print "noargs command"
# print "noargs command"
elif len(oscpath) > 1:
args[0] = str(oscpath[1])
#print "arg",oscpath[1]
commands.handler(oscpath[0].split("/"),args)
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)
# sendWSall("ws"+message)
def handle_timeout(self):
@ -371,10 +368,11 @@ def handle_timeout(self):
def sendWSall(message):
#if gstt.debug >0:
#print("WS sending %s" % (message))
# if gstt.debug >0:
# print("WS sending %s" % (message))
wserver.send_message_to_all(message)
'''
print ""
print "Midi Configuration"
@ -382,10 +380,11 @@ midi.InConfig()
midi.OutConfig()
'''
def fff(name):
print()
print('HELLO', name ) #indent
print()
print()
print('HELLO', name) # indent
print()
#
@ -395,26 +394,24 @@ def fff(name):
print("")
log.info("Creating startup point lists...")
if r.set("/clientkey", "/pl/" + str(gstt.SceneNumber) + "/") == True:
print("sent clientkey : /pl/" + str(gstt.SceneNumber) + "/")
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))
#digit_points = font1.DigitsDots(sceneid,65280)
# pdb.set_trace()
for sceneid in range(0, gstt.MaxScenes + 1):
print("Scene " + str(sceneid))
# digit_points = font1.DigitsDots(sceneid,65280)
# Order all lasers to show its number at startup -> tell all 4 laser process to USER PLs
for laserid in range(0,gstt.LaserNumber):
for laserid in range(0, gstt.LaserNumber):
digit_points = font1.DigitsDots(laserid,65280)
if r.set('/pl/'+str(sceneid)+'/'+str(laserid), str(digit_points)) == True:
digit_points = font1.DigitsDots(laserid, 65280)
if r.set('/pl/' + str(sceneid) + '/' + str(laserid), str(digit_points)) == True:
pass
#print( ast.literal_eval(r.get('/pl/'+str(sceneid)+'/'+str(laserid)).decode('ascii')))
#print("/pl/"+str(sceneid)+"/"+str(laserid)+" "+str(ast.literal_eval(r.get('/pl/'+str(sceneid)+'/'+str(laserid)).decode('ascii'))))
r.set('/order/'+str(laserid), 0)
# print( ast.literal_eval(r.get('/pl/'+str(sceneid)+'/'+str(laserid)).decode('ascii')))
# print("/pl/"+str(sceneid)+"/"+str(laserid)+" "+str(ast.literal_eval(r.get('/pl/'+str(sceneid)+'/'+str(laserid)).decode('ascii'))))
r.set('/order/' + str(laserid), 0)
#
# Starts one DAC process per requested Laser
@ -431,96 +428,98 @@ 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 etherdream
dac_worker0= Process(target=dac_process, args=(0,0,))
log.info("Starting " + str(gstt.LaserNumber) + " DACs process...")
# Launch one process (a tracer3 instance) for etherdream / helios
dac_family = None
if config["laser0"].get("dac_family"):
dac_family = config["laser0"]["dac_family"]
dac_worker0 = Process(target=dac_process, args=(0, 0, dac_family))
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,))
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 )
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,))
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 )
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:
# Websocket startup
wserver = WebsocketServer(wsPORT,host=serverIP)
wserver = WebsocketServer(wsPORT, host=serverIP)
plugins.Init(wserver)
log.info("Starting servers...")
# Launch OSC thread listening to oscserver
print("Launching OSC server...")
print("at", oscserverIPin, "port",str(oscserverPORTin))
oscserver.addMsgHandler( "/noteon", commands.NoteOn)
oscserver.addMsgHandler( "/scim", commands.Scim)
oscserver.addMsgHandler( "/line1", commands.Line1)
oscserver.addMsgHandler( "/forwardui", commands.ForwardUI)
# Default OSC handler for all OSC incoming message
oscserver.addMsgHandler("default", handler)
_thread.start_new_thread(osc_thread, ())
# print("Launching OSC server...")
# print("at", oscserverIPin, "port", str(oscserverPORTin))
# oscserver.addMsgHandler("/noteon", commands.NoteOn)
# oscserver.addMsgHandler("/scim", commands.Scim)
# oscserver.addMsgHandler("/line1", commands.Line1)
# oscserver.addMsgHandler("/forwardui", commands.ForwardUI)
# # Default OSC handler for all OSC incoming message
# oscserver.addMsgHandler("default", handler)
# _thread.start_new_thread(osc_thread, ())
print("Launching webUI Websocket server...")
print("at", serverIP, "port",wsPORT)
print("at", serverIP, "port", wsPORT)
wserver.set_fn_new_client(new_client)
wserver.set_fn_client_left(client_left)
wserver.set_fn_message_received(message_received)
print("")
log.info("Resetting all Homographies...")
for laserid in range(0,gstt.LaserNumber):
for laserid in range(0, gstt.LaserNumber):
homographyp.newEDH(laserid)
# 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()
@ -530,6 +529,3 @@ if __name__ == '__main__':
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)]
'''