#!/usr/bin/python # -*- coding: utf-8 -*- # # Copyright (C) 2011 Sebastian Lohff # Licensed under GPL v3 or later import base64 import gobject import gtk import mutex import opencv from opencv import highgui, adaptors import os from PIL import Image import qrencode import Queue import re import socket import struct import StringIO import subprocess import sys import threading import time import urllib import zbar sys.path.append("../../../") from ether2any import Ether2Any from conf import Conf mqueueMutex = threading.Lock() squeueMutex = threading.Lock() exqueue = Queue.Queue() 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 self.fullscreen() self.qrimgPadding = 20 (wx, wy) = self.getHackySize() # 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", self.quitGui) 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 quitGui(self, *args, **kwargs): exqueue.put(KeyboardInterrupt()) 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, shell=True) 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, displog) self.mqueue = mqueue self.squeue = squeue self.displog = displog def run(self): self.displog.info("Display GTK Gui is up and running.") try: gtk.main() except Exception, e: exqueue.push(e) 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(Conf.get("camnum", 0)) self.scanner = zbar.ImageScanner() self.scanner.parse_config('enable') def run(self): 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(" 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 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() self.setTimeout(1) network = Conf.get("network", {'mtu': 400}) self.packetDrop = Conf.get("packetDrop", 20) self.dev.ifconfig(**network) self.dev.up() # 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, msg): # prepare data for queue && display self.qrlog.debug("Data from the device") # add acttime to generate "unique" images acttime = struct.pack("" + 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 callAfterSelect(self): # check queue for excetions if exqueue.qsize() > 0: ex = exqueue.get() raise ex def quit(self): self.display.quit = True self.cam.quit = True gtk.main_quit() if __name__ == '__main__': try: qrnet = QrNet() qrnet.run() except KeyboardInterrupt: try: qrnet.quit() except NameError: pass sys.exit(0) except Exception, e: raise e