Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
  • 11 commits
  • 14 files changed
  • 0 comments
  • 1 contributor
1  abstrax/.gitignore
... ... @@ -0,0 +1 @@
  1 +abstrax
2  driver/Makefile
... ... @@ -1,2 +1,2 @@
1 1 EtherDream.dll: j4cDAC.c comm.c dac.c dac.h
2   - i586-mingw32msvc-gcc -shared j4cDAC.c comm.c dac.c ../../iniparser/src/*.c -o EtherDream.dll -I../../iniparser/src -I../common -Os -Wall -g -lshlwapi -lws2_32 -lwinmm -Wl,--kill-at
  2 + i586-mingw32msvc-gcc -shared j4cDAC.c comm.c dac.c -o EtherDream.dll -I../common -Os -Wall -g -lshlwapi -lws2_32 -lwinmm -Wl,--kill-at
3  driver/j4cDAC.c
@@ -26,7 +26,10 @@
26 26 #include <string.h>
27 27
28 28 #include "dac.h"
  29 +
  30 +#if 0
29 31 #include <iniparser.h>
  32 +#endif
30 33
31 34 #define EXPORT __declspec(dllexport)
32 35
11 firmware/.gitignore
... ... @@ -1,8 +1,7 @@
1 1 *.o
2   -j4cDAC.elf
3   -j4cDAC.hex
4   -j4cDAC.bin
5   -j4cDAC.binhex
6   -j4cDAC.map
7   -debugout.bin
  2 +*.elf
  3 +*.hex
  4 +*.bin
  5 +*.binhex
  6 +*.map
8 7 pc
7 firmware/inc/transform.h
@@ -20,7 +20,8 @@
20 20 #include <stdint.h>
21 21 #include <attrib.h>
22 22
23   -#define COORD_MAX 32768
  23 +#define COORD_MAX_EXP 16
  24 +#define COORD_MAX (1 << COORD_MAX_EXP)
24 25
25 26 #define COORD_TOO_CLOSE 150
26 27
@@ -44,8 +45,8 @@ void update_transform(void);
44 45 extern int32_t transform_matrix[8];
45 46
46 47 static inline int32_t ALWAYS_INLINE translate(int32_t *c, int x, int y) {
47   - int32_t xy_scale = x * y / COORD_MAX;
48   - return (c[0]*x + c[1]*y + c[2]*xy_scale) / COORD_MAX + c[3];
  48 + int32_t xy_scale = (x * y) >> COORD_MAX_EXP;
  49 + return ((c[0]*x + c[1]*y + c[2]*xy_scale) >> COORD_MAX_EXP) + c[3];
49 50 }
50 51
51 52 static inline int32_t ALWAYS_INLINE translate_x(int32_t x, int32_t y) {
2  firmware/net/broadcast.c
@@ -51,7 +51,7 @@ void fill_status(struct dac_status *status) {
51 51 status->point_count = dac_get_count();
52 52
53 53 status->source = playback_src;
54   - status->source_flags = 0; // XXX TODO
  54 + status->source_flags = playback_source_flags;
55 55 }
56 56
57 57 /* broadcast_send
BIN  releases/v0.3.0/j4cDAC.bin
Binary file not shown
BIN  releases/v0.3.0/j4cDAC.elf
Binary file not shown
2  releases/v0.3.0/j4cDAC.hex
@@ -6065,7 +6065,7 @@
6065 6065 :10BAF0007A6500002F67656F6D2F6F6666736574DA
6066 6066 :10BB00000000000080BA01008CBA010098BA010060
6067 6067 :10BB1000A4BA0100696E69745F7472616E73666FB6
6068   -:10BB2000726D000076302E332E302D646972747978
  6068 +:10BB2000726D000076302E332E30000000000000D1
6069 6069 :10BB30000000000000000000000000000000000005
6070 6070 :10BB40000000000000202020202020202020282885
6071 6071 :10BB500028282820202020202020202020202020CD
9 tools/.gitignore
... ... @@ -0,0 +1,9 @@
  1 +build
  2 +dist
  3 +*.log
  4 +*.exe
  5 +*.pyc
  6 +*.app
  7 +*.zip
  8 +warn*.txt
  9 +*/tk.pkg
