Compare commits

..

No commits in common. "9ec8d5bc41d5c6bbd75d1da02b334ba3cd387066" and "4a9cd73767e9ce11472db6d900feb579c7b70c97" have entirely different histories.

16 changed files with 1528 additions and 16571 deletions

View File

@ -1,235 +0,0 @@
# j4cDAC test code
#
# Copyright 2011 Jacob Potter
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import socket
import time
import struct
def pack_point(x, y, r, g, b, i = -1, u1 = 0, u2 = 0, flags = 0):
"""Pack some color values into a struct dac_point.
Values must be specified for x, y, r, g, and b. If a value is not
passed in for the other fields, i will default to max(r, g, b); the
rest default to zero.
"""
#print(r,g,b)
if i < 0:
i = max(r, g, b)
return struct.pack("<HhhHHHHHH", flags, x, y, r, g, b, i, u1, u2)
class ProtocolError(Exception):
"""Exception used when a protocol error is detected."""
pass
class Status(object):
"""Represents a status response from the DAC."""
def __init__(self, data):
"""Initialize from a chunk of data."""
self.protocol_version, self.le_state, self.playback_state, \
self.source, self.le_flags, self.playback_flags, \
self.source_flags, self.fullness, self.point_rate, \
self.point_count = \
struct.unpack("<BBBBHHHHII", data)
def dump(self, prefix = " - "):
"""Dump to a string."""
lines = [
"Light engine: state %d, flags 0x%x" %
(self.le_state, self.le_flags),
"Playback: state %d, flags 0x%x" %
(self.playback_state, self.playback_flags),
"Buffer: %d points" %
(self.fullness, ),
"Playback: %d kpps, %d points played" %
(self.point_rate, self.point_count),
"Source: %d, flags 0x%x" %
(self.source, self.source_flags)
]
for l in lines:
print(prefix + l)
class BroadcastPacket(object):
"""Represents a broadcast packet from the DAC."""
def __init__(self, st):
"""Initialize from a chunk of data."""
self.mac = st[:6]
self.hw_rev, self.sw_rev, self.buffer_capacity, \
self.max_point_rate = struct.unpack("<HHHI", st[6:16])
self.status = Status(st[16:36])
def dump(self, prefix = " - "):
"""Dump to a string."""
lines = [
"MAC: " + ":".join(
"%02x" % (ord(o), ) for o in self.mac),
"HW %d, SW %d" %
(self.hw_rev, self.sw_rev),
"Capabilities: max %d points, %d kpps" %
(self.buffer_capacity, self.max_point_rate)
]
for l in lines:
print(prefix + l)
self.status.dump(prefix)
class DAC(object):
"""A connection to a DAC."""
def read(self, l):
"""Read exactly length bytes from the connection."""
while l > len(self.buf):
buffy = self.conn.recv(4096)
#print(buffy)
self.buf += buffy
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]
cmdR = chr(data[1])
status = Status(data[2:])
status.dump()
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 __init__(self, host, port = 7765):
"""Connect to the DAC over TCP."""
conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
conn.connect((host, port))
conn.settimeout(1)
self.conn = conn
self.buf = b''
# Read the "hello" message
first_status = self.readresp("?")
first_status.dump()
'''
self.conn.sendall('v')
self.firmware_string = self.read(32).replace("\x00", " ").strip()
print "Firmware: %s" % (self.firmware_string, )
'''
def begin(self, lwm, rate):
cmd = struct.pack("<cHI", b'b', lwm, rate)
self.conn.sendall(cmd)
return self.readresp("b")
def update(self, lwm, rate):
cmd = struct.pack("<cHI", b'u', lwm, rate)
self.conn.sendall(cmd)
return self.readresp("u")
def encode_point(self, point):
return pack_point(*point)
def write(self, points):
epoints = list(map(self.encode_point, points))
cmd = struct.pack("<cH", b'd', len(epoints))
#print(cmd + b''.join(epoints))
self.conn.sendall(cmd + b''.join(epoints))
return self.readresp("d")
def prepare(self):
self.conn.sendall('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, stream):
# First, prepare the stream
if self.last_status.playback_state == 2:
raise Exception("already playing?!")
elif self.last_status.playback_state == 0:
self.prepare()
started = 0
while True:
# How much room?
cap = 1799 - self.last_status.fullness
points = stream.read(cap)
if cap < 100:
time.sleep(0.005)
cap += 150
# print "Writing %d points" % (cap, )
t0 = time.time()
self.write(points)
t1 = time.time()
# print "Took %f" % (t1 - t0, )
if not started:
self.begin(0, 30000)
started = 1
def find_dac():
"""Listen for broadcast packets."""
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(("0.0.0.0", 7654))
while True:
data, addr = s.recvfrom(1024)
bp = BroadcastPacket(data)
print("Packet from %s: " % (addr, ))
bp.dump()
def find_first_dac():
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(("0.0.0.0", 7654))
data, addr = s.recvfrom(1024)
bp = BroadcastPacket(data)
print("Packet from %s: " % (addr, ))
return addr[0]

View File

@ -1,35 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeOSTypes</key>
<array>
<string>****</string>
<string>fold</string>
<string>disk</string>
</array>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
</array>
<key>CFBundleExecutable</key>
<string>sitter</string>
<key>CFBundleIconFile</key>
<string>PythonApplet.icns</string>
<key>CFBundleIdentifier</key>
<string>sitter</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>sitter</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleSignature</key>
<string>????</string>
</dict>
</plist>

View File

@ -1,23 +0,0 @@
#!/System/Library/Frameworks/Python.framework/Versions/2.5/Resources/Python.app/Contents/MacOS/Python
import sys, os
execdir = os.path.dirname(sys.argv[0])
executable = os.path.join(execdir, "Python")
resdir = os.path.join(os.path.dirname(execdir), "Resources")
libdir = os.path.join(os.path.dirname(execdir), "Frameworks")
mainprogram = os.path.join(resdir, "__argvemulator_sitter.py")
sys.argv.insert(1, mainprogram)
if 0 or 0:
os.environ["PYTHONPATH"] = resdir
if 0:
os.environ["PYTHONHOME"] = resdir
else:
pypath = os.getenv("PYTHONPATH", "")
if pypath:
pypath = ":" + pypath
os.environ["PYTHONPATH"] = resdir + pypath
os.environ["PYTHONEXECUTABLE"] = executable
os.environ["DYLD_LIBRARY_PATH"] = libdir
os.environ["DYLD_FRAMEWORK_PATH"] = libdir
os.execve(executable, sys.argv, os.environ)

View File

@ -1 +0,0 @@
APPL????

View File

@ -1,4 +0,0 @@
import argvemulator, os
argvemulator.ArgvCollector().mainloop()
execfile(os.path.join(os.path.split(__file__)[0], "sitter.py"))

View File

@ -1,414 +0,0 @@
#!/usr/bin/python
# j4cDAC "sitter"
#
# Copyright 2012 Jacob Potter
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import socket
import time
import struct
def pack_point(x, y, r, g, b, i = -1, u1 = 0, u2 = 0, flags = 0):
"""Pack some color values into a struct dac_point.
Values must be specified for x, y, r, g, and b. If a value is not
passed in for the other fields, i will default to max(r, g, b); the
rest default to zero.
"""
if i < 0:
i = max(r, g, b)
return struct.pack("<HhhHHHHHH", flags, x, y, i, r, g, b, u1, u2)
class ProtocolError(Exception):
"""Exception used when a protocol error is detected."""
pass
class Status(object):
"""Represents a status response from the DAC."""
def __init__(self, data):
"""Initialize from a chunk of data."""
self.protocol_version, self.le_state, self.playback_state, \
self.source, self.le_flags, self.playback_flags, \
self.source_flags, self.fullness, self.point_rate, \
self.point_count = \
struct.unpack("<BBBBHHHHII", data)
def dump(self, prefix = " - "):
"""Dump to a string."""
lines = [
"Light engine: state %d, flags 0x%x" %
(self.le_state, self.le_flags),
"Playback: state %d, flags 0x%x" %
(self.playback_state, self.playback_flags),
"Buffer: %d points" %
(self.fullness, ),
"Playback: %d kpps, %d points played" %
(self.point_rate, self.point_count),
"Source: %d, flags 0x%x" %
(self.source, self.source_flags)
]
for l in lines:
print prefix + l
class BroadcastPacket(object):
"""Represents a broadcast packet from the DAC."""
def __init__(self, st, ip=None):
"""Initialize from a chunk of data."""
self.mac = st[:6]
self.hw_rev, self.sw_rev, self.buffer_capacity, \
self.max_point_rate = struct.unpack("<HHHI", st[6:16])
self.status = Status(st[16:36])
self.ip = ip
def dump(self, prefix = " - "):
"""Dump to a string."""
lines = [
"MAC: " + ":".join(
"%02x" % (ord(o), ) for o in self.mac),
"HW %d, SW %d" %
(self.hw_rev, self.sw_rev),
"Capabilities: max %d points, %d kpps" %
(self.buffer_capacity, self.max_point_rate)
]
for l in lines:
print prefix + l
self.status.dump(prefix)
def macstr(self):
return "".join("%02x" % (ord(c), ) for c in self.mac)
class DAC(object):
"""A connection to a DAC."""
def got_broadcast(self, bp):
self.last_broadcast = bp
self.last_broadcast_time = time.time()
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]
cmdR = data[1]
status = Status(data[2:])
# status.dump()
if cmdR != cmd:
raise ProtocolError("expected resp for %r, got %r"
% (cmd, cmdR))
if response != "a":
raise ProtocolError("expected ACK, got %r"
% (response, ))
self.last_status = status
return status
def __init__(self, macstr, bp):
self.macstr = macstr
self.firmware_string = "-"
self.got_broadcast(bp)
try:
t1 = time.time()
self.connect(self.last_broadcast.ip[0])
t = time.time() - t1
self.conn_status = "ok (%d ms)" % (t * 500)
if self.last_broadcast.sw_rev < 2:
self.firmware_string = "(old)"
else:
self.conn.sendall('v')
self.firmware_string = self.read(32).replace("\x00", " ").strip()
except e:
self.conn_status = str(e)
def connect(self, host, port = 7765):
"""Connect to the DAC over TCP."""
conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
conn.settimeout(0.2)
conn.connect((host, port))
self.conn = conn
self.buf = ""
# Read the "hello" message
first_status = self.readresp("?")
first_status.dump()
def begin(self, lwm, rate):
cmd = struct.pack("<cHI", "b", lwm, rate)
self.conn.sendall(cmd)
return self.readresp("b")
def update(self, lwm, rate):
cmd = struct.pack("<cHI", "u", lwm, rate)
self.conn.sendall(cmd)
return self.readresp("u")
def encode_point(self, point):
return pack_point(*point)
def write(self, points):
epoints = map(self.encode_point, points)
cmd = struct.pack("<cH", "d", len(epoints))
self.conn.sendall(cmd + "".join(epoints))
return self.readresp("d")
def prepare(self):
self.conn.sendall("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, stream):
# First, prepare the stream
if self.last_status.playback_state == 2:
raise Exception("already playing?!")
elif self.last_status.playback_state == 0:
self.prepare()
started = 0
while True:
# How much room?
cap = 1799 - self.last_status.fullness
points = stream.read(cap)
if cap < 100:
time.sleep(0.005)
cap += 150
# print "Writing %d points" % (cap, )
t0 = time.time()
self.write(points)
t1 = time.time()
# print "Took %f" % (t1 - t0, )
if not started:
self.begin(0, 30000)
started = 1
def find_dac():
"""Listen for broadcast packets."""
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(("0.0.0.0", 7654))
while True:
data, addr = s.recvfrom(1024)
bp = BroadcastPacket(data)
print "Packet from %s: " % (addr, )
bp.dump()
from Tkinter import *
import socket
import Queue
import thread
import time
class DacDisplay(LabelFrame):
def __init__(self, master):
LabelFrame.__init__(self, master, width=600, height=400)
self.grid_propagate(0)
Label(self, text="IP Address:").grid(row=0, column=0, sticky=N+E)
Label(self, text="Version:").grid(row=1, column=0, sticky=N+E)
Label(self, text="Status:").grid(row=2, column=0, sticky=N+E)
Label(self, text="Source:").grid(row=3, column=0, sticky=N+E)
Label(self, text="Network:").grid(row=4, column=0, sticky=N+E)
Label(self, text="Firmware:").grid(row=5, column=0, sticky=N+E)
self.iplabel = Label(self, text = "")
self.iplabel.grid(row=0, column=1, sticky=N+W)
self.verslabel = Label(self, text = "")
self.verslabel.grid(row=1, column=1, sticky=N+W)
self.stlabel = Label(self, text = "")
self.stlabel.grid(row=2, column=1, sticky=N+W)
self.srclabel = Label(self, text = "")
self.srclabel.grid(row=3, column=1, sticky=N+W)
self.netlabel = Label(self, text = "")
self.netlabel.grid(row=4, column=1, sticky=N+W)
self.fwlabel = Label(self, text = "")
self.fwlabel.grid(row=5, column=1, sticky=N+W)
self.display_none()
def display_none(self):
self['text'] = "Ether Dream"
for l in self.iplabel, self.verslabel, self.stlabel, self.srclabel, self.netlabel, self.fwlabel:
l['text'] = ""
def display_dac(self, dac):
b = dac.last_broadcast
self['text'] = "Ether Dream " + b.macstr()[6:]
self.iplabel['text'] = str(b.ip[0])
self.verslabel['text'] = "hardware %d, software %d" % (b.hw_rev, b.sw_rev)
st_str = ""
if b.status.le_state == 0:
st_str = "online, "
else:
st_str = "ESTOP ACTIVE (%d), " % (b.status.le_flags, )
if b.status.playback_state == 0:
st_str += "idle"
elif b.status.playback_state == 1:
st_str += "prepared"
elif b.status.playback_state == 2:
st_str += "playing (%d buffered, %d played)" % (b.status.fullness, b.status.point_count)
else:
st_str += "DAC state %d" % (b.status.playback_state, )
if b.status.point_rate:
st_str += ", %d pps" % (b.status.point_rate)
self.stlabel['text'] = st_str
if b.status.source == 0:
src_str = "network"
elif b.status.source == 1:
src_str = "file playback: %s, repeat %s" % (
b.status.source_flags & 1 and "playing" or "not playing",
b.status.source_flags & 2 and "on" or "off"
)
elif b.status.source == 2:
src_str = "abstract generator: %s" % (
b.status.source_flags & 1 and "playing" or "not playing",
)
else:
src_str = "unknown %d" % (b.status.source)
self.srclabel['text'] = src_str
self.netlabel['text'] = dac.conn_status
self.fwlabel['text'] = dac.firmware_string
class DacTracker(Listbox):
def __init__(self, master, *args, **kwargs):
Listbox.__init__(self, master, *args, **kwargs)
self.dac_list = []
self.dac_macstr_map = {}
self.bind("<<ListboxSelect>>", self.update_selection)
def update_selection(self, lb=None):
if self.dac_display:
try:
dac_obj = self.dac_list[self.index(ACTIVE)]
except:
return
self.dac_display.display_dac(dac_obj)
def got_packet(self, bp):
macstr = bp.macstr()
if macstr not in self.dac_macstr_map:
new_dac = DAC(macstr, bp)
self.insert(END, macstr[6:])
self.dac_list.append(new_dac)
self.dac_macstr_map[macstr] = new_dac
dac_obj = new_dac
else:
dac_obj = self.dac_macstr_map[macstr]
dac_obj.got_broadcast(bp)
if len(self.dac_list) == 1:
self.selection_set(0)
self.update_selection()
def check_on_dac():
if time.time() - dac_obj.last_broadcast_time < 2:
return
idx = self.dac_list.index(dac_obj)
self.dac_list.remove(dac_obj)
del self.dac_macstr_map[macstr]
self.delete(idx)
self.dac_display.display_none()
self.after(2000, check_on_dac)
# Set up the basic window
root = Tk()
root.title("Ether Dream")
root.resizable(FALSE, FALSE)
frame = Frame(root)
frame.grid()
disp = DacDisplay(root)
disp.grid(row=0, column=1, padx=5, pady=5)
tracker = DacTracker(root, height=22)
tracker.grid(row=0, column=0, padx=5, pady=5)
tracker.dac_display = disp
# Set up queue checker
packet_queue = Queue.Queue()
def queue_check():
try:
while True:
data, addr = packet_queue.get_nowait()
tracker.got_packet(BroadcastPacket(data, addr))
except Queue.Empty:
root.after(100, queue_check)
root.after(100, queue_check)
# Set up listening socket and thread
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(("0.0.0.0", 7654))
def socket_thread():
while True:
packet_queue.put(s.recvfrom(1024))
thread.start_new(socket_thread, ())
root.mainloop()

View File

@ -1,414 +0,0 @@
#!/usr/bin/python
# j4cDAC "sitter"
#
# Copyright 2012 Jacob Potter
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import socket
import time
import struct
def pack_point(x, y, r, g, b, i = -1, u1 = 0, u2 = 0, flags = 0):
"""Pack some color values into a struct dac_point.
Values must be specified for x, y, r, g, and b. If a value is not
passed in for the other fields, i will default to max(r, g, b); the
rest default to zero.
"""
if i < 0:
i = max(r, g, b)
return struct.pack("<HhhHHHHHH", flags, x, y, i, r, g, b, u1, u2)
class ProtocolError(Exception):
"""Exception used when a protocol error is detected."""
pass
class Status(object):
"""Represents a status response from the DAC."""
def __init__(self, data):
"""Initialize from a chunk of data."""
self.protocol_version, self.le_state, self.playback_state, \
self.source, self.le_flags, self.playback_flags, \
self.source_flags, self.fullness, self.point_rate, \
self.point_count = \
struct.unpack("<BBBBHHHHII", data)
def dump(self, prefix = " - "):
"""Dump to a string."""
lines = [
"Light engine: state %d, flags 0x%x" %
(self.le_state, self.le_flags),
"Playback: state %d, flags 0x%x" %
(self.playback_state, self.playback_flags),
"Buffer: %d points" %
(self.fullness, ),
"Playback: %d kpps, %d points played" %
(self.point_rate, self.point_count),
"Source: %d, flags 0x%x" %
(self.source, self.source_flags)
]
for l in lines:
print prefix + l
class BroadcastPacket(object):
"""Represents a broadcast packet from the DAC."""
def __init__(self, st, ip=None):
"""Initialize from a chunk of data."""
self.mac = st[:6]
self.hw_rev, self.sw_rev, self.buffer_capacity, \
self.max_point_rate = struct.unpack("<HHHI", st[6:16])
self.status = Status(st[16:36])
self.ip = ip
def dump(self, prefix = " - "):
"""Dump to a string."""
lines = [
"MAC: " + ":".join(
"%02x" % (ord(o), ) for o in self.mac),
"HW %d, SW %d" %
(self.hw_rev, self.sw_rev),
"Capabilities: max %d points, %d kpps" %
(self.buffer_capacity, self.max_point_rate)
]
for l in lines:
print prefix + l
self.status.dump(prefix)
def macstr(self):
return "".join("%02x" % (ord(c), ) for c in self.mac)
class DAC(object):
"""A connection to a DAC."""
def got_broadcast(self, bp):
self.last_broadcast = bp
self.last_broadcast_time = time.time()
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]
cmdR = data[1]
status = Status(data[2:])
# status.dump()
if cmdR != cmd:
raise ProtocolError("expected resp for %r, got %r"
% (cmd, cmdR))
if response != "a":
raise ProtocolError("expected ACK, got %r"
% (response, ))
self.last_status = status
return status
def __init__(self, macstr, bp):
self.macstr = macstr
self.firmware_string = "-"
self.got_broadcast(bp)
try:
t1 = time.time()
self.connect(self.last_broadcast.ip[0])
t = time.time() - t1
self.conn_status = "ok (%d ms)" % (t * 500)
if self.last_broadcast.sw_rev < 2:
self.firmware_string = "(old)"
else:
self.conn.sendall('v')
self.firmware_string = self.read(32).replace("\x00", " ").strip()
except Exception, e:
self.conn_status = str(e)
def connect(self, host, port = 7765):
"""Connect to the DAC over TCP."""
conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
conn.settimeout(0.2)
conn.connect((host, port))
self.conn = conn
self.buf = ""
# Read the "hello" message
first_status = self.readresp("?")
first_status.dump()
def begin(self, lwm, rate):
cmd = struct.pack("<cHI", "b", lwm, rate)
self.conn.sendall(cmd)
return self.readresp("b")
def update(self, lwm, rate):
cmd = struct.pack("<cHI", "u", lwm, rate)
self.conn.sendall(cmd)
return self.readresp("u")
def encode_point(self, point):
return pack_point(*point)
def write(self, points):
epoints = map(self.encode_point, points)
cmd = struct.pack("<cH", "d", len(epoints))
self.conn.sendall(cmd + "".join(epoints))
return self.readresp("d")
def prepare(self):
self.conn.sendall("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, stream):
# First, prepare the stream
if self.last_status.playback_state == 2:
raise Exception("already playing?!")
elif self.last_status.playback_state == 0:
self.prepare()
started = 0
while True:
# How much room?
cap = 1799 - self.last_status.fullness
points = stream.read(cap)
if cap < 100:
time.sleep(0.005)
cap += 150
# print "Writing %d points" % (cap, )
t0 = time.time()
self.write(points)
t1 = time.time()
# print "Took %f" % (t1 - t0, )
if not started:
self.begin(0, 30000)
started = 1
def find_dac():
"""Listen for broadcast packets."""
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(("0.0.0.0", 7654))
while True:
data, addr = s.recvfrom(1024)
bp = BroadcastPacket(data)
print "Packet from %s: " % (addr, )
bp.dump()
from Tkinter import *
import socket
import Queue
import thread
import time
class DacDisplay(LabelFrame):
def __init__(self, master):
LabelFrame.__init__(self, master, width=600, height=400)
self.grid_propagate(0)
Label(self, text="IP Address:").grid(row=0, column=0, sticky=N+E)
Label(self, text="Version:").grid(row=1, column=0, sticky=N+E)
Label(self, text="Status:").grid(row=2, column=0, sticky=N+E)
Label(self, text="Source:").grid(row=3, column=0, sticky=N+E)
Label(self, text="Network:").grid(row=4, column=0, sticky=N+E)
Label(self, text="Firmware:").grid(row=5, column=0, sticky=N+E)
self.iplabel = Label(self, text = "")
self.iplabel.grid(row=0, column=1, sticky=N+W)
self.verslabel = Label(self, text = "")
self.verslabel.grid(row=1, column=1, sticky=N+W)
self.stlabel = Label(self, text = "")
self.stlabel.grid(row=2, column=1, sticky=N+W)
self.srclabel = Label(self, text = "")
self.srclabel.grid(row=3, column=1, sticky=N+W)
self.netlabel = Label(self, text = "")
self.netlabel.grid(row=4, column=1, sticky=N+W)
self.fwlabel = Label(self, text = "")
self.fwlabel.grid(row=5, column=1, sticky=N+W)
self.display_none()
def display_none(self):
self['text'] = "Ether Dream"
for l in self.iplabel, self.verslabel, self.stlabel, self.srclabel, self.netlabel, self.fwlabel:
l['text'] = ""
def display_dac(self, dac):
b = dac.last_broadcast
self['text'] = "Ether Dream " + b.macstr()[6:]
self.iplabel['text'] = str(b.ip[0])
self.verslabel['text'] = "hardware %d, software %d" % (b.hw_rev, b.sw_rev)
st_str = ""
if b.status.le_state == 0:
st_str = "online, "
else:
st_str = "ESTOP ACTIVE (%d), " % (b.status.le_flags, )
if b.status.playback_state == 0:
st_str += "idle"
elif b.status.playback_state == 1:
st_str += "prepared"
elif b.status.playback_state == 2:
st_str += "playing (%d buffered, %d played)" % (b.status.fullness, b.status.point_count)
else:
st_str += "DAC state %d" % (b.status.playback_state, )
if b.status.point_rate:
st_str += ", %d pps" % (b.status.point_rate)
self.stlabel['text'] = st_str
if b.status.source == 0:
src_str = "network"
elif b.status.source == 1:
src_str = "file playback: %s, repeat %s" % (
b.status.source_flags & 1 and "playing" or "not playing",
b.status.source_flags & 2 and "on" or "off"
)
elif b.status.source == 2:
src_str = "abstract generator: %s" % (
b.status.source_flags & 1 and "playing" or "not playing",
)
else:
src_str = "unknown %d" % (b.status.source)
self.srclabel['text'] = src_str
self.netlabel['text'] = dac.conn_status
self.fwlabel['text'] = dac.firmware_string
class DacTracker(Listbox):
def __init__(self, master, *args, **kwargs):
Listbox.__init__(self, master, *args, **kwargs)
self.dac_list = []
self.dac_macstr_map = {}
self.bind("<<ListboxSelect>>", self.update_selection)
def update_selection(self, lb=None):
if self.dac_display:
try:
dac_obj = self.dac_list[self.index(ACTIVE)]
except:
return
self.dac_display.display_dac(dac_obj)
def got_packet(self, bp):
macstr = bp.macstr()
if macstr not in self.dac_macstr_map:
new_dac = DAC(macstr, bp)
self.insert(END, macstr[6:])
self.dac_list.append(new_dac)
self.dac_macstr_map[macstr] = new_dac
dac_obj = new_dac
else:
dac_obj = self.dac_macstr_map[macstr]
dac_obj.got_broadcast(bp)
if len(self.dac_list) == 1:
self.selection_set(0)
self.update_selection()
def check_on_dac():
if time.time() - dac_obj.last_broadcast_time < 2:
return
idx = self.dac_list.index(dac_obj)
self.dac_list.remove(dac_obj)
del self.dac_macstr_map[macstr]
self.delete(idx)
self.dac_display.display_none()
self.after(2000, check_on_dac)
# Set up the basic window
root = Tk()
root.title("Ether Dream")
root.resizable(FALSE, FALSE)
frame = Frame(root)
frame.grid()
disp = DacDisplay(root)
disp.grid(row=0, column=1, padx=5, pady=5)
tracker = DacTracker(root, height=22)
tracker.grid(row=0, column=0, padx=5, pady=5)
tracker.dac_display = disp
# Set up queue checker
packet_queue = Queue.Queue()
def queue_check():
try:
while True:
data, addr = packet_queue.get_nowait()
tracker.got_packet(BroadcastPacket(data, addr))
except Queue.Empty:
root.after(100, queue_check)
root.after(100, queue_check)
# Set up listening socket and thread
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(("0.0.0.0", 7654))
def socket_thread():
while True:
packet_queue.put(s.recvfrom(1024))
thread.start_new(socket_thread, ())
root.mainloop()

View File

@ -1,95 +0,0 @@
#!/usr/bin/env python
#
# j4cDAC test code
#
# Copyright 2011 Jacob Potter
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import dac3 as dac
class SquarePointStream(object):
'''
def produce(self):
pmax = 15600
pstep = 100
cmax = 65535
while True:
for x in xrange(-pmax, pmax, pstep):
yield (x, pmax, cmax, 0, 0, cmax)
for y in xrange(pmax, -pmax, -pstep):
yield (pmax, y, 0, cmax, 0, cmax)
for x in xrange(pmax, -pmax, -pstep):
yield (x, -pmax, 0, 0, cmax, cmax)
for y in xrange(-pmax, pmax, pstep):
yield (-pmax, y, cmax, cmax, cmax, cmax)
'''
def produce(self):
pmax = 15600
pstep = 100
Cmax = 65535
while True:
print("Cmax:",Cmax)
for x in range(-pmax, pmax, pstep):
yield (x, pmax, Cmax, 0, 0) # pure Red
#yield (x, pmax, 0, Cmax, 0) # pure Green
#yield (x, pmax, 0, 0, Cmax) # pure Blue
#yield (x, pmax, Cmax, Cmax, Cmax) # pure White
for y in range(pmax, -pmax, -pstep):
#yield (pmax, y, Cmax, 0, 0) # pure Red
yield (pmax, y, 0, Cmax, 0) # pure Green
#yield (pmax, y, 0, 0, Cmax) # pure Blue
#yield (pmax, y, Cmax, Cmax, Cmax) # pure White
for x in range(pmax, -pmax, -pstep):
#yield (x, -pmax, Cmax, 0, 0) # pure Red
#yield (x, -pmax, 0, Cmax, 0) # pure Green
yield (x, -pmax, 0, 0, Cmax) # pure Blue
#yield (x, -pmax, Cmax, Cmax, Cmax) # pure White
for y in range(-pmax, pmax, pstep):
#yield (-pmax, y, Cmax, 0, 0) # pure Red
#yield (-pmax, y,0, Cmax, 0) # pure Green
#yield (-pmax, y, 0, 0, Cmax) # pure Blue
yield (-pmax, y, Cmax, Cmax, Cmax) # pure White
def __init__(self):
self.stream = self.produce()
def read(self, n):
return [next(self.stream) for i in range(n)]
class NullPointStream(object):
def read(self, n):
return [(0, 0, 0, 0, 0)] * n
#dac.find_dac()
d = dac.DAC(dac.find_first_dac())
#d = dac.DAC("192.168.1.43")
d.play_stream(SquarePointStream())

View File

@ -1,21 +0,0 @@
#!/usr/bin/env python
#
# j4cDAC test code
#
# Copyright 2011 Jacob Potter
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import dac
dac.find_dac()

View File

@ -0,0 +1,986 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# -*- mode: Python -*-
'''
lj23layers v0.7.6 for LJ v0.8+
LJ functions (API) for python plugins/clients
"layers" version :
- "PL" has been replaced by "layer"
- "Client"
Each program using LJ should declare itself by call lj23layers Config :
Config(redisIP, client number, name)
Basic Draw :
- PolyLineOneColor, rPolyLineOneColor, LineTo, Line
- PolyLineRGB, rPolyLineRGB, LineRGBTo, LineRGB
- rgb2int(r,g,b)
- Drawlayer (point list number) : once you stacked all wanted elements, like 2 polylines, send them to lasers.
- DrawDests(): Draw all requested destinations for each layer .
High level draw :
- Text(word, integercolor, layer , xpos, ypos, resize, rotx, roty, rotz) : Display a word
- TextRGB(word, red, green, blue, ...)
- Embeded font1
Laser objects (name and convenient group of parameters for one or several point lists)
- RelativeObject
- FixedObject
"Destinations" : Tell for given Layer a scene/Laser ("destination").
Each Layer can have different destination (i.e to display same stuff on different laser)
OSC and plugins functions :
SendLJ(adress,message) : LJ remote control. See commands.py
SendResol(address,message): Send OSC message to Resolume.
WebStatus(message) : display message on webui
Ljscene(client): Change scene number in redis keys
Ljlayer(layer): Change layer number in redis keys = laser target.
ClosePlugin(name): Send UI closing info of given plugin
OSCstart(): Start the OSC system.
OSCframe(): Handle incoming OSC message. Calling the right callback
OSCstop(): Properly close the OSC system
OSCping(): /ping Answer to LJ pings by sending /pong name
OSCquit(): /quit Exit calling script using name in terminal
OSCadddest(): layer , scene, laser Add a destination
OSCdeldest(): layer , scene, lasers delete a destination
OSCobj(): /name/obj objectname attribute value for automation
OSCvar(): /name/var variablename value for automation
Joystick management is removed. Get it back in todolist
setup_controls(joystick)
XboxController : getLeftHori, getLeftVert, getRightHori, getRightVert, getLeftTrigger, getRightTrigger
Ps3Controller : getLeftHori, getLeftVert, getRightHori, getRightVert, getLeftTrigger, getRightTrigger, getUp, getDown, getLeft, getRight, getFire1, getFire2(self):
MySaitekController : getLeftHori,getLeftVert, getRightHori,getRightVert, getLeftTrigger,getRightTrigger
MyThrustController : getLeftHori, getLeftVert, getRightHori, getRightVert, getLeftTrigger, getRightTrigger
CSLController : getLeftHori,getLeftVert,getRightHori, getRightVert,getLeftTrigger,getRightTrigger,getFire1,getFire2
my USB Joystick : getUp,getDown,getLeft,getRight,etLeftTrigger, getRightTrigger,getFire1, getFire2
Class management manuals:
https://stackoverflow.com/questions/739882/iterating-over-object-instances-of-a-given-class-in-python
https://stackoverflow.com/questions/8628123/counting-instances-of-a-class
http://effbot.org/pyfaq/how-do-i-get-a-list-of-all-instances-of-a-given-class.htm
LICENCE : CC
Sam Neurohack
'''
import math
import redis
import sys
import weakref
import struct
import numpy as np
import gstt
from multiprocessing import Process, Queue, TimeoutError
is_py2 = sys.version[0] == '2'
if is_py2:
from OSC import OSCServer, OSCClient, OSCMessage
#print ("Importing lj23 and OSC from libs...")
else:
from OSC3 import OSCServer, OSCClient, OSCMessage
#print ("Importing lj23 and OSC3 from libs...")
#redisIP = '127.0.0.1'
#r = redis.StrictRedis(host=redisIP, port=6379, db=0)
ClientNumber = 0
name = "noname"
oscrun = True
point_list = []
layers = [[],[],[],[],[],[],[],[],[],[]]
fft3Groups = [-1,-1,-1,-1]
Dests = dict()
oscIPresol = "127.0.0.1"
oscPORTresol = 7000
# 3D to 2D projection parameters
fov = 256
viewer_distance = 2.2
'''
Laser "objects"
set a name and convenient group of parameters for one or several point lists
RelativeObject is for point lists around 0,0 with builtin move/rotation.
How to init with object color, xpos,... :
osciObj = lj.RelativeObject('osciObj', True, 255, [], white, red, green,blue,0 , False, centerX , centerY , 1 , Xrot , Yrot , Zrot)
How to use in drawing functions : you're free to use 0, some or all of any laserobject attributes
- draw one or several pointlists with 'A' laserobject color and 'B' laserobject xpos ypos ?
- Change color of 'main' object and all other objects using it will change also
how to change attribute :
osciObj.resize = 2 or /pluginame/change 'OsciObj' 'resize' 2
'''
class RelativeObject:
kind = 'relative'
counter = 0
def __init__(self, name, active, intensity, xy, color, red, green, blue, layer , closed, xpos , ypos , resize , rotx , roty , rotz):
self.name = name
self.active = active # True/False
self.intensity = intensity
self.xy = [] # Dots list
self.color = color # RGB color in int
self.red = red
self.green = green
self.blue = blue
self.layer = layer
self.closed = closed
self.xpos = xpos
self.ypos = ypos
self.resize = resize
self.rotx = rotx
self.roty = roty
self.rotz = rotz
RelativeObject.counter += 1
#type(self).counter += 1
def __del__(self):
RelativeObject.counter -= 1
# Fixed Laser object : point list in 'pygame' space (top left = 0,0 / bottom right)
class FixedObject:
kind = 'fixed'
counter = 0
def __init__(self, name, intensity, active, xy, color, red, green, blue, layer , closed):
self.name = name
self.active = active # True/False
self.intensity = intensity
self.xy = []
self.color = color
self.red = red
self.green = green
self.blue = blue
self.layer = layer
self.closed = closed
FixedObject.counter += 1
def __del__(self):
FixedObject.counter -= 1
'''
class IterDest(type):
def __new__ (cls, name, bases, dct):
dct['_instances'] = []
return super().__new__(cls, name, bases, dct)
def __call__(cls, *args, **kwargs):
instance = super().__call__(*args, **kwargs)
cls._instances.append(instance)
return instance
def __iter__(cls):
return iter(cls._instances)
class DestObject():
# class Destinations(metaclass=IterDest):
__metaclass__ = IterDest
counter = 0
def __init__(self, name, number, active, layer , scene, laser):
self.name = name
self.number = number
self.active = active
self.layer = layer
self.scene = scene
self.laser = laser
DestObject.counter += 1
def __del__(self):
DestObject.counter -= 1
'''
class DestObject():
# class Destinations(metaclass=IterDest):
_instances = set()
counter = 0
def __init__(self, name, number, active, layer , scene, laser):
self.name = name
self.number = number
self.active = active
self.layer = layer
self.scene = scene
self.laser = laser
self._instances.add(weakref.ref(self))
DestObject.counter += 1
@classmethod
def getinstances(cls):
dead = set()
for ref in cls._instances:
obj = ref()
if obj is not None:
yield obj
else:
dead.add(ref)
cls._instances -= dead
def __del__(self):
DestObject.counter -= 1
def Config(redIP,client,myname):
global ClientNumber, name, redisIP, r
redisIP = redIP
r = redis.StrictRedis(host=redisIP, port=6379, db=0)
# ClientNumber 255 are not drawing anything like artnet
ClientNumber = client
#print ("client configured",ClientNumber)
name = myname
print ("lj23layers : Plugin declare its name :",name)
#print layer
return r
def LjClient(client):
global ClientNumber
ClientNumber = client
def Ljlayer(somelayer):
global layer
layer = somelayer
def fromRedis(n):
encoded = r.get(n)
#print("")
#print('fromredis key',n,":",encoded)
h, w = struct.unpack('>II',encoded[:8])
#print("fromredis array size",n,":",h,w)
a = np.frombuffer(encoded, dtype=np.int16, offset=8).reshape(h,w)
#print("fromredis array",n,":",a)
return a
# Store Numpy array 'a' in Redis key 'n'
# Write also in redis key 'a' numpy array, its 2 dimensions size : h time w values
def toRedis(n,a):
#print("array.shape", a.shape, len(a.shape) )
if len(a.shape) == 1:
h = a.shape[0]
w = 1
else:
h,w = a.shape
#print("toredis", n,"h",h,"w",w,"a",a)
shape = struct.pack('>II',h,w)
#shape = struct.pack('>II',len(a),1)
#print("toredis",n,a)
encoded = shape + a.tobytes()
# Store encoded data in Redis
return r.set(n,encoded)
#
# OSC functions
#
# OSC clients
def SendLJ(oscaddress,oscargs=''):
oscmsg = OSCMessage()
oscmsg.setAddress(oscaddress)
oscmsg.append(oscargs)
osclientlj = OSCClient()
osclientlj.connect((redisIP, 8002))
print("lj23layers for",name,"sending OSC message :", oscmsg, "to", redisIP, ":8002")
if gstt.debug >0:
print("lj23layers for",name,"sending OSC message :", oscmsg, "to", redisIP, ":8002")
try:
osclientlj.sendto(oscmsg, (redisIP, 8002))
oscmsg.clearData()
except:
print ('Connection to LJ refused : died ?')
pass
#time.sleep(0.001
# Resolume OSC Arena client.
# sendresol(oscaddress, [arg1, arg2,...])
# example : sendresol("/noteon",note)
def SendResol(oscaddress,oscargs):
oscmsg = OSCMessage()
oscmsg.setAddress(oscaddress)
oscmsg.append(oscargs)
osclientresol = OSCClient()
osclientresol.connect((oscIPresol, oscPORTresol))
print("lj23layers sending OSC message : ", oscmsg, "to Resolume", oscIPresol, ":", oscPORTresol)
try:
osclientresol.sendto(oscmsg, (oscIPresol, oscPORTresol))
oscmsg.clearData()
except:
print ('Connection to Resolume refused : died ?')
pass
def SendIntensity(laser, intensity):
r.set('/intensity/' + str(laser), str(intensity))
r.set('/order/'+str(laser), 6)
SendLJ("/kpps/" + str(layer)+ " " + str(int(args[1])))
def Sendkpps(laser, kpps):
r.set('/kpps/' + str(laser), str(kpps))
r.set('/order/'+str(laser), 7)
def WebStatus(message):
SendLJ("/status", message)
# Closing plugin messages to LJ
def ClosePlugin():
WebStatus(name+" Exiting")
SendLJ("/"+name+"/start",0)
# RAW OSC Frame available ?
def OSCframe():
# clear timed_out flag
#print "oscframe"
oscserver.timed_out = False
# handle all pending requests then return
while not oscserver.timed_out:
oscserver.handle_request()
# Answer to LJ pings with /pong value
def OSCping(path, tags, args, source):
#def OSCping():
if gstt.debug >0:
print(name, "lj23layers got /ping from LJ -> reply /pong", name)
SendLJ("/pong",name)
# Properly close the system. Todo
def OSCstop():
oscserver.close()
# /quit
def OSCquit(path, tags, args, source):
global oscrun
oscrun = False
print('lj23layers got /quit for',name)
#WebStatus(name + " quit.")
#SendLJ("/"+name+"/start",0)
#print("Stopping OSC...")
#OSCstop()
#sys.exit()
# default handler
def OSChandler(path, tags, args, source):
oscaddress = ''.join(path.split("/"))
print("lj23layers Default OSC Handler for",name,": msg from Client :" + str(source[0]),)
print("OSC address", path)
if len(args) > 0:
print("with args", args)
#oscIPout = str(source[0])
#osclient.connect((oscIPout, oscPORTout))
# for any laser object : /pluginame/obj objectname attribute value
# like : /pluginname/obj 'fft' 'xpos' 100
# attributes for all lj Objects: name, xy_list, c, layer
# + for RelativeObjects : closed, xpos , ypos , resize , rotx , roty , rotz
def OSCobj(path, tags, args, source):
obj = eval(args[0]+"."+ args[1])
obj = args[2]
def OSCvar(path, tags, args, source):
obj = eval(args[0])
obj = args[1]
def addOSCdefaults(server):
global oscserver
oscserver = server
oscserver.addMsgHandler( "default", OSChandler )
oscserver.addMsgHandler( "/ping", OSCping)
oscserver.addMsgHandler( "/quit", OSCquit)
oscserver.addMsgHandler( "/"+ name + "/adddest", OSCadddest)
oscserver.addMsgHandler( "/"+ name + "/deldest", OSCdeldest)
oscserver.addMsgHandler( "/"+ name + "/dest", OSCdest)
oscserver.addMsgHandler( "/"+ name + "/obj", OSCobj)
oscserver.addMsgHandler( "/"+ name + "/var", OSCvar)
#
# Color functions
#
# input hexcode = '0xff00ff'
def hex2rgb(hexcode):
hexcode = hexcode[2:]
return tuple(int(hexcode[i:i+2], 16) for i in (0, 2, 4))
#return tuple(map(ord,hexcode[1:].decode('hex')))
# input rgb=(255,0,255) output '0xff00ff'
#def rgb2hex(rgb):
# return '0x%02x%02x%02x' % tuple(rgb)
def rgb2hex(r, g, b):
return hex((r << 16) + (g << 8) + b)
#def rgb2int(rgb):
# return int('0x%02x%02x%02x' % tuple(rgb),0)
def rgb2int(r,g,b):
return int('0x%02x%02x%02x' % (r,g,b),0)
def int2rgb(intcode):
#hexcode = '0x{0:06X}'.format(intcode)
hexcode = '{0:06X}'.format(intcode)
return tuple(int(hexcode[i:i+2], 16) for i in (0, 2, 4))
#
# Drawing basic functions
#
# Lines
def Line(xy1, xy2, c, layer ):
LineTo(xy1, 0, layer )
LineTo(xy2, c , layer )
def rLine(xy1, xy2, c, layer , xpos = 0, ypos =0, resize =0.7, rotx =0, roty =0 , rotz=0):
rLineTo(xy1, 0, layer )
rLineTo(xy2, c , layer )
def LineRGB(xy1, xy2, red,green,blue, layer ):
LineTo(xy1, 0, layer )
LineTo(xy2, int('0x%02x%02x%02x' % (red,green,blue),0) , layer )
# Lineto
def LineTo(xy, c, layer ):
layers[layer].append((xy + (c,)))
def LineRGBTo(xy, red, green, blue, layer ):
LineTo(xy, int('0x%02x%02x%02x' % (red,green,blue),0), layer )
def rLineTo(xy, c, layer , xpos = 0, ypos =0, resize =0.7, rotx =0, roty =0 , rotz=0):
layers[layer ].append((Pointransf(xy, xpos, ypos, resize, rotx, roty, rotz) + (c,)))
# Polylines
def PolyLineOneColor(xy_list, c, layer , closed ):
#print "--"
#print "c",c
#print "xy_list",xy_list
#print "--"
xy0 = None
for xy in xy_list:
if xy0 is None:
xy0 = xy
#print "xy0:",xy0
LineTo(xy0,0, layer )
LineTo(xy0,c, layer )
else:
#print "xy:",xy
LineTo(xy,c, layer )
if closed:
LineTo(xy0,c, layer )
def PolyLineRGB(xy_list, red, green, blue, layer , closed ):
PolyLineOneColor(xy_list, int('0x%02x%02x%02x' % (red,green,blue),0), layer , closed )
# rPolylines
# Send 2D point list around 0,0 with 3D rotation resizing and reposition around xpos ypos
#def rPolyLineOneColor(self, xy_list, c, layer , closed, xpos = 0, ypos =0, resize =1, rotx =0, roty =0 , rotz=0):
def rPolyLineOneColor(xy_list, c, layer , closed, xpos = 0, ypos =0, resize =0.7, rotx =0, roty =0 , rotz=0):
xy0 = None
for xy in xy_list:
print(xy,xy0)
if xy0 is None:
xy0 = xy
LineTo(Pointransf(xy0, xpos, ypos, resize, rotx, roty, rotz), 0, layer )
LineTo(Pointransf(xy0, xpos, ypos, resize, rotx, roty, rotz), c, layer )
else:
LineTo(Pointransf(xy, xpos, ypos, resize, rotx, roty, rotz), c, layer )
if closed:
LineTo(Pointransf(xy0, xpos, ypos, resize, rotx, roty, rotz), c, layer )
def rPolyLineRGB(xy_list, red, green, blue, layer , closed, xpos = 0, ypos =0, resize =0.7, rotx =0, roty =0 , rotz=0):
rPolyLineOneColor(xy_list, int('0x%02x%02x%02x' % (red,green,blue),0), layer , closed, xpos = 0, ypos =0, resize =0.7, rotx =0, roty =0 , rotz=0)
# Computing points coordinates for rPolyline function from 3D and around 0,0 to pygame coordinates
def Pointransf(xy, xpos = 0, ypos =0, resize =1, rotx =0, roty =0 , rotz=0):
x = xy[0] * resize
y = xy[1] * resize
z = xy[2] * resize
rad = math.radians(rotx)
cosaX = math.cos(rad)
sinaX = math.sin(rad)
y2 = y
y = y2 * cosaX - z * sinaX
z = y2 * sinaX + z * cosaX
rad = math.radians(roty)
cosaY = math.cos(rad)
sinaY = math.sin(rad)
z2 = z
z = z2 * cosaY - x * sinaY
x = z2 * sinaY + x * cosaY
rad = math.radians(rotz)
cosZ = math.cos(rad)
sinZ = math.sin(rad)
x2 = x
x = x2 * cosZ - y * sinZ
y = x2 * sinZ + y * cosZ
#print xy, (x + xpos,y+ ypos)
#return (x + xpos, y + ypos)
#to understand why it get negative Y
""" Transforms this 3D point to 2D using a perspective projection. """
factor = fov / (viewer_distance + z)
x = x * factor + xpos
y = y * factor + ypos
#y = - y * factor + ypos
return (x, y)
def Lineslayer(layer):
print("Stupido !! your code is to old : use Drawlayer() instead of LinesPL()")
Drawlayer(layer )
def Draw(layer):
#print '/pl/0/'+str(layer), str(layers[layer])
if r.set('/pl/'+str(ClientNumber)+'/'+str(layer), str(layers[layer])) == True:
#print '/pl/'+str(ClientNumber)+'/'+str(layer), str(layers[layer])
layers[layer] = []
return True
else:
return False
def Resetlayer(self, layer):
layers[layer] = []
#
# "Destinations" management for layers
#
# Add a destination for a given layer
def Addest(layer, scene, laser):
print (name,'adding',layer,scene,laser,'?')
if Findest(layer, scene, laser) == -1:
newdest = DestsObjects.counter + 1
Dest0 = lj.DestObject(str(newdest), newdest, True, layer , scene, laser)
print("New destination added with number", newdest)
else:
print("Destination already existed")
# OSC add a destination for a given layer
# /pluginame/dest layer, scene, laser
def OSCadddest(path, tags, args, source):
Addests(int(args[0]),int(args[1]),int(args[2]))
# Find layer destination with its parameters in destinations dictionnary
def Findest(layer, scene, laser):
print(name, 'searching layer,scene,laser',layer,scene,laser)
for item in DestObjects.getinstances():
#print(item)
if item.layer == layer and item.scene == scene and item.laser == laser:
#Dests.append(item[0])
print('found number',item.number)
return item.number
else:
print('no destination found')
return -1
'''
#Dests = list()
allDests = Dests.items()
for item in allDests:
print(item)
if item[1] == layer and item[2] == scene and item[3] == laser:
#Dests.append(item[0])
return Dests[item[0]]
else:
return -1
'''
# Find and remove a layer destination with its parameters in destinations dictionnary
def Deldest(layer, scene, laser):
Destnumber = Findest(layer, scene, laser)
print(name,'deleting Destination layer, scene, laser', layer,scene, laser)
if Destnumber != -1:
print('found DestObject', Destnumber)
delattr(DestObjects, str(Destnumber))
print("Destination", Destnumber,"was removed")
else:
print("Destination was not found")
# OSC Delete a destination for a given layer
# /pluginame/deldests layer, scene, laser
def OSCdeldest(path, tags, args, source):
Deldests(args[0], args[1], args[2])
# pluginame/dest layer, scene, laser
def OSCdest(path, tags, args, source):
# For single layer plugin : add a new destination
Addest(0, args[0], args[1])
# For single layer plugin : remove a destination
# For multiple layers plugin : add or remove
# Replace Drawlayer if Destinations paradigm is implemented in plugin code
def DrawDests():
# Objects style
#print("DrawDest")
for destination in DestObject.getinstances():
#print(Dests[str(destination)])
#print('/pl/'+str(Dests[str(destination)]["scene"])+'/'+str(Dests[str(destination)]["laser"]), ":", str(layers[Dests[str(destination)]["PL"]]))
#print(len(layers[destination.layer]))
if destination.active == True:
if r.set('/pl/'+str(destination.scene)+'/'+str(destination.laser), str(layers[destination.layer])) == True:
#print ('layer', destination.layer, '/pl/'+str(destination.scene)+'/'+str(destination.laser), str(layers[destination.layer]))
pass
else:
print('Redis key modification failed')
# Maybe one layer can be sent to multiple destination so they are all reset *after* all sending.
for layerss in range(4):
layers[layerss] = []
'''
# Dictionnary style
#print(Dests)
for destination in range(len(Dests)):
#print(Dests[str(destination)])
#print('/pl/'+str(Dests[str(destination)]["scene"])+'/'+str(Dests[str(destination)]["laser"]), ":", str(layers[Dests[str(destination)]["layer"]]))
if r.set('/pl/'+str(Dests[str(destination)]["scene"])+'/'+str(Dests[str(destination)]["laser"]), str(layers[Dests[str(destination)]["layer"]])) == True:
#print '/pl/'+str(ClientNumber)+'/'+str(layer), str(layers[layer])
pass
else:
print('Redis key modification failed')
# Maybe one layer can be sent to multiple destination so they are all reset *after* all sending.
for destination in range(len(Dests)):
layers[Dests[str(destination)]["layer"]] = []
'''
'''
scenes = 4
def DrawDestslayer(layer):
for scene in range(scenes):
if Dests[laser]["scene"] != -1:
if r.set('/pl/'+str(Dests[laser]["scene"])+'/'+str(Dests[laser]["laser"]), str(layers[Dests[laser]["laser"]])) == True:
if r.set('/pl/'+str(ClientNumber)+'/'+str(layer), str(layers[layer])) == True:
#print '/pl/'+str(ClientNumber)+'/'+str(layer), str(layers[layer])
layers[Dests[laser]["laser"]] = []
return True
else:
return False
'''
#
# High level drawing functions
#
# Font1
ASCII_GRAPHICS = [
#implementé
[(-50,30), (-30,-30), (30,-30), (10,30), (-50,30)], # 0
[(-20,30), (0,-30), (-20,30)], # 1
[(-30,-10), (0,-30), (30,-10), (30,0), (-30,30), (30,30)], # 2
[(-30,-30), (0,-30), (30,-10), (0,0), (30,10), (0,30), (-30,30)], # 3
[(30,10), (-30,10), (0,-30), (0,30)], # 4
[(30,-30), (-30,-30), (-30,0), (0,0), (30,10), (0,30), (-30,30)], # 5
[(30,-30), (0,-30), (-30,-10), (-30,30), (0,30), (30,10), (30,0), (-30,0)], # 6
[(-30,-30), (30,-30), (-30,30)], # 7
[(-30,30), (-30,-30), (30,-30), (30,30), (-30,30), (-30,0), (30,0)], # 8
[(30,0), (-30,0), (-30,-10), (0,-30), (30,-30), (30,10), (0,30), (-30,30)], # 9
# A implementer
[(-30,10), (30,-10), (30,10), (0,30), (-30,10), (-30,-10), (0,-30), (30,-10)], #:
[(-30,-10), (0,-30), (0,30)], [(-30,30), (30,30)], # ;
[(-30,-10), (0,-30), (30,-10), (30,0), (-30,30), (30,30)], # <
[(-30,-30), (0,-30), (30,-10), (0,0), (30,10), (0,30), (-30,30)], # =
[(30,10), (-30,10), (0,-30), (0,30)], # >
[(30,-30), (-30,-30), (-30,0), (0,0), (30,10), (0,30), (-30,30)], # ?
[(30,-30), (0,-30), (-30,-10), (-30,30), (0,30), (30,10), (30,0), (-30,0)], # @
# Implementé 65-90
[(-30,30), (-30,-30), (30,-30), (30,30), (30,0), (-30,0)], # A
[(-30,30), (-30,-30), (30,-30), (30,30), (30,0), (-30,0)], # A
[(-30,30), (-30,-30), (30,-30), (30,30), (-30,30), (-30,0), (30,0)], # B
[(30,30), (-30,30), (-30,-30), (30,-30)], # C
[(-30,30), (-30,-30), (30,-30), (30,30), (-30,30)], # D
[(30,30), (-30,30), (-30,-0), (30,0), (-30,0), (-30,-30), (30,-30)], # E
[(-30,30), (-30,-0), (30,0), (-30,0), (-30,-30), (30,-30)], # F
[(0,0), (30,0), (30,30), (-30,30), (-30,-30),(30,-30)], # G
[(-30,-30), (-30,30), (-30,0), (30,0), (30,30), (30,-30)], # H
[(0,30), (0,-30)], # I
[(-30,30), (0,-30), (0,-30), (-30,-30), (30,-30)], # J
[(-30,-30), (-30,30), (-30,0), (30,-30), (-30,0), (30,30)], # K
[(30,30), (-30,30), (-30,-30)], # L
[(-30,30), (-30,-30), (0,0), (30,-30), (30,30)], # M
[(-30,30), (-30,-30), (30,30), (30,-30)], # N
[(-30,30), (-30,-30), (30,-30), (30,30), (-30,30)], # O
[(-30,0), (30,0), (30,-30), (-30,-30), (-30,30)], # P
[(30,30), (30,-30), (-30,-30), (-30,30), (30,30),(35,35)], # Q
[(-30,30), (-30,-30), (30,-30), (30,0), (-30,0), (30,30)], # R
[(30,-30), (-30,-30), (-30,0), (30,0), (30,30), (-30,30)], # S
[(0,30), (0,-30), (-30,-30), (30,-30)], # T
[(-30,-30), (-30,30), (30,30), (30,-30)], # U
[(-30,-30), (0,30), (30,-30)], # V
[(-30,-30), (-30,30), (0,0), (30,30), (30,-30)], # W
[(-30,30), (30,-30), (-30,-30), (30,30)], # X
[(0,30), (0,0), (30,-30), (0,0), (-30,-30)], # Y
[(30,30), (-30,30), (30,-30), (-30,-30)], # Z
# A implementer
[(-30,-10), (0,-30), (0,30)], [(-30,30), (30,30)], # [
[(-30,-10), (0,-30), (30,-10), (30,0), (-30,30), (30,30)], # \
[(-30,-30), (0,-30), (30,-10), (0,0), (30,10), (0,30), (-30,30)], # ]
[(30,10), (-30,10), (0,-30), (0,30)], # ^
[(30,-30), (-30,-30), (-30,0), (0,0), (30,10), (0,30), (-30,30)], # _
[(30,-30), (0,-30), (-30,-10), (-30,30), (0,30), (30,10), (30,0), (-30,0)], # `
# Implementé 97-122
[(-20,20), (-20,-20), (20,-20), (20,20), (20,0), (-20,0)], # a
[(-20,20), (-20,-20), (20,-20), (20,20), (-20,20), (-20,0), (20,0)], # b
[(20,20), (-20,20), (-20,-20), (20,-20)], # c
[(-20,20), (-20,-20), (20,-20), (20,20), (-20,20)], # d
[(20,20), (-20,20), (-20,-0), (20,0), (-20,0), (-20,-20), (20,-20)], # e
[(-20,20), (-20,-0), (20,0), (-20,0), (-20,-20), (20,-20)], # f
[(0,0), (20,0), (20,20), (-20,20), (-20,-20),(20,-20)], # g
[(-20,-20), (-20,20), (-20,0), (20,0), (20,20), (20,-20)], # h
[(0,20), (0,-20)], # i
[(-20,20), (0,-20), (0,-20), (-20,-20), (20,-20)], # j
[(-20,-20), (-20,20), (-20,0), (20,-20), (-20,0), (20,20)], # k
[(20,20), (-20,20), (-20,-20)], # l
[(-20,20), (-20,-20), (0,0), (20,-20), (20,20)], # m
[(-20,20), (-20,-20), (20,20), (20,-20)], # n
[(-20,20), (-20,-20), (20,-20), (20,20), (-20,20)], # o
[(-20,0), (20,0), (20,-20), (-20,-20), (-20,20)], # p
[(20,20), (20,-20), (-20,-20), (-20,20), (20,20),(25,25)], # q
[(-20,20), (-20,-20), (20,-20), (20,0), (-20,0), (20,20)], # r
[(20,-20), (-20,-20), (-20,0), (20,0), (20,20), (-20,20)], # s
[(0,20), (0,-20), (-20,-20), (20,-20)], # t
[(-20,-20), (-20,20), (20,20), (20,-20)], # u
[(-20,-20), (0,20), (20,-20)], # v
[(-20,-20), (-20,20), (0,0), (20,20), (20,-20)], # w
[(-20,20), (20,-20)], [(-20,-20), (20,20)], # x
[(0,20), (0,0), (20,-20), (0,0), (-20,-20)], # y
[(20,20), (-20,20), (20,-20), (-20,-20)], # z
# A implementer
[(-2,15), (2,15)], # Point a la place de {
[(-30,-10), (0,-30), (0,30)], [(-30,30), (30,30)], # |
[(-30,-10), (0,-30), (30,-10), (30,0), (-30,30), (30,30)], # }
[(-30,-30), (0,-30), (30,-10), (0,0), (30,10), (0,30), (-30,30)], #
[(30,10), (-30,10), (0,-30), (0,30)], # DEL
# Accents 128-151 a implementer
[(30,30), (-30,30), (-30,-30), (30,-30)], # C
[(-20,-20), (-20,20), (20,20), (20,-20)], # û
[(20,20), (-20,20), (-20,-0), (20,0), (-20,0), (-20,-20), (20,-20)], # é
[(-20,20), (-20,-20), (20,-20), (20,20), (20,0), (-20,0)], # â
[(-20,20), (-20,-20), (20,-20), (20,20), (20,0), (-20,0)], # ä
[(-20,20), (-20,-20), (20,-20), (20,20), (20,0), (-20,0)], # a
[(20,20), (-20,20), (-20,-20), (20,-20)], # c
[(20,20), (-20,20), (-20,-0), (20,0), (-20,0), (-20,-20), (20,-20)], # é
[(20,20), (-20,20), (-20,-0), (20,0), (-20,0), (-20,-20), (20,-20)], # é
[(20,20), (-20,20), (-20,-0), (20,0), (-20,0), (-20,-20), (20,-20)], # é
[(0,20), (0,-20)], # i
[(0,20), (0,-20)], # i
[(0,20), (0,-20)], # i
[(-30,30), (-30,-30), (30,-30), (30,30), (30,0), (-30,0)], # A
[(-30,30), (-30,-30), (30,-30), (30,30), (30,0), (-30,0)], # A
[(30,30), (-30,30), (-30,-0), (30,0), (-30,0), (-30,-30), (30,-30)], # E
[(-20,20), (-20,-20), (20,-20), (20,20), (20,0), (-20,0)], # a
[(-20,20), (-20,-20), (20,-20), (20,20), (20,0), (-20,0)], # a
[(-20,20), (-20,-20), (20,-20), (20,20), (-20,20)], # o
[(-20,20), (-20,-20), (20,-20), (20,20), (-20,20)], # o
[(-20,20), (-20,-20), (20,-20), (20,20), (-20,20)], # o
[(-20,-20), (-20,20), (20,20), (20,-20)], # u
[(-20,-20), (-20,20), (20,20), (20,-20)] # u
]
def DigitsDots(number,color):
dots =[]
for dot in ASCII_GRAPHICS[number]:
#print dot
dots.append((gstt.xy_center[0]+dot[0],gstt.xy_center[1]+dot[1],color))
#self.point_list.append((xy + (c,)))
return dots
def CharDots(char,color):
dots =[]
for dot in ASCII_GRAPHICS[ord(char)-46]:
dots.append((dot[0],dot[1],color))
return dots
def Text(message, c, layer, xpos, ypos, resize, rotx, roty, rotz):
dots =[]
l = len(message)
i= 0
#print()
# print (message)
for ch in message:
#print ""
# texte centre en x automatiquement selon le nombre de lettres l
x_offset = 26 * (- (0.9*l) + 3*i)
# Digits
if ord(ch)<58:
char_layer_list = ASCII_GRAPHICS[ord(ch) - 48]
# Uppercase
elif 64 < ord(ch) < 91 :
char_layer_list = ASCII_GRAPHICS[ord(ch) - 46]
# Lowercase
elif 96 < ord(ch) < 123 :
char_layer_list = ASCII_GRAPHICS[ord(ch) - 45]
char_draw = []
#dots.append((char_layer_list[0][0] + x_offset,char_layer_list[0][1],0))
for xy in char_layer_list:
char_draw.append((xy[0] + x_offset,xy[1],c))
i +=1
#print ch,char_layer_list,char_draw
rPolyLineOneColor(char_draw, c, layer , False, xpos, ypos, resize, rotx, roty, rotz)
#dots.append(char_draw)
def TextRGB(message,c, layer, xpos, ypos, resize, rotx, roty, rotz):
Text(message,int('0x%02x%02x%02x' % (red,green,blue),0), layer, xpos, ypos, resize, rotx, roty, rotz)

View File

@ -0,0 +1,542 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# -*- mode: Python -*-
'''
Tracer
for LJ v0.8.2
Enhanced version (support for several lasers) of the etherdream python library from j4cDAC.
One tracer process is launched per requested laser. I/O based on redis keys.
LICENCE : CC
Sam Neurohack, pclf
Uses redis keys value for live inputs (Pointlists to draw,...) and outputs (DAC state, errors,..).
Most of redis keys are read and set at each main loop.
Includes live conversion in etherdream coordinates, geometric corrections,...
Etherdream IP is found in conf file for given laser number. (LJ.conf)
Redis keys to draw things :
/order select some change to adjust. See below
/pl/lasernumber [(x,y,color),(x1,y1,color),...] A string of list of points list.
/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
Redis keys for Etherdream DAC
- Control
/kpps see order 7
/intensity see order 6
/red see order 8
/green see order 8
/blue see order 8
- DAC status report
/lstt/lasernumber value etherdream last_status.playback_state (0: idle 1: prepare 2: playing)
/cap/lasernumber value number of empty points sent to fill etherdream buffer (up to 1799)
/lack/lasernumber value "a": ACK "F": Full "I": invalid. 64 or 35 for no connection.
Order
0 : Draw Normal point list
1 : Get the new EDH
2 : Draw BLACK point list
3 : Draw GRID point list
4 : Resampler Change (longs and shorts lsteps)
5 : Client Key change
6 : Intensity change
7 : kpps change
8 : color balance change
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 libs3 import homographyp
import numpy as np
import binascii
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)]
r = redis.StrictRedis(host=gstt.LjayServerIP, port=6379, db=0)
# r = redis.StrictRedis(host=gstt.LjayServerIP , port=6379, db=0, password='-+F816Y+-')
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", '64': "NOCONNECTION ?" }
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
#print("Tracer", laser,":", r,g,b,"intensity", intensity, "i", i)
#print(x, type(x), int(x))
return struct.pack("<HhhHHHHHH", flags, int(x), int(y), r, g, b, i, u1, u2)
class ProtocolError(Exception):
"""Exception used when a protocol error is detected."""
pass
class Status(object):
"""Represents a status response from the DAC."""
def __init__(self, data):
"""Initialize from a chunk of data."""
self.protocol_version, self.le_state, self.playback_state, \
self.source, self.le_flags, self.playback_flags, \
self.source_flags, self.fullness, self.point_rate, \
self.point_count = \
struct.unpack("<BBBBHHHHII", data)
def dump(self, prefix = " - "):
"""Dump to a string."""
lines = [
""
"Host ",
"Light engine: state %d, flags 0x%x" %
(self.le_state, self.le_flags),
"Playback: state %d, flags 0x%x" %
(self.playback_state, self.playback_flags),
"Buffer: %d points" %
(self.fullness, ),
"Playback: %d kpps, %d points played" %
(self.point_rate, self.point_count),
"Source: %d, flags 0x%x" %
(self.source, self.source_flags)
]
if gstt.debug == 2:
print()
for l in lines:
print(prefix + l)
class BroadcastPacket(object):
"""Represents a broadcast packet from the DAC."""
def __init__(self, st):
"""Initialize from a chunk of data."""
self.mac = st[:6]
self.hw_rev, self.sw_rev, self.buffer_capacity, \
self.max_point_rate = struct.unpack("<HHHI", st[6:16])
self.status = Status(st[16:36])
def dump(self, prefix = " - "):
"""Dump to a string."""
lines = [
"MAC: " + ":".join(
"%02x" % (ord(o), ) for o in self.mac),
"HW %d, SW %d" %
(self.hw_rev, self.sw_rev),
"Capabilities: max %d points, %d kpps" %
(self.buffer_capacity, self.max_point_rate)
]
print()
for l in lines:
print(prefix + l)
if gstt.debug > 1:
self.status.dump(prefix)
class DAC(object):
"""A connection to a DAC."""
# "Laser point List" Point generator
# each points is yielded : Getpoints() call n times OnePoint()
def OnePoint(self):
while True:
#pdb.set_trace()
for indexpoint,currentpoint in enumerate(self.pl):
#print indexpoint, currentpoint
xyc = [currentpoint[0],currentpoint[1],currentpoint[2]]
self.xyrgb = self.EtherPoint(xyc)
delta_x, delta_y = self.xyrgb[0] - self.xyrgb_prev[0], self.xyrgb[1] - self.xyrgb_prev[1]
#test adaptation selon longueur ligne
if math.hypot(delta_x, delta_y) < 4000:
# For glitch art : decrease lsteps
#l_steps = [ (1.0, 8)]
l_steps = gstt.stepshortline
else:
# For glitch art : decrease lsteps
#l_steps = [ (0.25, 3), (0.75, 3), (1.0, 10)]
l_steps = gstt.stepslongline
for e in l_steps:
step = e[0]
for i in range(0,e[1]):
self.xyrgb_step = (self.xyrgb_prev[0] + step*delta_x, self.xyrgb_prev[1] + step*delta_y) + self.xyrgb[2:]
yield self.xyrgb_step
self.xyrgb_prev = self.xyrgb
def GetPoints(self, n):
d = [next(self.newstream) for i in range(n)]
#print d
return d
# Etherpoint all transform in one matrix, with warp !!
# xyc : x y color
def EtherPoint(self,xyc):
c = xyc[2]
#print("")
#print("pygame point",[(xyc[0],xyc[1],xyc[2])])
#gstt.EDH[self.mylaser]= np.array(ast.literal_eval(r.get('/EDH/'+str(self.mylaser))))
position = homographyp.apply(gstt.EDH[self.mylaser],np.array([(xyc[0],xyc[1])]))
#print("etherdream point",position[0][0], position[0][1], ((c >> 16) & 0xFF) << 8, ((c >> 8) & 0xFF) << 8, (c & 0xFF) << 8)
return (position[0][0], position[0][1], ((c >> 16) & 0xFF) << 8, ((c >> 8) & 0xFF) << 8, (c & 0xFF) << 8)
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:])
r.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 __init__(self, mylaser, PL, port = 7765):
"""Connect to the DAC over TCP."""
socket.setdefaulttimeout(2)
self.mylaser = mylaser
self.clientkey = r.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
r.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(r.get(self.clientkey + str(self.mylaser)).decode('ascii'))
if r.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(r.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.newstream = self.OnePoint()
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 begin(self, lwm, rate):
cmd = struct.pack("<cHI", b'b', lwm, rate)
print("Tracer", str(self.mylaser), "begin with PL : ", str(self.PL))
self.conn.sendall(cmd)
return self.readresp("b")
def update(self, lwm, rate):
print(("update", lwm, rate))
cmd = struct.pack("<cHI", b'u', lwm, rate)
self.conn.sendall(cmd)
return self.readresp("u")
def encode_point(self, point):
return pack_point(self.mylaser, self.intensity, *point)
def write(self, points):
epoints = list(map(self.encode_point, points))
cmd = struct.pack("<cH", b'd', len(epoints))
self.conn.sendall(cmd + b''.join(epoints))
return self.readresp("d")
def prepare(self):
self.conn.sendall("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(r.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(r.get(self.clientkey+str(self.mylaser)).decode('ascii'))
#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(r.get('/EDH/'+str(self.mylaser)).decode('ascii')))
# Back to user point list
r.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(r.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
r.set('/order/'+str(self.mylaser), 0)
# Client Key change
if order == 5:
print("Tracer", self.mylaser, "new clientkey")
self.clientkey = r.get('/clientkey')
# Back to user point list order
r.set('/order/'+str(self.mylaser), 0)
# Intensity change
if order == 6:
self.intensity = int(r.get('/intensity/' + str(self.mylaser)).decode('ascii')) << 8
print("Tracer" , self.mylaser, "new Intensity", self.intensity)
gstt.intensity[self.mylaser] = self.intensity
r.set('/order/'+str(self.mylaser), "0")
# kpps change
if order == 7:
gstt.kpps[self.mylaser] = int(r.get('/kpps/' + str(self.mylaser)).decode('ascii'))
print("Tracer",self.mylaser,"new kpps", gstt.kpps[self.mylaser])
self.update(0, gstt.kpps[self.mylaser])
r.set('/order/'+str(self.mylaser), "0")
# color balance change
if order == 8:
gstt.red[self.mylaser] = int(r.get('/red/' + str(self.mylaser)).decode('ascii'))
gstt.green[self.mylaser] = int(r.get('/green/' + str(self.mylaser)).decode('ascii'))
gstt.blue[self.mylaser] = int(r.get('/blue/' + str(self.mylaser)).decode('ascii'))
print("Tracer",self.mylaser,"new color balance", gstt.red[self.mylaser], gstt.green[self.mylaser], gstt.blue[self.mylaser])
r.set('/order/'+str(self.mylaser), "0")
r.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)
r.set('/cap/'+str(self.mylaser), cap)
if cap < 100:
time.sleep(0.001)
cap += 150
# print("Writing %d points" % (cap, ))
#t0 = time.time()
#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
# not used in LJay.
def find_dac():
"""Listen for broadcast packets."""
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(("0.0.0.0", 7654))
while True:
data, addr = s.recvfrom(1024)
bp = BroadcastPacket(data)
print(("Packet from %s: " % (addr, )))
bp.dump()
'''
#Laser order bit 0 = 0
if not order & (1 << (self.mylaser*2)):
#print("laser",mylaser,"bit 0 : 0")
# Laser bit 0 = 0 and bit 1 = 0 : USER PL
if not order & (1 << (1+self.mylaser*2)):
#print("laser",mylaser,"bit 1 : 0")
self.pl = ast.literal_eval(r.get('/pl/'+str(self.mylaser)))
else:
# Laser bit 0 = 0 and bit 1 = 1 : New EDH
#print("laser",mylaser,"bit 1 : 1" )
print("Laser",self.mylaser,"new EDH ORDER in redis"
gstt.EDH[self.mylaser]= np.array(ast.literal_eval(r.get('/EDH/'+str(self.mylaser))))
# Back to USER PL
order = r.get('/order')
neworder = order & ~(1<< self.mylaser*2)
neworder = neworder & ~(1<< 1+ self.mylaser*2)
r.set('/order', str(neworder))
else:
# Laser bit 0 = 1
print("laser",mylaser,"bit 0 : 1")
# Laser bit 0 = 1 and bit 1 = 0 : Black PL
if not order & (1 << (1+self.mylaser*2)):
#print("laser",mylaser,"bit 1 : 0")
self.pl = black_points
else:
# Laser bit 0 = 1 and bit 1 = 1 : GRID PL
#print("laser",mylaser,"bit 1 : 1" )
self.pl = grid_points
'''

View File

@ -1,3 +0,0 @@
Source: https://github.com/auduno/clmtrackr
License: MIT
https://raw.githubusercontent.com/auduno/clmtrackr/dev/LICENSE.txt

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long