You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

248 lines
6.5 KiB

#!/usr/bin/python
import sys
import os
import re
import time
import struct
import base64
import StringIO
import opencv
from opencv import highgui, adaptors
import qrencode
import zbar
from PIL import Image
import gtk
import gobject
import urllib
import socket
import subprocess
import Queue
import threading
import mutex
sys.path.append("../../../")
from ether2any import Ether2Any
from conf import Conf
mqueueMutex = threading.Lock()
squeueMutex = threading.Lock()
class QrDisplay(gtk.Window):
def __init__(self, mqueue, squeue, displog, timeout=250):
super(QrDisplay, self).__init__()
self.fullscreen()
self.qrimgPadding = 20
(wx, wy) = self.getHackySize()
self.timeout = timeout
self.mqueue = mqueue
self.squeue = squeue
self.displog = displog
# 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
self.connect("destroy", gtk.main_quit)
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)
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)
p = subprocess.Popen('xrandr|egrep "\*+"|egrep -o "[0-9]+x[0-9]+"', stdout=subprocess.PIPE)
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
self.qrdisplay = QrDisplay(mqueue, squeue, )
self.mqueue = mqueue
self.squeue = squeue
self.displog = displog
def run(self):
self.displog.info("Display GTK Gui is up and running.")
gtk.main()
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 = ""
self.reader = highgui.cvCreateCameraCapture(camnum)
self.scanner = zbar.ImageScanner()
self.scanner.parse_config('enable')
def run(self):
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:
print " ==> base64 error"
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
# status report to gui
if self.frame % self.reportAfter == 0:
self.frame = self.success = 0
# too much status codes? flush 'em
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()
class QrNet(Ether2Any):
pidlen = 16
def __init__(self):
# device
Ether2Any.__init__(self, tap=True)
self.qrlog = self.setupLogging("QrNet")
self.dev.ifconfig(address=ip, netmask=netmask, mtu=mtu)
self.packetDrop = packetDrop
self.mqueue = Queue.Queue()
self.squeue = Queue.Queue()
# 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()
def sendToNet(self):
# prepare data for queue && display
self.qrlog.debug("Data from the device")
msg = self.dev.read()
# 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()
def quit(self):
self.display.quit = True
self.cam.quit = True
if __name__ == '__main__':
qrnet = QrNet()
qrnet.run()