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*
|
.*swp*
|
||||||
*__pycache__
|
*__pycache__
|
||||||
www/config.js
|
www/config.js
|
||||||
|
.venv/
|
||||||
|
.idea
|
||||||
|
5
LJ.conf
5
LJ.conf
@ -1,15 +1,16 @@
|
|||||||
[General]
|
[General]
|
||||||
lasernumber = 1
|
lasernumber = 1
|
||||||
debug = 1
|
debug = 2
|
||||||
ljayserverip = 0.0.0.0
|
ljayserverip = 0.0.0.0
|
||||||
wwwip = 127.0.0.1
|
wwwip = 127.0.0.1
|
||||||
nozoscip = 127.0.0.1
|
nozoscip = 127.0.0.1
|
||||||
bhoroscip = 127.0.0.1
|
bhoroscip = 127.0.0.1
|
||||||
autostart = artnet
|
autostart =
|
||||||
wstype = ws
|
wstype = ws
|
||||||
wsport = 9001
|
wsport = 9001
|
||||||
|
|
||||||
[laser0]
|
[laser0]
|
||||||
|
dac_family = helios
|
||||||
color = -1
|
color = -1
|
||||||
type = DS1000
|
type = DS1000
|
||||||
ip = 127.0.0.1
|
ip = 127.0.0.1
|
||||||
|
@ -17,7 +17,7 @@ from /team/laser
|
|||||||
#ConfigName = "setexample.conf"
|
#ConfigName = "setexample.conf"
|
||||||
ConfigName = "LJ.conf"
|
ConfigName = "LJ.conf"
|
||||||
|
|
||||||
debug = 0
|
debug = 10
|
||||||
ljpath=''
|
ljpath=''
|
||||||
|
|
||||||
anims= [[],[],[],[]]
|
anims= [[],[],[],[]]
|
||||||
|
@ -151,8 +151,7 @@ def find_affine(points1,points2):
|
|||||||
return H
|
return H
|
||||||
|
|
||||||
def apply(H,points):
|
def apply(H,points):
|
||||||
|
p = np.ones((len(points),2),'float64')
|
||||||
p = np.ones((len(points),3),'float64')
|
|
||||||
p[:,:2] = points
|
p[:,:2] = points
|
||||||
pp = np.dot(p,H.T)
|
pp = np.dot(p,H.T)
|
||||||
pp[:,:2]/=pp[:,2].reshape(len(p),1)
|
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
|
# import pdb
|
||||||
|
|
||||||
from libs3 import log
|
from libs3 import log
|
||||||
|
|
||||||
print("")
|
print("")
|
||||||
print("")
|
print("")
|
||||||
log.infog("LJ Laser Server")
|
log.infog("LJ Laser Server")
|
||||||
@ -35,11 +36,13 @@ print("")
|
|||||||
|
|
||||||
import redis
|
import redis
|
||||||
import os
|
import os
|
||||||
|
|
||||||
ljpath = r'%s' % os.getcwd().replace('\\', '/')
|
ljpath = r'%s' % os.getcwd().replace('\\', '/')
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
# sys.path.append('libs3/')
|
# sys.path.append('libs3/')
|
||||||
from libs3 import gstt, settings
|
from libs3 import gstt, settings
|
||||||
|
config = settings.config
|
||||||
gstt.ljpath = ljpath
|
gstt.ljpath = ljpath
|
||||||
|
|
||||||
log.info("Reading " + gstt.ConfigName + " setup file...")
|
log.info("Reading " + gstt.ConfigName + " setup file...")
|
||||||
@ -47,16 +50,15 @@ settings.Read()
|
|||||||
|
|
||||||
# Arguments may alter .conf file so import settings first then cli
|
# Arguments may alter .conf file so import settings first then cli
|
||||||
from libs3 import cli
|
from libs3 import cli
|
||||||
|
|
||||||
settings.Write()
|
settings.Write()
|
||||||
|
|
||||||
from multiprocessing import Process, set_start_method
|
from multiprocessing import Process, set_start_method
|
||||||
import random, ast
|
import random, ast
|
||||||
from libs3 import plugins
|
from libs3 import plugins
|
||||||
|
|
||||||
|
|
||||||
# from libs3 import lasytracer as tracer
|
# from libs3 import lasytracer as tracer
|
||||||
from libs3 import tracer3 as tracer
|
from libs3 import tracer
|
||||||
|
|
||||||
|
|
||||||
from libs3 import homographyp, commands, font1
|
from libs3 import homographyp, commands, font1
|
||||||
# import subprocess
|
# import subprocess
|
||||||
@ -67,15 +69,12 @@ from websocket_server import WebsocketServer
|
|||||||
# import socket
|
# import socket
|
||||||
import types, _thread, time
|
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+-')
|
# 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
|
import sys
|
||||||
from libs3 import gstt
|
from libs3 import gstt
|
||||||
|
|
||||||
@ -83,7 +82,7 @@ def dac_process(number, pl):
|
|||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
d = tracer.DAC(number,pl)
|
d = tracer.DAC(number, pl, dac_family=dac_family)
|
||||||
d.play_stream()
|
d.play_stream()
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -92,6 +91,7 @@ def dac_process(number, pl):
|
|||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
if gstt.debug > 0:
|
if gstt.debug > 0:
|
||||||
|
# if True:
|
||||||
log.err('\n---------------------')
|
log.err('\n---------------------')
|
||||||
log.err('Exception: %s' % e)
|
log.err('Exception: %s' % e)
|
||||||
log.err('- - - - - - - - - - -')
|
log.err('- - - - - - - - - - -')
|
||||||
@ -103,7 +103,6 @@ def dac_process(number, pl):
|
|||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Servers init variables
|
# Servers init variables
|
||||||
#
|
#
|
||||||
@ -121,10 +120,10 @@ print("OSCserver IP :", oscserverIP)
|
|||||||
nozoscIP = gstt.nozoscip
|
nozoscIP = gstt.nozoscip
|
||||||
print("Nozosc IP :", nozoscIP)
|
print("Nozosc IP :", nozoscIP)
|
||||||
|
|
||||||
|
# gstt.debug = 1
|
||||||
debug = gstt.debug
|
debug = gstt.debug
|
||||||
print("Debug :", debug)
|
print("Debug :", debug)
|
||||||
|
|
||||||
|
|
||||||
# Websocket listening port
|
# Websocket listening port
|
||||||
wsPORT = 9001
|
wsPORT = 9001
|
||||||
|
|
||||||
@ -140,7 +139,6 @@ oscserverPORTin = 8002
|
|||||||
oscserverIPout = oscserverIP
|
oscserverIPout = oscserverIP
|
||||||
oscserverPORTout = 8001
|
oscserverPORTout = 8001
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
# Nozoid OSC Client : to send OSC message to Nozoid inport 8003
|
# Nozoid OSC Client : to send OSC message to Nozoid inport 8003
|
||||||
NozoscIPout = nozoscIP
|
NozoscIPout = nozoscIP
|
||||||
@ -171,12 +169,12 @@ OSCRunning = True
|
|||||||
def handle_timeout(self):
|
def handle_timeout(self):
|
||||||
self.timed_out = True
|
self.timed_out = True
|
||||||
|
|
||||||
|
|
||||||
oscserver.handle_timeout = types.MethodType(handle_timeout, oscserver)
|
oscserver.handle_timeout = types.MethodType(handle_timeout, oscserver)
|
||||||
|
|
||||||
|
|
||||||
# OSC default path handler : send incoming OSC message to UI via websocket 9001
|
# OSC default path handler : send incoming OSC message to UI via websocket 9001
|
||||||
def handler(path, tags, args, source):
|
def handler(path, tags, args, source):
|
||||||
|
|
||||||
oscpath = path.split("/")
|
oscpath = path.split("/")
|
||||||
if gstt.debug > 0:
|
if gstt.debug > 0:
|
||||||
print("")
|
print("")
|
||||||
@ -196,8 +194,8 @@ def osc_frame():
|
|||||||
while not oscserver.timed_out:
|
while not oscserver.timed_out:
|
||||||
oscserver.handle_request()
|
oscserver.handle_request()
|
||||||
|
|
||||||
def PingAll():
|
|
||||||
|
|
||||||
|
def PingAll():
|
||||||
if gstt.debug > 0:
|
if gstt.debug > 0:
|
||||||
print("Pinging all plugins...")
|
print("Pinging all plugins...")
|
||||||
|
|
||||||
@ -208,10 +206,8 @@ def PingAll():
|
|||||||
plugins.Ping(plugin)
|
plugins.Ping(plugin)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# OSC server Thread : handler, dacs reports and simulator points sender to UI.
|
# OSC server Thread : handler, dacs reports and simulator points sender to UI.
|
||||||
def osc_thread():
|
def osc_thread():
|
||||||
|
|
||||||
# while True:
|
# while True:
|
||||||
try:
|
try:
|
||||||
while True:
|
while True:
|
||||||
@ -234,8 +230,10 @@ def osc_thread():
|
|||||||
if lstt == "2": # Dac PLAYING (2) -> led is green (1)
|
if lstt == "2": # Dac PLAYING (2) -> led is green (1)
|
||||||
sendWSall("/lstt/" + str(laserid) + " 1")
|
sendWSall("/lstt/" + str(laserid) + " 1")
|
||||||
|
|
||||||
|
ackstate = {'61': 'ACK', '46': 'FULL', '49': "INVALID", '21': 'STOP', '64': "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"}
|
'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')
|
lack = r.get('/lack/' + str(laserid)).decode('ascii')
|
||||||
|
|
||||||
if gstt.debug > 1:
|
if gstt.debug > 1:
|
||||||
@ -263,7 +261,8 @@ def osc_thread():
|
|||||||
|
|
||||||
# print("Sending simu frame from",'/pl/'+str(gstt.SceneNumber)+'/'+str(gstt.Laser))
|
# print("Sending simu frame from",'/pl/'+str(gstt.SceneNumber)+'/'+str(gstt.Laser))
|
||||||
# print(r.get('/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:
|
if random.randint(0, 100) > 95:
|
||||||
plugins.sendbroadcast()
|
plugins.sendbroadcast()
|
||||||
|
|
||||||
@ -276,13 +275,13 @@ def osc_thread():
|
|||||||
traceback.print_tb(sys.exc_info()[2])
|
traceback.print_tb(sys.exc_info()[2])
|
||||||
print("\n")
|
print("\n")
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Websocket part
|
# Websocket part
|
||||||
#
|
#
|
||||||
|
|
||||||
# Called for every WS client connecting (after handshake)
|
# Called for every WS client connecting (after handshake)
|
||||||
def new_client(client, wserver):
|
def new_client(client, wserver):
|
||||||
|
|
||||||
print("New WS client connected and was given id %d" % client['id'])
|
print("New WS client connected and was given id %d" % client['id'])
|
||||||
sendWSall("/status Hello " + str(client['id']))
|
sendWSall("/status Hello " + str(client['id']))
|
||||||
|
|
||||||
@ -310,6 +309,7 @@ def new_client(client, wserver):
|
|||||||
else:
|
else:
|
||||||
sendWSall("/swap/Y/" + str(laserid) + " 0")
|
sendWSall("/swap/Y/" + str(laserid) + " 0")
|
||||||
|
|
||||||
|
|
||||||
# Called for every WS client disconnecting
|
# Called for every WS client disconnecting
|
||||||
def client_left(client, wserver):
|
def client_left(client, wserver):
|
||||||
print("WS Client(%d) disconnected" % client['id'])
|
print("WS Client(%d) disconnected" % client['id'])
|
||||||
@ -317,7 +317,6 @@ def client_left(client, wserver):
|
|||||||
|
|
||||||
# Called for each WS received message.
|
# Called for each WS received message.
|
||||||
def message_received(client, wserver, message):
|
def message_received(client, wserver, message):
|
||||||
|
|
||||||
# if len(message) > 200:
|
# if len(message) > 200:
|
||||||
# message = message[:200]+'..'
|
# message = message[:200]+'..'
|
||||||
|
|
||||||
@ -346,7 +345,6 @@ def message_received(client, wserver, message):
|
|||||||
else:
|
else:
|
||||||
print("plugins detected", plugin, "offline.")
|
print("plugins detected", plugin, "offline.")
|
||||||
|
|
||||||
|
|
||||||
# WS received message is an LJ command
|
# WS received message is an LJ command
|
||||||
|
|
||||||
if message4plugin == False:
|
if message4plugin == False:
|
||||||
@ -361,7 +359,6 @@ def message_received(client, wserver, message):
|
|||||||
|
|
||||||
commands.handler(oscpath[0].split("/"), args)
|
commands.handler(oscpath[0].split("/"), args)
|
||||||
|
|
||||||
|
|
||||||
# if needed a loop back : WS Client -> server -> WS Client
|
# if needed a loop back : WS Client -> server -> WS Client
|
||||||
# sendWSall("ws"+message)
|
# sendWSall("ws"+message)
|
||||||
|
|
||||||
@ -375,6 +372,7 @@ def sendWSall(message):
|
|||||||
# print("WS sending %s" % (message))
|
# print("WS sending %s" % (message))
|
||||||
wserver.send_message_to_all(message)
|
wserver.send_message_to_all(message)
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
print ""
|
print ""
|
||||||
print "Midi Configuration"
|
print "Midi Configuration"
|
||||||
@ -382,6 +380,7 @@ midi.InConfig()
|
|||||||
midi.OutConfig()
|
midi.OutConfig()
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
def fff(name):
|
def fff(name):
|
||||||
print()
|
print()
|
||||||
print('HELLO', name) # indent
|
print('HELLO', name) # indent
|
||||||
@ -395,7 +394,6 @@ def fff(name):
|
|||||||
print("")
|
print("")
|
||||||
log.info("Creating startup point lists...")
|
log.info("Creating startup point lists...")
|
||||||
|
|
||||||
|
|
||||||
if r.set("/clientkey", "/pl/" + str(gstt.SceneNumber) + "/") == True:
|
if r.set("/clientkey", "/pl/" + str(gstt.SceneNumber) + "/") == True:
|
||||||
print("sent clientkey : /pl/" + str(gstt.SceneNumber) + "/")
|
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)
|
r.set('/order/' + str(laserid), 0)
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Starts one DAC process per requested Laser
|
# Starts one DAC process per requested Laser
|
||||||
#
|
#
|
||||||
@ -437,11 +434,13 @@ if __name__ == '__main__':
|
|||||||
lasernumber = gstt.LaserNumber - 1
|
lasernumber = gstt.LaserNumber - 1
|
||||||
print("LaserNumber = ", gstt.LaserNumber)
|
print("LaserNumber = ", gstt.LaserNumber)
|
||||||
|
|
||||||
|
|
||||||
log.info("Starting " + str(gstt.LaserNumber) + " DACs process...")
|
log.info("Starting " + str(gstt.LaserNumber) + " DACs process...")
|
||||||
|
|
||||||
# Launch one process (a tracer3 instance) by etherdream
|
# Launch one process (a tracer3 instance) for etherdream / helios
|
||||||
dac_worker0= Process(target=dac_process, args=(0,0,))
|
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()
|
dac_worker0.start()
|
||||||
commands.worker0 = dac_worker0
|
commands.worker0 = dac_worker0
|
||||||
print("Tracer 0 : name", dac_worker0.name, "pid", dac_worker0.pid)
|
print("Tracer 0 : name", dac_worker0.name, "pid", dac_worker0.pid)
|
||||||
@ -477,15 +476,15 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
log.info("Starting servers...")
|
log.info("Starting servers...")
|
||||||
# Launch OSC thread listening to oscserver
|
# Launch OSC thread listening to oscserver
|
||||||
print("Launching OSC server...")
|
# print("Launching OSC server...")
|
||||||
print("at", oscserverIPin, "port",str(oscserverPORTin))
|
# print("at", oscserverIPin, "port", str(oscserverPORTin))
|
||||||
oscserver.addMsgHandler( "/noteon", commands.NoteOn)
|
# oscserver.addMsgHandler("/noteon", commands.NoteOn)
|
||||||
oscserver.addMsgHandler( "/scim", commands.Scim)
|
# oscserver.addMsgHandler("/scim", commands.Scim)
|
||||||
oscserver.addMsgHandler( "/line1", commands.Line1)
|
# oscserver.addMsgHandler("/line1", commands.Line1)
|
||||||
oscserver.addMsgHandler( "/forwardui", commands.ForwardUI)
|
# oscserver.addMsgHandler("/forwardui", commands.ForwardUI)
|
||||||
# Default OSC handler for all OSC incoming message
|
# # Default OSC handler for all OSC incoming message
|
||||||
oscserver.addMsgHandler("default", handler)
|
# oscserver.addMsgHandler("default", handler)
|
||||||
_thread.start_new_thread(osc_thread, ())
|
# _thread.start_new_thread(osc_thread, ())
|
||||||
|
|
||||||
print("Launching webUI Websocket server...")
|
print("Launching webUI Websocket server...")
|
||||||
print("at", serverIP, "port", wsPORT)
|
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)]
|
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