diff --git a/v2/backend/arduino/VideoDisplayTeensy31/VideoDisplayTeensy31.ino b/v2/backend/arduino/VideoDisplayTeensy31/VideoDisplayTeensy31.ino index feefec5..5502fea 100644 --- a/v2/backend/arduino/VideoDisplayTeensy31/VideoDisplayTeensy31.ino +++ b/v2/backend/arduino/VideoDisplayTeensy31/VideoDisplayTeensy31.ino @@ -92,12 +92,10 @@ void loop() { if (startChar == '*') { unsigned int startAt = micros(); unsigned int usecUntilFrameSync = 0; - count = Serial.readBytes((char *)drawingMemory, sizeof(int) * ledsPerStrip*6); - if (count >= sizeof(int) * ledsPerStrip*6) { - digitalWrite(13, HIGH); - leds.show(); - digitalWrite(13, LOW); - } + count = Serial.readBytesUntil('#', (char *)drawingMemory, sizeof(int) * ledsPerStrip*6 + 1); + digitalWrite(13, HIGH); + leds.show(); + digitalWrite(13, LOW); } else if (startChar >= 0) { // discard unknown characters } diff --git a/v2/backend/forwarding/TODO b/v2/backend/forwarding/TODO index 62146e6..07b174c 100644 --- a/v2/backend/forwarding/TODO +++ b/v2/backend/forwarding/TODO @@ -1,13 +1,4 @@ -Forwarder -========= +Both sides +========== -* Control framerate in send function -* Define a max framerate and announce it in the config (redis) -* Remove commented code - -Receiver -======== - -* Listen on an other port to give the config to the client (H/W, max framerate) -* Allow the user to set a lower framerate than the max one anounced by the forwarder -* Remove debug code +Support screen sizes > 1byte diff --git a/v2/backend/forwarding/forward.py b/v2/backend/forwarding/forward.py index 294e678..9c775d7 100644 --- a/v2/backend/forwarding/forward.py +++ b/v2/backend/forwarding/forward.py @@ -5,22 +5,31 @@ import time from serial import Serial, SerialException import sys -height = 50 -width = 20 +max_height = 5 +max_width = 8 +max_framerate = 40 + +wait_time = None + + +def update_framerate(): + global wait_time + new_framerate = int(r.hget('config', 'cur_framerate')) + if new_framerate >= max_framerate or new_framerate == 0: + wait_time = 1.0 / max_framerate + else: + wait_time = 1.0 / new_framerate def send(r, s): print(r.llen('new')) data = r.rpop('new') if data is not None and len(data) > 0: - a = bytes([ord('*')]) + bytearray(data) - #la = len(a) + now = time.time() + end = now + wait_time + a = bytes([ord('*')]) + bytearray(data) + bytes([ord('#')]) s.write(a) - #time.sleep(.05) - #data = s.read(la) - #print(data) - # size = s.write(data) - # print('Data sent ({} bytes)'.format(size)) + time.sleep(end - now) def serialConfigure(port_name, baudrate=9600): @@ -38,7 +47,7 @@ def serialConfigure(port_name, baudrate=9600): sys.stderr.write("Could not open serial port %s: %s\n" % (ser.portstr, e)) return - ledsPerStrip = height * width + ledsPerStrip = max_height * max_width print(ledsPerStrip) ser.write(ledsPerStrip.to_bytes(4, byteorder='little')) @@ -64,10 +73,16 @@ def serialDataConfigure(port_name, baudrate=115200): if __name__ == "__main__": r = redis.Redis() - r.hset('config', 'imgsize', height * width * 24) + r.hset('config', 'height', max_height) + r.hset('config', 'width', max_width) + r.hset('config', 'imgsize', max_height * max_width * 24) + r.hset('config', 'max_framerate', max_framerate) + r.hset('config', 'cur_framerate', max_framerate) s = serialConfigure('/dev/ttyACM0') - #s_data = serialDataConfigure('/dev/ttyUSB0') + # s_data = serialDataConfigure('/dev/ttyUSB0') + wait_time = 1.0 / max_framerate while True: while r.llen('new') > 0: send(r, s) time.sleep(1) + update_framerate() diff --git a/v2/backend/forwarding/receiver.py b/v2/backend/forwarding/receiver.py index 6b1dda8..f4fbd6e 100644 --- a/v2/backend/forwarding/receiver.py +++ b/v2/backend/forwarding/receiver.py @@ -13,16 +13,51 @@ class MyTCPHandler(socketserver.BaseRequestHandler): client. """ - def get_config(self): + def _get_config(self): + self.max_height = int(self.r.hget('config', 'height')) + self.max_width = int(self.r.hget('config', 'width')) + self.max_framerate = int(self.r.hget('config', 'max_framerate')) + self.cur_framerate = int(self.r.hget('config', 'cur_framerate')) self.imgsize = int(self.r.hget('config', 'imgsize')) + def _set_config(self, framerate, height, width): + self.r.hset('config', 'cur_framerate', framerate) + self.imgsize = height * width * 24 + + def _send_config_to_client(self): + self.request.sendall(bytearray([self.max_height])) + self.request.sendall(bytearray([self.max_width])) + self.request.sendall(bytearray([self.max_framerate])) + + def _receive_client_config(self): + height = int.from_bytes(self.request.recv(1), byteorder='little') + width = int.from_bytes(self.request.recv(1), byteorder='little') + framerate = int.from_bytes(self.request.recv(1), byteorder='little') + good, reason = self._check_config(height, width, framerate) + if good: + self._set_config(framerate, height, width) + return good, reason + + def _check_config(self, height, width, framerate): + if height > 0 and height > self.max_height: + return False, "height has to be between 0 and {}. Current: {}".format(self.max_height, height) + if width > 0 and width > self.max_width: + return False, "width has to be between 0 and {}. Current: {}".format(self.max_width, width) + if framerate > 0 and framerate > self.max_framerate: + return False, "framerate has to be between 0 and {}. Current: {}".format(self.max_framerate, framerate) + return True, None + def handle(self): - print('Start receiving from {}...'.format(self.client_address[0])) self.r = redis.Redis() - self.get_config() + self._get_config() + self._send_config_to_client() + good, reason = self._receive_client_config() + if not good: + print(reason) + return None + print('Start receiving from {}...'.format(self.client_address[0])) while True: data = self.request.recv(self.imgsize) - print(len(data)) self.r.lpush('new', data) if len(data) == 0: break diff --git a/v2/backend/processing/PixelControl_TCP/PixelControl_TCP.pyde b/v2/backend/processing/PixelControl_TCP/PixelControl_TCP.pyde index 179167b..a793b42 100644 --- a/v2/backend/processing/PixelControl_TCP/PixelControl_TCP.pyde +++ b/v2/backend/processing/PixelControl_TCP/PixelControl_TCP.pyde @@ -1,11 +1,17 @@ add_library('net') import math import jarray +import time +import struct + +# Config, will be checked upstream +height = 5 +width = 8 +framerate = 30 +##################################### gamma = 1.7 brightness = 4 -errorCount = 0 -framerate = 30 dimension = 0 # TODO: test with real serial @@ -58,22 +64,53 @@ def colorWiring(c): def send_TCP(): image2data(data) - #println(data) ledTCP.write(data) def prepare_data(): global data data = jarray.zeros(dimension * 24, "b") +def receive_config(): + max_height = jarray.zeros(1, "b") + max_width = jarray.zeros(1, "b") + max_framerate = jarray.zeros(1, "b") + while True: + available_bytes = ledTCP.available() + if available_bytes > 0: + break + time.sleep(1) + ledTCP.readBytes(max_height) + ledTCP.readBytes(max_width) + ledTCP.readBytes(max_framerate) + return max_height[0], max_width[0], max_framerate[0] + +def check_config(max_height, max_width, max_framerate): + if height > max_height: + return False, "height cannot be higher than {}".format(max_height) + if width > max_width: + return False, "width cannot be higher than {}".format(max_width) + if framerate > max_framerate: + return False, "framerate cannot be higher than {}".format(max_framerate) + return True, None + +def send_config(): + ledTCP.write(height) + ledTCP.write(width) + ledTCP.write(framerate) + def setup(): global gammatable global dimension - size(50, 30) + TCPConfigure("127.0.0.1", 9999) + max_height, max_width, max_framerate = receive_config() + + good, reason = check_config(max_height, max_width, max_framerate) + if not good: + raise Exception(reason) + send_config() + size(width, height) dimension = width * height frameRate(framerate) - TCPConfigure("127.0.0.1", 9999) - if (errorCount > 0): - exit() gammatable = [int((math.pow(i / 255.0, gamma) * 255.0 + 0.5) * brightness) for i in range(0, 256)] prepare_data() loadPixels() diff --git a/v2/backend/processing/PixelControl_TCP/TODO b/v2/backend/processing/PixelControl_TCP/TODO index c98bf24..cfa38e3 100644 --- a/v2/backend/processing/PixelControl_TCP/TODO +++ b/v2/backend/processing/PixelControl_TCP/TODO @@ -1,4 +1,2 @@ -* Get config (H/W and max framerate) from the config server -* Set current framerate (lower than max), ad send it to the config server * Optimize the datastream generator * Split the processing code (setup & dray) from the datastreem generator => library