Merge branch 'master' of repos.ctdo.de:psychose

This commit is contained in:
Lucas Pleß 2014-05-03 11:46:27 +02:00
commit 0fd969766d
30 changed files with 4216 additions and 743 deletions

View File

@ -1,3 +0,0 @@
[chaosc]
ipv4_only = True
subscription_file = ~/dev/psychose/config_files/targets.config

View File

@ -1,31 +0,0 @@
[chaosc_ctl]
ipv4_only = True
client_host = lucas
client_port = 11111
chaosc_host = chaosc
[chaosc_dump]
ipv4_only = True
client_host = lucas
client_port = 11112
subscribe = True
chaosc_host = chaosc
[chaosc_emitter]
ipv4_only = True
client_host = lucas
client_port = 11113
chaosc_host = chaosc
[ekgplotter]
ipv4_only = True
client_host = lucas
client_port = 11114
chaosc_host = chaosc
[chaosc_recorder]
ipv4_only = True
client_host = lucas
client_port = 111115
chaosc_host = chaosc

View File

@ -1,11 +0,0 @@
[ekg2osc]
ipv4_only = True
chaosc_host = chaosc
[pulse2osc]
ipv4_only = True
chaosc_host = chaosc
[ehealth2osc]
ipv4_only = True
chaosc_host = chaosc

View File

@ -1,31 +0,0 @@
[chaosc_ctl]
ipv4_only = True
client_host = stefan
client_port = 11111
chaosc_host = chaosc
[chaosc_dump]
ipv4_only = True
client_host = stefan
client_port = 11112
subscribe = True
chaosc_host = chaosc
[chaosc_emitter]
ipv4_only = True
client_host = stefan
client_port = 11113
chaosc_host = chaosc
[ekgplotter]
ipv4_only = True
client_host = stefan
client_port = 11114
chaosc_host = chaosc
[chaosc_recorder]
ipv4_only = True
client_host = stefan
client_port = 111115
chaosc_host = chaosc

View File

@ -1,19 +0,0 @@
Port 8090
BindAddress 0.0.0.0
MaxClients 10
MaxBandwidth 1000000
CustomLog /tmp/ffserver.log
<Feed textcast.ffm>
file /tmp/textcast.ffm
FileMaxSize 10M
ACL allow 127.0.0.1
</Feed>
<Stream textcast.mjpeg>
Feed textcast.ffm
Format mjpeg
VideoFrameRate 25
VideoSize 768x576
Noaudio
</Stream>

View File

@ -0,0 +1,58 @@
[chaosc]
chaosc_host = chaosc
ipv4_only = True
subscription_file = ~/dev/psychose/config_files/test_targets.config
[pulsemerle]
chaosc_host = chaosc
ipv4_only = True
actor = merle
device = /dev/psy_spo2_a
[pulseuwe]
chaosc_host = chaosc
ipv4_only = True
actor = uwe
device = /dev/psy_spo2_b
[pulsebjoern]
chaosc_host = chaosc
ipv4_only = True
actor = bjoern
device = /dev/psy_spo2_c
[ehealthmerle]
chaosc_host = chaosc
ipv4_only = True
actor = merle
device = /dev/psy_ehealth_a
[ehealthuwe]
chaosc_host = chaosc
ipv4_only = True
actor = uwe
device = /dev/psy_ehealth_b
[ehealthbjoern]
chaosc_host = chaosc
ipv4_only = True
actor = bjoern
device = /dev/psy_ehealth_c
[ekgmerle]
chaosc_host = chaosc
ipv4_only = True
actor = merle
device = /dev/psy_ekg_a
[ekguwe]
chaosc_host = chaosc
ipv4_only = True
actor = uwe
device = /dev/psy_ekg_b
[ekgbjoern]
chaosc_host = chaosc
ipv4_only = True
actor = bjoern
device = /dev/psy_ekg_c

View File

