wip: heading to DAC modularity
This commit is contained in:
parent
88998abde7
commit
1847c8ebef
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,3 +1,5 @@
|
||||
.*swp*
|
||||
*__pycache__
|
||||
www/config.js
|
||||
.venv/
|
||||
.idea
|
||||
|
5
LJ.conf
5
LJ.conf
@ -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
|
||||
|
@ -17,7 +17,7 @@ from /team/laser
|
||||
#ConfigName = "setexample.conf"
|
||||
ConfigName = "LJ.conf"
|
||||
|
||||
debug = 0
|
||||
debug = 10
|
||||
ljpath=''
|
||||
|
||||
anims= [[],[],[],[]]
|
||||
|
@ -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
BIN
libs3/libHeliosDacAPI.so
Normal file
Binary file not shown.
94
libs3/tracer.py
Normal file
94
libs3/tracer.py
Normal 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
363
libs3/tracer_common.py
Normal 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
400
libs3/tracer_etherdream.py
Normal 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
148
libs3/tracer_helios.py
Normal 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()
|
74
main.py
74
main.py
@ -25,6 +25,7 @@ Plugins OSC Ports (see LJ.conf)
|
||||
# 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('\\', '/')
|
||||
import sys
|
||||
|
||||
# sys.path.append('libs3/')
|
||||
from libs3 import gstt, settings
|
||||
config = settings.config
|
||||
gstt.ljpath = ljpath
|
||||
|
||||
log.info("Reading " + gstt.ConfigName + " setup file...")
|
||||
@ -47,16 +50,15 @@ 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 tracer
|
||||
|
||||
from libs3 import homographyp, commands, font1
|
||||
# import subprocess
|
||||
@ -67,15 +69,12 @@ from websocket_server import WebsocketServer
|
||||
# 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, password='-+F816Y+-')
|
||||
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('- - - - - - - - - - -')
|
||||
@ -103,7 +103,6 @@ def dac_process(number, pl):
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Servers init variables
|
||||
#
|
||||
@ -121,10 +120,10 @@ print("OSCserver IP :", oscserverIP)
|
||||
nozoscIP = gstt.nozoscip
|
||||
print("Nozosc IP :", nozoscIP)
|
||||
|
||||
# gstt.debug = 1
|
||||
debug = gstt.debug
|
||||
print("Debug :", debug)
|
||||
|
||||
|
||||
# Websocket listening port
|
||||
wsPORT = 9001
|
||||
|
||||
@ -140,7 +139,6 @@ oscserverPORTin = 8002
|
||||
oscserverIPout = oscserverIP
|
||||
oscserverPORTout = 8001
|
||||
|
||||
|
||||
'''
|
||||
# Nozoid OSC Client : to send OSC message to Nozoid inport 8003
|
||||
NozoscIPout = nozoscIP
|
||||
@ -171,12 +169,12 @@ 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("")
|
||||
@ -196,8 +194,8 @@ def osc_frame():
|
||||
while not oscserver.timed_out:
|
||||
oscserver.handle_request()
|
||||
|
||||
def PingAll():
|
||||
|
||||
def PingAll():
|
||||
if gstt.debug > 0:
|
||||
print("Pinging all plugins...")
|
||||
|
||||
@ -208,10 +206,8 @@ def PingAll():
|
||||
plugins.Ping(plugin)
|
||||
|
||||
|
||||
|
||||
# OSC server Thread : handler, dacs reports and simulator points sender to UI.
|
||||
def osc_thread():
|
||||
|
||||
# while True:
|
||||
try:
|
||||
while True:
|
||||
@ -234,8 +230,10 @@ 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"}
|
||||
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:
|
||||
@ -263,7 +261,8 @@ 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('/pl/' + str(gstt.SceneNumber) + '/' + str(gstt.Laser)).decode('ascii')))
|
||||
if random.randint(0, 100) > 95:
|
||||
plugins.sendbroadcast()
|
||||
|
||||
@ -276,13 +275,13 @@ def osc_thread():
|
||||
traceback.print_tb(sys.exc_info()[2])
|
||||
print("\n")
|
||||
|
||||
|
||||
#
|
||||
# Websocket part
|
||||
#
|
||||
|
||||
# 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']))
|
||||
|
||||
@ -310,6 +309,7 @@ def new_client(client, wserver):
|
||||
else:
|
||||
sendWSall("/swap/Y/" + str(laserid) + " 0")
|
||||
|
||||
|
||||
# Called for every WS client disconnecting
|
||||
def client_left(client, wserver):
|
||||
print("WS Client(%d) disconnected" % client['id'])
|
||||
@ -317,7 +317,6 @@ def client_left(client, wserver):
|
||||
|
||||
# Called for each WS received message.
|
||||
def message_received(client, wserver, message):
|
||||
|
||||
# if len(message) > 200:
|
||||
# message = message[:200]+'..'
|
||||
|
||||
@ -346,7 +345,6 @@ def message_received(client, wserver, message):
|
||||
else:
|
||||
print("plugins detected", plugin, "offline.")
|
||||
|
||||
|
||||
# WS received message is an LJ command
|
||||
|
||||
if message4plugin == False:
|
||||
@ -361,7 +359,6 @@ def message_received(client, wserver, message):
|
||||
|
||||
commands.handler(oscpath[0].split("/"), args)
|
||||
|
||||
|
||||
# if needed a loop back : WS Client -> server -> WS Client
|
||||
# sendWSall("ws"+message)
|
||||
|
||||
@ -375,6 +372,7 @@ def sendWSall(message):
|
||||
# print("WS sending %s" % (message))
|
||||
wserver.send_message_to_all(message)
|
||||
|
||||
|
||||
'''
|
||||
print ""
|
||||
print "Midi Configuration"
|
||||
@ -382,6 +380,7 @@ midi.InConfig()
|
||||
midi.OutConfig()
|
||||
'''
|
||||
|
||||
|
||||
def fff(name):
|
||||
print()
|
||||
print('HELLO', name) # indent
|
||||
@ -395,7 +394,6 @@ 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) + "/")
|
||||
|
||||
@ -415,7 +413,6 @@ for sceneid in range(0,gstt.MaxScenes+1):
|
||||
|
||||
r.set('/order/' + str(laserid), 0)
|
||||
|
||||
|
||||
#
|
||||
# Starts one DAC process per requested Laser
|
||||
#
|
||||
@ -437,11 +434,13 @@ if __name__ == '__main__':
|
||||
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,))
|
||||
# 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)
|
||||
@ -477,15 +476,15 @@ if __name__ == '__main__':
|
||||
|
||||
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)
|
||||
@ -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)]
|
||||
'''
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user