diff --git a/ekgplotter/ekgplotter/analyze_test.py b/ekgplotter/ekgplotter/analyze_test.py
new file mode 100644
index 0000000..1fe3255
--- /dev/null
+++ b/ekgplotter/ekgplotter/analyze_test.py
@@ -0,0 +1,106 @@
+data = [20, 14, 9, 9, 37, 42, 33, 31, 20, 42, 255, 47, 29, 34, 8, 16, 4, 5, 10, 18, 7, 10, 19, 4, 12, 11, 29, 46, 48,
+ 44, 25, 27, 255, 46, 48, 28, 13, 13, 13, 10, 17, 16, 20, 12, 8, 13, 0, 2, 40, 45, 37, 37, 39, 29, 255, 21, 25, 23,
+ 18, 8, 14, 3, 16, 19, 2, 6, 20, 13, 5, 5, 37, 36, 38, 34, 21, 27, 255, 35, 31, 48, 11, 17, 1, 17, 14, 12, 20, 0, 6,
+ 17, 1, 9, 27, 46, 21, 50, 44, 26, 255, 50, 38, 36, 35, 17, 20, 4, 18, 20, 6, 16, 20, 12, 10, 20, 8, 20, 20, 45, 40,
+ 21, 37, 38, 255, 35, 44, 29, 17, 7, 6, 14, 6, 13, 16, 9, 8, 10, 7, 13, 49, 43, 41, 49, 40, 50, 49, 255, 29, 42, 36,
+ 7, 5, 10, 20, 0, 19, 6, 18, 18, 13, 16, 3, 50, 40, 46, 26, 45, 49, 36, 255, 24, 39, 36, 2, 7, 3, 1, 1, 15, 12, 6,
+ 6, 5, 0, 7, 32, 43, 30, 50, 39, 50, 47, 255, 23, 41, 24, 6, 6, 1, 11, 9, 16, 5, 6, 3, 11, 7, 17, 12, 28, 47, 31,
+ 23, 31, 37, 32, 255, 50, 21, 22, 50, 1, 2, 1, 6, 12, 15, 9, 2, 4, 10, 14, 13, 46, 35, 39, 44, 39, 42, 29, 255, 20,
+ 45, 38, 29, 13, 20, 7, 13, 12, 12, 3, 12, 10, 14, 15, 20, 26, 30, 44, 27, 48, 46, 21, 255, 39, 40, 38, 22, 18, 3, 20,
+ 20, 4, 14, 11, 14, 10, 0, 12, 0, 25, 25, 28, 24, 44, 22, 31, 255, 29, 25, 39, 28, 7, 1, 6, 7, 7, 11, 15, 7, 10, 17,
+ 0, 0, 27, 23, 41, 21, 21, 41, 45, 45, 255, 27, 36, 46, 10, 13, 14, 8, 3, 15, 14, 4, 15, 12, 11, 2, 14, 35, 42, 50, 26,
+ 37, 30, 35, 38, 255, 34, 47, 33, 20, 3, 2, 2, 14, 11, 11, 7, 3, 15, 18, 9, 13, 27, 30, 27, 47, 34, 22, 38, 20, 255,
+ 22, 46, 50, 3, 9, 18, 19, 11, 19, 6, 2, 4, 0, 14, 13, 5, 39, 40, 48, 43, 33, 25, 43, 20, 255, 45, 42, 47, 11, 4, 0,
+ 1, 6, 8, 15, 16, 18, 1, 11, 0, 6, 5, 38, 47, 32, 23, 40, 37, 39, 255, 26, 30, 36, 37, 7, 5, 7, 11, 8, 13, 12, 12, 17,
+ 12, 1, 11, 8, 14, 44, 25, 31, 41, 50, 39, 46, 255, 49, 39, 44, 23, 4, 5, 14, 15, 1, 13, 7, 9, 7, 5, 4, 7, 16, 2, 41,
+ 30, 37, 36, 34, 23, 32, 255, 49, 32, 33, 41, 2, 13, 17, 8, 19, 18, 15, 4, 12, 18, 6, 19, 10, 8, 38, 31, 36, 34, 44,
+ 50, 20, 255, 39, 39, 24, 30, 11, 5, 12, 16, 20, 18, 2, 8, 17, 14, 24, 7, 10, 13, 6, 27, 41, 31, 46, 29, 46, 39, 28,
+ 255, 43, 28, 38, 49, 11, 11, 19, 1, 12, 14, 0, 18, 4, 21, 4, 16, 11, 16, 42, 44, 49, 23, 38, 31, 35, 47, 255, 30, 23,
+ 23, 45, 1, 10, 3, 8, 16, 16, 6, 17, 10, 24, 3, 19, 11, 3, 24, 27, 42, 45, 27, 46, 26, 41, 255, 31, 44, 39, 49, 10,
+ 4, 20, 3, 9, 15, 7, 15, 5, 19, 4, 10, 9, 13, 30, 29, 47, 21, 24, 36, 45, 20, 255, 33, 45, 25, 24, 2, 9, 19, 2, 20,
+ 17, 19, 10, 20, 12, 10, 19, 20, 9, 20, 30, 38, 34, 22, 46, 26, 24, 26, 255, 23, 26, 29, 37, 0, 10, 9, 20, 14, 19,
+ 2, 0, 1, 4, 12, 19, 6, 17, 17, 46, 47, 42, 34, 32, 29, 40, 47, 255, 27, 30, 25, 36, 14, 3, 11, 20, 4, 0, 1, 9, 19,
+ 15, 13, 2, 19, 1, 7, 42, 20, 25, 46, 30, 49, 39, 28, 255, 34, 43, 24, 34, 6, 1, 18, 9, 8, 11, 11, 17, 11, 6, 26,
+ 7, 3, 1, 14, 49, 41, 37, 27, 34, 22, 47, 20, 24, 255, 36, 34, 20, 26, 13, 7, 18, 10, 6, 9, 4, 0, 14, 14, 27, 5,
+ 13, 0, 7, 39, 21, 42, 34, 36, 45, 24, 28, 43, 255, 20, 26, 36, 31, 8, 8, 0, 0, 14, 0, 1, 8, 15, 1, 19, 13, 15,
+ 17, 9, 44, 38, 33, 21, 37, 48, 32, 30, 34, 255, 32, 32, 33, 40, 19, 6, 5, 2, 7, 3, 10, 19, 10, 12, 14, 16, 15,
+ 14, 7, 29, 29, 50, 31, 26, 36, 31, 22, 32, 255, 48, 45, 42, 31, 50, 13, 9, 5, 16, 7, 12, 12, 4, 6, 1, 24, 14, 12,
+ 6, 3, 25, 27, 50, 40, 25, 35, 37, 25, 47, 255, 30, 29, 45, 36, 34, 0, 13, 20, 13, 18, 11, 16, 16, 0, 9, 23, 8,
+ 7, 4, 18, 41, 50, 20, 45, 48, 43, 31, 36, 30, 255, 37, 30, 22, 38, 39, 10, 16, 9, 7, 13, 18, 1, 5, 14, 20, 21,
+ 13, 19, 15, 13, 34, 26, 21, 45, 35, 44, 39, 23, 21, 255, 27, 47, 45, 41, 39, 9, 11, 12, 10, 13, 4, 8, 15, 4,
+ 19, 3, 1, 15, 9, 5, 2, 8, 33, 38, 35, 26, 48, 42, 25, 50, 23, 255, 24, 26, 29, 20, 32, 12, 1, 9, 10, 12, 6,
+ 14, 6, 14, 1, 19, 14, 20, 2, 8, 4, 31, 43, 27, 24, 33, 33, 27, 23, 21, 255, 41, 37, 23, 28, 33, 2, 17, 8, 9,
+ 16, 10, 17, 11, 4, 4, 4, 17, 19, 13, 3, 0, 20, 36, 31, 50, 48, 31, 43, 36, 34, 255, 31, 41, 29, 47, 21, 18,
+ 15, 11, 20, 14, 14, 11, 4, 12, 2, 12]
+
+
+from collections import deque
+
+data_points = 20
+item_data1 = deque([0] * data_points)
+
+pos1 = 0
+
+lengths = [0]
+
+item_point1 = 0
+
+def set_point(plotPoint, pos, value, ix, max_items):
+ scale = 254 / max_items * ix
+ return 6 * ix + value / max_items + scale
+
+
+def find_max_value(item_data):
+ max_value = 0
+ max_index = 0
+ for ix, i in enumerate(item_data):
+ if i > max_value:
+ max_value = i
+ max_index = ix
+ return max_index, max_value
+
+
+def rearrange(item_data, actual_pos, max_items):
+ max_value_index, max_value = find_max_value(item_data)
+ mean = int(max_items / 2.)
+ start = mean - max_value_index
+ if start != 0:
+ item_data.rotate(start)
+ pos = (actual_pos + start) % max_items
+ else:
+ pos = actual_pos
+ print "rearrange", mean, start, actual_pos, pos, item_data
+ return pos
+
+
+def set_value(item_data, pos, max_pos, value):
+ print "setValue before", pos, None, max_pos, value, item_data
+ item_data[pos] = value
+ new_pos = (pos + 1) % max_pos
+ print "setValue after ", pos, new_pos, max_pos, value, item_data
+ return new_pos
+
+def resize(item_data, max_length, new_max_length):
+ if new_max_length > max_length:
+ pad = (new_max_length - max_length)
+ print "pad", pad
+ item_data.extend([0] * pad)
+ return new_max_length
+ else:
+ return max_length
+
+for value in data:
+ if value > 250:
+ data_points = resize(item_data1, data_points, lengths[-1])
+ lengths.append(0)
+ else:
+ lengths[-1] += 1
+
+ ix = 0
+ set_point(None, pos1, value, ix, 3)
+ pos1 = set_value(item_data1, pos1, data_points, value)
+ pos1 = rearrange(item_data1, pos1, data_points)
+
+ print
+
+print "lengths", lengths
diff --git a/ekgplotter/ekgplotter/ekg_plotter_qt_only.py b/ekgplotter/ekgplotter/ekg_plotter_qt_only.py
new file mode 100644
index 0000000..a370410
--- /dev/null
+++ b/ekgplotter/ekgplotter/ekg_plotter_qt_only.py
@@ -0,0 +1,266 @@
+# -*- coding: utf-8 -*-
+"""
+Demonstrates use of PlotWidget class. This is little more than a
+GraphicsView with a PlotItem placed in its center.
+"""
+
+
+
+from collections import deque
+
+from PyQt4 import QtNetwork
+from pyqtgraph.Qt import QtGui, QtCore
+import numpy as np
+import pyqtgraph as pg
+
+import numpy as np
+
+
+try:
+ from chaosc.c_osc_lib import decode_osc
+except ImportError as e:
+ print(e)
+ from chaosc.osc_lib import decode_osc
+
+
+
+class OSCPlotter(QtGui.QWidget):
+ def __init__(self, parent=None):
+ super(OSCPlotter, self).__init__(parent)
+ self.plot_data1 = deque([0] * 100)
+ self.plot_data2 = deque([254 * 0.3] * 100)
+ self.plot_data3 = deque([254 * 0.6] * 100)
+ self.is_item1 = True
+ self.is_item2 = True
+ self.is_item3 = True
+ self.osc_sock = QtNetwork.QUdpSocket(self)
+ self.osc_sock.bind(10000)
+ self.osc_sock.readyRead.connect(self.receive_osc)
+ self.tcpServer = QtNetwork.QTcpServer(self)
+ self.tcpServer.listen(QtNetwork.QHostAddress("0.0.0.0"), 9000)
+ self.tcpServer.newConnection.connect(self.addConnection)
+ self.connections = []
+ self.streams = []
+ self.streaming_timer = QtCore.QTimer(self)
+ self.streaming_timer.timeout.connect(self.sendMJpeg)
+ self.streaming_timer.start(20)
+
+
+ def addConnection(self):
+ clientConnection = self.tcpServer.nextPendingConnection()
+ #clientConnection.nextBlockSize = 0
+ self.connections.append(clientConnection)
+
+ clientConnection.readyRead.connect(self.receiveMessage)
+ clientConnection.disconnected.connect(self.removeConnection)
+ clientConnection.error.connect(self.socketError)
+
+ def removeConnection(self):
+ pass
+
+ def socketError(self):
+ pass
+
+ def receiveMessage(self):
+ for ix, s in enumerate(self.connections):
+ if s.bytesAvailable() > 0:
+ stream = QtCore.QDataStream(s)
+ stream.setVersion(QtCore.QDataStream.Qt_4_8)
+
+ #if s.nextBlockSize == 0:
+ #if s.bytesAvailable() < 4:
+ #return
+ #s.nextBlockSize = stream.readUInt32()
+ #if s.bytesAvailable() < s.nextBlockSize:
+ #return
+
+ textFromClient = stream.readRawData(s.bytesAvailable())
+ print "data", repr(textFromClient)
+ socketId = s.socketDescriptor()
+ if textFromClient.startswith("GET /index.html"):
+ self.sendMessage("HTTP/1.1 200 Ok\r\nContent-Language: en\r\nContent-type: text/html; charset=\"utf-8\"\r\n\r\n" + open("index.html").read() + "\r\n\r\n",
+ s.socketDescriptor())
+ elif textFromClient.startswith("GET /camera.jpg"):
+ self.sendImage(socketId)
+ elif textFromClient.startswith("GET /camera.mjpeg"):
+ self.prepareMJpeg(socketId)
+ #self.sendImage(s.socketDescriptor())
+ else:
+ self.sendMessage("HTTP/1.1 404 Not Found\r\n\r\n", s.socketDescriptor())
+
+
+ def sendMessage(self, text, socketId):
+ for s in self.connections:
+ if s.socketDescriptor() == socketId:
+ print "sendMessage"
+
+ reply = QtCore.QByteArray()
+ stream = QtCore.QDataStream(reply, QtCore.QIODevice.WriteOnly)
+ #stream.setVersion(QtCore.QDataStream.Qt_4_8)
+ stream.writeString(text)
+
+ s.write(reply)
+ s.close()
+
+
+ def prepareMJpeg(self, socketId):
+ for s in self.connections:
+ if s.socketDescriptor() == socketId:
+ self.streams.append(socketId)
+ reply = QtCore.QByteArray()
+ stream = QtCore.QDataStream(reply, QtCore.QIODevice.WriteOnly)
+ stream.setVersion(QtCore.QDataStream.Qt_4_8)
+ stream.writeRawData("HTTP/1.1 200 OK\r\nContent-Type: multipart/x-mixed-replace; boundary=--aaboundary\r\n\r\n")
+ s.write(reply)
+ #s.close()
+
+
+ def sendMJpeg(self):
+ reply = QtCore.QByteArray()
+ stream = QtCore.QDataStream(reply, QtCore.QIODevice.WriteOnly)
+ stream.setVersion(QtCore.QDataStream.Qt_4_8)
+ stream.writeRawData("--aaboundary\r\nContent-Type: image/jpeg\r\nContent-length: %d\r\n\r\n%s\r\n\r\n\r\n" % (len(self.jpeg_data), self.jpeg_data))
+ for socketId in self.streams:
+ for connection in self.connections:
+ if connection.socketDescriptor() == socketId:
+ connection.write(reply)
+ #connection.close()
+
+
+ def sendImage(self, socketId):
+ for connection in self.connections:
+ if connection.socketDescriptor() == socketId:
+ reply = QtCore.QByteArray()
+ stream = QtCore.QDataStream(reply, QtCore.QIODevice.WriteOnly)
+ stream.setVersion(QtCore.QDataStream.Qt_4_8)
+
+ #tmp = open("camera.jpg", "rb").read()
+ header = QtCore.QString("HTTP/1.1 200 OK\r\nContent-Type: image/jpeg\r\nContent-length: %d\r\n\r\n" % len(self.jpeg_data))
+ stream.writeRawData(header)
+ stream.writeRawData(self.jpeg_data)
+ stream.writeRawData("\r\n\r\n\r\n")
+ connection.write(reply)
+ connection.close()
+
+
+ def init(self):
+ self.plt = pg.PlotWidget(name='EKG') ## giving the plots names allows us to link their axes together
+ #self.legend = self.plt.addLegend()
+
+ l = QtGui.QVBoxLayout()
+ self.statusLabel = QtGui.QLabel("Listening for broadcasted messages")
+ self.setLayout(l)
+ l.addWidget(self.plt)
+ l.addWidget(self.statusLabel)
+
+ self.plotItem1 = pg.PlotCurveItem(pen=pg.mkPen('r', width=4), name="bjoern")
+ self.plotItem2 = pg.PlotCurveItem(pen=pg.mkPen('g', width=4), name="merle")
+ self.plotItem3 = pg.PlotCurveItem(pen=pg.mkPen('b', width=4), name="uwe")
+ #self.plotItem1.setPos(0, 0*6)
+ #self.plotItem2.setPos(0, 1*6)
+ #self.plotItem3.setPos(0, 2*6)
+ self.plt.addItem(self.plotItem1)
+ self.plt.addItem(self.plotItem2)
+ self.plt.addItem(self.plotItem3)
+ self.plt.setLabel('left', "EKG")
+ self.plt.setLabel('bottom', "Time")
+ self.plt.showGrid(True, True)
+ ba = self.plt.getAxis("bottom")
+ bl = self.plt.getAxis("left")
+ ba.setTicks([])
+ bl.setTicks([])
+ self.plt.setYRange(0, 254)
+ self.plotItem1.setData(y=np.array(self.plot_data1), clear=True)
+ self.plotItem2.setData(y=np.array(self.plot_data2), clear=True)
+ self.plotItem3.setData(y=np.array(self.plot_data3), clear=True)
+ #self.plotItem1.setShadowPen(pg.mkPen((200, 200, 200), width=6, cosmetic=True))
+ #self.plotItem2.setShadowPen(pg.mkPen((200, 200, 200), width=6, cosmetic=True))
+ #self.plotItem3.setShadowPen(pg.mkPen((200, 200, 200), width=6, cosmetic=True))
+
+
+
+ def receive_osc(self):
+ #print "receive_osc"
+ while self.osc_sock.hasPendingDatagrams():
+ packet, address, port = self.osc_sock.readDatagram(self.osc_sock.pendingDatagramSize())
+ osc_address, typetags, args = decode_osc(packet, 0, len(packet))
+
+ #print "osc", osc_address, args[0]
+ self.statusLabel.setText(osc_address)
+ update = False
+ if osc_address == "/bjoern/ekg":
+ self.plot_data1.appendleft(args[0] / 3)
+ self.plot_data1.pop()
+ update = True
+ elif osc_address == "/merle/ekg":
+ self.plot_data2.appendleft(args[0] / 3 + 254/3)
+ self.plot_data2.pop()
+ update = True
+ elif osc_address == "/uwe/ekg":
+ self.plot_data3.appendleft(args[0] /3 + 254/3*2)
+ self.plot_data3.pop()
+ update = True
+ #elif osc_address == "/plot/uwe":
+ #if args[0] == 1 and self.is_item3 == False:
+ #self.plt.addItem(self.plotItem3)
+ #self.is_item3 = True
+ ##self.legend.addItem(self.plotItem3, "uwe")
+ #elif args[0] == 0 and self.is_item3 == True:
+ #self.plt.removeItem(self.plotItem3)
+ #self.is_item3 = False
+ ##self.legend.removeItem("uwe")
+ #elif osc_address == "/plot/merle":
+ #if args[0] == 1 and self.is_item2 == False:
+ #self.plt.addItem(self.plotItem2)
+ #self.is_item2 = True
+ ##self.legend.addItem(self.plotItem2, "merle")
+ #elif args[0] == 0 and self.is_item2 == True:
+ #self.plt.removeItem(self.plotItem2)
+ #self.is_item2 = True
+ ##self.legend.removeItem("merle")
+ #elif osc_address == "/plot/bjoern":
+ #if args[0] == 1 and self.is_item1 == False:
+ #self.plt.addItem(self.plotItem1)
+ #self.is_item1 = True
+ ##self.legend.addItem(self.plotItem1, name="bjoern")
+ #elif args[0] == 0 and self.is_item1 == True:
+ #self.plt.removeItem(self.plotItem1)
+ #self.is_item1 = False
+ ##self.legend.removeItem("bjoern")
+
+ if update:
+ self.plotItem1.setData(y=np.array(self.plot_data1), clear=True)
+ self.plotItem2.setData(y=np.array(self.plot_data2), clear=True)
+ self.plotItem3.setData(y=np.array(self.plot_data3), clear=True)
+ #item = plt.plot(plot_data1, pen=(0, 3*1.3), clear=True)
+
+ exporter = pg.exporters.ImageExporter.ImageExporter(self.plt.plotItem)
+ exporter.parameters()['width'] = 1280
+ #exporter.parameters()['height'] = 720
+ name = 'tmpfile'
+ img = exporter.export(name, True)
+ buffer = QtCore.QBuffer()
+ buffer.open(QtCore.QIODevice.ReadWrite)
+ img.save(buffer, "JPG", 100)
+ self.jpeg_data = buffer.data()
+
+
+
+#QtGui.QApplication.setGraphicsSystem('raster')
+app = QtGui.QApplication([])
+mw = QtGui.QMainWindow()
+mw.setWindowTitle('pyqtgraph example: PlotWidget')
+mw.resize(1280, 720)
+cw = OSCPlotter()
+cw.init()
+mw.setCentralWidget(cw)
+
+mw.show()
+
+
+
+## Start Qt event loop unless running in interactive mode or using pyside.
+if __name__ == '__main__':
+ import sys
+ if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
+ QtGui.QApplication.instance().exec_()
diff --git a/ekgplotter/ekgplotter/main.py b/ekgplotter/ekgplotter/main.py
index a6e949b..757ee6f 100644
--- a/ekgplotter/ekgplotter/main.py
+++ b/ekgplotter/ekgplotter/main.py
@@ -55,10 +55,10 @@ from pyqtgraph.widgets.PlotWidget import PlotWidget
from chaosc.argparser_groups import *
from chaosc.lib import resolve_host
-#try:
- #from chaosc.c_osc_lib import *
-#except ImportError:
-from chaosc.osc_lib import *
+try:
+ from chaosc.c_osc_lib import *
+except ImportError:
+ from chaosc.osc_lib import *
try:
@@ -69,16 +69,18 @@ except ImportError as e:
+
class OSCThread(threading.Thread):
def __init__(self, args):
super(OSCThread, self).__init__()
self.args = args
self.running = True
- self.own_address = socket.getaddrinfo(args.own_host, args.own_port, socket.AF_INET6, socket.SOCK_DGRAM, 0, socket.AI_V4MAPPED | socket.AI_ALL | socket.AI_CANONNAME)[-1][4][:2]
- self.chaosc_address = chaosc_host, chaosc_port = socket.getaddrinfo(args.chaosc_host, args.chaosc_port, socket.AF_INET6, socket.SOCK_DGRAM, 0, socket.AI_V4MAPPED | socket.AI_ALL | socket.AI_CANONNAME)[-1][4][:2]
+ self.own_address = resolve_host(args.own_host, args.own_port, args.address_family)
- self.osc_sock = socket.socket(10, 2, 17)
+ self.chaosc_address = chaosc_host, chaosc_port = resolve_host(args.chaosc_host, args.chaosc_port, args.address_family)
+
+ self.osc_sock = socket.socket(args.address_family, 2, 17)
self.osc_sock.bind(self.own_address)
self.osc_sock.setblocking(0)
@@ -125,10 +127,11 @@ class OSCThread(threading.Thread):
while self.running:
reads, writes, errs = select.select([self.osc_sock], [], [], 0.05)
if reads:
- osc_input = reads[0].recv(4096)
+ osc_input = reads[0].recv(128)
osc_address, typetags, messages = decode_osc(osc_input, 0, len(osc_input))
#print("thread osc_address", osc_address)
if osc_address.find(b"ekg") > -1 or osc_address.find(b"plot") != -1:
+ #print("send", osc_address)
msg_queue.put_nowait((osc_address, messages))
else:
msg_queue.put_nowait((b"/bjoern/ekg", [0]))
@@ -220,7 +223,6 @@ class Actor(object):
class EkgPlot(object):
def __init__(self, actor_names, num_data, colors):
- self.qtapp = QtGui.QApplication([])
self.plot = pg.PlotWidget(title="
EKG
")
self.plot.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.plot.hide()
@@ -269,34 +271,50 @@ class EkgPlot(object):
def update(self, osc_address, value):
+ print("update"), osc_address
res = self.ekg_regex.match(osc_address)
if res:
+ #print("matched data")
actor_name = res.group(1)
actor_obj = self.actors[actor_name]
max_actors = len(self.active_actors)
- ix = self.active_actors.index(actor_obj)
actor_data = actor_obj.data
data_pointer = actor_obj.data_pointer
actor_data[data_pointer] = value
- actor_obj.set_point(value, ix, max_actors)
+ try:
+ ix = self.active_actors.index(actor_obj)
+ actor_obj.set_point(value, ix, max_actors)
+ actor_obj.plotItem.setData(y=np.array(actor_obj.scale_data(ix, max_actors)), clear=True)
+ except ValueError as e:
+ #print("data", e)
+ pass
actor_obj.data_pointer = (data_pointer + 1) % self.num_data
- actor_obj.plotItem.setData(y=np.array(actor_obj.scale_data(ix, max_actors)), clear=True)
return
res = self.ctl_regex.match(osc_address)
if res:
actor_name = res.group(1)
actor_obj = self.actors[actor_name]
+ #print("matched ctl", value, actor_name, actor_obj.active)
if value == 1 and not actor_obj.active:
- print("actor on", actor_name)
- self.plot.addItem(actor_obj)
+ #print("actor on", actor_name, actor_obj, self.active_actors)
actor_obj.active = True
- self.active_actors.append(actor_obj)
- elif value == 0 and not actor_obj.active:
- print("actor off", actor_name)
- self.plot.removeItem(actor_obj)
- actor_obj.active = True
- self.active_actors.remove(actor_obj)
+ if actor_obj not in self.active_actors:
+ self.plot.addItem(actor_obj.plotItem)
+ self.plot.addItem(actor_obj.plotPoint)
+ self.active_actors.append(actor_obj)
+ assert actor_obj in self.active_actors
+ elif value == 0 and actor_obj.active:
+ #print("actor off", actor_name, actor_obj, self.active_actors)
+ actor_obj.active = False
+ self.plot.removeItem(actor_obj.plotItem)
+ self.plot.removeItem(actor_obj.plotPoint)
+ try:
+ self.active_actors.remove(actor_obj)
+ except ValueError as e:
+ #print("ctl", e)
+ pass
+ assert actor_obj not in self.active_actors
self.set_positions()
@@ -362,9 +380,7 @@ class MyHandler(BaseHTTPRequestHandler):
print("children", plotter.plot.children())
plotter.plot.deleteLater()
plotter.plot.close()
- self.plotter.qtapp.processEvents()
del self.plotter.plot
- del self.plotter.qtapp
del self.plotter
del plotter
thread.running = False
@@ -394,61 +410,49 @@ class MyHandler(BaseHTTPRequestHandler):
self.wfile.write(data)
return
except (KeyboardInterrupt, SystemError):
- print("queue size", queue.qsize())
+ print("queue size", msg_queue.qsize())
thread.running = False
thread.join()
if hasattr(self, "plotter"):
plotter.plot.deleteLater()
- except IOError:
+ except IOError as e:
+ print("ioerror", e)
+ print('-'*40)
+ print('Exception happened during processing of request from')
+ import traceback
+ traceback.print_exc() # XXX But this goes to stderr!
+ print( '-'*40)
self.send_error(404,'File Not Found: %s' % self.path)
class JustAHTTPServer(HTTPServer):
- address_family = socket.AF_INET6
pass
def main():
- a = create_arg_parser("ekgplotter")
- own_group = add_main_group(a)
+ arg_parser = create_arg_parser("ekgplotter")
+ own_group = add_main_group(arg_parser)
own_group.add_argument('-x', "--http_host", default="::",
help='my host, defaults to "socket.gethostname()"')
own_group.add_argument('-X', "--http_port", default=9000,
type=int, help='my port, defaults to 9000')
- add_chaosc_group(a)
- add_subscriber_group(a, "ekgplotter")
- args = finalize_arg_parser(a)
+ add_chaosc_group(arg_parser)
+ add_subscriber_group(arg_parser, "ekgplotter")
+ args = finalize_arg_parser(arg_parser)
+ qtapp = QtGui.QApplication([])
- http_host, http_port = resolve_host(args.http_host, args.http_port)
- print(http_host, http_port)
+ http_host, http_port = resolve_host(args.http_host, args.http_port, args.address_family)
server = JustAHTTPServer((http_host, http_port), MyHandler)
+ server.address_family = args.address_family
server.args = args
print("%s: starting up http server on '%s:%d'" % (
datetime.now().strftime("%x %X"), http_host, http_port))
- print("before start:")
- #objgraph.show_growth()
try:
server.serve_forever()
except KeyboardInterrupt:
- print('^C received, shutting down server')
- print()
- #print(gc.garbage)
- #print()
- #print "queue size", queue.qsize()
- #print "show growth", objgraph.show_growth()
- #import random
- #objgraph.show_chain(
- #objgraph.find_backref_chain(
- #random.choice(objgraph.by_type('function')),
- #objgraph.is_proper_module),
- #filename='chain.png')
- #roots = objgraph.get_leaking_objects()
- #print "root", len(roots)
- #objgraph.show_most_common_types(objects=roots)
- #objgraph.show_refs(roots[:3], refcounts=True, filename='roots.png')
server.socket.close()
diff --git a/ekgplotter/ekgplotter/main_old.py b/ekgplotter/ekgplotter/main_old.py
new file mode 100644
index 0000000..feeae76
--- /dev/null
+++ b/ekgplotter/ekgplotter/main_old.py
@@ -0,0 +1,217 @@
+import numpy as np
+import string,cgi,time, random, socket
+from os import curdir, sep
+from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
+from SocketServer import ThreadingMixIn, ForkingMixIn
+import select
+import re
+
+from collections import deque
+
+from PyQt4.QtCore import QBuffer, QByteArray, QIODevice, QThread, QObject
+from PyQt4 import QtGui
+from PyQt4 import QtCore
+import pyqtgraph as pg
+
+from pyqtgraph.widgets.PlotWidget import PlotWidget
+
+
+try:
+ from chaosc.c_osc_lib import decode_osc
+except ImportError as e:
+ print(e)
+ from chaosc.osc_lib import decode_osc
+
+QAPP = None
+
+def mkQApp():
+ if QtGui.QApplication.instance() is None:
+ global QAPP
+ QAPP = QtGui.QApplication([])
+
+
+class PlotWindow(PlotWidget):
+ def __init__(self, title=None, **kargs):
+ mkQApp()
+ self.win = QtGui.QMainWindow()
+ PlotWidget.__init__(self, **kargs)
+ self.win.setCentralWidget(self)
+ for m in ['resize']:
+ setattr(self, m, getattr(self.win, m))
+ if title is not None:
+ self.win.setWindowTitle(title)
+
+
+class WorkThread(QThread):
+ osc_received = QtCore.pyqtSignal(str, int, name='osc_received')
+
+ def __init__(self):
+ QThread.__init__(self)
+ self.osc_sock = socket.socket(2, 2, 17)
+ self.osc_sock.setblocking(0)
+ self.osc_sock.setsockopt(socket.SOL_SOCKET,
+ socket.SO_RCVBUF, 4096 * 8)
+ self.osc_sock.bind(("", 10000))
+
+
+ def __del__(self):
+ self.wait()
+
+ def run(self):
+ while 1:
+ reads, writes, errs = select.select([self.osc_sock], [], [], 0.01)
+ if reads:
+ osc_input = reads[0].recv(4096)
+ osc_address, typetags, args = decode_osc(osc_input, 0, len(osc_input))
+ print "signal", osc_address, args[0]
+ self.osc_received.emit(osc_address, args[0])
+
+
+class MyHandler(QtCore.QObject, BaseHTTPRequestHandler):
+
+ def __init__(self, request, client_address, parent):
+ self.plot_data1 = deque([0] * 100)
+ self.plot_data2 = deque([254/3] * 100)
+ self.plot_data3 = deque([254/3*2] * 100)
+ self.is_item1 = True
+ self.is_item2 = True
+ self.is_item3 = True
+ QtCore.QObject.__init__(self)
+ BaseHTTPRequestHandler.__init__(self, request, client_address, parent)
+
+ @QtCore.pyqtSlot('QString', int, name="receive_osc")
+ def receive_osc(self, osc_address, value):
+ print "change", osc_address, value
+ if osc_address == "/bjoern/ekg":
+ self.plot_data1.appendleft(args[0] / 3)
+ self.plot_data1.pop()
+ elif osc_address == "/merle/ekg":
+ self.plot_data2.appendleft(args[0] / 3 + 254/3)
+ self.plot_data2.pop()
+ elif osc_address == "/uwe/ekg":
+ self.plot_data3.appendleft(args[0] / 3 + 254/3*2)
+ self.plot_data3.pop()
+ elif osc_address == "/plot/uwe":
+ if value == 1 and self.is_item3 == False:
+ self.plt.addItem(self.plotItem3)
+ elif value == 0 and self.is_item3 == True:
+ self.plt.removeItem(self.plotItem3)
+ elif osc_address == "/plot/merle":
+ if value == 1 and self.is_item2 == False:
+ self.plt.addItem(self.plotItem2)
+ elif value == 0 and self.is_item2 == True:
+ self.plt.removeItem(self.plotItem2)
+ elif osc_address == "/plot/bjoern":
+ if value == 1 and self.is_item1 == False:
+ self.plt.addItem(self.plotItem1)
+ elif value == 0 and self.is_item1 == True:
+ self.plt.removeItem(self.plotItem1)
+
+ def do_GET(self):
+ print "get"
+ global plotValues
+ try:
+ self.path=re.sub('[^.a-zA-Z0-9]', "",str(self.path))
+ if self.path=="" or self.path==None or self.path[:1]==".":
+ return
+ if self.path.endswith(".html"):
+ f = open(curdir + sep + self.path)
+ self.send_response(200)
+ self.send_header('Content-type', 'text/html')
+ self.end_headers()
+ self.wfile.write(f.read())
+ f.close()
+ return
+ if self.path.endswith(".mjpeg"):
+ self.thread = WorkThread()
+ #self.thread.osc_received.connect(self.change)
+ #self.connect(self.thread, thread.osc_received, self.change)
+ self.thread.osc_received.connect(self.receive_osc)
+ self.thread.start()
+
+ self.send_response(200)
+
+ self.plt = plt = PlotWindow(title="EKG", name="Merle")
+ plt.addLegend()
+ #plt = pg.plot(pen=(0, 3*1.3))
+ plt.resize(1280, 720)
+ self.plotItem1 = plotItem1 = pg.PlotCurveItem(pen=pg.mkPen('r', width=4), name="bjoern")
+ self.plotItem2 = plotItem2 = pg.PlotCurveItem(pen=pg.mkPen('g', width=4), name="merle")
+ self.plotItem3 = plotItem3 = pg.PlotCurveItem(pen=pg.mkPen('b', width=4), name="uwe")
+ plotItem1.setPos(0, 0*6)
+ plotItem2.setPos(0, 1*6)
+ plotItem3.setPos(0, 2*6)
+ plt.addItem(plotItem1)
+ plt.addItem(plotItem2)
+ plt.addItem(plotItem3)
+
+ plt.setLabel('left', "EKG")
+ plt.setLabel('bottom', "Time")
+ plt.showGrid(True, True)
+ ba = plt.getAxis("bottom")
+ bl = plt.getAxis("left")
+ ba.setTicks([])
+ bl.setTicks([])
+ plt.setYRange(0, 254)
+ #print type(plt)
+ self.wfile.write("Content-Type: multipart/x-mixed-replace; boundary=--aaboundary")
+ self.wfile.write("\r\n\r\n")
+
+ last = time.time()
+ now = last
+
+ while 1:
+ plotItem1.setData(y=np.array(self.plot_data1), clear=True)
+ plotItem2.setData(y=np.array(self.plot_data2), clear=True)
+ plotItem3.setData(y=np.array(self.plot_data3), clear=True)
+ #item = plt.plot(plot_data1, pen=(0, 3*1.3), clear=True)
+
+ exporter = pg.exporters.ImageExporter.ImageExporter(plt.plotItem)
+ exporter.parameters()['width'] = 1280
+ #exporter.parameters()['height'] = 720
+ name = 'tmpfile'
+ img = exporter.export(name, True)
+ buffer = QBuffer()
+ buffer.open(QIODevice.ReadWrite)
+ img.save(buffer, "JPG", 100)
+ JpegData = buffer.data()
+ self.wfile.write("--aaboundary\r\n")
+ self.wfile.write("Content-Type: image/jpeg\r\n")
+ self.wfile.write("Content-length: %d\r\n\r\n" % len(JpegData))
+ self.wfile.write(JpegData)
+ self.wfile.write("\r\n\r\n\r\n")
+ now = time.time()
+ dur = now - last
+ #print dur
+ wait = 0.04 - dur
+ if wait > 0:
+ time.sleep(wait)
+ last = now
+ return
+ if self.path.endswith(".jpeg"):
+ f = open(curdir + sep + self.path)
+ self.send_response(200)
+ self.send_header('Content-type','image/jpeg')
+ self.end_headers()
+ self.wfile.write(f.read())
+ f.close()
+ return
+ return
+ except IOError:
+ self.send_error(404,'File Not Found: %s' % self.path)
+
+
+class ThreadedHTTPServer(HTTPServer, ForkingMixIn):
+ """Handle requests in a separate process."""
+
+def main():
+ try:
+ server = ThreadedHTTPServer(('0.0.0.0', 9000), MyHandler)
+ print 'started httpserver...'
+ server.serve_forever()
+ except KeyboardInterrupt:
+ print '^C received, shutting down server'
+ server.socket.close()
+
+if __name__ == '__main__':
+ main()
diff --git a/ekgplotter/ekgplotter/main_workstations.py b/ekgplotter/ekgplotter/main_workstations.py
new file mode 100644
index 0000000..a6c145f
--- /dev/null
+++ b/ekgplotter/ekgplotter/main_workstations.py
@@ -0,0 +1,461 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# This file is part of sensors2osc package
+#
+# sensors2osc 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, either version 3 of the License, or
+# (at your option) any later version.
+#
+# sensors2osc 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 sensors2osc. If not, see .
+#
+# found the mjpeg part here, thanks for the nice code :)
+# http://hardsoftlucid.wordpress.com/2013/04/11/mjpeg-server-for-webcam-in-python-with-opencv/
+# the osc integration stuff is implemented by me
+#
+# Copyright (C) 2014 Stefan Kögl
+
+from __future__ import absolute_import
+
+from datetime import datetime
+import threading
+import Queue
+import numpy as np
+import string,cgi,time, random, socket
+from os import curdir, sep
+from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
+from SocketServer import ThreadingMixIn, ForkingMixIn
+import select
+import re
+
+from collections import deque
+
+from PyQt4.QtCore import QBuffer, QByteArray, QIODevice
+from PyQt4 import QtGui
+import pyqtgraph as pg
+
+from pyqtgraph.widgets.PlotWidget import PlotWidget
+
+from chaosc.argparser_groups import *
+
+try:
+ from chaosc.c_osc_lib import *
+except ImportError:
+ from chaosc.osc_lib import *
+
+QtGui.QApplication.setGraphicsSystem('opengl')
+
+
+try:
+ from chaosc.c_osc_lib import decode_osc
+except ImportError as e:
+ print(e)
+ from chaosc.osc_lib import decode_osc
+
+QAPP = QtGui.QApplication([])
+
+
+class PlotWindow(PlotWidget):
+ def __init__(self, title=None, **kargs):
+ self.win = QtGui.QMainWindow()
+ PlotWidget.__init__(self, **kargs)
+ self.win.setCentralWidget(self)
+ for m in ['resize']:
+ setattr(self, m, getattr(self.win, m))
+ if title is not None:
+ self.win.setWindowTitle(title)
+
+
+class OSCThread(threading.Thread):
+ def __init__(self, args):
+ super(OSCThread, self).__init__()
+ self.args = args
+ self.running = True
+ self.own_address = socket.getaddrinfo(args.own_host, args.own_port, socket.AF_INET6, socket.SOCK_DGRAM, 0, socket.AI_V4MAPPED | socket.AI_ALL | socket.AI_CANONNAME)[-1][4][:2]
+
+ self.chaosc_address = chaosc_host, chaosc_port = socket.getaddrinfo(args.chaosc_host, args.chaosc_port, socket.AF_INET6, socket.SOCK_DGRAM, 0, socket.AI_V4MAPPED | socket.AI_ALL | socket.AI_CANONNAME)[-1][4][:2]
+
+ self.osc_sock = socket.socket(2, 2, 17)
+ self.osc_sock.bind(self.own_address)
+ self.osc_sock.setblocking(0)
+
+ print "%s: starting up osc receiver on '%s:%d'" % (
+ datetime.now().strftime("%x %X"), self.own_address[0], self.own_address[1])
+
+ self.subscribe_me()
+
+ def subscribe_me(self):
+ """Use this procedure for a quick'n dirty subscription to your chaosc instance.
+
+ :param chaosc_address: (chaosc_host, chaosc_port)
+ :type chaosc_address: tuple
+
+ :param receiver_address: (host, port)
+ :type receiver_address: tuple
+
+ :param token: token to get authorized for subscription
+ :type token: str
+ """
+ print "%s: subscribing to '%s:%d' with label %r" % (datetime.now().strftime("%x %X"), self.chaosc_address[0], self.chaosc_address[1], self.args.subscriber_label)
+ msg = OSCMessage("/subscribe")
+ msg.appendTypedArg(self.own_address[0], "s")
+ msg.appendTypedArg(self.own_address[1], "i")
+ msg.appendTypedArg(self.args.authenticate, "s")
+ if self.args.subscriber_label is not None:
+ msg.appendTypedArg(self.args.subscriber_label, "s")
+ self.osc_sock.sendto(msg.encode_osc(), self.chaosc_address)
+
+
+ def unsubscribe_me(self):
+ if self.args.keep_subscribed:
+ return
+
+ print "%s: unsubscribing from '%s:%d'" % (datetime.now().strftime("%x %X"), self.chaosc_address[0], self.chaosc_address[1])
+ msg = OSCMessage("/unsubscribe")
+ msg.appendTypedArg(self.own_address[0], "s")
+ msg.appendTypedArg(self.own_address[1], "i")
+ msg.appendTypedArg(self.args.authenticate, "s")
+ self.osc_sock.sendto(msg.encode_osc(), self.chaosc_address)
+
+ def run(self):
+
+ while self.running:
+ reads, writes, errs = select.select([self.osc_sock], [], [], 0.05)
+ if reads:
+ osc_input = reads[0].recv(4096)
+ osc_address, typetags, messages = decode_osc(osc_input, 0, len(osc_input))
+ if osc_address.find("ekg") > -1 or osc_address.find("plot") != -1:
+ queue.put_nowait((osc_address, messages))
+ else:
+ queue.put_nowait(("/bjoern/ekg", [0]))
+ queue.put_nowait(("/merle/ekg", [0]))
+ queue.put_nowait(("/uwe/ekg", [0]))
+ self.unsubscribe_me()
+ print "OSCThread is going down"
+
+
+queue = Queue.Queue()
+
+class MyHandler(BaseHTTPRequestHandler):
+
+ def __del__(self):
+ self.thread.running = False
+ self.thread.join()
+
+ def do_GET(self):
+ print "get"
+
+ self.thread = thread = OSCThread(self.server.args)
+ thread.daemon = True
+ thread.start()
+
+ actors = list()
+ is_item1 = True
+ is_item2 = True
+ is_item3 = True
+
+ def setPositions():
+ for ix, item in enumerate(actors):
+ item.setPos(0, ix*6)
+
+
+ def scale_data(data, ix, max_items):
+ scale = 254 / max_items * ix
+ return [value / max_items + scale for value in data]
+
+
+ def set_point(plotPoint, pos, value, ix, max_items):
+ scale = 254 / max_items * ix
+ y = 6 * ix + value / max_items + scale
+ plotPoint.setData(x = [pos], y = [y])
+
+
+ def find_max_value(item_data):
+ max_index = -1
+ for ix, i in enumerate(item_data):
+ if i > 250:
+ return ix, i
+ return None, None
+
+
+ def rearrange(item_data, actual_pos, max_items):
+ max_value_index, max_value = find_max_value(item_data)
+ if max_value_index is None:
+ return actual_pos
+ mean = int(max_items / 2.)
+ start = mean - max_value_index
+ if start != 0:
+ item_data.rotate(start)
+ pos = (actual_pos + start) % max_items
+ else:
+ pos = actual_pos
+ #print "rearrange", mean, start, actual_pos, pos, item_data
+ return pos
+
+
+ def set_value(item_data, pos, max_pos, value):
+ #print "setValue before", pos, None, max_pos, value, item_data, len(item_data)
+ item_data[pos] = value
+ new_pos = (pos + 1) % max_pos
+ #print "setValue after ", pos, new_pos, max_pos, value, item_data, len(item_data)
+ return new_pos
+
+ def resize(item_data, max_length, new_max_length, pos):
+ #print "resize", max_length, new_max_length
+ if new_max_length < 15:
+ return max_length, pos
+
+ if new_max_length > max_length:
+ pad = (new_max_length - max_length)
+ #print "pad", pad
+ for i in range(pad):
+ if i % 2 == 0:
+ item_data.append(0)
+ else:
+ item_data.appendleft(0)
+ pos += 1
+ return new_max_length, pos
+ elif new_max_length < max_length:
+ pad = (max_length - new_max_length)
+ for i in range(pad):
+ if i % 2 == 0:
+ item_data.pop()
+ if pos >= new_max_length:
+ pos = 0
+ else:
+ item_data.popleft()
+ if pos > 0:
+ pos -= 1
+ return new_max_length, pos
+ return max_length, pos
+
+ try:
+ self.path=re.sub('[^.a-zA-Z0-9]', "",str(self.path))
+ if self.path=="" or self.path==None or self.path[:1]==".":
+ return
+
+ if self.path.endswith(".html"):
+ f = open(curdir + sep + self.path)
+ self.send_response(200)
+ self.send_header('Content-type', 'text/html')
+ self.end_headers()
+ self.wfile.write(f.read())
+ f.close()
+ elif self.path.endswith(".mjpeg"):
+ data_points = 43
+
+ self.send_response(200)
+ pos1 = 0
+ pos2 = 0
+ pos3 = 0
+
+ lengths1 = [0]
+
+ data1_max_value = 0
+ data2_max_value = 0
+ data3_max_value = 0
+
+ data1_distance = data_points
+ data2_distance = data_points
+ data3_distance = data_points
+
+ plot_data1 = deque([0] * data_points)
+ plot_data2 = deque([0] * data_points)
+ plot_data3 = deque([0] * data_points)
+ plt = PlotWidget(title="EKG
")
+ plt.hide()
+ plotItem1 = pg.PlotCurveItem(pen=pg.mkPen('r', width=1), width=1, name="bjoern")
+ plotItem2 = pg.PlotCurveItem(pen=pg.mkPen('g', width=1), width=1, name="merle")
+ plotItem3 = pg.PlotCurveItem(pen=pg.mkPen('b', width=1), width=1, name="uwe")
+ shadowPen = pg.mkPen("w", width=10)
+ plotItem1.setShadowPen(pen=shadowPen, width=3, cosmetic=True)
+ plotItem2.setShadowPen(pen=shadowPen, width=3, cosmetic=True)
+ plotItem3.setShadowPen(pen=shadowPen, width=3, cosmetic=True)
+ pen = pg.mkPen("w", size=1)
+ brush = pg.mkBrush("w")
+ plotPoint1 = pg.ScatterPlotItem(pen=pen, brush=brush, size=15)
+ plotPoint2 = pg.ScatterPlotItem(pen=pen, brush=brush, size=10)
+ plotPoint3 = pg.ScatterPlotItem(pen=pen, brush=brush, size=10)
+ actors.append(plotItem1)
+ actors.append(plotItem2)
+ actors.append(plotItem3)
+ plotItem1.setPos(0, 0*6)
+ plotItem2.setPos(0, 1*6)
+ plotItem3.setPos(0, 2*6)
+ plt.addItem(plotItem1)
+ plt.addItem(plotItem2)
+ plt.addItem(plotItem3)
+ plt.addItem(plotPoint1)
+ plt.addItem(plotPoint2)
+ plt.addItem(plotPoint3)
+
+ plt.setLabel('left', "Amplitude
")
+ plt.setLabel('bottom', "Time
")
+ plt.showGrid(True, True)
+ ba = plt.getAxis("bottom")
+ bl = plt.getAxis("left")
+ ba.setTicks([])
+ bl.setTicks([])
+ ba.setWidth(0)
+ ba.setHeight(0)
+ bl.setWidth(0)
+ bl.setHeight(0)
+ plt.setYRange(0, 255)
+
+ self.wfile.write("Content-Type: multipart/x-mixed-replace; boundary=--aaboundary")
+ self.wfile.write("\r\n\r\n")
+
+
+ plt.resize(1280, 720)
+
+ while 1:
+ while 1:
+ try:
+ osc_address, args = queue.get_nowait()
+ except Queue.Empty:
+ break
+ max_items = len(actors)
+ value = args[0]
+
+ if osc_address == "/bjoern/ekg":
+ #if value > 250:
+ #data_points, pos1 = resize(plot_data1, len(plot_data1), lengths1[-1], pos1)
+ #foo, pos2 = resize(plot_data2, len(plot_data2), lengths1[-1], pos2)
+ #foo, pos3 = resize(plot_data3, len(plot_data3), lengths1[-1], pos3)
+ #print "length1", lengths1
+ #lengths1.append(0)
+ #else:
+ #lengths1[-1] += 1
+
+ ix = actors.index(plotItem1)
+
+ #pos1 = rearrange(plot_data1, pos1, data_points)
+ set_point(plotPoint1, pos1, value, ix, max_items)
+ pos1 = set_value(plot_data1, pos1, data_points, value)
+ try:
+ plotItem1.setData(y=np.array(scale_data(plot_data1, ix, max_items)), clear=True)
+ except ValueError:
+ pass
+
+ elif osc_address == "/merle/ekg":
+ ix = actors.index(plotItem2)
+
+ #pos2 = rearrange(plot_data2, pos2, data_points)
+ set_point(plotPoint2, pos2, value, ix, max_items)
+ pos2 = set_value(plot_data2, pos2, data_points, value)
+ try:
+ plotItem2.setData(y=np.array(scale_data(plot_data2, ix, max_items)), clear=True)
+ except ValueError:
+ pass
+ elif osc_address == "/uwe/ekg":
+ ix = actors.index(plotItem3)
+ #pos3 = rearrange(plot_data3, pos3, data_points)
+ set_point(plotPoint3, pos3, value, ix, max_items)
+ pos3 = set_value(plot_data3, pos3, data_points, value)
+ try:
+ plotItem3.setData(y=np.array(scale_data(plot_data3, ix, max_items)), clear=True)
+ except ValueError:
+ pass
+ elif osc_address == "/plot/uwe":
+ if value == 1 and is_item3 == False:
+ print "uwe on"
+ plt.addItem(plotItem3)
+ is_item3 = True
+ actors.append(plotItem3)
+ setPositions()
+ elif value == 0 and is_item3 == True:
+ print "uwe off"
+ plt.removeItem(plotItem3)
+ is_item3 = False
+ actors.remove(plotItem3)
+ setPositions()
+ elif osc_address == "/plot/merle":
+ if value == 1 and is_item2 == False:
+ print "merle on"
+ plt.addItem(plotItem2)
+ is_item2 = True
+ actors.append(plotItem2)
+ setPositions()
+ elif value == 0 and is_item2 == True:
+ print "merle off"
+ plt.removeItem(plotItem2)
+ is_item2 = False
+ actors.remove(plotItem2)
+ setPositions()
+ elif osc_address == "/plot/bjoern":
+ if value == 1 and is_item1 == False:
+ print "bjoern on"
+ plt.addItem(plotItem1)
+ is_item1 = True
+ actors.append(plotItem1)
+ setPositions()
+ elif value == 0 and is_item1 == True:
+ print "bjoern off"
+ plt.removeItem(plotItem1)
+ is_item1 = False
+ actors.remove(plotItem1)
+ setPositions()
+
+ exporter = pg.exporters.ImageExporter.ImageExporter(plt.plotItem)
+ img = exporter.export("tmpfile", True)
+ buffer = QBuffer()
+ buffer.open(QIODevice.WriteOnly)
+ img.save(buffer, "JPG", 100)
+ JpegData = buffer.data()
+ del buffer
+ self.wfile.write("--aaboundary\r\nContent-Type: image/jpeg\r\nContent-length: %d\r\n\r\n%s\r\n\r\n\r\n" % (len(JpegData), JpegData))
+
+ elif self.path.endswith(".jpeg"):
+ f = open(curdir + sep + self.path)
+ self.send_response(200)
+ self.send_header('Content-type','image/jpeg')
+ self.end_headers()
+ self.wfile.write(f.read())
+ f.close()
+ return
+ except (KeyboardInterrupt, SystemError):
+ thread.running = False
+ thread.join()
+ except IOError:
+ self.send_error(404,'File Not Found: %s' % self.path)
+
+
+class JustAHTTPServer(HTTPServer):
+
+ pass
+
+
+def main():
+ a = create_arg_parser("ekgplotter")
+ own_group = add_main_group(a)
+ own_group.add_argument('-x', "--http_host", default="0.0.0.0",
+ help='my host, defaults to "socket.gethostname()"')
+ own_group.add_argument('-X', "--http_port", default=9000,
+ type=int, help='my port, defaults to 9000')
+ add_chaosc_group(a)
+ add_subscriber_group(a, "ekgplotter")
+ args = finalize_arg_parser(a)
+
+ try:
+ host, port = socket.getaddrinfo(args.http_host, args.http_port, socket.AF_INET6, socket.SOCK_DGRAM, 0, socket.AI_V4MAPPED | socket.AI_ALL | socket.AI_CANONNAME)[-1][4][:2]
+
+ server = JustAHTTPServer(("0.0.0.0", 9000), MyHandler)
+ server.args = args
+ print "%s: starting up http server on '%s:%d'" % (
+ datetime.now().strftime("%x %X"), host, port)
+ server.serve_forever()
+ except KeyboardInterrupt:
+ print '^C received, shutting down server'
+ server.socket.close()
+
+
+if __name__ == '__main__':
+ main()
+
diff --git a/ekgplotter/ekgplotter/ok_main.py b/ekgplotter/ekgplotter/ok_main.py
new file mode 100644
index 0000000..e3b89a2
--- /dev/null
+++ b/ekgplotter/ekgplotter/ok_main.py
@@ -0,0 +1,408 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# This file is part of sensors2osc package
+#
+# sensors2osc 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, either version 3 of the License, or
+# (at your option) any later version.
+#
+# sensors2osc 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 sensors2osc. If not, see .
+#
+# found the mjpeg part here, thanks for the nice code :)
+# http://hardsoftlucid.wordpress.com/2013/04/11/mjpeg-server-for-webcam-in-python-with-opencv/
+# the osc integration stuff is implemented by me
+#
+# Copyright (C) 2014 Stefan Kögl
+
+from __future__ import absolute_import
+
+from datetime import datetime
+import threading
+import Queue
+import numpy as np
+import string,cgi,time, random, socket
+from os import curdir, sep
+from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
+from SocketServer import ThreadingMixIn, ForkingMixIn
+import select
+import re
+
+from collections import deque
+
+from PyQt4.QtCore import QBuffer, QByteArray, QIODevice
+from PyQt4 import QtGui
+import pyqtgraph as pg
+
+from pyqtgraph.widgets.PlotWidget import PlotWidget
+
+from chaosc.argparser_groups import *
+
+try:
+ from chaosc.c_osc_lib import *
+except ImportError:
+ from chaosc.osc_lib import *
+
+QtGui.QApplication.setGraphicsSystem('opengl')
+
+
+try:
+ from chaosc.c_osc_lib import decode_osc
+except ImportError as e:
+ print(e)
+ from chaosc.osc_lib import decode_osc
+
+QAPP = QtGui.QApplication([])
+
+
+class PlotWindow(PlotWidget):
+ def __init__(self, title=None, **kargs):
+ self.win = QtGui.QMainWindow()
+ PlotWidget.__init__(self, **kargs)
+ self.win.setCentralWidget(self)
+ for m in ['resize']:
+ setattr(self, m, getattr(self.win, m))
+ if title is not None:
+ self.win.setWindowTitle(title)
+
+
+class OSCThread(threading.Thread):
+ def __init__(self, args):
+ super(OSCThread, self).__init__()
+ self.args = args
+ self.running = True
+ self.own_address = socket.getaddrinfo(args.own_host, args.own_port, socket.AF_INET6, socket.SOCK_DGRAM, 0, socket.AI_V4MAPPED | socket.AI_ALL | socket.AI_CANONNAME)[-1][4][:2]
+
+ self.chaosc_address = chaosc_host, chaosc_port = socket.getaddrinfo(args.chaosc_host, args.chaosc_port, socket.AF_INET6, socket.SOCK_DGRAM, 0, socket.AI_V4MAPPED | socket.AI_ALL | socket.AI_CANONNAME)[-1][4][:2]
+
+ self.osc_sock = socket.socket(2, 2, 17)
+ self.osc_sock.bind(self.own_address)
+ self.osc_sock.setblocking(0)
+
+ print "%s: starting up osc receiver on '%s:%d'" % (
+ datetime.now().strftime("%x %X"), self.own_address[0], self.own_address[1])
+
+ self.subscribe_me()
+
+ def subscribe_me(self):
+ """Use this procedure for a quick'n dirty subscription to your chaosc instance.
+
+ :param chaosc_address: (chaosc_host, chaosc_port)
+ :type chaosc_address: tuple
+
+ :param receiver_address: (host, port)
+ :type receiver_address: tuple
+
+ :param token: token to get authorized for subscription
+ :type token: str
+ """
+ print "%s: subscribing to '%s:%d' with label %r" % (datetime.now().strftime("%x %X"), self.chaosc_address[0], self.chaosc_address[1], self.args.subscriber_label)
+ msg = OSCMessage("/subscribe")
+ msg.appendTypedArg(self.own_address[0], "s")
+ msg.appendTypedArg(self.own_address[1], "i")
+ msg.appendTypedArg(self.args.authenticate, "s")
+ if self.args.subscriber_label is not None:
+ msg.appendTypedArg(self.args.subscriber_label, "s")
+ self.osc_sock.sendto(msg.encode_osc(), self.chaosc_address)
+
+
+ def unsubscribe_me(self):
+ if self.args.keep_subscribed:
+ return
+
+ print "%s: unsubscribing from '%s:%d'" % (datetime.now().strftime("%x %X"), self.chaosc_address[0], self.chaosc_address[1])
+ msg = OSCMessage("/unsubscribe")
+ msg.appendTypedArg(self.own_address[0], "s")
+ msg.appendTypedArg(self.own_address[1], "i")
+ msg.appendTypedArg(self.args.authenticate, "s")
+ self.osc_sock.sendto(msg.encode_osc(), self.chaosc_address)
+
+ def run(self):
+
+ while self.running:
+ reads, writes, errs = select.select([self.osc_sock], [], [], 0.05)
+ if reads:
+ osc_input = reads[0].recv(4096)
+ osc_address, typetags, messages = decode_osc(osc_input, 0, len(osc_input))
+ if osc_address.find("ekg") > -1 or osc_address.find("plot") != -1:
+ queue.put_nowait((osc_address, messages))
+ else:
+ queue.put_nowait(("/bjoern/ekg", [0]))
+ queue.put_nowait(("/merle/ekg", [0]))
+ queue.put_nowait(("/uwe/ekg", [0]))
+ self.unsubscribe_me()
+ print "OSCThread is going down"
+
+
+queue = Queue.Queue()
+
+class MyHandler(BaseHTTPRequestHandler):
+
+ def do_GET(self):
+ print "get"
+
+ self.thread = thread = OSCThread(self.server.args)
+ thread.daemon = True
+ thread.start()
+
+ actors = list()
+ is_item1 = True
+ is_item2 = True
+ is_item3 = True
+
+ def setPositions():
+ for ix, item in enumerate(actors):
+ item.setPos(0, ix*6)
+
+
+ def scale_data(data, ix, max_items):
+ scale = 254 / max_items * ix
+ return [value / max_items + scale for value in data]
+
+ def set_point(plotPoint, pos, value, ix, max_items):
+ scale = 254 / max_items * ix
+ plotPoint.setData(x = [pos], y = [6*ix + value / max_items + scale])
+
+
+ def setValue(dataItem, pos, maxPos, value):
+ dataItem[pos] = value
+ return (pos + 1) % maxPos
+
+ def find_max_index(dataItem):
+ max_value = 0
+ max_index = 0
+ for ix, i in enumerate(dataItem):
+ if i > max_value:
+ max_value = i
+ max_index = ix
+ return max_index, max_value
+
+ def rearrange(data, index, max_items):
+ max_value_index, max_value = findMax(data)
+ mean = int(max_items / 2.)
+ start = mean - max_value_index
+ data.rotate(start)
+ pos = (index + start) % max_items
+ print "rearrange", index, max_items, pos
+ return pos
+
+ def checkDataPoints(value, data_max_value):
+ if value > max_value and value > 200:
+ return True, value
+ return False, data_max_value
+
+ try:
+ self.path=re.sub('[^.a-zA-Z0-9]', "",str(self.path))
+ if self.path=="" or self.path==None or self.path[:1]==".":
+ return
+
+ if self.path.endswith(".html"):
+ f = open(curdir + sep + self.path)
+ self.send_response(200)
+ self.send_header('Content-type', 'text/html')
+ self.end_headers()
+ self.wfile.write(f.read())
+ f.close()
+ elif self.path.endswith(".mjpeg"):
+ data_points = 21
+
+ self.send_response(200)
+ pos1 = 0
+ pos2 = 0
+ pos3 = 0
+
+ data1_max_value = 0
+ data2_max_value = 0
+ data3_max_value = 0
+
+ data1_distance = data_points
+ data2_distance = data_points
+ data3_distance = data_points
+
+ plot_data1 = deque([0] * data_points)
+ plot_data2 = deque([0] * data_points)
+ plot_data3 = deque([0] * data_points)
+ plt = PlotWidget(title="EKG
", name="Merle")
+ plt.hide()
+ plotItem1 = pg.PlotCurveItem(pen=pg.mkPen('r', width=2), width=2, name="bjoern")
+ plotItem2 = pg.PlotCurveItem(pen=pg.mkPen('g', width=2), width=2, name="merle")
+ plotItem3 = pg.PlotCurveItem(pen=pg.mkPen('b', width=2), width=2, name="uwe")
+ shadowPen = pg.mkPen("w", width=10)
+ plotItem1.setShadowPen(pen=shadowPen, width=6, cosmetic=True)
+ plotItem2.setShadowPen(pen=shadowPen, width=6, cosmetic=True)
+ plotItem3.setShadowPen(pen=shadowPen, width=6, cosmetic=True)
+ pen = pg.mkPen("w", size=1)
+ brush = pg.mkBrush("w")
+ plotPoint1 = pg.ScatterPlotItem(pen=pen, brush=brush, size=10)
+ plotPoint2 = pg.ScatterPlotItem(pen=pen, brush=brush, size=10)
+ plotPoint3 = pg.ScatterPlotItem(pen=pen, brush=brush, size=10)
+ actors.append(plotItem1)
+ actors.append(plotItem2)
+ actors.append(plotItem3)
+ plotItem1.setPos(0, 0*6)
+ plotItem2.setPos(0, 1*6)
+ plotItem3.setPos(0, 2*6)
+ plt.addItem(plotItem1)
+ plt.addItem(plotItem2)
+ plt.addItem(plotItem3)
+ plt.addItem(plotPoint1)
+ plt.addItem(plotPoint2)
+ plt.addItem(plotPoint3)
+
+ plt.setLabel('left', "Amplitude
")
+ plt.setLabel('bottom', "Time
")
+ plt.showGrid(True, True)
+ ba = plt.getAxis("bottom")
+ bl = plt.getAxis("left")
+ ba.setTicks([])
+ bl.setTicks([])
+ plt.setYRange(0, 254)
+
+ self.wfile.write("Content-Type: multipart/x-mixed-replace; boundary=--aaboundary")
+ self.wfile.write("\r\n\r\n")
+
+
+ plt.resize(1280, 720)
+
+ while 1:
+ while 1:
+ try:
+ osc_address, args = queue.get_nowait()
+ except Queue.Empty:
+ break
+ max_items = len(actors)
+ value = args[0]
+
+ if osc_address == "/bjoern/ekg":
+ ix = actors.index(plotItem1)
+ res, tmp = checkDataPoints(value, data1_max_value)
+ if res and res > 20:
+ data_points = tmp
+ data1_maxdata1_max_value = 0
+ set_point(plotPoint1, pos1, value, ix, max_items)
+ pos1 = setValue(plot_data1, pos1, data_points, value)
+ pos1 = rearrange(plot_data1, pos1, data_points)
+ try:
+ plotItem1.setData(y=np.array(scale_data(plot_data1, ix, max_items)), clear=True)
+ except ValueError:
+ pass
+ elif osc_address == "/merle/ekg":
+ ix = actors.index(plotItem2)
+ set_point(plotPoint2, pos2, value, ix, max_items)
+ pos2 = setValue(plot_data2, pos2, data_points, value)
+ pos2 = rearrange(plot_data2, pos2, data_points)
+ try:
+ plotItem2.setData(y=np.array(scale_data(plot_data2, ix, max_items)), clear=True)
+ except ValueError:
+ pass
+ elif osc_address == "/uwe/ekg":
+ ix = actors.index(plotItem3)
+ set_point(plotPoint3, pos3, value, ix, max_items)
+ pos3 = setValue(plot_data3, pos3, data_points, value)
+ pos3 = rearrange(plot_data3, pos3, data_points)
+ try:
+ plotItem3.setData(y=np.array(scale_data(plot_data3, ix, max_items)), clear=True)
+ except ValueError:
+ pass
+ elif osc_address == "/plot/uwe":
+ if value == 1 and is_item3 == False:
+ print "uwe on"
+ plt.addItem(plotItem3)
+ is_item3 = True
+ actors.append(plotItem3)
+ setPositions()
+ elif value == 0 and is_item3 == True:
+ print "uwe off"
+ plt.removeItem(plotItem3)
+ is_item3 = False
+ actors.remove(plotItem3)
+ setPositions()
+ elif osc_address == "/plot/merle":
+ if value == 1 and is_item2 == False:
+ print "merle on"
+ plt.addItem(plotItem2)
+ is_item2 = True
+ actors.append(plotItem2)
+ setPositions()
+ elif value == 0 and is_item2 == True:
+ print "merle off"
+ plt.removeItem(plotItem2)
+ is_item2 = False
+ actors.remove(plotItem2)
+ setPositions()
+ elif osc_address == "/plot/bjoern":
+ if value == 1 and is_item1 == False:
+ print "bjoern on"
+ plt.addItem(plotItem1)
+ is_item1 = True
+ actors.append(plotItem1)
+ setPositions()
+ elif value == 0 and is_item1 == True:
+ print "bjoern off"
+ plt.removeItem(plotItem1)
+ is_item1 = False
+ actors.remove(plotItem1)
+ setPositions()
+
+ exporter = pg.exporters.ImageExporter.ImageExporter(plt.plotItem)
+ img = exporter.export("tmpfile", True)
+ buffer = QBuffer()
+ buffer.open(QIODevice.WriteOnly)
+ img.save(buffer, "JPG", 100)
+ JpegData = buffer.data()
+ del buffer
+ self.wfile.write("--aaboundary\r\nContent-Type: image/jpeg\r\nContent-length: %d\r\n\r\n%s\r\n\r\n\r\n" % (len(JpegData), JpegData))
+
+ elif self.path.endswith(".jpeg"):
+ f = open(curdir + sep + self.path)
+ self.send_response(200)
+ self.send_header('Content-type','image/jpeg')
+ self.end_headers()
+ self.wfile.write(f.read())
+ f.close()
+ return
+ except (KeyboardInterrupt, SystemError):
+ thread.running = False
+ thread.join()
+ except IOError:
+ self.send_error(404,'File Not Found: %s' % self.path)
+
+
+class JustAHTTPServer(HTTPServer):
+ pass
+
+
+def main():
+ a = create_arg_parser("ekgplotter")
+ own_group = add_main_group(a)
+ own_group.add_argument('-x', "--http_host", default="0.0.0.0",
+ help='my host, defaults to "socket.gethostname()"')
+ own_group.add_argument('-X', "--http_port", default=9000,
+ type=int, help='my port, defaults to 9000')
+ add_chaosc_group(a)
+ add_subscriber_group(a, "ekgplotter")
+ args = finalize_arg_parser(a)
+
+ try:
+ host, port = socket.getaddrinfo(args.http_host, args.http_port, socket.AF_INET6, socket.SOCK_DGRAM, 0, socket.AI_V4MAPPED | socket.AI_ALL | socket.AI_CANONNAME)[-1][4][:2]
+
+ server = JustAHTTPServer(("0.0.0.0", 9000), MyHandler)
+ server.args = args
+ print "%s: starting up http server on '%s:%d'" % (
+ datetime.now().strftime("%x %X"), host, port)
+ server.serve_forever()
+ except KeyboardInterrupt:
+ print '^C received, shutting down server'
+ server.socket.close()
+
+
+if __name__ == '__main__':
+ main()
+