From 7e2c51dc2645c4dffe7cc33e8533f0667b8775a6 Mon Sep 17 00:00:00 2001 From: jaseg Date: Sun, 29 Dec 2013 02:52:28 +0100 Subject: Added basic text rendering & TCP server --- host/matelight/config.py | 9 +---- host/matelight/host.py | 2 +- host/matelight/listeners.py | 80 ++++++++++++++++++++++++++++++++++++------ host/matelight/nyancat-test.py | 2 +- host/matelight/renderers.py | 55 ++++++++++++++++------------- 5 files changed, 104 insertions(+), 44 deletions(-) mode change 100644 => 100755 host/matelight/listeners.py (limited to 'host') diff --git a/host/matelight/config.py b/host/matelight/config.py index 2bc97c1..b68bee5 100644 --- a/host/matelight/config.py +++ b/host/matelight/config.py @@ -1,4 +1,3 @@ -import bdflib # Used to read the bitmap font # Hard timeout in seconds after which (approximately) the rendering of a single item will be cut off RENDERER_TIMEOUT = 20.0 @@ -7,13 +6,7 @@ DEFAULT_IMAGE_DURATION = 10.0 # Default scrolling speed in pixels/second DEFAULT_SCROLL_SPEED = 4 # Pixels to leave blank between two letters -LETTER_SPACING = 1 - -#FONT = bdflib.reader.read_bdf(open('fonts/5x8.bdf').readlines()) -#FONT_WIDTH = 5 - -# Computed value -#FONT_PADDED_BINARY = ('{:0'+str(FONT_WIDTH+'b}').format +LETTER_SPACING = 0 # Display geometry # ┌─────────┐ ┌───┬───┬ ⋯ ┬───┬───┐ diff --git a/host/matelight/host.py b/host/matelight/host.py index 394c299..4fa8578 100644 --- a/host/matelight/host.py +++ b/host/matelight/host.py @@ -9,7 +9,7 @@ dev = usb.core.find(idVendor=0x1cbe, idProduct=0x0003) def sendframe(framedata): # not isinstance(framedata, np.array) or if framedata.shape != (DISPLAY_HEIGHT, DISPLAY_WIDTH, 3) or framedata.dtype != np.uint8: - raise ValueError('framedata must be a ({}, {}, 3)-numpy array of int8s. Got a {}-numpy array of {}'.format(DISPLAY_WIDTH, DISPLAY_HEIGHT, framedata.shape, framedata.dtype)) + raise ValueError('framedata must be a ({}, {}, 3)-numpy array of uint8s. Got a {}-numpy array of {}'.format(DISPLAY_HEIGHT, DISPLAY_WIDTH, framedata.shape, framedata.dtype)) for cy, cx in itertools.product(range(CRATES_Y), range(CRATES_X)): cratedata = framedata[cy*CRATE_HEIGHT:(cy+1)*CRATE_HEIGHT, cx*CRATE_WIDTH:(cx+1)*CRATE_WIDTH] diff --git a/host/matelight/listeners.py b/host/matelight/listeners.py old mode 100644 new mode 100755 index bb0ce72..91175cf --- a/host/matelight/listeners.py +++ b/host/matelight/listeners.py @@ -1,19 +1,79 @@ +#!/usr/bin/env python3 from socketserver import * +import threading import zlib import struct +import host +import numpy as np +import time +import renderers +from PIL import Image, ImageSequence +from config import * +# Loading frame (for the big font file) +img = Image.open(open('../nyancat.png', 'rb')) +frame = np.array(img.convert('RGB').getdata(), dtype=np.uint8).reshape((DISPLAY_HEIGHT, DISPLAY_WIDTH, 3)) +host.sendframe(frame) +from font import * class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass +default_renderer = renderers.TextRenderer('\x1B[91mFeed \x1B[92mme via \x1B[93mTCP on \x1B[94;101mml.jaseg.net:1337\x1B[0;91m ! \x1B[95mI can\x1B[96m parse\x1B[97m ANSI\x1B[92m color\x1B[93m codes\x1B[91m!\x1B[38;5;207m http://github.com/jaseg/matelight') +global renderer, count +renderer = default_renderer +count = 0 + class MateLightUDPHandler(BaseRequestHandler): - def handle(self): - data = self.request[0].strip() - if len(data) != FRAME_SIZE+4: - raise ValueError('Invalid frame size: Expected {}, got {}'.format(FRAME_SIZE+4, len(frame))) - frame = data[:-4] - crc1, = struct.unpack('!I', data[-4:]) - crc2 = zlib.crc32(frame), - if crc1 != crc2: - raise ValueError('Invalid frame CRC checksum: Expected {}, got {}'.format(crc2, crc1)) - socket.sendto(b'ACK', self.client_address) + def handle(self): + data = self.request[0].strip() + if len(data) != FRAME_SIZE: #+4 + raise ValueError('Invalid frame size: Expected {}, got {}'.format(FRAME_SIZE, len(frame))) #+4 + frame = data[:-4] + #crc1, = struct.unpack('!I', data[-4:]) + crc2 = zlib.crc32(frame), + if crc1 != crc2: + raise ValueError('Invalid frame CRC checksum: Expected {}, got {}'.format(crc2, crc1)) + #socket.sendto(b'ACK', self.client_address) + a = np.array(frame, dtype=np.uint8) + a.reshape((DISPLAY_HEIGHT, DISPLAY_WIDTH, 3)) + host.sendframe(a) + +class MateLightTCPTextHandler(BaseRequestHandler): + def handle(self): + try: + data = str(self.request.recv(1024).strip(), 'UTF-8') + if len(data) > 140: + self.request.sendall('TOO MUCH INFORMATION!\n') + return + global renderer, count + print(data+'\x1B[0m') + renderer = renderers.TextRenderer(data) + count = 3 + self.request.sendall(b'KTHXBYE!\n') + except: + pass + +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() + +while True: + global renderer, count + foo = renderer + if count == 0: + renderer = default_renderer + else: + count = count - 1 + for frame, delay in foo.frames(): + #print(list(frame.flatten())) + host.sendframe(np.swapaxes(frame, 0, 1)) + #time.sleep(delay) diff --git a/host/matelight/nyancat-test.py b/host/matelight/nyancat-test.py index aaabe85..73fd28e 100755 --- a/host/matelight/nyancat-test.py +++ b/host/matelight/nyancat-test.py @@ -20,7 +20,7 @@ bar = np.array(im.getdata(), dtype=np.uint8) foo = bar.reshape((DISPLAY_HEIGHT, 300, 3)) while True: - for i in range(20): + for i in range(60): for data in datas: host.sendframe(data) time.sleep(0.1) diff --git a/host/matelight/renderers.py b/host/matelight/renderers.py index 0e223a2..f507513 100644 --- a/host/matelight/renderers.py +++ b/host/matelight/renderers.py @@ -1,11 +1,13 @@ -import numpy as np +import time try: import re2 as re except ImportError: import re +import numpy as np from PIL import Image from pixelterm import xtermcolors from config import * +from font import * default_palette = [ (0x00, 0x00, 0x00), # 0 normal colors @@ -24,17 +26,19 @@ default_palette = [ (0xff, 0x00, 0xff), # 13 (0x00, 0xff, 0xff), # 14 (0xff, 0xff, 0xff)] # 15 +default_colors = (default_palette[8], default_palette[0]) class CharGenerator: def __init__(self, seq=None, lg=None, text=''): - settings = False, False, False, default_palette[8], default_palette[0] + settings = False, False, False, default_colors if lg: - settings = lg,bold, lg.blink, lg.underscore, lg.fg, lg.bg - self.bold, self.blink, self.underscore, self.fg, self.bg = settings + settings = lg.bold, lg.blink, lg.underscore, (lg.fg, lg.bg) + self.bold, self.blink, self.underscore, (self.fg, self.bg) = settings self.text = text - self.parse_escape_sequence(seq) + if seq: + self.parse_escape_sequence(seq) - def parse_escape_sequence(seq): + def parse_escape_sequence(self, seq): codes = list(map(int, seq[2:-1].split(';'))) fg, bg, reverse, i = self.fg, self.bg, False, 0 while i