414 tools/sitter/sitter.py
... ... @@ -0,0 +1,414 @@
  1 +#!/usr/bin/python
  2 +# j4cDAC "sitter"
  3 +#
  4 +# Copyright 2012 Jacob Potter
  5 +#
  6 +# This program is free software: you can redistribute it and/or modify
  7 +# it under the terms of the GNU General Public License as published by
  8 +# the Free Software Foundation, version 3.
  9 +#
  10 +# This program is distributed in the hope that it will be useful,
  11 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13 +# GNU General Public License for more details.
  14 +#
  15 +# You should have received a copy of the GNU General Public License
  16 +# along with this program. If not, see <http://www.gnu.org/licenses/>.
  17 +
  18 +import socket
  19 +import time
  20 +import struct
  21 +
  22 +def pack_point(x, y, r, g, b, i = -1, u1 = 0, u2 = 0, flags = 0):
  23 + """Pack some color values into a struct dac_point.
  24 +
  25 + Values must be specified for x, y, r, g, and b. If a value is not
  26 + passed in for the other fields, i will default to max(r, g, b); the
  27 + rest default to zero.
  28 + """
  29 +
  30 + if i < 0:
  31 + i = max(r, g, b)
  32 +
  33 + return struct.pack("<HhhHHHHHH", flags, x, y, i, r, g, b, u1, u2)
  34 +
  35 +
  36 +class ProtocolError(Exception):
  37 + """Exception used when a protocol error is detected."""
  38 + pass
  39 +
  40 +
  41 +class Status(object):
  42 + """Represents a status response from the DAC."""
  43 +
  44 + def __init__(self, data):
  45 + """Initialize from a chunk of data."""
  46 + self.protocol_version, self.le_state, self.playback_state, \
  47 + self.source, self.le_flags, self.playback_flags, \
  48 + self.source_flags, self.fullness, self.point_rate, \
  49 + self.point_count = \
  50 + struct.unpack("<BBBBHHHHII", data)
  51 +
  52 + def dump(self, prefix = " - "):
  53 + """Dump to a string."""
  54 + lines = [
  55 + "Light engine: state %d, flags 0x%x" %
  56 + (self.le_state, self.le_flags),
  57 + "Playback: state %d, flags 0x%x" %
  58 + (self.playback_state, self.playback_flags),
  59 + "Buffer: %d points" %
  60 + (self.fullness, ),
  61 + "Playback: %d kpps, %d points played" %
  62 + (self.point_rate, self.point_count),
  63 + "Source: %d, flags 0x%x" %
  64 + (self.source, self.source_flags)
  65 + ]
  66 + for l in lines:
  67 + print prefix + l
  68 +
  69 +
  70 +class BroadcastPacket(object):
  71 + """Represents a broadcast packet from the DAC."""
  72 +
  73 + def __init__(self, st, ip=None):
  74 + """Initialize from a chunk of data."""
  75 + self.mac = st[:6]
  76 + self.hw_rev, self.sw_rev, self.buffer_capacity, \
  77 + self.max_point_rate = struct.unpack("<HHHI", st[6:16])
  78 + self.status = Status(st[16:36])
  79 + self.ip = ip
  80 +
  81 + def dump(self, prefix = " - "):
  82 + """Dump to a string."""
  83 + lines = [
  84 + "MAC: " + ":".join(
  85 + "%02x" % (ord(o), ) for o in self.mac),
  86 + "HW %d, SW %d" %
  87 + (self.hw_rev, self.sw_rev),
  88 + "Capabilities: max %d points, %d kpps" %
  89 + (self.buffer_capacity, self.max_point_rate)
  90 + ]
  91 + for l in lines:
  92 + print prefix + l
  93 + self.status.dump(prefix)
  94 +
  95 + def macstr(self):
  96 + return "".join("%02x" % (ord(c), ) for c in self.mac)
  97 +
  98 +
  99 +class DAC(object):
  100 + """A connection to a DAC."""
  101 +
  102 + def got_broadcast(self, bp):
  103 + self.last_broadcast = bp
  104 + self.last_broadcast_time = time.time()
  105 +
  106 + def read(self, l):
  107 + """Read exactly length bytes from the connection."""
  108 + while l > len(self.buf):
  109 + self.buf += self.conn.recv(4096)
  110 +
  111 + obuf = self.buf
  112 + self.buf = obuf[l:]
  113 + return obuf[:l]
  114 +
  115 + def readresp(self, cmd):
  116 + """Read a response from the DAC."""
  117 + data = self.read(22)
  118 + response = data[0]
  119 + cmdR = data[1]
  120 + status = Status(data[2:])
  121 +
  122 +# status.dump()
  123 +
  124 + if cmdR != cmd:
  125 + raise ProtocolError("expected resp for %r, got %r"
  126 + % (cmd, cmdR))
  127 +
  128 + if response != "a":
  129 + raise ProtocolError("expected ACK, got %r"
  130 + % (response, ))
  131 +
  132 + self.last_status = status
  133 + return status
  134 +
  135 + def __init__(self, macstr, bp):
  136 + self.macstr = macstr
  137 + self.firmware_string = "-"
  138 + self.got_broadcast(bp)
  139 +
  140 + try:
  141 + t1 = time.time()
  142 + self.connect(self.last_broadcast.ip[0])
  143 + t = time.time() - t1
  144 + self.conn_status = "ok (%d ms)" % (t * 500)
  145 +
  146 + if self.last_broadcast.sw_rev < 2:
  147 + self.firmware_string = "(old)"
  148 + else:
  149 + self.conn.sendall('v')
  150 + self.firmware_string = self.read(32).replace("\x00", " ").strip()
  151 + except Exception, e:
  152 + self.conn_status = str(e)
  153 +
  154 + def connect(self, host, port = 7765):
  155 + """Connect to the DAC over TCP."""
  156 + conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  157 + conn.settimeout(0.2)
  158 + conn.connect((host, port))
  159 + self.conn = conn
  160 + self.buf = ""
  161 +
  162 + # Read the "hello" message
  163 + first_status = self.readresp("?")
  164 + first_status.dump()
  165 +
  166 +
  167 +
  168 + def begin(self, lwm, rate):
  169 + cmd = struct.pack("<cHI", "b", lwm, rate)
  170 + self.conn.sendall(cmd)
  171 + return self.readresp("b")
  172 +
  173 + def update(self, lwm, rate):
  174 + cmd = struct.pack("<cHI", "u", lwm, rate)
  175 + self.conn.sendall(cmd)
  176 + return self.readresp("u")
  177 +
  178 + def encode_point(self, point):
  179 + return pack_point(*point)
  180 +
  181 + def write(self, points):
  182 + epoints = map(self.encode_point, points)
  183 + cmd = struct.pack("<cH", "d", len(epoints))
  184 + self.conn.sendall(cmd + "".join(epoints))
  185 + return self.readresp("d")
  186 +
  187 + def prepare(self):
  188 + self.conn.sendall("p")
  189 + return self.readresp("p")
  190 +
  191 + def stop(self):
  192 + self.conn.sendall("s")
  193 + return self.readresp("s")
  194 +
  195 + def estop(self):
  196 + self.conn.sendall("\xFF")
  197 + return self.readresp("\xFF")
  198 +
  199 + def clear_estop(self):
  200 + self.conn.sendall("c")
  201 + return self.readresp("c")
  202 +
  203 + def ping(self):
  204 + self.conn.sendall("?")
  205 + return self.readresp("?")
  206 +
  207 + def play_stream(self, stream):
  208 + # First, prepare the stream
  209 + if self.last_status.playback_state == 2:
  210 + raise Exception("already playing?!")
  211 + elif self.last_status.playback_state == 0:
  212 + self.prepare()
  213 +
  214 + started = 0
  215 +
  216 + while True:
  217 + # How much room?
  218 + cap = 1799 - self.last_status.fullness
  219 + points = stream.read(cap)
  220 +
  221 + if cap < 100:
  222 + time.sleep(0.005)
  223 + cap += 150
  224 +
  225 +# print "Writing %d points" % (cap, )
  226 + t0 = time.time()
  227 + self.write(points)
  228 + t1 = time.time()
  229 +# print "Took %f" % (t1 - t0, )
  230 +
  231 + if not started:
  232 + self.begin(0, 30000)
  233 + started = 1
  234 +
  235 +
  236 +def find_dac():
  237 + """Listen for broadcast packets."""
  238 +
  239 + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  240 + s.bind(("0.0.0.0", 7654))
  241 +
  242 + while True:
  243 + data, addr = s.recvfrom(1024)
  244 + bp = BroadcastPacket(data)
  245 +
  246 + print "Packet from %s: " % (addr, )
  247 + bp.dump()
  248 +
  249 +
  250 +from Tkinter import *
  251 +import socket
  252 +import Queue
  253 +import thread
  254 +import time
  255 +
  256 +class DacDisplay(LabelFrame):
  257 + def __init__(self, master):
  258 + LabelFrame.__init__(self, master, width=600, height=400)
  259 + self.grid_propagate(0)
  260 +
  261 + Label(self, text="IP Address:").grid(row=0, column=0, sticky=N+E)
  262 + Label(self, text="Version:").grid(row=1, column=0, sticky=N+E)
  263 + Label(self, text="Status:").grid(row=2, column=0, sticky=N+E)
  264 + Label(self, text="Source:").grid(row=3, column=0, sticky=N+E)
  265 + Label(self, text="Network:").grid(row=4, column=0, sticky=N+E)
  266 + Label(self, text="Firmware:").grid(row=5, column=0, sticky=N+E)
  267 +
  268 + self.iplabel = Label(self, text = "")
  269 + self.iplabel.grid(row=0, column=1, sticky=N+W)
  270 + self.verslabel = Label(self, text = "")
  271 + self.verslabel.grid(row=1, column=1, sticky=N+W)
  272 + self.stlabel = Label(self, text = "")
  273 + self.stlabel.grid(row=2, column=1, sticky=N+W)
  274 + self.srclabel = Label(self, text = "")
  275 + self.srclabel.grid(row=3, column=1, sticky=N+W)
  276 + self.netlabel = Label(self, text = "")
  277 + self.netlabel.grid(row=4, column=1, sticky=N+W)
  278 + self.fwlabel = Label(self, text = "")
  279 + self.fwlabel.grid(row=5, column=1, sticky=N+W)
  280 +
  281 + self.display_none()
  282 +
  283 + def display_none(self):
  284 + self['text'] = "Ether Dream"
  285 +
  286 + for l in self.iplabel, self.verslabel, self.stlabel, self.srclabel, self.netlabel, self.fwlabel:
  287 + l['text'] = ""
  288 +
  289 + def display_dac(self, dac):
  290 + b = dac.last_broadcast
  291 + self['text'] = "Ether Dream " + b.macstr()[6:]
  292 + self.iplabel['text'] = str(b.ip[0])
  293 + self.verslabel['text'] = "hardware %d, software %d" % (b.hw_rev, b.sw_rev)
  294 +
  295 + st_str = ""
  296 + if b.status.le_state == 0:
  297 + st_str = "online, "
  298 + else:
  299 + st_str = "ESTOP ACTIVE (%d), " % (b.status.le_flags, )
  300 +
  301 + if b.status.playback_state == 0:
  302 + st_str += "idle"
  303 + elif b.status.playback_state == 1:
  304 + st_str += "prepared"
  305 + elif b.status.playback_state == 2:
  306 + st_str += "playing (%d buffered, %d played)" % (b.status.fullness, b.status.point_count)
  307 + else:
  308 + st_str += "DAC state %d" % (b.status.playback_state, )
  309 +
  310 + if b.status.point_rate:
  311 + st_str += ", %d pps" % (b.status.point_rate)
  312 +
  313 + self.stlabel['text'] = st_str
  314 +
  315 + if b.status.source == 0:
  316 + src_str = "network"
  317 + elif b.status.source == 1:
  318 + src_str = "file playback: %s, repeat %s" % (
  319 + b.status.source_flags & 1 and "playing" or "not playing",
  320 + b.status.source_flags & 2 and "on" or "off"
  321 + )
  322 + elif b.status.source == 2:
  323 + src_str = "abstract generator: %s" % (
  324 + b.status.source_flags & 1 and "playing" or "not playing",
  325 + )
  326 + else:
  327 + src_str = "unknown %d" % (b.status.source)
  328 +
  329 + self.srclabel['text'] = src_str
  330 + self.netlabel['text'] = dac.conn_status
  331 + self.fwlabel['text'] = dac.firmware_string
  332 +
  333 +class DacTracker(Listbox):
  334 + def __init__(self, master, *args, **kwargs):
  335 + Listbox.__init__(self, master, *args, **kwargs)
  336 +
  337 + self.dac_list = []
  338 + self.dac_macstr_map = {}
  339 +
  340 + self.bind("<<ListboxSelect>>", self.update_selection)
  341 +
  342 + def update_selection(self, lb=None):
  343 + if self.dac_display:
  344 + try:
  345 + dac_obj = self.dac_list[self.index(ACTIVE)]
  346 + except:
  347 + return
  348 + self.dac_display.display_dac(dac_obj)
  349 +
  350 + def got_packet(self, bp):
  351 + macstr = bp.macstr()
  352 + if macstr not in self.dac_macstr_map:
  353 + new_dac = DAC(macstr, bp)
  354 + self.insert(END, macstr[6:])
  355 + self.dac_list.append(new_dac)
  356 + self.dac_macstr_map[macstr] = new_dac
  357 + dac_obj = new_dac
  358 + else:
  359 + dac_obj = self.dac_macstr_map[macstr]
  360 + dac_obj.got_broadcast(bp)
  361 +
  362 + if len(self.dac_list) == 1:
  363 + self.selection_set(0)
  364 + self.update_selection()
  365 +
  366 + def check_on_dac():
  367 + if time.time() - dac_obj.last_broadcast_time < 2:
  368 + return
  369 +
  370 + idx = self.dac_list.index(dac_obj)
  371 + self.dac_list.remove(dac_obj)
  372 + del self.dac_macstr_map[macstr]
  373 + self.delete(idx)
  374 + self.dac_display.display_none()
  375 +
  376 +
  377 + self.after(2000, check_on_dac)
  378 +
  379 +
  380 +
  381 +# Set up the basic window
  382 +root = Tk()
  383 +root.title("Ether Dream")
  384 +root.resizable(FALSE, FALSE)
  385 +frame = Frame(root)
  386 +frame.grid()
  387 +
  388 +disp = DacDisplay(root)
  389 +disp.grid(row=0, column=1, padx=5, pady=5)
  390 +tracker = DacTracker(root, height=22)
  391 +tracker.grid(row=0, column=0, padx=5, pady=5)
  392 +tracker.dac_display = disp
  393 +
  394 +# Set up queue checker
  395 +packet_queue = Queue.Queue()
  396 +def queue_check():
  397 + try:
  398 + while True:
  399 + data, addr = packet_queue.get_nowait()
  400 + tracker.got_packet(BroadcastPacket(data, addr))
  401 + except Queue.Empty:
  402 + root.after(100, queue_check)
  403 +
  404 +root.after(100, queue_check)
  405 +
  406 +# Set up listening socket and thread
  407 +s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  408 +s.bind(("0.0.0.0", 7654))
  409 +def socket_thread():
  410 + while True:
  411 + packet_queue.put(s.recvfrom(1024))
  412 +thread.start_new(socket_thread, ())
  413 +
  414 +root.mainloop()
