Improve dynamic configuration

* Control framerate in the forwarder
* The processing client can use a smaller framerate than the default/max
* The processing client can send an image smaller than the full screen
    Known Bug: doesn't work if the width is smaller than the one of the screen
* The default config is sent to the processing client by the server
    Sanity checks are made on the client configuration
* Code Cleanup
master
Raphaël Vinot 2015-03-20 00:39:53 +01:00
parent 8d371b95df
commit 9da3123796
6 changed files with 117 additions and 43 deletions

View File

@ -92,12 +92,10 @@ void loop() {
if (startChar == '*') { if (startChar == '*') {
unsigned int startAt = micros(); unsigned int startAt = micros();
unsigned int usecUntilFrameSync = 0; unsigned int usecUntilFrameSync = 0;
count = Serial.readBytes((char *)drawingMemory, sizeof(int) * ledsPerStrip*6); count = Serial.readBytesUntil('#', (char *)drawingMemory, sizeof(int) * ledsPerStrip*6 + 1);
if (count >= sizeof(int) * ledsPerStrip*6) {
digitalWrite(13, HIGH); digitalWrite(13, HIGH);
leds.show(); leds.show();
digitalWrite(13, LOW); digitalWrite(13, LOW);
}
} else if (startChar >= 0) { } else if (startChar >= 0) {
// discard unknown characters // discard unknown characters
} }

View File

@ -1,13 +1,4 @@
Forwarder Both sides
========= ==========
* Control framerate in send function Support screen sizes > 1byte
* 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

View File

@ -5,22 +5,31 @@ import time
from serial import Serial, SerialException from serial import Serial, SerialException
import sys import sys
height = 50 max_height = 5
width = 20 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): def send(r, s):
print(r.llen('new')) print(r.llen('new'))
data = r.rpop('new') data = r.rpop('new')
if data is not None and len(data) > 0: if data is not None and len(data) > 0:
a = bytes([ord('*')]) + bytearray(data) now = time.time()
#la = len(a) end = now + wait_time
a = bytes([ord('*')]) + bytearray(data) + bytes([ord('#')])
s.write(a) s.write(a)
#time.sleep(.05) time.sleep(end - now)
#data = s.read(la)
#print(data)
# size = s.write(data)
# print('Data sent ({} bytes)'.format(size))
def serialConfigure(port_name, baudrate=9600): 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)) sys.stderr.write("Could not open serial port %s: %s\n" % (ser.portstr, e))
return return
ledsPerStrip = height * width ledsPerStrip = max_height * max_width
print(ledsPerStrip) print(ledsPerStrip)
ser.write(ledsPerStrip.to_bytes(4, byteorder='little')) ser.write(ledsPerStrip.to_bytes(4, byteorder='little'))
@ -64,10 +73,16 @@ def serialDataConfigure(port_name, baudrate=115200):
if __name__ == "__main__": if __name__ == "__main__":
r = redis.Redis() 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 = serialConfigure('/dev/ttyACM0')
# s_data = serialDataConfigure('/dev/ttyUSB0') # s_data = serialDataConfigure('/dev/ttyUSB0')
wait_time = 1.0 / max_framerate
while True: while True:
while r.llen('new') > 0: while r.llen('new') > 0:
send(r, s) send(r, s)
time.sleep(1) time.sleep(1)
update_framerate()

View File

@ -13,16 +13,51 @@ class MyTCPHandler(socketserver.BaseRequestHandler):
client. 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')) 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): def handle(self):
print('Start receiving from {}...'.format(self.client_address[0]))
self.r = redis.Redis() 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: while True:
data = self.request.recv(self.imgsize) data = self.request.recv(self.imgsize)
print(len(data))
self.r.lpush('new', data) self.r.lpush('new', data)
if len(data) == 0: if len(data) == 0:
break break

View File

@ -1,11 +1,17 @@
add_library('net') add_library('net')
import math import math
import jarray import jarray
import time
import struct
# Config, will be checked upstream
height = 5
width = 8
framerate = 30
#####################################
gamma = 1.7 gamma = 1.7
brightness = 4 brightness = 4
errorCount = 0
framerate = 30
dimension = 0 dimension = 0
# TODO: test with real serial # TODO: test with real serial
@ -58,22 +64,53 @@ def colorWiring(c):
def send_TCP(): def send_TCP():
image2data(data) image2data(data)
#println(data)
ledTCP.write(data) ledTCP.write(data)
def prepare_data(): def prepare_data():
global data global data
data = jarray.zeros(dimension * 24, "b") 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(): def setup():
global gammatable global gammatable
global dimension 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 dimension = width * height
frameRate(framerate) 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)] gammatable = [int((math.pow(i / 255.0, gamma) * 255.0 + 0.5) * brightness) for i in range(0, 256)]
prepare_data() prepare_data()
loadPixels() loadPixels()

View File

@ -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 * Optimize the datastream generator
* Split the processing code (setup & dray) from the datastreem generator => library * Split the processing code (setup & dray) from the datastreem generator => library