made ekgplotter ready for ipv4_only
This commit is contained in:
parent
9bcdc6b377
commit
8dc6e67d1d
|
@ -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
|
|
@ -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_()
|
|
@ -55,9 +55,9 @@ from pyqtgraph.widgets.PlotWidget import PlotWidget
|
||||||
from chaosc.argparser_groups import *
|
from chaosc.argparser_groups import *
|
||||||
from chaosc.lib import resolve_host
|
from chaosc.lib import resolve_host
|
||||||
|
|
||||||
#try:
|
try:
|
||||||
#from chaosc.c_osc_lib import *
|
from chaosc.c_osc_lib import *
|
||||||
#except ImportError:
|
except ImportError:
|
||||||
from chaosc.osc_lib import *
|
from chaosc.osc_lib import *
|
||||||
|
|
||||||
|
|
||||||
|
@ -69,16 +69,18 @@ except ImportError as e:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class OSCThread(threading.Thread):
|
class OSCThread(threading.Thread):
|
||||||
def __init__(self, args):
|
def __init__(self, args):
|
||||||
super(OSCThread, self).__init__()
|
super(OSCThread, self).__init__()
|
||||||
self.args = args
|
self.args = args
|
||||||
self.running = True
|
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.bind(self.own_address)
|
||||||
self.osc_sock.setblocking(0)
|
self.osc_sock.setblocking(0)
|
||||||
|
|
||||||
|
@ -125,10 +127,11 @@ class OSCThread(threading.Thread):
|
||||||
while self.running:
|
while self.running:
|
||||||
reads, writes, errs = select.select([self.osc_sock], [], [], 0.05)
|
reads, writes, errs = select.select([self.osc_sock], [], [], 0.05)
|
||||||
if reads:
|
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))
|
osc_address, typetags, messages = decode_osc(osc_input, 0, len(osc_input))
|
||||||
#print("thread osc_address", osc_address)
|
#print("thread osc_address", osc_address)
|
||||||
if osc_address.find(b"ekg") > -1 or osc_address.find(b"plot") != -1:
|
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))
|
msg_queue.put_nowait((osc_address, messages))
|
||||||
else:
|
else:
|
||||||
msg_queue.put_nowait((b"/bjoern/ekg", [0]))
|
msg_queue.put_nowait((b"/bjoern/ekg", [0]))
|
||||||
|
@ -220,7 +223,6 @@ class Actor(object):
|
||||||
|
|
||||||
class EkgPlot(object):
|
class EkgPlot(object):
|
||||||
def __init__(self, actor_names, num_data, colors):
|
def __init__(self, actor_names, num_data, colors):
|
||||||
self.qtapp = QtGui.QApplication([])
|
|
||||||
self.plot = pg.PlotWidget(title="<h1>EKG</h1>")
|
self.plot = pg.PlotWidget(title="<h1>EKG</h1>")
|
||||||
self.plot.setAttribute(QtCore.Qt.WA_DeleteOnClose)
|
self.plot.setAttribute(QtCore.Qt.WA_DeleteOnClose)
|
||||||
self.plot.hide()
|
self.plot.hide()
|
||||||
|
@ -269,34 +271,50 @@ class EkgPlot(object):
|
||||||
|
|
||||||
def update(self, osc_address, value):
|
def update(self, osc_address, value):
|
||||||
|
|
||||||
|
print("update"), osc_address
|
||||||
res = self.ekg_regex.match(osc_address)
|
res = self.ekg_regex.match(osc_address)
|
||||||
if res:
|
if res:
|
||||||
|
#print("matched data")
|
||||||
actor_name = res.group(1)
|
actor_name = res.group(1)
|
||||||
actor_obj = self.actors[actor_name]
|
actor_obj = self.actors[actor_name]
|
||||||
max_actors = len(self.active_actors)
|
max_actors = len(self.active_actors)
|
||||||
ix = self.active_actors.index(actor_obj)
|
|
||||||
actor_data = actor_obj.data
|
actor_data = actor_obj.data
|
||||||
data_pointer = actor_obj.data_pointer
|
data_pointer = actor_obj.data_pointer
|
||||||
actor_data[data_pointer] = value
|
actor_data[data_pointer] = value
|
||||||
|
try:
|
||||||
|
ix = self.active_actors.index(actor_obj)
|
||||||
actor_obj.set_point(value, ix, max_actors)
|
actor_obj.set_point(value, ix, max_actors)
|
||||||
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)
|
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
|
||||||
return
|
return
|
||||||
|
|
||||||
res = self.ctl_regex.match(osc_address)
|
res = self.ctl_regex.match(osc_address)
|
||||||
if res:
|
if res:
|
||||||
actor_name = res.group(1)
|
actor_name = res.group(1)
|
||||||
actor_obj = self.actors[actor_name]
|
actor_obj = self.actors[actor_name]
|
||||||
|
#print("matched ctl", value, actor_name, actor_obj.active)
|
||||||
if value == 1 and not actor_obj.active:
|
if value == 1 and not actor_obj.active:
|
||||||
print("actor on", actor_name)
|
#print("actor on", actor_name, actor_obj, self.active_actors)
|
||||||
self.plot.addItem(actor_obj)
|
|
||||||
actor_obj.active = True
|
actor_obj.active = True
|
||||||
|
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)
|
self.active_actors.append(actor_obj)
|
||||||
elif value == 0 and not actor_obj.active:
|
assert actor_obj in self.active_actors
|
||||||
print("actor off", actor_name)
|
elif value == 0 and actor_obj.active:
|
||||||
self.plot.removeItem(actor_obj)
|
#print("actor off", actor_name, actor_obj, self.active_actors)
|
||||||
actor_obj.active = True
|
actor_obj.active = False
|
||||||
|
self.plot.removeItem(actor_obj.plotItem)
|
||||||
|
self.plot.removeItem(actor_obj.plotPoint)
|
||||||
|
try:
|
||||||
self.active_actors.remove(actor_obj)
|
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()
|
self.set_positions()
|
||||||
|
|
||||||
|
@ -362,9 +380,7 @@ class MyHandler(BaseHTTPRequestHandler):
|
||||||
print("children", plotter.plot.children())
|
print("children", plotter.plot.children())
|
||||||
plotter.plot.deleteLater()
|
plotter.plot.deleteLater()
|
||||||
plotter.plot.close()
|
plotter.plot.close()
|
||||||
self.plotter.qtapp.processEvents()
|
|
||||||
del self.plotter.plot
|
del self.plotter.plot
|
||||||
del self.plotter.qtapp
|
|
||||||
del self.plotter
|
del self.plotter
|
||||||
del plotter
|
del plotter
|
||||||
thread.running = False
|
thread.running = False
|
||||||
|
@ -394,61 +410,49 @@ class MyHandler(BaseHTTPRequestHandler):
|
||||||
self.wfile.write(data)
|
self.wfile.write(data)
|
||||||
return
|
return
|
||||||
except (KeyboardInterrupt, SystemError):
|
except (KeyboardInterrupt, SystemError):
|
||||||
print("queue size", queue.qsize())
|
print("queue size", msg_queue.qsize())
|
||||||
thread.running = False
|
thread.running = False
|
||||||
thread.join()
|
thread.join()
|
||||||
if hasattr(self, "plotter"):
|
if hasattr(self, "plotter"):
|
||||||
plotter.plot.deleteLater()
|
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)
|
self.send_error(404,'File Not Found: %s' % self.path)
|
||||||
|
|
||||||
|
|
||||||
class JustAHTTPServer(HTTPServer):
|
class JustAHTTPServer(HTTPServer):
|
||||||
address_family = socket.AF_INET6
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
a = create_arg_parser("ekgplotter")
|
arg_parser = create_arg_parser("ekgplotter")
|
||||||
own_group = add_main_group(a)
|
own_group = add_main_group(arg_parser)
|
||||||
own_group.add_argument('-x', "--http_host", default="::",
|
own_group.add_argument('-x', "--http_host", default="::",
|
||||||
help='my host, defaults to "socket.gethostname()"')
|
help='my host, defaults to "socket.gethostname()"')
|
||||||
own_group.add_argument('-X', "--http_port", default=9000,
|
own_group.add_argument('-X', "--http_port", default=9000,
|
||||||
type=int, help='my port, defaults to 9000')
|
type=int, help='my port, defaults to 9000')
|
||||||
add_chaosc_group(a)
|
add_chaosc_group(arg_parser)
|
||||||
add_subscriber_group(a, "ekgplotter")
|
add_subscriber_group(arg_parser, "ekgplotter")
|
||||||
args = finalize_arg_parser(a)
|
args = finalize_arg_parser(arg_parser)
|
||||||
|
|
||||||
|
qtapp = QtGui.QApplication([])
|
||||||
|
|
||||||
http_host, http_port = resolve_host(args.http_host, args.http_port)
|
http_host, http_port = resolve_host(args.http_host, args.http_port, args.address_family)
|
||||||
print(http_host, http_port)
|
|
||||||
|
|
||||||
server = JustAHTTPServer((http_host, http_port), MyHandler)
|
server = JustAHTTPServer((http_host, http_port), MyHandler)
|
||||||
|
server.address_family = args.address_family
|
||||||
server.args = args
|
server.args = args
|
||||||
print("%s: starting up http server on '%s:%d'" % (
|
print("%s: starting up http server on '%s:%d'" % (
|
||||||
datetime.now().strftime("%x %X"), http_host, http_port))
|
datetime.now().strftime("%x %X"), http_host, http_port))
|
||||||
|
|
||||||
print("before start:")
|
|
||||||
#objgraph.show_growth()
|
|
||||||
try:
|
try:
|
||||||
server.serve_forever()
|
server.serve_forever()
|
||||||
except KeyboardInterrupt:
|
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()
|
server.socket.close()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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()
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# 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="<h1>EKG</h1>")
|
||||||
|
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', "<h2>Amplitude</h2>")
|
||||||
|
plt.setLabel('bottom', "<h2><sup>Time</sup></h2>")
|
||||||
|
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()
|
||||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# 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="<h1>EKG</h1>", 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', "<h2>Amplitude</h2>")
|
||||||
|
plt.setLabel('bottom', "<h2>Time</h2>")
|
||||||
|
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()
|
||||||
|
|
Loading…
Reference in New Issue