@ -2,7 +2,7 @@
depend() { depend() {
need net need net
use dns localmount chaosc use dns localmount
after bootmisc after bootmisc
provide dump_grabber provide dump_grabber
} }
@ -10,7 +10,7 @@ depend() {
start() { start() {
ebegin "starting dump_grabber" ebegin "starting dump_grabber"
start-stop-daemon --start --pidfile /var/run/dump_grabber.pid --make-pidfile --user stefan --group stefan --background --exec env DISPLAY=:0 /usr/bin/dump_grabber start-stop-daemon --start --pidfile /var/run/dump_grabber.pid --make-pidfile --user sarah --group sarah --background --exec env DISPLAY=:0 /usr/bin/dump_grabber
eend $? eend $?
} }

View File

@ -2,7 +2,7 @@
depend() { depend() {
need net need net
use dns localmount chaosc use dns localmount
after bootmisc after bootmisc
provide ekgplotter provide ekgplotter
} }
@ -10,7 +10,7 @@ depend() {
start() { start() {
ebegin "starting ekgplotter" ebegin "starting ekgplotter"
start-stop-daemon --start --pidfile /var/run/ekgplotter.pid --make-pidfile --user stefan --group stefan --background --exec env DISPLAY=:0 /usr/bin/ekgplotter start-stop-daemon --start --pidfile /var/run/ekgplotter.pid --make-pidfile --user sarah --group sarah --background --exec env DISPLAY=:0 /usr/bin/ekgplotter
eend $? eend $?
} }

View File

@ -0,0 +1,22 @@
#!/sbin/runscript
depend() {
need net
use dns localmount
after bootmisc
provide psydisplay
}
start() {
ebegin "starting psydisplay"
start-stop-daemon --start --pidfile /var/run/psydisplay.pid --make-pidfile --user sarah --group sarah --background --exec /usr/bin/psydisplay
eend $?
}
stop() {
ebegin "stopping psydisplay"
start-stop-daemon --stop --quiet --pidfile /var/run/psydisplay.pid
eend $?
}

View File

@ -0,0 +1,13 @@
[ekgplotter]
ipv4_only = True
chaosc_host = chaosc
client_host = sensors
client_port = 8000
http_port = 9000
[dump_grabber]
ipv4_only = True
chaosc_host = chaosc
client_host = sensors
client_port = 8001
http_port = 9001

File diff suppressed because it is too large Load Diff

View File

@ -15,49 +15,42 @@ set -g terminal-overrides 'xterm*:smcup@:rmcup@'
new-session -s 'csession' new-session -s 'csession'
attach-session -t 'csession' attach-session -t 'csession'
new-window -n 'chaosc' -t 'csession:1' '/usr/bin/chaosc -4'
new-window -n 'socat-ekg-bjoern' -t 'csession:2' 'socat -d -d PTY,raw,echo=0,link=/tmp/ekg2osc-bjoern-in,b115200,user=stefan PTY,raw,echo=0,link=/tmp/ekg2osc-bjoern-out,b115200,user=stefan'
new-window -n 'socat-ekg-merle' -t 'csession:3' 'socat -d -d PTY,raw,echo=0,link=/tmp/ekg2osc-merle-in,b115200,user=stefan PTY,raw,echo=0,link=/tmp/ekg2osc-merle-out,b115200,user=stefan' new-window -n 'socat-ekg-merle' -t 'csession:3' 'socat -d -d PTY,raw,echo=0,link=/tmp/ekg2osc-merle-in,b115200,user=stefan PTY,raw,echo=0,link=/tmp/ekg2osc-merle-out,b115200,user=stefan'
new-window -n 'socat-ekg-uwe' -t 'csession:4' 'socat -d -d PTY,raw,echo=0,link=/tmp/ekg2osc-uwe-in,b115200,user=stefan PTY,raw,echo=0,link=/tmp/ekg2osc-uwe-out,b115200,user=stefan' new-window -n 'socat-ekg-uwe' -t 'csession:4' 'socat -d -d PTY,raw,echo=0,link=/tmp/ekg2osc-uwe-in,b115200,user=stefan PTY,raw,echo=0,link=/tmp/ekg2osc-uwe-out,b115200,user=stefan'
new-window -n 'socat-ekg-bjoern' -t 'csession:2' 'socat -d -d PTY,raw,echo=0,link=/tmp/ekg2osc-bjoern-in,b115200,user=stefan PTY,raw,echo=0,link=/tmp/ekg2osc-bjoern-out,b115200,user=stefan'
new-window -n 'socat-pulse-bjoern' -t 'csession:5' 'socat -d -d PTY,raw,echo=0,link=/tmp/pulse2osc-bjoern-in,b115200,user=stefan PTY,raw,echo=0,link=/tmp/pulse2osc-bjoern-out,b115200,user=stefan'
new-window -n 'socat-pulse-merle' -t 'csession:6' 'socat -d -d PTY,raw,echo=0,link=/tmp/pulse2osc-merle-in,b115200,user=stefan PTY,raw,echo=0,link=/tmp/pulse2osc-merle-out,b115200,user=stefan' new-window -n 'socat-pulse-merle' -t 'csession:6' 'socat -d -d PTY,raw,echo=0,link=/tmp/pulse2osc-merle-in,b115200,user=stefan PTY,raw,echo=0,link=/tmp/pulse2osc-merle-out,b115200,user=stefan'
new-window -n 'socat-pulse-uwe' -t 'csession:7' 'socat -d -d PTY,raw,echo=0,link=/tmp/pulse2osc-uwe-in,b115200,user=stefan PTY,raw,echo=0,link=/tmp/pulse2osc-uwe-out,b115200,user=stefan' new-window -n 'socat-pulse-uwe' -t 'csession:7' 'socat -d -d PTY,raw,echo=0,link=/tmp/pulse2osc-uwe-in,b115200,user=stefan PTY,raw,echo=0,link=/tmp/pulse2osc-uwe-out,b115200,user=stefan'
new-window -n 'socat-pulse-bjoern' -t 'csession:5' 'socat -d -d PTY,raw,echo=0,link=/tmp/pulse2osc-bjoern-in,b115200,user=stefan PTY,raw,echo=0,link=/tmp/pulse2osc-bjoern-out,b115200,user=stefan'
new-window -n 'socat-ehealth-bjoern' -t 'csession:8' 'socat -d -d PTY,raw,echo=0,link=/tmp/ehealth2osc-bjoern-in,b115200,user=stefan PTY,raw,echo=0,link=/tmp/ehealth2osc-bjoern-out,b115200,user=stefan'
new-window -n 'socat-ehealth-merle' -t 'csession:9' 'socat -d -d PTY,raw,echo=0,link=/tmp/ehealth2osc-merle-in,b115200,user=stefan PTY,raw,echo=0,link=/tmp/ehealth2osc-merle-out,b115200,user=stefan' new-window -n 'socat-ehealth-merle' -t 'csession:9' 'socat -d -d PTY,raw,echo=0,link=/tmp/ehealth2osc-merle-in,b115200,user=stefan PTY,raw,echo=0,link=/tmp/ehealth2osc-merle-out,b115200,user=stefan'
new-window -n 'socat-ehealth-uwe' -t 'csession:10' 'socat -d -d PTY,raw,echo=0,link=/tmp/ehealth2osc-uwe-in,b115200,user=stefan PTY,raw,echo=0,link=/tmp/ehealth2osc-uwe-out,b115200,user=stefan' new-window -n 'socat-ehealth-uwe' -t 'csession:10' 'socat -d -d PTY,raw,echo=0,link=/tmp/ehealth2osc-uwe-in,b115200,user=stefan PTY,raw,echo=0,link=/tmp/ehealth2osc-uwe-out,b115200,user=stefan'
new-window -n 'socat-ehealth-bjoern' -t 'csession:8' 'socat -d -d PTY,raw,echo=0,link=/tmp/ehealth2osc-bjoern-in,b115200,user=stefan PTY,raw,echo=0,link=/tmp/ehealth2osc-bjoern-out,b115200,user=stefan'
new-window -n 'ekg2osc-bjoern' -t 'csession:11' 'ekg2osc -4 -D /tmp/ekg2osc-bjoern-out -a bjoern' new-window -n 'ekg2osc-merle' -t 'csession:11' 'ekgmerle -D /tmp/ekg2osc-merle-out'
new-window -n 'ekg2osc-merle' -t 'csession:12' 'ekg2osc -4 -D /tmp/ekg2osc-merle-out -a merle' new-window -n 'ekg2osc-uwe' -t 'csession:12' 'ekguwe -D /tmp/ekg2osc-uwe-out'
new-window -n 'ekg2osc-uwe' -t 'csession:13' 'ekg2osc -4 -D /tmp/ekg2osc-uwe-out -a uwe' new-window -n 'ekg2osc-bjoern' -t 'csession:13' 'ekgbjoern -D /tmp/ekg2osc-bjoern-out'
new-window -n 'pulse2osc-bjoern' -t 'csession:14' 'pulse2osc -4 -D /tmp/pulse2osc-bjoern-out -a bjoern' new-window -n 'pulse2osc-merle' -t 'csession:14' 'pulse2osc -D /tmp/pulse2osc-merle-out -a merle'
new-window -n 'pulse2osc-merle' -t 'csession:15' 'pulse2osc -4 -D /tmp/pulse2osc-merle-out -a merle' new-window -n 'pulse2osc-uwe' -t 'csession:15' 'pulse2osc -D /tmp/pulse2osc-uwe-out -a uwe'
new-window -n 'pulse2osc-uwe' -t 'csession:16' 'pulse2osc -4 -D /tmp/pulse2osc-uwe-out -a uwe' new-window -n 'pulse2osc-bjoern' -t 'csession:16' 'pulse2osc -D /tmp/pulse2osc-bjoern-out -a bjoern'
new-window -n 'ehealth2osc-bjoern' -t 'csession:17' 'sleep 1 && ehealth2osc -4 -D /tmp/ehealth2osc-bjoern-out -a bjoern' new-window -n 'ehealth2osc-merle' -t 'csession:17' 'sleep 1 && ehealthmerle -D /tmp/ehealth2osc-merle-out'
new-window -n 'ehealth2osc-merle' -t 'csession:18' 'sleep 1 && ehealth2osc -4 -D /tmp/ehealth2osc-merle-out -a merle' new-window -n 'ehealth2osc-uwe' -t 'csession:18' 'sleep 1 && ehealthuwe -D /tmp/ehealth2osc-uwe-out'
new-window -n 'ehealth2osc-uwe' -t 'csession:19' 'sleep 1 && ehealth2osc -4 -D /tmp/ehealth2osc-uwe-out -a uwe' new-window -n 'ehealth2osc-bjoern' -t 'csession:19' 'sleep 1 && ehealthbjoern -D /tmp/ehealth2osc-bjoern-out'
new-window -n 'test-ekg-bjoern' -t 'csession:20' 'python /home/stefan/dev/psychose/sensors2osc/sensors2osc/socat_ekg_test.py /tmp/ekg2osc-bjoern-in'
new-window -n 'test-ekg-merle' -t 'csession:21' 'python /home/stefan/dev/psychose/sensors2osc/sensors2osc/socat_ekg_test.py /tmp/ekg2osc-merle-in' new-window -n 'test-ekg-merle' -t 'csession:21' 'python /home/stefan/dev/psychose/sensors2osc/sensors2osc/socat_ekg_test.py /tmp/ekg2osc-merle-in'
new-window -n 'test-ekg-uwe' -t 'csession:22' 'python /home/stefan/dev/psychose/sensors2osc/sensors2osc/socat_ekg_test.py /tmp/ekg2osc-uwe-in' new-window -n 'test-ekg-uwe' -t 'csession:22' 'python /home/stefan/dev/psychose/sensors2osc/sensors2osc/socat_ekg_test.py /tmp/ekg2osc-uwe-in'
new-window -n 'test-ekg-bjoern' -t 'csession:20' 'python /home/stefan/dev/psychose/sensors2osc/sensors2osc/socat_ekg_test.py /tmp/ekg2osc-bjoern-in'
new-window -n 'test-pulse-bjoern' -t 'csession:23' 'python /home/stefan/dev/psychose/sensors2osc/sensors2osc/socat_pulse_test.py /tmp/pulse2osc-bjoern-in'
new-window -n 'test-pulse-merle' -t 'csession:24' 'python /home/stefan/dev/psychose/sensors2osc/sensors2osc/socat_pulse_test.py /tmp/pulse2osc-merle-in' new-window -n 'test-pulse-merle' -t 'csession:24' 'python /home/stefan/dev/psychose/sensors2osc/sensors2osc/socat_pulse_test.py /tmp/pulse2osc-merle-in'
new-window -n 'test-pulse-uwe' -t 'csession:25' 'python /home/stefan/dev/psychose/sensors2osc/sensors2osc/socat_pulse_test.py /tmp/pulse2osc-uwe-in' new-window -n 'test-pulse-uwe' -t 'csession:25' 'python /home/stefan/dev/psychose/sensors2osc/sensors2osc/socat_pulse_test.py /tmp/pulse2osc-uwe-in'
new-window -n 'test-pulse-bjoern' -t 'csession:23' 'python /home/stefan/dev/psychose/sensors2osc/sensors2osc/socat_pulse_test.py /tmp/pulse2osc-bjoern-in'
new-window -n 'test-ehealth-bjoern' -t 'csession:26' 'python /home/stefan/dev/psychose/sensors2osc/sensors2osc/socat_ehealth_test.py /tmp/ehealth2osc-bjoern-in'
new-window -n 'test-ehealth-merle' -t 'csession:27' 'python /home/stefan/dev/psychose/sensors2osc/sensors2osc/socat_ehealth_test.py /tmp/ehealth2osc-merle-in' new-window -n 'test-ehealth-merle' -t 'csession:27' 'python /home/stefan/dev/psychose/sensors2osc/sensors2osc/socat_ehealth_test.py /tmp/ehealth2osc-merle-in'
new-window -n 'test-ehealth-uwe' -t 'csession:28' 'python /home/stefan/dev/psychose/sensors2osc/sensors2osc/socat_ehealth_test.py /tmp/ehealth2osc-uwe-in' new-window -n 'test-ehealth-uwe' -t 'csession:28' 'python /home/stefan/dev/psychose/sensors2osc/sensors2osc/socat_ehealth_test.py /tmp/ehealth2osc-uwe-in'
new-window -n 'test-ehealth-bjoern' -t 'csession:26' 'python /home/stefan/dev/psychose/sensors2osc/sensors2osc/socat_ehealth_test.py /tmp/ehealth2osc-bjoern-in'
# new-window -n 'ekgplotter' -t 'csession:29' 'sleep 5 && ekgplotter -s' select-window -t 'csession:2'
# new-window -n 'vlc' -t 'csession:30' 'sleep 10 && vlc "http://localhost:9000/camera.mjpeg"'
#new-window -n 'chaosc_emitter' -t 'csession:31' 'chaosc_emitter'
select-window -t 'csession:1'
set aggressive-resize on set aggressive-resize on

View File

@ -19,63 +19,114 @@
# #
# Copyright (C) 2014 Stefan Kögl # Copyright (C) 2014 Stefan Kögl
from __future__ import absolute_import from __future__ import absolute_import
import os
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from chaosc.argparser_groups import *
from chaosc.lib import logger, resolve_host
from collections import deque
from datetime import datetime
from dump_grabber.dump_grabber_ui import Ui_MainWindow
from os import curdir, sep
from PyKDE4.kdecore import ki18n, KCmdLineArgs, KAboutData
from PyKDE4.kdeui import KMainWindow, KApplication
from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import QBuffer, QByteArray, QIODevice
from SocketServer import ThreadingMixIn, ForkingMixIn
import logging import logging
import numpy as np import os
import os.path import os.path
import Queue import Queue
import random
import re import re
import select import select
import socket import socket
import string
import sys import sys
import threading import threading
import time import time
import traceback
from datetime import datetime
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from chaosc.argparser_groups import *
from chaosc.lib import logger, resolve_host
from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import QBuffer, QByteArray, QIODevice
from dump_grabber.dump_grabber_ui import Ui_MainWindow
try: try:
from chaosc.c_osc_lib import OSCMessage, decode_osc from chaosc.c_osc_lib import OSCMessage, decode_osc
except ImportError as e: except ImportError as e:
from chaosc.osc_lib import OSCMessage, decode_osc from chaosc.osc_lib import OSCMessage, decode_osc
app = QtGui.QApplication([])
class TextStorage(object):
def __init__(self, columns):
super(TextStorage, self).__init__()
self.column_count = columns
self.colors = (QtCore.Qt.red, QtCore.Qt.green, QtGui.QColor(46, 100, 254))
def init_columns(self):
raise NotImplementedError()
def add_text(self, column, text):
raise NotImplementedError()
appName = "dump_grabber" class ColumnTextStorage(TextStorage):
catalog = "dump_grabber" def __init__(self, columns, default_font, column_width, line_height, scene):
programName = ki18n("dump_grabber") super(ColumnTextStorage, self).__init__(columns)
version = "0.1" self.columns = list()
self.default_font = default_font
self.column_width = column_width
self.line_height = line_height
self.graphics_scene = scene
self.num_lines, self.offset = divmod(775, self.line_height)
aboutData = KAboutData(appName, catalog, programName, version) def init_columns(self):
for x in range(self.column_count):
column = list()
color = self.colors[x]
for y in range(self.num_lines):
text_item = self.graphics_scene.addSimpleText("%d:%d" % (x, y), self.default_font)
text_item.setBrush(color)
text_item.setPos(x * self.column_width, y * self.line_height)
column.append(text_item)
self.columns.append(column)
KCmdLineArgs.init (sys.argv, aboutData) def add_text(self, column, text):
text_item = self.graphics_scene.addSimpleText(text, self.default_font)
color = self.colors[column]
text_item.setBrush(color)
app = KApplication() old_item = self.columns[column].pop(0)
self.graphics_scene.removeItem(old_item)
self.columns[column].append(text_item)
for iy, text_item in enumerate(self.columns[column]):
text_item.setPos(column * self.column_width, iy * self.line_height)
fh = logging.FileHandler(os.path.expanduser("~/.chaosc/dump_grabber.log"))
fh.setLevel(logging.DEBUG)
logger.addHandler(fh)
class MainWindow(KMainWindow, Ui_MainWindow): class ExclusiveTextStorage(TextStorage):
def __init__(self, parent=None, columns=3): def __init__(self, columns, default_font, column_width, line_height, scene):
super(ExclusiveTextStorage, self).__init__(columns)
self.column_count = columns
self.lines = list()
self.default_font = default_font
self.column_width = column_width
self.line_height = line_height
self.graphics_scene = scene
self.num_lines, self.offset = divmod(775, self.line_height)
def init_columns(self):
color = self.colors[0]
for y in range(self.num_lines):
text_item = self.graphics_scene.addSimpleText("", self.default_font)
text_item.setBrush(color)
text_item.setPos(0, y * self.line_height)
self.lines.append(text_item)
def add_text(self, column, text):
text_item = self.graphics_scene.addSimpleText(text, self.default_font)
text_item.setX(column * self.column_width)
color = self.colors[column]
text_item.setBrush(color)
old_item = self.lines.pop(0)
self.graphics_scene.removeItem(old_item)
self.lines.append(text_item)
for iy, text_item in enumerate(self.lines):
text_item.setY(iy * self.line_height)
class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None, columns=3, column_exclusive=False):
super(MainWindow, self).__init__(parent) super(MainWindow, self).__init__(parent)
self.setupUi(self) self.setupUi(self)
self.graphics_view.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.graphics_view.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
@ -88,55 +139,27 @@ class MainWindow(KMainWindow, Ui_MainWindow):
self.default_font = QtGui.QFont("Monospace", 14) self.default_font = QtGui.QFont("Monospace", 14)
self.default_font.setStyleHint(QtGui.QFont.Monospace) self.default_font.setStyleHint(QtGui.QFont.Monospace)
self.default_font.setBold(True) self.default_font.setBold(True)
self.blue_color = QtGui.QColor(47,147,235) self.graphics_scene.setFont(self.default_font)
self.font_metrics = QtGui.QFontMetrics(self.default_font) self.font_metrics = QtGui.QFontMetrics(self.default_font)
self.line_height = self.font_metrics.height() self.line_height = self.font_metrics.height()
self.num_lines = 775/self.line_height
self.graphics_scene.setFont(self.default_font)
self.brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
self.brush.setStyle(QtCore.Qt.SolidPattern)
self.column_width = 775 / columns self.column_width = 775 / columns
self.column_count = columns self.text_storage = ExclusiveTextStorage(columns, self.default_font, self.column_width, self.line_height, self.graphics_scene)
self.columns = list() #self.text_storage = ColumnTextStorage(columns, self.default_font, self.column_width, self.line_height, self.graphics_scene)
for i in range(columns): self.text_storage.init_columns()
column = list()
for j in range(self.num_lines):
text_item = self.graphics_scene.addSimpleText("", self.default_font)
if column == 0:
text_item.setBrush(QtCore.Qt.red)
elif column == 1:
text_item.setBrush(QtCore.Qt.green)
elif column == 2:
text_item.setBrush(self.blue_color)
text_item.setPos(j * self.line_height, i * self.column_width)
column.append(text_item)
self.columns.append(column)
self.graphics_view.show()
def add_text(self, column, text): def add_text(self, column, text):
text_item = self.graphics_scene.addSimpleText(text, self.default_font) self.text_storage.add_text(column, text)
if column == 0:
text_item.setBrush(QtCore.Qt.red)
elif column == 1:
text_item.setBrush(QtCore.Qt.green)
elif column == 2:
text_item.setBrush(self.blue_color)
old_item = self.columns[column].pop(0)
self.graphics_scene.removeItem(old_item)
self.columns[column].append(text_item)
for ix, text_item in enumerate(self.columns[column]):
text_item.setPos(column * self.column_width, ix * self.line_height)
def render(self): def render(self):
image = QtGui.QImage(768, 576, QtGui.QImage.Format_ARGB32) image = QtGui.QImage(768, 576, QtGui.QImage.Format_ARGB32_Premultiplied)
image.fill(QtCore.Qt.black) image.fill(QtCore.Qt.black)
painter = QtGui.QPainter(image) painter = QtGui.QPainter(image)
#painter.setPen(QtCore.Qt.white) painter.setRenderHints(QtGui.QPainter.RenderHint(QtGui.QPainter.Antialiasing | QtGui.QPainter.TextAntialiasing), True)
painter.setFont(self.default_font) painter.setFont(self.default_font)
self.graphics_view.render(painter, target=QtCore.QRectF(0,0,768,576),source=QtCore.QRect(0,0,768,576)) self.graphics_view.render(painter, target=QtCore.QRectF(0,0,768,576),source=QtCore.QRect(0,0,768,576))
painter.end()
return image return image
@ -159,17 +182,6 @@ class OSCThread(threading.Thread):
self.subscribe_me() self.subscribe_me()
def subscribe_me(self): 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
"""
logger.info("%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) logger.info("%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 = OSCMessage("/subscribe")
msg.appendTypedArg(self.client_address[0], "s") msg.appendTypedArg(self.client_address[0], "s")
@ -224,7 +236,6 @@ class MyHandler(BaseHTTPRequestHandler):
if self.path=="" or self.path==None or self.path[:1]==".": if self.path=="" or self.path==None or self.path[:1]==".":
self.send_error(403,'Forbidden') self.send_error(403,'Forbidden')
if self.path.endswith(".html"): if self.path.endswith(".html"):
directory = os.path.dirname(os.path.abspath(__file__)) directory = os.path.dirname(os.path.abspath(__file__))
data = open(os.path.join(directory, self.path), "rb").read() data = open(os.path.join(directory, self.path), "rb").read()
@ -244,53 +255,52 @@ class MyHandler(BaseHTTPRequestHandler):
self.end_headers() self.end_headers()
event_loop = QtCore.QEventLoop() event_loop = QtCore.QEventLoop()
last_frame = time.time() - 1.
frame_rate = 16.0
frame_length = 1. / frame_rate
regex = re.compile("^/(uwe|merle|bjoern)/(.*?)$")
while 1: while 1:
event_loop.processEvents() event_loop.processEvents()
app.sendPostedEvents(None, 0) app.sendPostedEvents(None, 0)
while 1: while 1:
try: try:
osc_address, args = queue.get_nowait() osc_address, args = queue.get_nowait()
print osc_address
except Queue.Empty: except Queue.Empty:
break break
else: else:
if "merle" in osc_address: try:
window.add_text(0, "%s = %s" % (osc_address[7:], ", ".join([str(i) for i in args]))) actor, text = regex.match(osc_address).groups()
elif "uwe" in osc_address: if actor == "merle":
window.add_text(1, "%s = %s" % (osc_address[5:], ", ".join([str(i) for i in args]))) window.add_text(0, "%s = %s" % (text, ", ".join([str(i) for i in args])))
elif "bjoern" in osc_address: if actor == "uwe":
window.add_text(2, "%s = %s" % (osc_address[8:], ", ".join([str(i) for i in args]))) window.add_text(1, "%s = %s" % (text, ", ".join([str(i) for i in args])))
if actor == "bjoern":
window.add_text(2, "%s = %s" % (text, ", ".join([str(i) for i in args])))
except AttributeError:
pass
img = window.render() now = time.time()
buffer = QBuffer() delta = now - last_frame
buffer.open(QIODevice.WriteOnly) if delta > frame_length:
img.save(buffer, "JPG", 50) last_frame = now
img.save("/tmp/test.jpg", "JPG", 50) img = window.render()
buffer = QBuffer()
JpegData = buffer.data() buffer.open(QIODevice.WriteOnly)
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)) img.save(buffer, "JPG")
JpegData = buffer.data()
JpegData = None 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))
buffer = None JpegData = None
img = None buffer = None
time.sleep(0.06) img = None
time.sleep(0.01)
elif self.path.endswith(".jpeg"):
directory = os.path.dirname(os.path.abspath(__file__))
data = open(os.path.join(directory, self.path), "rb").read()
self.send_response(200)
self.send_header('Content-type','image/jpeg')
self.end_headers()
self.wfile.write(data)
return return
except (KeyboardInterrupt, SystemError): except (KeyboardInterrupt, SystemError):
#print "queue size", queue.qsize()
if hasattr(self, "thread") and self.thread is not None: if hasattr(self, "thread") and self.thread is not None:
self.thread.running = False self.thread.running = False
self.thread.join() self.thread.join()
self.thread = None self.thread = None
except IOError, e: except IOError, e:
#print "ioerror", e, e[0]
#print dir(e)
if e[0] in (32, 104): if e[0] in (32, 104):
if hasattr(self, "thread") and self.thread is not None: if hasattr(self, "thread") and self.thread is not None:
self.thread.running = False self.thread.running = False
@ -298,11 +308,6 @@ class MyHandler(BaseHTTPRequestHandler):
self.thread = None self.thread = None
else: else:
pass pass
#print '-'*40
#print 'Exception happened during processing of request from'
#traceback.print_exc() # XXX But this goes to stderr!
#print '-'*40
#self.send_error(404,'File Not Found: %s' % self.path)
class JustAHTTPServer(HTTPServer): class JustAHTTPServer(HTTPServer):

View File

@ -24,61 +24,96 @@
from __future__ import absolute_import from __future__ import absolute_import
from datetime import datetime
import threading
import Queue
import traceback
import logging
import numpy as np
import string
import time
import random
import socket
import os.path
from os import curdir, sep
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer 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, QtCore
import pyqtgraph as pg
from pyqtgraph.widgets.PlotWidget import PlotWidget
from chaosc.argparser_groups import * from chaosc.argparser_groups import *
from chaosc.lib import logger, resolve_host from chaosc.lib import logger, resolve_host
from datetime import datetime
from operator import attrgetter
from PyQt4 import QtGui, QtCore
from PyQt4.QtCore import QBuffer, QByteArray, QIODevice
from SocketServer import ThreadingMixIn, ForkingMixIn
import logging
import numpy as np
import os.path
import pyqtgraph as pg
import Queue
import re
import select
import socket
import threading
import time
fh = logging.FileHandler(os.path.expanduser("~/.chaosc/ekgplotter.log"))
fh.setLevel(logging.DEBUG)
logger.addHandler(fh)
try: try:
from chaosc.c_osc_lib import OSCMessage, decode_osc from chaosc.c_osc_lib import OSCMessage, decode_osc
except ImportError as e: except ImportError as e:
print(e) logging.exception(e)
from chaosc.osc_lib import OSCMessage, decode_osc from chaosc.osc_lib import OSCMessage, decode_osc
class Generator(object):
def __init__(self):
self.count = 0
self.max_count = 200
self.min_puls = 75
self.max_pulse = 160
self.pulse = 83
class PlotWindow(PlotWidget): def run(self):
def __init__(self, title=None, **kargs): data_points = 0
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)
min_puls = 70
max_pulse = 130
pulse = random.randint(min_puls, max_pulse)
steps, sleep_time = get_steps(pulse, sleep_time)
count = 0
delta = 1
result = list()
print "pulse", pulse
print "sleep_time", sleep_time
print "steps", steps
while 1:
value = random.randint(0, steps)
if count < int(steps / 100. * 20):
value = random.randint(0,20)
elif count < int(steps / 100. * 30):
value = random.randint(20, 30)
elif count < int(steps / 100. * 40):
value = random.randint(30,100)
elif count < int(steps / 2.):
value = random.randint(100,200)
elif count == int(steps / 2.):
value = 255
elif count < int(steps / 100. * 60):
value = random.randint(100, 200)
elif count < int(steps / 100. * 70):
value = random.randint(50, 100)
elif count < int(steps / 100. * 80):
value = random.randint(20, 50)
elif count <= steps:
value = random.randint(0,20)
elif count >= steps:
count = 0
#if data_points % (5 * steps) == 0:
#print "new steps", steps, delta
#steps += delta
#if steps <= min_steps:
#delta = 1
#elif steps >= max_steps:
#print "change step sign", steps, delta
#delta = -1
time.sleep(sleep_time)
count += 1
#data_points += 1
serial_sock.write(struct.pack("B", value))
class OSCThread(threading.Thread): class OSCThread(threading.Thread):
def __init__(self, args): def __init__(self, args):
@ -94,24 +129,13 @@ class OSCThread(threading.Thread):
self.osc_sock.bind(self.client_address) self.osc_sock.bind(self.client_address)
self.osc_sock.setblocking(0) self.osc_sock.setblocking(0)
print "%s: starting up osc receiver on '%s:%d'" % ( logger.info("%s: starting up osc receiver on '%s:%d'",
datetime.now().strftime("%x %X"), self.client_address[0], self.client_address[1]) datetime.now().strftime("%x %X"), self.client_address[0], self.client_address[1])
self.subscribe_me() self.subscribe_me()
def subscribe_me(self): def subscribe_me(self):
"""Use this procedure for a quick'n dirty subscription to your chaosc instance. logger.info("%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)
: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 = OSCMessage("/subscribe")
msg.appendTypedArg(self.client_address[0], "s") msg.appendTypedArg(self.client_address[0], "s")
msg.appendTypedArg(self.client_address[1], "i") msg.appendTypedArg(self.client_address[1], "i")
@ -125,7 +149,7 @@ class OSCThread(threading.Thread):
if self.args.keep_subscribed: if self.args.keep_subscribed:
return return
print "%s: unsubscribing from '%s:%d'" % (datetime.now().strftime("%x %X"), self.chaosc_address[0], self.chaosc_address[1]) logger.info("%s: unsubscribing from '%s:%d'", datetime.now().strftime("%x %X"), self.chaosc_address[0], self.chaosc_address[1])
msg = OSCMessage("/unsubscribe") msg = OSCMessage("/unsubscribe")
msg.appendTypedArg(self.client_address[0], "s") msg.appendTypedArg(self.client_address[0], "s")
msg.appendTypedArg(self.client_address[1], "i") msg.appendTypedArg(self.client_address[1], "i")
@ -136,9 +160,9 @@ class OSCThread(threading.Thread):
while self.running: while self.running:
try: try:
reads, writes, errs = select.select([self.osc_sock], [], [], 0.01) reads, writes, errs = select.select([self.osc_sock], [], [], 0.005)
except Exception, e: except Exception, e:
print "select error", e logging.exception(e)
pass pass
else: else:
if reads: if reads:
@ -147,107 +171,65 @@ class OSCThread(threading.Thread):
osc_address, typetags, messages = decode_osc(osc_input, 0, len(osc_input)) osc_address, typetags, messages = decode_osc(osc_input, 0, len(osc_input))
queue.put_nowait((osc_address, messages)) queue.put_nowait((osc_address, messages))
except Exception, e: except Exception, e:
print "recvfrom error", e logger.info(e)
else:
queue.put_nowait(("/bjoern/ekg", [0]))
queue.put_nowait(("/merle/ekg", [0]))
queue.put_nowait(("/uwe/ekg", [0]))
self.unsubscribe_me() self.unsubscribe_me()
print "OSCThread is going down" self.osc_sock.close()
logger.info("OSCThread is going down")
queue = Queue.Queue() queue = Queue.Queue()
class Actor(object): class Actor(object):
shadowPen = pg.mkPen(255, 255, 255) def __init__(self, name, num_data, color, ix, max_actors, actor_height):
brush = pg.mkBrush("w")
def __init__(self, name, num_data, color):
self.data = [0] * num_data
self.data_pointer = 0
self.name = name self.name = name
self.active = True
self.plotItem = pg.PlotCurveItem(pen=pg.mkPen(color, width=3), name=name)
self.num_data = num_data self.num_data = num_data
#self.plotItem.setShadowPen(pen=Actor.shadowPen, width=3, cosmetic=True) self.color = color
self.plotPoint = pg.ScatterPlotItem(pen=Actor.shadowPen, brush=self.brush, size=5) self.ix = ix
self.max_actors = max_actors
self.actor_height = actor_height
self.updated = 0
self.offset = ix * actor_height
self.data = np.array([self.offset] * num_data)
self.head = 0
self.pre_head = 0
self.plotItem = pg.PlotCurveItem(pen=pg.mkPen(color, width=3), name=name)
self.plotPoint = pg.ScatterPlotItem(pen=pg.mkPen("w", width=5), brush=pg.mkBrush(color), size=5)
def __str__(self): def __str__(self):
return "<Actor name:%r, active=%r, position=%r>" % (self.name, self.active, self.data_pointer) return "<Actor name:%r, active=%r, position=%r>" % (self.name, self.active, self.head)
__repr__ = __str__ __repr__ = __str__
def scale_data(self, ix, max_items):
scale = 255 / max_items * ix
return [value / max_items + scale for value in self.data]
def set_point(self, value, ix, max_items): def add_value(self, value):
scale = 255 / max_items * ix dp = self.head
self.plotPoint.setData(x = [self.data_pointer], y = [value / max_items + scale]) self.data[dp] = value / self.max_actors + self.offset
self.pre_head = dp
self.head = (dp + 1) % self.num_data
self.updated += 1
#def find_max_value(self, item_data): def fill_missing(self, count):
#max_index = -1 dp = self.head
#for ix, i in enumerate(item_data): for i in range(count):
#if i > 250: self.data[dp] = self.offset
#return ix, i dp = (dp + 1) % self.num_data
#return None, None self.updated += 1
self.pre_head = (dp - 1) % self.num_data
self.head = dp
#def rearrange(self, item_data, actual_pos, max_items): def render(self):
#max_value_index, max_value = find_max_value(item_data) self.plotItem.setData(y=self.data, clear=True)
#if max_value_index is None: self.plotPoint.setData(x=[self.pre_head], y = [self.data[self.pre_head]])
#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(self, value):
self.data[self.data_pointer] = value
self.data_pointer = (self.data_pointer + 1) % self.num_data
#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
class EkgPlot(object): class EkgPlot(object):
def __init__(self, actor_names, num_data, colors): def __init__(self, actor_names, num_data, colors):
self.plot = pg.PlotWidget() self.plot = pg.PlotWidget()
#self.plot.setConfigOptions(antialias=True)
self.plot.hide() self.plot.hide()
#self.plot.show()
#self.plot.setLabel('left', "<h2>Amplitude</h2>")
#self.plot.setLabel('bottom', "<h2><sup>Time</sup></h2>")
self.plot.showGrid(False, False) self.plot.showGrid(False, False)
self.plot.setYRange(0, 255) self.plot.setYRange(0, 255)
self.plot.setXRange(0, num_data) self.plot.setXRange(0, num_data)
@ -265,8 +247,11 @@ class EkgPlot(object):
self.lengths1 = [0] self.lengths1 = [0]
self.num_data = num_data self.num_data = num_data
for actor_name, color in zip(actor_names, colors): self.max_value = 255
self.add_actor(actor_name, num_data, color) self.max_actors = len(actor_names)
self.actor_height = self.max_value / self.max_actors
for ix, (actor_name, color) in enumerate(zip(actor_names, colors)):
self.add_actor(actor_name, num_data, color, ix, self.max_actors, self.actor_height)
self.set_positions() self.set_positions()
@ -275,8 +260,8 @@ class EkgPlot(object):
self.updated_actors = set() self.updated_actors = set()
def add_actor(self, actor_name, num_data, color): def add_actor(self, actor_name, num_data, color, ix, max_actors, actor_height):
actor_obj = Actor(actor_name, num_data, color) actor_obj = Actor(actor_name, num_data, color, ix, max_actors, actor_height)
self.actors[actor_name] = actor_obj self.actors[actor_name] = actor_obj
self.plot.addItem(actor_obj.plotItem) self.plot.addItem(actor_obj.plotItem)
self.plot.addItem(actor_obj.plotPoint) self.plot.addItem(actor_obj.plotPoint)
@ -285,61 +270,43 @@ class EkgPlot(object):
def set_positions(self): def set_positions(self):
for ix, actor_obj in enumerate(self.active_actors): for ix, actor_obj in enumerate(self.active_actors):
actor_obj.plotItem.setPos(0, ix * 6) actor_obj.plotItem.setPos(0, ix * 2)
actor_obj.plotPoint.setPos(0, ix * 6) actor_obj.plotPoint.setPos(0, ix * 2)
def active_actor_count(self): def active_actor_count(self):
return len(self.active_actors) return self.max_actors
def new_round(self):
for ix, actor in enumerate(self.active_actors):
actor.updated = 0
def update_missing_actors(self):
liste = sorted(self.active_actors, key=attrgetter("updated"))
max_values = liste[-1].updated
if max_values == 0:
# handling no signal
for actor in self.active_actors:
actor.add_value(0)
return
for ix, actor in enumerate(self.active_actors):
diff = max_values - actor.updated
if diff > 0:
for i in range(diff):
actor.add_value(0)
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) actor_obj.add_value(value)
actor_data = actor_obj.data
data_pointer = actor_obj.data_pointer
actor_data[data_pointer] = value
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
return
res = self.ctl_regex.match(osc_address)
if res:
print "received cmd", osc_address
actor_name = res.group(1)
actor_obj = self.actors[actor_name]
if value == 1 and not actor_obj.active:
print "actor on", actor_name, self.active_actors
self.plot.addItem(actor_obj.plotItem)
self.plot.addItem(actor_obj.plotPoint)
actor_obj.active = True
if not actor_obj in self.active_actors:
self.active_actors.append(actor_obj)
elif value == 0 and actor_obj.active:
print "actor off", actor_name, 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 "active actors error", e, self.active_actors
pass
assert actor_obj not in self.active_actors
else:
print "internal data not in sync", self.active_actors, actor_obj
self.set_positions() def render(self):
for ix, actor in enumerate(self.active_actors):
actor.render()
class MyHandler(BaseHTTPRequestHandler): class MyHandler(BaseHTTPRequestHandler):
@ -351,7 +318,6 @@ class MyHandler(BaseHTTPRequestHandler):
if self.path=="" or self.path==None or self.path[:1]==".": if self.path=="" or self.path==None or self.path[:1]==".":
self.send_error(403,'Forbidden') self.send_error(403,'Forbidden')
if self.path.endswith(".html"): if self.path.endswith(".html"):
directory = os.path.dirname(os.path.abspath(__file__)) directory = os.path.dirname(os.path.abspath(__file__))
data = open(os.path.join(directory, self.path), "rb").read() data = open(os.path.join(directory, self.path), "rb").read()
@ -363,83 +329,61 @@ class MyHandler(BaseHTTPRequestHandler):
self.thread = thread = OSCThread(self.server.args) self.thread = thread = OSCThread(self.server.args)
thread.daemon = True thread.daemon = True
thread.start() thread.start()
actor_names = ["merle", "bjoern", "uwe"] actor_names = ["merle", "uwe", "bjoern" ]
num_data = 100 num_data = 100
colors = ["r", "g", "b"] colors = ["r", "g", "b"]
qtapp = QtGui.QApplication([]) qtapp = QtGui.QApplication([])
plotter = EkgPlot(actor_names, num_data, colors) plotter = EkgPlot(actor_names, num_data, colors)
self.send_response(200) self.send_response(200)
self.send_header("Content-Type", "multipart/x-mixed-replace; boundary=--aaboundary") self.send_header("Content-Type", "multipart/x-mixed-replace; boundary=--2342")
self.end_headers() self.end_headers()
#lastTime = time.time()
#fps = None
event_loop = QtCore.QEventLoop() event_loop = QtCore.QEventLoop()
last_frame = time.time() - 1.0
frame_rate = 13.0
frame_length = 1. / frame_rate
plotter.new_round()
while 1: while 1:
event_loop.processEvents() event_loop.processEvents()
qtapp.sendPostedEvents(None, 0) qtapp.sendPostedEvents(None, 0)
while 1: while 1:
try: try:
osc_address, args = queue.get_nowait() osc_address, args = queue.get_nowait()
plotter.update(osc_address, args[0])
except Queue.Empty: except Queue.Empty:
break break
else:
plotter.update(osc_address, args[0])
exporter = pg.exporters.ImageExporter.ImageExporter(plotter.plot.plotItem) now = time.time()
exporter.parameters()['width'] = 768 delta = now - last_frame
img = exporter.export("tmpfile", True) if delta > frame_length:
buffer = QBuffer() plotter.update_missing_actors()
buffer.open(QIODevice.WriteOnly) plotter.render()
img.save(buffer, "JPG") exporter = pg.exporters.ImageExporter.ImageExporter(plotter.plot.plotItem)
img.save("/tmp/test2.jpg", "JPG") exporter.parameters()['width'] = 768
img = exporter.export(toBytes=True)
buffer = QBuffer()
buffer.open(QIODevice.WriteOnly)
img.save(buffer, "JPG")
JpegData = buffer.data()
self.wfile.write("--2342\r\nContent-Type: image/jpeg\r\nContent-length: %d\r\n\r\n%s\r\n\r\n\r\n" % (len(JpegData), JpegData))
last_frame = now
plotter.new_round()
#JpegData = None
#buffer = None
#img = None
#exporter = None
time.sleep(0.01)
JpegData = buffer.data() except (KeyboardInterrupt, SystemError), e:
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)) raise e
JpegData = None
buffer = None
img = None
exporter = None
#now = time.time()
#dt = now - lastTime
#lastTime = now
#if fps is None:
#fps = 1.0/dt
#else:
#s = np.clip(dt*3., 0, 1)
#fps = fps * (1-s) + (1.0/dt) * s
#print '%0.2f fps' % fps
time.sleep(0.05)
elif self.path.endswith(".jpeg"):
directory = os.path.dirname(os.path.abspath(__file__))
data = open(os.path.join(directory, self.path), "rb").read()
self.send_response(200)
self.send_header('Content-type','image/jpeg')
self.end_headers()
self.wfile.write(data)
return
except (KeyboardInterrupt, SystemError):
print "queue size", queue.qsize()
if hasattr(self, "thread") and self.thread is not None:
self.thread.running = False
self.thread.join()
self.thread = None
except IOError, e: except IOError, e:
print "ioerror", e, e[0]
print dir(e)
if e[0] in (32, 104): if e[0] in (32, 104):
if hasattr(self, "thread") and self.thread is not None: if hasattr(self, "thread") and self.thread is not None:
self.thread.running = False self.thread.running = False
self.thread.join() self.thread.join()
self.thread = None self.thread = None
else: else:
print '-'*40 pass
print 'Exception happened during processing of request from'
traceback.print_exc() # XXX But this goes to stderr!
print '-'*40
self.send_error(404,'File Not Found: %s' % self.path)
class JustAHTTPServer(HTTPServer): class JustAHTTPServer(HTTPServer):
@ -463,18 +407,15 @@ def main():
server = JustAHTTPServer((http_host, http_port), MyHandler) server = JustAHTTPServer((http_host, http_port), MyHandler)
server.address_family = args.address_family server.address_family = args.address_family
server.args = args server.args = args
print "%s: starting up http server on '%s:%d'" % ( logger.info("%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)
try: try:
server.serve_forever() server.serve_forever()
except KeyboardInterrupt: except KeyboardInterrupt:
print '^C received, shutting down server' logger.info('^C received, shutting down server')
server.socket.close() server.socket.close()
sys.exit(0) sys.exit(0)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@ -25,6 +25,7 @@ import os.path
import serial import serial
import socket import socket
import time import time
import sys
from chaosc.argparser_groups import ArgParser from chaosc.argparser_groups import ArgParser
@ -39,6 +40,7 @@ except ImportError as e:
class Platform(object): class Platform(object):
def __init__(self, args): def __init__(self, args):
self.args = args self.args = args
self.remote = (self.args.chaosc_host, self.args.chaosc_port)
self.serial_sock = None self.serial_sock = None
self.osc_sock = socket.socket(args.address_family, 2, 17) self.osc_sock = socket.socket(args.address_family, 2, 17)
self.osc_sock.connect((self.args.chaosc_host, self.args.chaosc_port)) self.osc_sock.connect((self.args.chaosc_host, self.args.chaosc_port))
@ -78,10 +80,10 @@ def create_args(name):
arg_parser = ArgParser(name) arg_parser = ArgParser(name)
arg_parser.add_global_group() arg_parser.add_global_group()
main_group = arg_parser.add_argument_group("main") main_group = arg_parser.add_argument_group("main")
arg_parser.add_argument(main_group, "-D", '--device', required=True, arg_parser.add_argument(main_group, "-D", '--device',
type=str, help='device node under /dev') help='device node under /dev')
arg_parser.add_argument(main_group, "-a", '--actor', required=True, arg_parser.add_argument(main_group, "-a", '--actor',
type=str, help='actor name') help='actor name')
arg_parser.add_argument(main_group, '-b', '--baudrate', type=int, default=115200, choices=sorted(serial.baudrate_constants.keys()), arg_parser.add_argument(main_group, '-b', '--baudrate', type=int, default=115200, choices=sorted(serial.baudrate_constants.keys()),
help='selects the baudrate, default=115200, for valid values execute "import serial;print sorted(serial.baudrate_constants.keys())"') help='selects the baudrate, default=115200, for valid values execute "import serial;print sorted(serial.baudrate_constants.keys())"')
arg_parser.add_chaosc_group() arg_parser.add_chaosc_group()
@ -90,8 +92,8 @@ def create_args(name):
return args return args
def init(name): def init():
args = create_args(name) args = create_args(os.path.basename(sys.argv[0]))
platform = Platform(args) platform = Platform(args)
platform.connect() platform.connect()
atexit.register(platform.close) atexit.register(platform.close)

View File

@ -21,11 +21,11 @@
from __future__ import absolute_import from __future__ import absolute_import
from sensors2osc.common import * from sensors2osc.common import *
import time, select import time, select, sys
def main(): def main():
platform = init("ehealth2osc") platform = init()
actor = platform.args.actor actor = platform.args.actor
@ -42,7 +42,7 @@ def main():
print "serial socket error!!!", msg print "serial socket error!!!", msg
platform.reconnect() platform.reconnect()
print "got data", repr(data) print "data", repr(data)
try: try:
airFlow, emg, temp = data.split(";") airFlow, emg, temp = data.split(";")
except ValueError, e: except ValueError, e:
@ -58,7 +58,7 @@ def main():
try: try:
osc_message = OSCMessage("/%s/airFlow" % actor) osc_message = OSCMessage("/%s/airFlow" % actor)
osc_message.appendTypedArg(airFlow, "i") osc_message.appendTypedArg(airFlow, "i")
platform.osc_sock.sendall(osc_message.encode_osc()) platform.osc_sock.sendto(osc_message.encode_osc(), platform.remote)
except socket.error, msg: except socket.error, msg:
print "cannot connect to chaosc", msg print "cannot connect to chaosc", msg
continue continue
@ -73,7 +73,7 @@ def main():
try: try:
osc_message = OSCMessage("/%s/emg" % actor) osc_message = OSCMessage("/%s/emg" % actor)
osc_message.appendTypedArg(emg, "i") osc_message.appendTypedArg(emg, "i")
platform.osc_sock.sendall(osc_message.encode_osc()) platform.osc_sock.sendto(osc_message.encode_osc(), platform.remote)
except socket.error, msg: except socket.error, msg:
print "cannot connect to chaosc", msg print "cannot connect to chaosc", msg
continue continue
@ -88,7 +88,7 @@ def main():
try: try:
osc_message = OSCMessage("/%s/temperatur" % actor) osc_message = OSCMessage("/%s/temperatur" % actor)
osc_message.appendTypedArg(temp, "i") osc_message.appendTypedArg(temp, "i")
platform.osc_sock.sendall(osc_message.encode_osc()) platform.osc_sock.sendto(osc_message.encode_osc(), platform.remote)
except socket.error, msg: except socket.error, msg:
print "cannot connect to chaosc", msg print "cannot connect to chaosc", msg
continue continue

View File

@ -20,27 +20,30 @@
from __future__ import absolute_import from __future__ import absolute_import
import time, select import time, select, sys
from sensors2osc.common import * from sensors2osc.common import *
from chaosc.lib import logger
def main(): def main():
platform = init("ekg2osc") platform = init()
actor = platform.args.actor actor = platform.args.actor
msg_count = 0
while 1: while 1:
try: try:
toread, towrite, toerrors = select.select([platform.serial_sock], [],[], 0.05) toread, towrite, toerrors = select.select([platform.serial_sock], [],[], 0.01)
if toread: if toread:
t = platform.serial_sock.read(1) t = platform.serial_sock.read(1)
else: else:
continue continue
except (socket.error, serial.serialutil.SerialException), msg: except (socket.error, serial.serialutil.SerialException), msg:
# got disconnected? # got disconnected?
print "serial socket error!!!", msg logger.exception(msg)
logger.info("serial socket error!!! - try to reconnect")
platform.reconnect() platform.reconnect()
try: try:
@ -48,17 +51,21 @@ def main():
except TypeError, e: except TypeError, e:
continue continue
if msg_count >= 20:
logger.info("value = %d", t)
msg_count = 0
else:
msg_count += 1
try: try:
print "got value", t
osc_message = OSCMessage("/%s/ekg" % actor) osc_message = OSCMessage("/%s/ekg" % actor)
osc_message.appendTypedArg(t, "i") osc_message.appendTypedArg(t, "i")
platform.osc_sock.sendall(osc_message.encode_osc()) platform.osc_sock.sendto(osc_message.encode_osc(), platform.remote)
except socket.error, msg: except socket.error, msg:
print "cannot connect to chaosc" logger.info("ekg2osc error")
logger.exception(msg)
continue continue
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@ -20,7 +20,7 @@
from __future__ import absolute_import from __future__ import absolute_import
import time, select import time, select, sys
from datetime import datetime from datetime import datetime
from sensors2osc.common import * from sensors2osc.common import *
@ -61,7 +61,7 @@ class RingBuffer(object):
def main(): def main():
platform = init("pulse2osc") platform = init()
actor = platform.args.actor actor = platform.args.actor
@ -102,7 +102,7 @@ def main():
osc_message.appendTypedArg(1, "i") osc_message.appendTypedArg(1, "i")
osc_message.appendTypedArg(heart_rate, "i") osc_message.appendTypedArg(heart_rate, "i")
osc_message.appendTypedArg(o2, "i") osc_message.appendTypedArg(o2, "i")
platform.osc_sock.sendall(osc_message.encode_osc()) platform.osc_sock.sendto(osc_message.encode_osc(), platform.remote)
print "on heartbeat", datetime.now(), heart_signal, heart_rate, o2, pulse print "on heartbeat", datetime.now(), heart_signal, heart_rate, o2, pulse
except socket.error, msg: except socket.error, msg:
print "cannot connect to chaosc" print "cannot connect to chaosc"
@ -115,7 +115,7 @@ def main():
osc_message.appendTypedArg(0, "i") osc_message.appendTypedArg(0, "i")
osc_message.appendTypedArg(heart_rate, "i") osc_message.appendTypedArg(heart_rate, "i")
osc_message.appendTypedArg(o2, "i") osc_message.appendTypedArg(o2, "i")
platform.osc_sock.sendall(osc_message.encode_osc()) platform.osc_sock.sendto(osc_message.encode_osc(), platform.remote)
except socket.error, msg: except socket.error, msg:
print "cannot connect to chaosc" print "cannot connect to chaosc"
continue continue

View File

@ -23,6 +23,14 @@
import serial, sys, time, random, struct import serial, sys, time, random, struct
def get_steps(pulse_rate, rate):
beat_length = 60. / pulse_rate
steps_pre = int(beat_length / rate) + 1
used_sleep_time = beat_length / steps_pre
steps = int(beat_length / used_sleep_time)
return steps, used_sleep_time
serial_sock = serial.Serial() serial_sock = serial.Serial()
serial_sock.port = sys.argv[1] serial_sock.port = sys.argv[1]
serial_sock.baudrate = 115200 serial_sock.baudrate = 115200
@ -31,40 +39,57 @@ serial_sock.open()
data_points = 0 data_points = 0
min_steps = 17 sleep_time = 0.04
max_steps = 43
steps = random.randint(17,43) min_puls = 70
max_pulse = 130
pulse = random.randint(min_puls, max_pulse)
steps, sleep_time = get_steps(pulse, sleep_time)
count = 0 count = 0
delta = 1 delta = 1
result = list() result = list()
print "pulse", pulse
print "sleep_time", sleep_time
print "steps", steps
while 1: while 1:
value = random.randint(0, steps) value = random.randint(0, steps)
if count < int(steps / 100. * 20): if count < int(steps / 100. * 20):
value = random.randint(0,20) value = random.randint(0,20)
elif count < int(steps / 100. * 30):
value = random.randint(20, 30)
elif count < int(steps / 100. * 40):
value = random.randint(30,100)
elif count < int(steps / 2.): elif count < int(steps / 2.):
value = random.randint(20,50) value = random.randint(100,200)
elif count == int(steps / 2.): elif count == int(steps / 2.):
value = 255 value = 255
elif count < int(steps / 100. * 60):
value = random.randint(100, 200)
elif count < int(steps / 100. * 70): elif count < int(steps / 100. * 70):
value = random.randint(20,50) value = random.randint(50, 100)
elif count < int(steps / 100. * 80):
value = random.randint(20, 50)
elif count <= steps: elif count <= steps:
value = random.randint(0,20) value = random.randint(0,20)
elif count >= steps: elif count >= steps:
count = 0 count = 0
if data_points % (5 * steps) == 0: #if data_points % (5 * steps) == 0:
print "new steps", steps, delta #print "new steps", steps, delta
steps += delta #steps += delta
if steps <= min_steps: #if steps <= min_steps:
delta = 1 #delta = 1
elif steps >= max_steps: #elif steps >= max_steps:
print "change step sign", steps, delta #print "change step sign", steps, delta
delta = -1 #delta = -1
time.sleep(0.02) time.sleep(sleep_time)
count += 1 count += 1
data_points += 1 #data_points += 1
serial_sock.write(struct.pack("B", value)) serial_sock.write(struct.pack("B", value))

View File

@ -31,11 +31,18 @@ setup(
# predefined extension points, e.g. for plugins # predefined extension points, e.g. for plugins
entry_points = """ entry_points = """
[console_scripts] [console_scripts]
sensors2osc = sensors2osc.main:main
sensorTest = sensors2osc.sensorTest:main
ekg2osc = sensors2osc.ekg2osc:main ekg2osc = sensors2osc.ekg2osc:main
ekgmerle = sensors2osc.ekg2osc:main
ekguwe = sensors2osc.ekg2osc:main
ekgbjoern = sensors2osc.ekg2osc:main
pulse2osc = sensors2osc.pulse2osc:main pulse2osc = sensors2osc.pulse2osc:main
pulsemerle = sensors2osc.pulse2osc:main
pulseuwe = sensors2osc.pulse2osc:main
pulsebjoern = sensors2osc.pulse2osc:main
ehealth2osc = sensors2osc.ehealth2osc:main ehealth2osc = sensors2osc.ehealth2osc:main
ehealthmerle = sensors2osc.ehealth2osc:main
ehealthuwe = sensors2osc.ehealth2osc:main
ehealthbjoern = sensors2osc.ehealth2osc:main
""", """,
# pypi metadata # pypi metadata
author = "Stefan Kögl", author = "Stefan Kögl",

View File

@ -1,2 +1,2 @@
pyuic4 -o texter_ui.py texter3.ui pyuic4 -o texter_ui.py texter3.ui
# pykdeuic4-python2.7 -o text_sorter_ui.py texter4.ui pyuic4 -o text_sorter_ui.py texter4.ui

View File

@ -71,6 +71,10 @@ class TextSorterDialog(QtGui.QWidget, Ui_TextSorterDialog):
def fill_list(self): def fill_list(self):
self.model = self.parent().parent().model self.model = self.parent().parent().model
self.text_list.setModel(self.model) self.text_list.setModel(self.model)
ix = self.parent().parent().current_index
index = self.model.index(ix, 0)
self.text_list.setCurrentIndex(index)
def slot_text_up(self): def slot_text_up(self):
row = self.text_list.currentIndex().row() row = self.text_list.currentIndex().row()
@ -81,6 +85,7 @@ class TextSorterDialog(QtGui.QWidget, Ui_TextSorterDialog):
text_db[row-1], text_db[row] = text_db[row], text_db[row-1] text_db[row-1], text_db[row] = text_db[row], text_db[row-1]
self.text_list.setCurrentIndex(self.model.index(row - 1, 0)) self.text_list.setCurrentIndex(self.model.index(row - 1, 0))
self.text_list.clicked.emit(self.model.index(row - 1, 0)) self.text_list.clicked.emit(self.model.index(row - 1, 0))
self.parent().parent().db_dirty = True
return True return True
def slot_text_down(self): def slot_text_down(self):
@ -93,6 +98,7 @@ class TextSorterDialog(QtGui.QWidget, Ui_TextSorterDialog):
index = self.model.index(row + 1, 0) index = self.model.index(row + 1, 0)
self.text_list.setCurrentIndex(index) self.text_list.setCurrentIndex(index)
self.text_list.clicked.emit(index) self.text_list.clicked.emit(index)
self.parent().parent().db_dirty = True
return True return True
def slot_show_text(self, model_index): def slot_show_text(self, model_index):
@ -108,6 +114,7 @@ class TextSorterDialog(QtGui.QWidget, Ui_TextSorterDialog):
index = self.model.index(0, 0) index = self.model.index(0, 0)
self.text_list.setCurrentIndex(index) self.text_list.setCurrentIndex(index)
self.text_list.clicked.emit(index) self.text_list.clicked.emit(index)
self.parent().parent().db_dirty = True
class FadeAnimation(QtCore.QObject): class FadeAnimation(QtCore.QObject):
animation_started = QtCore.pyqtSignal() animation_started = QtCore.pyqtSignal()
@ -120,8 +127,8 @@ class FadeAnimation(QtCore.QObject):
self.fade_steps = fade_steps self.fade_steps = fade_steps
self.current_alpha = 255 self.current_alpha = 255
self.timer = None self.timer = None
def start_animation(self): def start_animation(self):
print "start_animation" print "start_animation"
self.animation_started.emit() self.animation_started.emit()
@ -165,7 +172,6 @@ class FadeAnimation(QtCore.QObject):
self.animation_finished.emit() self.animation_finished.emit()
print "animation_finished" print "animation_finished"
class TextAnimation(QtCore.QObject): class TextAnimation(QtCore.QObject):
animation_started = QtCore.pyqtSignal() animation_started = QtCore.pyqtSignal()
@ -245,6 +251,7 @@ class TextAnimation(QtCore.QObject):
try: try:
char = self.text.next() char = self.text.next()
self.dst_cursor.insertText(char) self.dst_cursor.insertText(char)
self.dst_text_edit.ensureCursorVisible()
except StopIteration: except StopIteration:
self.fragment_iter += 1 self.fragment_iter += 1
self.text = None self.text = None
@ -287,11 +294,14 @@ class MainWindow(KMainWindow, Ui_MainWindow):
self.db_dirty = False self.db_dirty = False
self.is_animate = False self.is_animate = False
self.fade_animation = None self.fade_animation = None
self.dialog = None
self.current_object = None
self.current_index = -1
self.is_auto_publish = False self.is_auto_publish = False
self.setupUi(self) self.setupUi(self)
self.fade_animation = FadeAnimation(self.live_text, 6, self) self.fade_animation = FadeAnimation(self.live_text, 6, self)
self.font = QtGui.QFont("monospace", self.default_size) self.font = QtGui.QFont("monospace", self.default_size)
@ -321,7 +331,6 @@ class MainWindow(KMainWindow, Ui_MainWindow):
self.publish_action.triggered.connect(self.slot_publish) self.publish_action.triggered.connect(self.slot_publish)
self.clear_live_action.triggered.connect(self.slot_clear_live) self.clear_live_action.triggered.connect(self.slot_clear_live)
self.clear_preview_action.triggered.connect(self.slot_clear_preview) self.clear_preview_action.triggered.connect(self.slot_clear_preview)
#self.remove_item_button.triggered.connect(self.slot_removeItem)
self.text_combo.triggered[int].connect(self.slot_load_preview_text) self.text_combo.triggered[int].connect(self.slot_load_preview_text)
app.focusChanged.connect(self.focusChanged) app.focusChanged.connect(self.focusChanged)
@ -334,7 +343,7 @@ class MainWindow(KMainWindow, Ui_MainWindow):
self.preview_size_action.triggered[QtGui.QAction].connect(self.slot_preview_font_size) self.preview_size_action.triggered[QtGui.QAction].connect(self.slot_preview_font_size)
self.live_size_action.triggered[QtGui.QAction].connect(self.slot_live_font_size) self.live_size_action.triggered[QtGui.QAction].connect(self.slot_live_font_size)
self.fade_action.triggered.connect(self.slot_fade) #self.fade_action.triggered.connect(self.slot_fade)
self.next_action.triggered.connect(self.slot_next_item) self.next_action.triggered.connect(self.slot_next_item)
self.previous_action.triggered.connect(self.slot_previous_item) self.previous_action.triggered.connect(self.slot_previous_item)
@ -365,6 +374,7 @@ class MainWindow(KMainWindow, Ui_MainWindow):
"format_font_family", "format_font_family",
#"format_font_size", #"format_font_size",
"format_text_background_color", "format_text_background_color",
"format_list_style",
"format_list_indent_more", "format_list_indent_more",
"format_list_indent_less", "format_list_indent_less",
"format_text_bold", "format_text_bold",
@ -372,7 +382,7 @@ class MainWindow(KMainWindow, Ui_MainWindow):
"format_text_strikeout", "format_text_strikeout",
"format_text_italic", "format_text_italic",
"format_align_right", "format_align_right",
"format_align_justify", #"format_align_justify",
"manage_link", "manage_link",
"format_text_subscript", "format_text_subscript",
"format_text_superscript", "format_text_superscript",
@ -381,6 +391,7 @@ class MainWindow(KMainWindow, Ui_MainWindow):
for action in self.live_editor_collection.actions(): for action in self.live_editor_collection.actions():
text = str(action.objectName()) text = str(action.objectName())
print "text", text
if text in disabled_action_names: if text in disabled_action_names:
action.setVisible(False) action.setVisible(False)
@ -494,12 +505,12 @@ class MainWindow(KMainWindow, Ui_MainWindow):
spacer = KToolBarSpacerAction(self.action_collection) spacer = KToolBarSpacerAction(self.action_collection)
self.action_collection.addAction("1_spacer", spacer) self.action_collection.addAction("1_spacer", spacer)
self.fade_action = self.action_collection.addAction("fade_action") #self.fade_action = self.action_collection.addAction("fade_action")
#icon = QtGui.QIcon.fromTheme(_fromUtf8("go-previous-view-page")) ##icon = QtGui.QIcon.fromTheme(_fromUtf8("go-previous-view-page"))
#self.fade_action.setIcon(icon) ##self.fade_action.setIcon(icon)
self.fade_action.setIconText("fade") #self.fade_action.setIconText("fade")
self.fade_action.setShortcut(KShortcut(QtGui.QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_F)), KAction.ShortcutTypes(KAction.ActiveShortcut | KAction.DefaultShortcut)) #self.fade_action.setShortcut(KShortcut(QtGui.QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_F)), KAction.ShortcutTypes(KAction.ActiveShortcut | KAction.DefaultShortcut))
self.previous_action = self.action_collection.addAction("previous_action") self.previous_action = self.action_collection.addAction("previous_action")
icon = QtGui.QIcon.fromTheme(_fromUtf8("go-previous-view-page")) icon = QtGui.QIcon.fromTheme(_fromUtf8("go-previous-view-page"))
@ -548,7 +559,7 @@ class MainWindow(KMainWindow, Ui_MainWindow):
public_rect = self.live_text.geometry() public_rect = self.live_text.geometry()
global_rect = QtCore.QRect(self.mapToGlobal(public_rect.topLeft()), self.mapToGlobal(public_rect.bottomRight())) global_rect = QtCore.QRect(self.mapToGlobal(public_rect.topLeft()), self.mapToGlobal(public_rect.bottomRight()))
self.ffserver = subprocess.Popen("ffserver -f /etc/ffserver.conf", shell=True, close_fds=True) self.ffserver = subprocess.Popen("ffserver -f /etc/ffserver.conf", shell=True, close_fds=True)
self.ffmpeg = subprocess.Popen("ffmpeg -f x11grab -s 768x576 -r 30 -i :0.0+%d,%d -vcodec mjpeg -pix_fmt yuvj444p -r 30 -aspect 4:3 http://localhost:8090/webcam.ffm" % (global_rect.x()+5, global_rect.y()+5), shell=True, close_fds=True) self.ffmpeg = subprocess.Popen("ffmpeg -f x11grab -show_region 1 -s 768x576 -r 30 -i :0.0+%d,%d -vcodec mjpeg -pix_fmt yuvj444p -r 30 -aspect 4:3 http://localhost:8090/webcam.ffm" % (global_rect.x()+3, global_rect.y()+3), shell=True, close_fds=True)
self.is_streaming = True self.is_streaming = True
def focusChanged(self, old, new): def focusChanged(self, old, new):
@ -602,13 +613,6 @@ class MainWindow(KMainWindow, Ui_MainWindow):
pass pass
def slot_toggleToolbox(self, index):
if index == 0:
self.toolBar.setEnabled(True)
else:
self.toolBar.setEnabled(False)
def slot_publish(self): def slot_publish(self):
if self.is_animate: if self.is_animate:
self.animation.start_animation(self.preview_text, self.live_text, 0) self.animation.start_animation(self.preview_text, self.live_text, 0)
@ -645,7 +649,6 @@ class MainWindow(KMainWindow, Ui_MainWindow):
self.preview_size_action.setFontSize(self.default_size) self.preview_size_action.setFontSize(self.default_size)
self.preview_text.document().setDefaultFont(self.font) self.preview_text.document().setDefaultFont(self.font)
def slot_set_live_defaults(self): def slot_set_live_defaults(self):
self.live_center_action.setChecked(True) self.live_center_action.setChecked(True)
self.live_text.alignCenter() self.live_text.alignCenter()
@ -653,42 +656,35 @@ class MainWindow(KMainWindow, Ui_MainWindow):
self.live_size_action.setFontSize(self.default_size) self.live_size_action.setFontSize(self.default_size)
self.live_text.document().setDefaultFont(self.font) self.live_text.document().setDefaultFont(self.font)
def slot_clear_live(self): def slot_clear_live(self):
self.live_text.clear() self.live_text.clear()
self.slot_set_live_defaults() self.slot_set_live_defaults()
def slot_clear_preview(self): def slot_clear_preview(self):
self.preview_text.clear() self.preview_text.clear()
self.slot_set_preview_defaults() self.slot_set_preview_defaults()
def slot_fade(self): def slot_fade(self):
if self.fade_animation.timer is None: if self.fade_animation.timer is None:
self.fade_animation.start_animation() self.fade_animation.start_animation()
def fill_combo_box(self): def fill_combo_box(self):
if self.dialog is not None:
self.dialog.deleteLater()
self.dialog = None
self.text_combo.clear() self.text_combo.clear()
for preview, text in self.model.text_db: current_row = -1
for ix, list_obj in enumerate(self.model.text_db):
preview, text = list_obj
self.text_combo.addAction(preview) self.text_combo.addAction(preview)
if list_obj == self.current_object:
current_row = ix
self.text_combo.setCurrentItem(0) if current_row == -1:
self.slot_load_preview_text(0) current_row = self.current_index
self.slot_load_preview_text(current_row)
self.text_combo.setCurrentItem(current_row)
def slot_removeItem(self):
text = self.edit_item_selection.currentText()
index = self.edit_item_selection.currentIndex()
title = text.split(": ")[1]
del self.items[title]
self.edit_item_selection.removeItem(index)
new_index = self.edit_item_selection.currentIndex()
if new_index != -1:
self.slot_editLoadItem()
else:
self.item_title.clear()
self.item_position_input.setValue(0)
def slot_load_preview_text(self, index): def slot_load_preview_text(self, index):
try: try:
@ -699,7 +695,6 @@ class MainWindow(KMainWindow, Ui_MainWindow):
if self.is_auto_publish: if self.is_auto_publish:
self.slot_publish() self.slot_publish()
def slot_save_live_text(self): def slot_save_live_text(self):
text = self.live_text.toHtml() text = self.live_text.toHtml()
preview = self.get_preview_text(unicode(self.live_text.toPlainText())) preview = self.get_preview_text(unicode(self.live_text.toPlainText()))
@ -754,6 +749,12 @@ class MainWindow(KMainWindow, Ui_MainWindow):
def slot_open_dialog(self): def slot_open_dialog(self):
self.current_index = self.text_combo.currentItem()
self.current_object = self.model.text_db[self.current_index]
if self.dialog is not None:
self.dialog.deleteLater()
self.dialog = None
self.dialog = KDialog(self) self.dialog = KDialog(self)
self.dialog_widget = TextSorterDialog(self.dialog) self.dialog_widget = TextSorterDialog(self.dialog)
self.dialog.setMainWidget(self.dialog_widget) self.dialog.setMainWidget(self.dialog_widget)
@ -766,8 +767,6 @@ class MainWindow(KMainWindow, Ui_MainWindow):
#self.dialog.setFixedSize(x, global_height-40) #self.dialog.setFixedSize(x, global_height-40)
self.dialog.okClicked.connect(self.fill_combo_box) self.dialog.okClicked.connect(self.fill_combo_box)
self.dialog.exec_() self.dialog.exec_()
self.dialog.deleteLater()
self.dialog = None
def slot_load(self): def slot_load(self):
path = os.path.expanduser("~/.texter") path = os.path.expanduser("~/.texter")

View File

@ -19,6 +19,8 @@ class TextModel(QtCore.QAbstractTableModel):
return 2 return 2
def data(self, index, role): def data(self, index, role):
if role not in (1,3,4,5,6,7,8,9,10,13):
print "role", role
if not index.isValid() or \ if not index.isValid() or \
not 0 <= index.row() < self.rowCount(): not 0 <= index.row() < self.rowCount():
return QVariant() return QVariant()
@ -28,6 +30,10 @@ class TextModel(QtCore.QAbstractTableModel):
if role == QtCore.Qt.DisplayRole: if role == QtCore.Qt.DisplayRole:
return self.text_db[row][column] return self.text_db[row][column]
#return "foo bar" #return "foo bar"
elif role == QtCore.Qt.ForegroundRole:
return QtGui.QBrush(QtCore.Qt.black)
elif role == QtCore.Qt.BackgroundRole:
return QtGui.QBrush(QtCore.Qt.white)
return QtCore.QVariant() return QtCore.QVariant()
@ -43,7 +49,11 @@ class TextModel(QtCore.QAbstractTableModel):
def setData(self, index, value, role): def setData(self, index, value, role):
if role == QtCore.Qt.EditRole: if role == QtCore.Qt.EditRole:
self.text_db[index.row()][index.column()] = value.toString() text = value.toString()
if not text:
return False
else:
self.text_db[index.row()][index.column()] = text
return True return True

View File

@ -1,11 +1,12 @@
#!/usr/bin/env python # -*- coding: utf-8 -*-
# coding=UTF-8
# Form implementation generated from reading ui file 'texter4.ui'
# #
# Generated by pykdeuic4 from texter4.ui on Mon Apr 21 01:34:50 2014 # Created: Mon Apr 28 21:58:51 2014
# by: PyQt4 UI code generator 4.10.3
# #
# WARNING! All changes to this file will be lost. # WARNING! All changes made in this file will be lost!
from PyKDE4 import kdecore
from PyKDE4 import kdeui
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
try: try:
@ -39,44 +40,6 @@ class Ui_TextSorterDialog(object):
self.text_list.setSizePolicy(sizePolicy) self.text_list.setSizePolicy(sizePolicy)
self.text_list.setMinimumSize(QtCore.QSize(200, 576)) self.text_list.setMinimumSize(QtCore.QSize(200, 576))
self.text_list.setMaximumSize(QtCore.QSize(16777215, 576)) self.text_list.setMaximumSize(QtCore.QSize(16777215, 576))
palette = QtGui.QPalette()
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
brush.setStyle(QtCore.Qt.SolidPattern)
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.WindowText, brush)
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
brush.setStyle(QtCore.Qt.SolidPattern)
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Text, brush)
brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
brush.setStyle(QtCore.Qt.SolidPattern)
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Base, brush)
brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
brush.setStyle(QtCore.Qt.SolidPattern)
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Window, brush)
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
brush.setStyle(QtCore.Qt.SolidPattern)
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.WindowText, brush)
brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
brush.setStyle(QtCore.Qt.SolidPattern)
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Text, brush)
brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
brush.setStyle(QtCore.Qt.SolidPattern)
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Base, brush)
brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
brush.setStyle(QtCore.Qt.SolidPattern)
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Window, brush)
brush = QtGui.QBrush(QtGui.QColor(128, 125, 123))
brush.setStyle(QtCore.Qt.SolidPattern)
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.WindowText, brush)
brush = QtGui.QBrush(QtGui.QColor(128, 125, 123))
brush.setStyle(QtCore.Qt.SolidPattern)
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Text, brush)
brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
brush.setStyle(QtCore.Qt.SolidPattern)
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Base, brush)
brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
brush.setStyle(QtCore.Qt.SolidPattern)
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Window, brush)
self.text_list.setPalette(palette)
self.text_list.setObjectName(_fromUtf8("text_list")) self.text_list.setObjectName(_fromUtf8("text_list"))
self.text_preview = KRichTextWidget(self.splitter) self.text_preview = KRichTextWidget(self.splitter)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
@ -250,7 +213,7 @@ class Ui_TextSorterDialog(object):
QtCore.QMetaObject.connectSlotsByName(TextSorterDialog) QtCore.QMetaObject.connectSlotsByName(TextSorterDialog)
def retranslateUi(self, TextSorterDialog): def retranslateUi(self, TextSorterDialog):
TextSorterDialog.setWindowTitle(kdecore.i18n(_fromUtf8("Form"))) TextSorterDialog.setWindowTitle(_translate("TextSorterDialog", "Form", None))
self.remove_button.setText(kdecore.i18n(_fromUtf8("Remove"))) self.remove_button.setText(_translate("TextSorterDialog", "Remove", None))
from PyKDE4.kdeui import KButtonGroup, KArrowButton, KPushButton, KRichTextWidget from PyKDE4.kdeui import KButtonGroup, KArrowButton, KPushButton, KRichTextWidget

