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 Cleanupmaster
parent
8d371b95df
commit
9da3123796
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue