Compare commits
No commits in common. "9ec8d5bc41d5c6bbd75d1da02b334ba3cd387066" and "4a9cd73767e9ce11472db6d900feb579c7b70c97" have entirely different histories.
9ec8d5bc41
...
4a9cd73767
@ -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]
|
|
@ -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>
|
|
Binary file not shown.
@ -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)
|
|
@ -1 +0,0 @@
|
|||||||
APPL????
|
|
Binary file not shown.
@ -1,4 +0,0 @@
|
|||||||
import argvemulator, os
|
|
||||||
|
|
||||||
argvemulator.ArgvCollector().mainloop()
|
|
||||||
execfile(os.path.join(os.path.split(__file__)[0], "sitter.py"))
|
|
@ -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()
|
|
@ -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()
|
|
@ -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())
|
|
@ -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()
|
|
986
libs3/lj23layers.sync-conflict-20200803-100618-TAXKCAL.py
Normal file
986
libs3/lj23layers.sync-conflict-20200803-100618-TAXKCAL.py
Normal 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)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
542
libs3/tracer3.sync-conflict-20200728-024608-NJKFP4Q.py
Normal file
542
libs3/tracer3.sync-conflict-20200728-024608-NJKFP4Q.py
Normal 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
|
||||||
|
'''
|
@ -1,3 +0,0 @@
|
|||||||
Source: https://github.com/auduno/clmtrackr
|
|
||||||
License: MIT
|
|
||||||
https://raw.githubusercontent.com/auduno/clmtrackr/dev/LICENSE.txt
|
|
15325
www/build/clmtrackr.js
15325
www/build/clmtrackr.js
File diff suppressed because one or more lines are too long
1
www/build/clmtrackr.min.js
vendored
1
www/build/clmtrackr.min.js
vendored
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user