View File

@ -90,13 +90,13 @@
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>775</width> <width>775</width>
<height>578</height> <height>582</height>
</size> </size>
</property> </property>
<property name="maximumSize"> <property name="maximumSize">
<size> <size>
<width>775</width> <width>775</width>
<height>578</height> <height>582</height>
</size> </size>
</property> </property>
<property name="palette"> <property name="palette">
@ -233,7 +233,7 @@
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextEditable|Qt::TextEditorInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> <set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextEditable|Qt::TextEditorInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property> </property>
<property name="richTextSupport"> <property name="richTextSupport">
<set>KRichTextWidget::SupportAlignment|KRichTextWidget::SupportChangeListStyle|KRichTextWidget::SupportFontFamily|KRichTextWidget::SupportFontSize|KRichTextWidget::SupportIndentLists|KRichTextWidget::SupportTextForegroundColor</set> <set>KRichTextWidget::SupportAlignment|KRichTextWidget::SupportFontFamily|KRichTextWidget::SupportFontSize|KRichTextWidget::SupportTextForegroundColor</set>
</property> </property>
</widget> </widget>
</item> </item>
@ -248,13 +248,13 @@
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>300</width> <width>300</width>
<height>577</height> <height>582</height>
</size> </size>
</property> </property>
<property name="maximumSize"> <property name="maximumSize">
<size> <size>
<width>769</width> <width>775</width>
<height>577</height> <height>582</height>
</size> </size>
</property> </property>
<property name="palette"> <property name="palette">

