ether2any/tunnel/qrnet/qrnet.py

283 lines
7.2 KiB
Python
Raw Normal View History

2011-10-30 01:22:45 +02:00
#!/usr/bin/python
2012-01-16 22:35:15 +01:00
# -*- coding: utf-8 -*-
#
# Copyright (C) 2011 Sebastian Lohff <seba@seba-geek.de>
# Licensed under GPL v3 or later
2011-10-30 01:22:45 +02:00
import base64
2012-01-16 22:35:15 +01:00
import gobject
import gtk
import mutex
2011-10-30 01:22:45 +02:00
import opencv
from opencv import highgui, adaptors
2012-01-16 22:35:15 +01:00
import os
2011-10-30 01:22:45 +02:00
from PIL import Image
2012-01-16 22:35:15 +01:00
import qrencode
import Queue
import re
2011-10-30 01:22:45 +02:00
import socket
2012-01-16 22:35:15 +01:00
import struct
import StringIO
2011-10-30 01:22:45 +02:00
import subprocess
2012-01-16 22:35:15 +01:00
import sys
2011-10-30 01:22:45 +02:00
import threading
2012-01-16 22:35:15 +01:00
import time
import urllib
import zbar
2011-10-30 01:22:45 +02:00
sys.path.append("../../../")
from ether2any import Ether2Any
from conf import Conf
mqueueMutex = threading.Lock()
squeueMutex = threading.Lock()
2011-10-30 02:56:45 +01:00
exqueue = Queue.Queue()
2011-10-30 01:22:45 +02:00
class QrDisplay(gtk.Window):
def __init__(self, mqueue, squeue, displog, timeout=250):
super(QrDisplay, self).__init__()
self.timeout = timeout
self.mqueue = mqueue
self.squeue = squeue
self.displog = displog
2011-10-30 02:56:45 +01:00
self.fullscreen()
self.qrimgPadding = 20
(wx, wy) = self.getHackySize()
2011-10-30 01:22:45 +02:00
# build up gui
self.vbox = gtk.VBox(False, 0)
self.qrimg = gtk.Image()
self.qrimg.show()
self.vbox.pack_start(self.qrimg, True, True, self.qrimgPadding)
self.vbox.show()
self.pbar = gtk.ProgressBar()
self.pbar.show()
self.vbox.pack_start(self.pbar, False, False, 0)
self.add(self.vbox)
# connect signals
2011-10-30 02:56:45 +01:00
self.connect("destroy", self.quitGui)
2011-10-30 01:22:45 +02:00
self.set_size_request(wx, wy)
self.maximize()
self.set_position(gtk.WIN_POS_CENTER)
self.show()
self.qrSet("")
gobject.timeout_add(self.timeout, self.checkQueue)
2011-10-30 02:56:45 +01:00
def quitGui(self, *args, **kwargs):
exqueue.put(KeyboardInterrupt())
2011-10-30 01:22:45 +02:00
def checkQueue(self):
#print "Check queue...",
mqueueMutex.acquire()
if not self.mqueue.empty():
print "new data available"
bmsg = self.mqueue.get()
self.qrSet(bmsg)
mqueueMutex.release()
#else:
# print "no new data available"
# progress
squeueMutex.acquire()
if not self.squeue.empty():
(frames, success) = self.squeue.get()
if frames > 0:
self.pbar.set_fraction(success/float(frames))
self.pbar.set_text("%02d / %02d (%03.02f)" % (success, frames, success / float(frames) * 100.0))
print frames, success
squeueMutex.release()
return True
def getHackySize(self):
""" Obtain current size of screen via xrandr. """
#p = subprocess.Popen(["bash", "-c", 'xrandr|egrep "\*+"|egrep -o "[0-9]+x[0-9]+"'], stdout=subprocess.PIPE)
2011-10-30 02:56:45 +01:00
p = subprocess.Popen('xrandr|egrep "\*+"|egrep -o "[0-9]+x[0-9]+"', stdout=subprocess.PIPE, shell=True)
2011-10-30 01:22:45 +02:00
p.wait()
(myout, myin) = p.communicate()
return map(lambda x: int(x)-self.qrimgPadding, myout.strip().split("x"))
def image2pixbuf(self, im):
(a, b, c, d) = self.qrimg.get_allocation()
# correct size, must be 1:1 (so select the smaller one)
x = min(c-a, d-b)
if(x < 10):
x = 100
imgSize = (x, x)
im = im.resize(imgSize)
file1 = StringIO.StringIO()
im.save(file1, "ppm")
contents = file1.getvalue()
file1.close()
loader = gtk.gdk.PixbufLoader("pnm")
loader.write(contents, len(contents))
pixbuf = loader.get_pixbuf()
loader.close()
return pixbuf
def qrSet(self, msg):
""" Set content of displayed qr image. """
if msg == None or msg == "":
msg = "Katze"
(qrVersion, qrSize, qrImg) = qrencode.encode(msg, 0)
self.qrimg.set_from_pixbuf(self.image2pixbuf(qrImg))
class DisplayThread(threading.Thread):
""" Thread that runs the GTK-GUI to display outgoing network qr codes. """
def __init__(self, dev, mqueue, squeue, displog):
threading.Thread.__init__(self)
self.dev = dev
self.quit = False
2011-10-30 02:56:45 +01:00
self.qrdisplay = QrDisplay(mqueue, squeue, displog)
2011-10-30 01:22:45 +02:00
self.mqueue = mqueue
self.squeue = squeue
self.displog = displog
def run(self):
self.displog.info("Display GTK Gui is up and running.")
2011-10-30 02:56:45 +01:00
try:
gtk.main()
except Exception, e:
exqueue.push(e)
2011-10-30 01:22:45 +02:00
class CamThread(threading.Thread):
""" Captures images from a webcam and decodes them.
Captures images from the first webcam it can find, decodes them
and writes them to the interface. """
def __init__(self, dev, squeue, camlog):
threading.Thread.__init__(self)
self.dev = dev
self.squeue = squeue
self.camlog = camlog
self.frame = 0
self.reportAfter = 20 # frames
self.quit = False
self.success = 0
self.lastPacket = ""
2011-10-30 02:56:45 +01:00
self.reader = highgui.cvCreateCameraCapture(Conf.get("camnum", 0))
2011-10-30 01:22:45 +02:00
self.scanner = zbar.ImageScanner()
self.scanner.parse_config('enable')
def run(self):
2011-10-30 02:56:45 +01:00
try:
while not self.quit:
frame = highgui.cvQueryFrame(self.reader)
self.frame += 1
frame = opencv.cvGetMat(frame)
img = adaptors.Ipl2PIL(frame)
width, height = img.size
zimg = zbar.Image(width, height, 'Y800', img.convert("L").tostring())
self.scanner.scan(zimg)
data = None
for symbol in zimg:
data = symbol.data
self.camlog.debug("Data is: %s" % data)
self.success += 1
# handle data
if not self.lastPacket == data:
self.lastPacket = data
try:
msg = base64.b64decode(data)
(rawtime, packet) = (msg[0:8], msg[8:])
ptime = struct.unpack("<d", rawtime)
self.camlog.debug("Network packet! Heade (time) is %s" % (ptime,))
self.dev.write(packet)
except (base64.binascii.Error, TypeError):
self.camlog.error("Base64 error - could not decode packet")
except struct.error:
self.camlog.error("Header error - could not extract header information")
else:
# packet is already known, discard
pass
2011-10-30 01:22:45 +02:00
2011-10-30 02:56:45 +01:00
# status report to gui
if self.frame % self.reportAfter == 0:
self.frame = self.success = 0
squeueMutex.acquire()
if self.squeue.qsize() > self.reportAfter/2:
while not self.squeue.empty():
self.squeue.get()
# add new status code
self.squeue.put((self.frame, self.success))
squeueMutex.release()
except Exception, e:
exqueue.put(e)
raise e
2011-10-30 01:22:45 +02:00
class QrNet(Ether2Any):
pidlen = 16
def __init__(self):
# device
Ether2Any.__init__(self, tap=True)
self.qrlog = self.setupLogging("QrNet")
self.mqueue = Queue.Queue()
self.squeue = Queue.Queue()
2011-10-30 02:56:45 +01:00
self.setTimeout(1)
network = Conf.get("network", {'mtu': 400})
self.packetDrop = Conf.get("packetDrop", 20)
self.dev.ifconfig(**network)
self.dev.up()
2011-10-30 01:22:45 +02:00
# thread starting...
gtk.gdk.threads_init()
self.cam = CamThread(self.dev, self.squeue, self.setupLogging("CamThread"))
self.cam.start()
self.display = DisplayThread(self.dev, self.mqueue, self.squeue, self.setupLogging("DisplayThread"))
self.display.start()
2011-10-30 02:56:45 +01:00
def sendToNet(self, msg):
2011-10-30 01:22:45 +02:00
# prepare data for queue && display
self.qrlog.debug("Data from the device")
2011-10-30 02:56:45 +01:00
2011-10-30 01:22:45 +02:00
# add acttime to generate "unique" images
acttime = struct.pack("<d", time.time())
bmsg = base64.b64encode(acttime + msg)
self.qrlog.debug("==>" + bmsg)
# add packet to queue, maybe drop packet
mqueueMutex.acquire()
if self.mqueue.qsize() < self.packetDrop:
self.mqueue.put(bmsg)
else:
self.qrlog.debug("Dropping packet!")
mqueueMutex.release()
2011-10-30 02:56:45 +01:00
def callAfterSelect(self):
# check queue for excetions
if exqueue.qsize() > 0:
ex = exqueue.get()
raise ex
2011-10-30 01:22:45 +02:00
def quit(self):
self.display.quit = True
self.cam.quit = True
2011-10-30 02:56:45 +01:00
gtk.main_quit()
2011-10-30 01:22:45 +02:00
if __name__ == '__main__':
2011-10-30 02:56:45 +01:00
try:
qrnet = QrNet()
qrnet.run()
except KeyboardInterrupt:
try:
qrnet.quit()
except NameError:
pass
sys.exit(0)
except Exception, e:
raise e