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 0000000..c9c7a21 Binary files /dev/null and b/libs3/libHeliosDacAPI.so differ 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)] ''' - - -