From 1847c8ebef21b9ab49327ec08f6ba279582a9f7e Mon Sep 17 00:00:00 2001 From: alban Date: Fri, 24 Feb 2023 13:37:49 +0100 Subject: [PATCH] wip: heading to DAC modularity --- .gitignore | 2 + LJ.conf | 5 +- libs3/gstt.py | 2 +- libs3/homographyp.py | 3 +- libs3/libHeliosDacAPI.so | Bin 0 -> 34016 bytes libs3/tracer.py | 94 +++++++++ libs3/tracer_common.py | 363 +++++++++++++++++++++++++++++++++ libs3/tracer_etherdream.py | 400 +++++++++++++++++++++++++++++++++++++ libs3/tracer_helios.py | 148 ++++++++++++++ main.py | 374 +++++++++++++++++----------------- 10 files changed, 1197 insertions(+), 194 deletions(-) create mode 100644 libs3/libHeliosDacAPI.so create mode 100644 libs3/tracer.py create mode 100644 libs3/tracer_common.py create mode 100644 libs3/tracer_etherdream.py create mode 100644 libs3/tracer_helios.py diff --git a/.gitignore b/.gitignore index 06df7ba..6fdac33 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ .*swp* *__pycache__ www/config.js +.venv/ +.idea diff --git a/LJ.conf b/LJ.conf index f765675..2467c11 100644 --- a/LJ.conf +++ b/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 diff --git a/libs3/gstt.py b/libs3/gstt.py index 78ec2e2..6c0186e 100644 --- a/libs3/gstt.py +++ b/libs3/gstt.py @@ -17,7 +17,7 @@ from /team/laser #ConfigName = "setexample.conf" ConfigName = "LJ.conf" -debug = 0 +debug = 10 ljpath='' anims= [[],[],[],[]] diff --git a/libs3/homographyp.py b/libs3/homographyp.py index 3d4cc24..b741cdd 100644 --- a/libs3/homographyp.py +++ b/libs3/homographyp.py @@ -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) diff --git a/libs3/libHeliosDacAPI.so b/libs3/libHeliosDacAPI.so new file mode 100644 index 0000000000000000000000000000000000000000..c9c7a21d7566f4cb2a097075582f2104fff2432e GIT binary patch literal 34016 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 literal 0 HcmV?d00001 diff --git a/libs3/tracer.py b/libs3/tracer.py new file mode 100644 index 0000000..120d8d3 --- /dev/null +++ b/libs3/tracer.py @@ -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) diff --git a/libs3/tracer_common.py b/libs3/tracer_common.py new file mode 100644 index 0000000..8c2d656 --- /dev/null +++ b/libs3/tracer_common.py @@ -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(" 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 diff --git a/libs3/tracer_etherdream.py b/libs3/tracer_etherdream.py new file mode 100644 index 0000000..72486c8 --- /dev/null +++ b/libs3/tracer_etherdream.py @@ -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("> 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 diff --git a/libs3/tracer_helios.py b/libs3/tracer_helios.py new file mode 100644 index 0000000..0dff392 --- /dev/null +++ b/libs3/tracer_helios.py @@ -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() diff --git a/main.py b/main.py index 90764c2..fe82127 100755 --- a/main.py +++ b/main.py @@ -22,9 +22,10 @@ All used ports: Plugins OSC Ports (see LJ.conf) ''' -#import pdb +# import pdb from libs3 import log + print("") print("") log.infog("LJ Laser Server") @@ -35,11 +36,13 @@ print("") import redis import os -ljpath = r'%s' % os.getcwd().replace('\\','/') + +ljpath = r'%s' % os.getcwd().replace('\\', '/') import sys -#sys.path.append('libs3/') +# sys.path.append('libs3/') from libs3 import gstt, settings +config = settings.config gstt.ljpath = ljpath log.info("Reading " + gstt.ConfigName + " setup file...") @@ -47,35 +50,31 @@ settings.Read() # Arguments may alter .conf file so import settings first then cli from libs3 import cli + settings.Write() from multiprocessing import Process, set_start_method import random, ast from libs3 import plugins - -#from libs3 import lasytracer as tracer -from libs3 import tracer3 as tracer - +# from libs3 import lasytracer as tracer +from libs3 import tracer from libs3 import homographyp, commands, font1 -#import subprocess +# import subprocess import os -#import midi -from libs3 import OSC3 +# import midi +from libs3 import OSC3 from websocket_server import WebsocketServer -#import socket +# import socket import types, _thread, time - - -r = redis.StrictRedis(host=gstt.LjayServerIP , port=6379, db=0) +r = redis.StrictRedis(host=gstt.LjayServerIP, port=6379, db=0) # r = redis.StrictRedis(host=gstt.LjayServerIP , port=6379, db=0, password='-+F816Y+-') -args =[0,0] +args = [0, 0] -def dac_process(number, pl): - +def dac_process(number, pl, dac_family): import sys from libs3 import gstt @@ -83,7 +82,7 @@ def dac_process(number, pl): while True: try: - d = tracer.DAC(number,pl) + d = tracer.DAC(number, pl, dac_family=dac_family) d.play_stream() except Exception as e: @@ -92,6 +91,7 @@ def dac_process(number, pl): import traceback if gstt.debug > 0: + # if True: log.err('\n---------------------') log.err('Exception: %s' % e) log.err('- - - - - - - - - - -') @@ -101,14 +101,13 @@ def dac_process(number, pl): except KeyboardInterrupt: sys.exit(0) - # # Servers init variables # -print("Start Scene number :",gstt.SceneNumber) +print("Start Scene number :", gstt.SceneNumber) print("WebUI connect to :", gstt.wwwIP) @@ -121,26 +120,25 @@ print("OSCserver IP :", oscserverIP) nozoscIP = gstt.nozoscip print("Nozosc IP :", nozoscIP) -debug = gstt.debug +# gstt.debug = 1 +debug = gstt.debug print("Debug :", debug) - # Websocket listening port wsPORT = 9001 # oscserver # OSC Server : accept OSC message on port 8002 -#oscIPin = "192.168.1.10"s +# oscIPin = "192.168.1.10"s oscserverIPin = serverIP print("oscserverIPin", oscserverIPin) oscserverPORTin = 8002 # OSC Client : to send OSC message to an IP port 8001 -oscserverIPout = oscserverIP +oscserverIPout = oscserverIP oscserverPORTout = 8001 - ''' # Nozoid OSC Client : to send OSC message to Nozoid inport 8003 NozoscIPout = nozoscIP @@ -155,15 +153,15 @@ planetPORTout = plugins.Port("planet") import socket -#retry = 1 -#delay = 1 +# retry = 1 +# delay = 1 # # OSC # -oscserver = OSC3.OSCServer( (oscserverIPin, oscserverPORTin) ) +oscserver = OSC3.OSCServer((oscserverIPin, oscserverPORTin)) oscserver.timeout = 0 OSCRunning = True @@ -171,110 +169,112 @@ OSCRunning = True def handle_timeout(self): self.timed_out = True + oscserver.handle_timeout = types.MethodType(handle_timeout, oscserver) # OSC default path handler : send incoming OSC message to UI via websocket 9001 def handler(path, tags, args, source): - oscpath = path.split("/") if gstt.debug > 0: print("") - print("OSC handler in main said : path", path," oscpath ", oscpath," args", args) + print("OSC handler in main said : path", path, " oscpath ", oscpath, " args", args) if oscpath[1] != "pong": sendWSall(path + " " + str(args[0])) - commands.handler(oscpath,args) + commands.handler(oscpath, args) # RAW OSC Frame available ? def osc_frame(): - #print 'oscframe' + # print 'oscframe' # clear timed_out flag oscserver.timed_out = False # handle all pending requests then return while not oscserver.timed_out: oscserver.handle_request() -def PingAll(): +def PingAll(): if gstt.debug > 0: print("Pinging all plugins...") - + for plugin in list(gstt.plugins.keys()): if gstt.debug > 0: print("pinging", plugin) - #sendWSall("/"+ plugin + "/start 0") + # sendWSall("/"+ plugin + "/start 0") plugins.Ping(plugin) - # OSC server Thread : handler, dacs reports and simulator points sender to UI. def osc_thread(): + # while True: + try: + while True: - #while True: - try: - while True: + time.sleep(0.1) + osc_frame() + for laserid in range(0, gstt.LaserNumber): # Laser not used -> led is not lit - time.sleep(0.1) - osc_frame() - for laserid in range(0,gstt.LaserNumber): # Laser not used -> led is not lit + lstate = {'0': 'IDLE', '1': 'PREPARE', '2': "PLAYING", '64': "NOCONNECTION ?"} + lstt = r.get('/lstt/' + str(laserid)).decode('ascii') + # print ("laserid", laserid,"lstt",lstt, type(lstt)) + if gstt.debug > 1: + print("DAC", laserid, "is in (lstt) :", lstt, lstate[str(lstt)]) + if lstt == "0": # Dac IDLE state(0) -> led is blue (3) + sendWSall("/lstt/" + str(laserid) + " 3") - lstate = {'0': 'IDLE', '1': 'PREPARE', '2': "PLAYING", '64': "NOCONNECTION ?" } - lstt = r.get('/lstt/'+ str(laserid)).decode('ascii') - #print ("laserid", laserid,"lstt",lstt, type(lstt)) - if gstt.debug >1: - print("DAC", laserid, "is in (lstt) :", lstt , lstate[str(lstt)]) - if lstt == "0": # Dac IDLE state(0) -> led is blue (3) - sendWSall("/lstt/" + str(laserid) + " 3") + if lstt == "1": # Dac PREPARE state (1) -> led is cyan (2) + sendWSall("/lstt/" + str(laserid) + " 2") - if lstt == "1": # Dac PREPARE state (1) -> led is cyan (2) - sendWSall("/lstt/" + str(laserid) + " 2") + if lstt == "2": # Dac PLAYING (2) -> led is green (1) + sendWSall("/lstt/" + str(laserid) + " 1") - if lstt == "2": # Dac PLAYING (2) -> led is green (1) - sendWSall("/lstt/" + str(laserid) + " 1") - + ackstate = {'61': 'ACK', '46': 'FULL', '49': "INVALID", '21': 'STOP', '64': "NOCONNECTION ?", + '35': "NOCONNECTION ?", '97': 'ACK', '70': 'FULL', '73': "INVALID", '33': 'STOP', + '100': "NOCONNECTION", '48': "NOCONNECTION", 'a': 'ACK', 'F': 'FULL', 'I': "INVALID", + '!': 'STOP', 'd': "NOCONNECTION", '0': "NOCONNECTION"} + lack = r.get('/lack/' + str(laserid)).decode('ascii') - ackstate = {'61': 'ACK', '46': 'FULL', '49': "INVALID", '21': 'STOP', '64': "NOCONNECTION ?", '35': "NOCONNECTION ?" , '97': 'ACK', '70': 'FULL', '73': "INVALID", '33': 'STOP', '100': "NOCONNECTION", '48': "NOCONNECTION", 'a': 'ACK', 'F': 'FULL', 'I': "INVALID", '!': 'STOP', 'd': "NOCONNECTION", '0': "NOCONNECTION"} - lack= r.get('/lack/'+str(laserid)).decode('ascii') + if gstt.debug > 1: + print("DAC", laserid, "answered (lack):", lack, chr(int(lack)), ackstate[str(lack)]) - if gstt.debug >1: - print("DAC", laserid, "answered (lack):", lack, chr(int(lack)), ackstate[str(lack)]) + if chr(int(lack)) == 'a': # Dac sent ACK ("a") -> led is green (1) + sendWSall("/lack/" + str(laserid) + " 1") - if chr(int(lack)) == 'a': # Dac sent ACK ("a") -> led is green (1) - sendWSall("/lack/" + str(laserid) +" 1") + if chr(int(lack)) == 'F': # Dac sent FULL ("F") -> led is orange (5) + sendWSall("/lack/" + str(laserid) + " 5") - if chr(int(lack)) == 'F': # Dac sent FULL ("F") -> led is orange (5) - sendWSall("/lack/" + str(laserid) +" 5") + if chr(int(lack)) == 'I': # Dac sent INVALID ("I") -> led is yellow (4) + sendWSall("/lack/" + str(laserid) + " 4") + # print lack - if chr(int(lack)) == 'I': # Dac sent INVALID ("I") -> led is yellow (4) - sendWSall("/lack/" + str(laserid)+" 4") - #print lack - - if lack == "64" or lack =="35": # no connection to dac -> leds are red (6) - sendWSall("/lack/" + str(laserid) + " 6") - sendWSall("/lstt/" + str(laserid) + " 6") - #sendWSall("/lstt/" + str(laserid) + " 0") - sendWSall("/points/" + str(laserid) + " 6") - - else: - # last number of points sent to etherdream buffer - sendWSall("/points/" + str(laserid) + " " + str(r.get('/cap/'+str(laserid)).decode('ascii'))) + if lack == "64" or lack == "35": # no connection to dac -> leds are red (6) + sendWSall("/lack/" + str(laserid) + " 6") + sendWSall("/lstt/" + str(laserid) + " 6") + # sendWSall("/lstt/" + str(laserid) + " 0") + sendWSall("/points/" + str(laserid) + " 6") - #print("Sending simu frame from",'/pl/'+str(gstt.SceneNumber)+'/'+str(gstt.Laser)) - #print(r.get('/pl/'+str(gstt.SceneNumber)+'/'+str(gstt.Laser))) - sendWSall("/simul" +" "+ str(r.get('/pl/'+str(gstt.SceneNumber)+'/'+str(gstt.Laser)).decode('ascii'))) - if random.randint(0,100)>95: - plugins.sendbroadcast() + else: + # last number of points sent to etherdream buffer + sendWSall("/points/" + str(laserid) + " " + str(r.get('/cap/' + str(laserid)).decode('ascii'))) + + # print("Sending simu frame from",'/pl/'+str(gstt.SceneNumber)+'/'+str(gstt.Laser)) + # print(r.get('/pl/'+str(gstt.SceneNumber)+'/'+str(gstt.Laser))) + sendWSall( + "/simul" + " " + str(r.get('/pl/' + str(gstt.SceneNumber) + '/' + str(gstt.Laser)).decode('ascii'))) + if random.randint(0, 100) > 95: + plugins.sendbroadcast() - except Exception as e: - import sys, traceback - print('\n--------------------------') - print('OSC Thread Exception: %s' % e) - print('- - - - - - - - - - - - - - ') - traceback.print_tb(sys.exc_info()[2]) - print("\n") + except Exception as e: + import sys, traceback + print('\n--------------------------') + print('OSC Thread Exception: %s' % e) + print('- - - - - - - - - - - - - - ') + traceback.print_tb(sys.exc_info()[2]) + print("\n") + # # Websocket part @@ -282,33 +282,33 @@ def osc_thread(): # Called for every WS client connecting (after handshake) def new_client(client, wserver): - print("New WS client connected and was given id %d" % client['id']) sendWSall("/status Hello " + str(client['id'])) - for laserid in range(0,gstt.LaserNumber): + for laserid in range(0, gstt.LaserNumber): sendWSall("/ip/" + str(laserid) + " " + str(gstt.lasersIPS[laserid])) - sendWSall("/kpps/" + str(laserid)+ " " + str(gstt.kpps[laserid])) - #sendWSall("/laser"+str(laserid)+"/start 1") - sendWSall("/laser "+str(laserid)) - #print("/laser "+str(laserid)) + sendWSall("/kpps/" + str(laserid) + " " + str(gstt.kpps[laserid])) + # sendWSall("/laser"+str(laserid)+"/start 1") + sendWSall("/laser " + str(laserid)) + # print("/laser "+str(laserid)) sendWSall("/lack/" + str(laserid) + " 6") - #print("/lack/" + str(laserid) + " 6") - sendWSall("/lstt/" + str(laserid) + " 6") - #print("/lstt/" + str(laserid) + " 6") + # print("/lack/" + str(laserid) + " 6") + sendWSall("/lstt/" + str(laserid) + " 6") + # print("/lstt/" + str(laserid) + " 6") sendWSall("/points/" + str(laserid) + " 0") - #print("/points/" + str(laserid) + " 0") + # print("/points/" + str(laserid) + " 0") if gstt.swapX[laserid] == 1: - sendWSall("/swap/X/" + str(laserid)+ " 1") + sendWSall("/swap/X/" + str(laserid) + " 1") else: - sendWSall("/swap/X/" + str(laserid)+ " 0") + sendWSall("/swap/X/" + str(laserid) + " 0") if gstt.swapY[laserid] == 1: - sendWSall("/swap/Y/" + str(laserid)+ " 1") + sendWSall("/swap/Y/" + str(laserid) + " 1") else: - sendWSall("/swap/Y/" + str(laserid)+ " 0") + sendWSall("/swap/Y/" + str(laserid) + " 0") + # Called for every WS client disconnecting def client_left(client, wserver): @@ -317,53 +317,50 @@ def client_left(client, wserver): # Called for each WS received message. def message_received(client, wserver, message): - - #if len(message) > 200: + # if len(message) > 200: # message = message[:200]+'..' - #if gstt.debug >0: + # if gstt.debug >0: # print ("") # print("WS Client(%d) said: %s" % (client['id'], message)) - + oscpath = message.split(" ") - #print "WS Client", client['id'], "said :", message, "splitted in an oscpath :", oscpath + # print "WS Client", client['id'], "said :", message, "splitted in an oscpath :", oscpath if gstt.debug > 0: print("WS Client", client['id'], "said :", message, "splitted in an oscpath :", oscpath) - + PingAll() message4plugin = False # WS received Message is for a plugin ? for plugin in list(gstt.plugins.keys()): - + if oscpath[0].find(plugin) != -1: - + message4plugin = True - #print(oscpath) + # print(oscpath) if plugins.Send(plugin, oscpath): print("plugins sent incoming WS correctly to", plugin) else: print("plugins detected", plugin, "offline.") - - # WS received message is an LJ command + # WS received message is an LJ command if message4plugin == False: if len(oscpath) == 1: args[0] = "noargs" - #print "noargs command" - + # print "noargs command" + elif len(oscpath) > 1: - args[0] = str(oscpath[1]) - #print "arg",oscpath[1] - - commands.handler(oscpath[0].split("/"),args) - + args[0] = str(oscpath[1]) + # print "arg",oscpath[1] + + commands.handler(oscpath[0].split("/"), args) # if needed a loop back : WS Client -> server -> WS Client - #sendWSall("ws"+message) + # sendWSall("ws"+message) def handle_timeout(self): @@ -371,10 +368,11 @@ def handle_timeout(self): def sendWSall(message): - #if gstt.debug >0: - #print("WS sending %s" % (message)) + # if gstt.debug >0: + # print("WS sending %s" % (message)) wserver.send_message_to_all(message) - + + ''' print "" print "Midi Configuration" @@ -382,10 +380,11 @@ midi.InConfig() midi.OutConfig() ''' + def fff(name): - print() - print('HELLO', name ) #indent - print() + print() + print('HELLO', name) # indent + print() # @@ -395,26 +394,24 @@ def fff(name): print("") log.info("Creating startup point lists...") +if r.set("/clientkey", "/pl/" + str(gstt.SceneNumber) + "/") == True: + print("sent clientkey : /pl/" + str(gstt.SceneNumber) + "/") -if r.set("/clientkey","/pl/"+str(gstt.SceneNumber)+"/")==True: - print("sent clientkey : /pl/"+str(gstt.SceneNumber)+"/") - -#pdb.set_trace() -for sceneid in range(0,gstt.MaxScenes+1): - print("Scene "+ str(sceneid)) - #digit_points = font1.DigitsDots(sceneid,65280) +# pdb.set_trace() +for sceneid in range(0, gstt.MaxScenes + 1): + print("Scene " + str(sceneid)) + # digit_points = font1.DigitsDots(sceneid,65280) # Order all lasers to show its number at startup -> tell all 4 laser process to USER PLs - for laserid in range(0,gstt.LaserNumber): + for laserid in range(0, gstt.LaserNumber): - digit_points = font1.DigitsDots(laserid,65280) - if r.set('/pl/'+str(sceneid)+'/'+str(laserid), str(digit_points)) == True: + digit_points = font1.DigitsDots(laserid, 65280) + if r.set('/pl/' + str(sceneid) + '/' + str(laserid), str(digit_points)) == True: pass - #print( ast.literal_eval(r.get('/pl/'+str(sceneid)+'/'+str(laserid)).decode('ascii'))) - #print("/pl/"+str(sceneid)+"/"+str(laserid)+" "+str(ast.literal_eval(r.get('/pl/'+str(sceneid)+'/'+str(laserid)).decode('ascii')))) - - r.set('/order/'+str(laserid), 0) + # print( ast.literal_eval(r.get('/pl/'+str(sceneid)+'/'+str(laserid)).decode('ascii'))) + # print("/pl/"+str(sceneid)+"/"+str(laserid)+" "+str(ast.literal_eval(r.get('/pl/'+str(sceneid)+'/'+str(laserid)).decode('ascii')))) + r.set('/order/' + str(laserid), 0) # # Starts one DAC process per requested Laser @@ -431,96 +428,98 @@ if __name__ == '__main__': commands.DAChecks() print("dacs", gstt.dacs) - else: + else: log.infog("Resquested DACs mode") - lasernumber = gstt.LaserNumber -1 + lasernumber = gstt.LaserNumber - 1 print("LaserNumber = ", gstt.LaserNumber) - - log.info("Starting "+str(gstt.LaserNumber) + " DACs process...") - - # Launch one process (a tracer3 instance) by etherdream - dac_worker0= Process(target=dac_process, args=(0,0,)) + log.info("Starting " + str(gstt.LaserNumber) + " DACs process...") + + # Launch one process (a tracer3 instance) for etherdream / helios + dac_family = None + if config["laser0"].get("dac_family"): + dac_family = config["laser0"]["dac_family"] + dac_worker0 = Process(target=dac_process, args=(0, 0, dac_family)) dac_worker0.start() commands.worker0 = dac_worker0 - print("Tracer 0 : name", dac_worker0.name , "pid", dac_worker0.pid ) - - if lasernumber >0: - dac_worker1= Process(target=dac_process, args=(1,0,)) + print("Tracer 0 : name", dac_worker0.name, "pid", dac_worker0.pid) + + if lasernumber > 0: + dac_worker1 = Process(target=dac_process, args=(1, 0,)) commands.worker1 = dac_worker1 - print("Tracer 1 : name", dac_worker1.name , "pid", dac_worker1.pid ) + print("Tracer 1 : name", dac_worker1.name, "pid", dac_worker1.pid) dac_worker1.start() - - if lasernumber >1: - dac_worker2= Process(target=dac_process, args=(2,0,)) + + if lasernumber > 1: + dac_worker2 = Process(target=dac_process, args=(2, 0,)) dac_worker2.start() commands.worker2 = dac_worker2 - print("Tracer 2 : name", dac_worker2.name , "pid", dac_worker2.pid ) - - if lasernumber >2: - dac_worker3= Process(target=dac_process, args=(3,0,)) - print("Tracer 3 : name", dac_worker3.name , "pid", dac_worker3.pid ) + print("Tracer 2 : name", dac_worker2.name, "pid", dac_worker2.pid) + + if lasernumber > 2: + dac_worker3 = Process(target=dac_process, args=(3, 0,)) + print("Tracer 3 : name", dac_worker3.name, "pid", dac_worker3.pid) commands.worker3 = dac_worker3 dac_worker3.start() print("") - + # # start WS and OSC servers # - + try: - + # Websocket startup - wserver = WebsocketServer(wsPORT,host=serverIP) + wserver = WebsocketServer(wsPORT, host=serverIP) plugins.Init(wserver) - + log.info("Starting servers...") # Launch OSC thread listening to oscserver - print("Launching OSC server...") - print("at", oscserverIPin, "port",str(oscserverPORTin)) - oscserver.addMsgHandler( "/noteon", commands.NoteOn) - oscserver.addMsgHandler( "/scim", commands.Scim) - oscserver.addMsgHandler( "/line1", commands.Line1) - oscserver.addMsgHandler( "/forwardui", commands.ForwardUI) - # Default OSC handler for all OSC incoming message - oscserver.addMsgHandler("default", handler) - _thread.start_new_thread(osc_thread, ()) - + # print("Launching OSC server...") + # print("at", oscserverIPin, "port", str(oscserverPORTin)) + # oscserver.addMsgHandler("/noteon", commands.NoteOn) + # oscserver.addMsgHandler("/scim", commands.Scim) + # oscserver.addMsgHandler("/line1", commands.Line1) + # oscserver.addMsgHandler("/forwardui", commands.ForwardUI) + # # Default OSC handler for all OSC incoming message + # oscserver.addMsgHandler("default", handler) + # _thread.start_new_thread(osc_thread, ()) + print("Launching webUI Websocket server...") - print("at", serverIP, "port",wsPORT) + print("at", serverIP, "port", wsPORT) wserver.set_fn_new_client(new_client) wserver.set_fn_client_left(client_left) wserver.set_fn_message_received(message_received) print("") log.info("Resetting all Homographies...") - for laserid in range(0,gstt.LaserNumber): + for laserid in range(0, gstt.LaserNumber): homographyp.newEDH(laserid) - + # plugins autostart print("") log.info("Plugins startup...") - + if gstt.autostart != "": - + for pluginname in gstt.autostart.split(","): print("Autostarting", pluginname, "...") plugins.Start(pluginname) - + print("") log.infog("LJ server running...") - + # websocket loop wserver.run_forever() - - + + except Exception: log.err("Exception") traceback.print_exc() - + # Gently stop on CTRL C - + finally: commands.LJautokill() @@ -530,6 +529,3 @@ if __name__ == '__main__': random_points = [(300.0+random.randint(-100, 100), 200.0+random.randint(-100, 100), 0), (500.0+random.randint(-100, 100), 200.0+random.randint(-100, 100), 65280), (500.0+random.randint(-100, 100), 400.0+random.randint(-100, 100), 65280), (300.0+random.randint(-100, 100), 400.0+random.randint(-100, 100), 65280), (300.0+random.randint(-100, 100), 200.0+random.randint(-100, 100), 65280)] ''' - - -