4 tools/updater/.gitignore
... ... @@ -1,4 +0,0 @@
1   -build
2   -dist
3   -*.exe
4   -*.pyc
3  tools/updater/dfu/dfu.py
@@ -98,7 +98,8 @@ def download(dev, filename, msg):
98 98
99 99 Returns True if download was successful; False otherwise.
100 100 """
101   - filename = os.path.join(os.environ["_MEIPASS2"], filename)
  101 + if "_MEIPASS2" in os.environ:
  102 + filename = os.path.join(os.environ["_MEIPASS2"], filename)
102 103 try:
103 104 file_data = file(filename, "rb").read()
104 105 except:
19 tools/updater/update.py
@@ -31,12 +31,14 @@ def pressed():
31 31 def queue_check():
32 32 try:
33 33 while True:
34   - state, text = to_ui.get_nowait()
  34 + state, text, btn = to_ui.get_nowait()
35 35 label['text'] = text
36   - if state:
37   - go_button.configure(state=NORMAL, text="Update")
  36 + if state == "quit":
  37 + root.quit()
  38 + elif state:
  39 + go_button.configure(state=NORMAL, text=btn)
38 40 else:
39   - go_button.configure(state=DISABLED, text="Update")
  41 + go_button.configure(state=DISABLED, text=btn)
40 42 except Queue.Empty:
41 43 root.after(200, queue_check)
42 44
@@ -44,7 +46,7 @@ def queue_check():
44 46
45 47 def msg(s):
46 48 print s
47   - to_ui.put((False, s))
  49 + to_ui.put((False, s, "Update"))
48 50
49 51 # USB thread
50 52 def usb_thread():
@@ -54,16 +56,17 @@ def usb_thread():
54 56 time.sleep(1)
55 57 continue
56 58
57   - to_ui.put((True, "Ready."))
  59 + to_ui.put((True, "Ready.", "Update"))
58 60
59 61 # Wait for button
60 62 from_ui.get()
61 63
62 64 dfu.download(dev, "j4cDAC.bin", msg)
63 65
64   - # Wait for them to ask us to do it again, I guess?
65   - to_ui.put((True, "Done."))
  66 + to_ui.put((True, "Done.", "Exit"))
66 67 from_ui.get()
  68 + to_ui.put(("quit", None, None))
  69 +
67 70
68 71 thread.start_new(usb_thread, ())
69 72

No commit comments for this range

Something went wrong with that request. Please try again.