Network handling works now

This commit is contained in:
jaseg 2014-02-17 20:34:36 +01:00
parent 6578445931
commit 1392b46636

View file

@ -1,16 +1,27 @@
#!/usr/bin/env python #!/usr/bin/env python
from ctypes import CDLL, POINTER, c_void_p, Structure, c_uint8, c_size_t, cast, addressof from socketserver import *
import numpy as np from time import time, strftime, sleep
from collections import namedtuple
from itertools import product from itertools import product
import threading
import random
from ctypes import CDLL, POINTER, c_void_p, Structure, c_uint8, c_size_t, cast, addressof
import numpy as np
from matelight import sendframe, DISPLAY_WIDTH, DISPLAY_HEIGHT from matelight import sendframe, DISPLAY_WIDTH, DISPLAY_HEIGHT
from terminal import printframe
UDP_TIMEOUT = 3.0
class COLOR(Structure): class COLOR(Structure):
_fields_ = [('r', c_uint8), ('g', c_uint8), ('b', c_uint8), ('a', c_uint8)] _fields_ = [('r', c_uint8), ('g', c_uint8), ('b', c_uint8), ('a', c_uint8)]
class FRAMEBUFFER(Structure): class FRAMEBUFFER(Structure):
_fields_ = [('data', POINTER(COLOR)), ('w', c_size_t), ('h', c_size_t)] _fields_ = [('data', POINTER(COLOR)), ('w', c_size_t), ('h', c_size_t)]
bdf = CDLL('./libbdf.so') bdf = CDLL('./libbdf.so')
bdf.read_bdf_file.restype = c_void_p bdf.read_bdf_file.restype = c_void_p
@ -19,31 +30,130 @@ bdf.framebuffer_render_text.restype = POINTER(FRAMEBUFFER)
unifont = bdf.read_bdf_file('unifont.bdf') unifont = bdf.read_bdf_file('unifont.bdf')
def render_text(text): def render_text(text):
assert unifont assert unifont
fb = bdf.framebuffer_render_text(bytes(str(text), 'UTF-8'), unifont) fb = bdf.framebuffer_render_text(bytes(str(text), 'UTF-8'), unifont)
fbd = fb.contents fbd = fb.contents
buf = np.ctypeslib.as_array(cast(fbd.data, POINTER(c_uint8)), shape=(fbd.h, fbd.w, 4)) buf = np.ctypeslib.as_array(cast(fbd.data, POINTER(c_uint8)), shape=(fbd.h, fbd.w, 4))
# Set data pointer to NULL before freeing framebuffer struct to prevent free_framebuffer from also freeing the data # Set data pointer to NULL before freeing framebuffer struct to prevent free_framebuffer from also freeing the data
# buffer that is now used by numpy # buffer that is now used by numpy
#bdf.console_render_buffer(fb) #bdf.console_render_buffer(fb)
fbd.data = cast(c_void_p(), POINTER(COLOR)) fbd.data = cast(c_void_p(), POINTER(COLOR))
bdf.free_framebuffer(fb) bdf.free_framebuffer(fb)
return buf return buf
def printframe(fb): def printframe(fb):
h,w,_ = fb.shape h,w,_ = fb.shape
print('\033[H\033[2J') print('\033[s\033[H', end='')
bdf.console_render_buffer(fb.ctypes.data_as(POINTER(c_uint8)), w, h) bdf.console_render_buffer(fb.ctypes.data_as(POINTER(c_uint8)), w, h)
print('\033[0m\033[u', end='')
def scroll(text):
""" Returns whether it could scroll all the text uninterrupted """
fb = render_text(text);
h,w,_ = fb.shape
for i in range(-DISPLAY_WIDTH,w+1):
if current_entry.entrytype == 'udp' or (current_entry in defaulttexts and textqueue):
return False
leftpad = np.zeros((DISPLAY_HEIGHT, max(-i, 0), 4), dtype=np.uint8)
framedata = fb[:, max(0, i):min(i+DISPLAY_WIDTH, w)]
rightpad = np.zeros((DISPLAY_HEIGHT, min(DISPLAY_WIDTH, max(0, i+DISPLAY_WIDTH-w)), 4), dtype=np.uint8)
dice = np.concatenate((leftpad, framedata, rightpad), 1)
sendframe(dice)
#printframe(dice)
fb = render_text(text);
return True
QueueEntry = namedtuple('QueueEntry', ['entrytype', 'remote', 'timestamp', 'text'])
defaulttexts = [QueueEntry('text', '127.0.0.1', 0, t) for t in [
'\x1B[92mMate Light\x1B[93m@\x1B[92mPlay store or \x1B[94;101mtcp://matelight.cbrp3.c-base.org:1337\x1B[0;91m ♥',
'\x1B[92mMate Light\x1B[0;91m ♥ \x1B[92mUnicode',
'\x1B[92mMate Light\x1B[0m powered by \x1B[95mMicrosoft™ \x1B[96mMarquee Manager® Professional OEM',
'\x1B[92mMate Light\x1B[0m powered by \x1B[95mData Becker™ \x1B[96mLaufschriftstudio 2000® Platinum Edition',
'\x1B[92mMate Light\x1B[0m powered by \x1B[95mApple™ \x1B[96miScroll®',
'\x1B[92mMate Light\x1B[0m powered by \x1B[95mSiemens™ \x1B[96mLaufschrift® v.0.1.2b fuer Intel™ Pentium®',
]]
current_entry = random.choice(defaulttexts)
conns = {}
textqueue = []
def log(*args):
print(strftime('[%m-%d %H:%M:%S]'), *args)
class MateLightUDPHandler(BaseRequestHandler):
def handle(self):
try:
global current_entry, conns
data = self.request[0].strip()
if len(data) != FRAME_SIZE+4:
#raise ValueError('Invalid frame size: Expected {}, got {}'.format(FRAME_SIZE+4, len(data)))
return
frame = data[:-4]
#crc1, = struct.unpack('!I', data[-4:])
#crc2, = zlib.crc32(frame, 0),
#if crc1 != crc2:
# raise ValueError('Invalid frame CRC checksum: Expected {}, got {}'.format(crc2, crc1))
#socket.sendto(b'ACK', self.client_address)
a = np.array(list(frame), dtype=np.uint8)
timestamp = time()
addr = self.client_address[0]
if addr not in conns:
current_entry = QueueEntry('udp', addr, timestamp, '')
conns[addr] = current_entry
log('New UDP connection from', addr)
else:
conns[addr].timestamp = timestamp
if current_entry.entrytype == 'udp' and current_entry.remote == addr:
frame = a.reshape((DISPLAY_HEIGHT, DISPLAY_WIDTH, 3))
sendframe(frame)
#printframe(frame)
except Exception as e:
print('Error receiving UDP frame:', e)
ex_type, ex, tb = sys.exc_info()
traceback.print_tb(tb)
class MateLightTCPTextHandler(BaseRequestHandler):
def handle(self):
global current_entry, conns
data = str(self.request.recv(1024).strip(), 'UTF-8')
addr = self.client_address[0]
timestamp = time()
if len(data) > 140:
self.request.sendall('TOO MUCH INFORMATION!\n')
return
log('Text from {}: {}\x1B[0m'.format(addr, data))
textqueue.append(QueueEntry('text', addr, timestamp, data))
self.request.sendall(b'KTHXBYE!\n')
TCPServer.allow_reuse_address = True
server = TCPServer(('', 1337), MateLightTCPTextHandler)
t = threading.Thread(target=server.serve_forever)
t.daemon = True
t.start()
UDPServer.allow_reuse_address = True
userver = UDPServer(('', 1337), MateLightUDPHandler)
t = threading.Thread(target=userver.serve_forever)
t.daemon = True
t.start()
if __name__ == '__main__': if __name__ == '__main__':
fb = render_text('\033[31;48;5;167;4;6mfoo\033[0;91mbar\033[93;106;5mbaz\033[0m\033[0;94;6m♥♥♥'); print('\n'*7)
h,w,_ = fb.shape while True:
for i in range(-DISPLAY_WIDTH,w+1): if current_entry.entrytype == 'text':
leftpad = np.zeros((DISPLAY_HEIGHT, max(-i, 0), 4), dtype=np.uint8) if scroll(current_entry.text):
framedata = fb[:, max(0, i):min(i+DISPLAY_WIDTH, w)] textqueue.remove(current_entry)
rightpad = np.zeros((DISPLAY_HEIGHT, min(DISPLAY_WIDTH, max(0, i+DISPLAY_WIDTH-w)), 4), dtype=np.uint8) if textqueue:
dice = np.concatenate((leftpad, framedata, rightpad), 1) current_entry = textqueue[0]
sendframe(dice) else:
printframe(dice) if conns:
fb = render_text('\033[31;48;5;167;4;6mfoo\033[0;91mbar\033[93;106;5mbaz\033[0m\033[0;94;6m♥♥♥'); current_entry = random.choice(conns.values())
else:
current_entry = random.choice(defaulttexts)
if current_entry.entrytype != 'udp' and textqueue:
current_entry = textqueue[0]
if current_entry.entrytype == 'udp':
if time() - current_entry.timestamp > UDP_TIMEOUT:
current_entry = random.choice(defaulttexts)
else:
sleep(0.2)