View File

@ -38,124 +38,6 @@
<height>576</height> <height>576</height>
</size> </size>
</property> </property>
<property name="palette">
<palette>
<active>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="Text">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="Text">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>128</red>
<green>125</green>
<blue>123</blue>
</color>
</brush>
</colorrole>
<colorrole role="Text">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>128</red>
<green>125</green>
<blue>123</blue>
</color>
</brush>
</colorrole>
<colorrole role="Base">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
<colorrole role="Window">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
</widget> </widget>
<widget class="KRichTextWidget" name="text_preview"> <widget class="KRichTextWidget" name="text_preview">
<property name="sizePolicy"> <property name="sizePolicy">

View File

@ -57,8 +57,8 @@ class Ui_MainWindow(object):
self.horizontalLayout = QtGui.QHBoxLayout() self.horizontalLayout = QtGui.QHBoxLayout()
self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout")) self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout"))
self.live_text = KRichTextWidget(self.centralwidget) self.live_text = KRichTextWidget(self.centralwidget)
self.live_text.setMinimumSize(QtCore.QSize(775, 578)) self.live_text.setMinimumSize(QtCore.QSize(775, 582))
self.live_text.setMaximumSize(QtCore.QSize(775, 578)) self.live_text.setMaximumSize(QtCore.QSize(775, 582))
palette = QtGui.QPalette() palette = QtGui.QPalette()
brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
brush.setStyle(QtCore.Qt.SolidPattern) brush.setStyle(QtCore.Qt.SolidPattern)
@ -111,8 +111,8 @@ class Ui_MainWindow(object):
sizePolicy.setVerticalStretch(0) sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.preview_text.sizePolicy().hasHeightForWidth()) sizePolicy.setHeightForWidth(self.preview_text.sizePolicy().hasHeightForWidth())
self.preview_text.setSizePolicy(sizePolicy) self.preview_text.setSizePolicy(sizePolicy)
self.preview_text.setMinimumSize(QtCore.QSize(300, 577)) self.preview_text.setMinimumSize(QtCore.QSize(300, 582))
self.preview_text.setMaximumSize(QtCore.QSize(769, 577)) self.preview_text.setMaximumSize(QtCore.QSize(769, 582))
palette = QtGui.QPalette() palette = QtGui.QPalette()
brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
brush.setStyle(QtCore.Qt.SolidPattern) brush.setStyle(QtCore.Qt.SolidPattern)