Stefan Schuermans commited on 2017-05-26 17:35:57
Showing 4 changed files, with 83 additions and 15 deletions.
... | ... |
@@ -1,3 +1,5 @@ |
1 |
+import socket |
|
2 |
+ |
|
1 | 3 |
from distributor import Distributor |
2 | 4 |
from mapping import Mapping |
3 | 5 |
from msg import Msg, MsgDef |
... | ... |
@@ -20,6 +22,14 @@ class Display(object): |
20 | 22 |
# read config file |
21 | 23 |
if not self._proc_config_file(config_file): |
22 | 24 |
raise Exception("error(s) while reading config file") |
25 |
+ # create and bind socket |
|
26 |
+ self._socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) |
|
27 |
+ self._socket.setblocking(False) |
|
28 |
+ self._socket.bind(self._bind_addr) |
|
29 |
+ |
|
30 |
+ def close(self): |
|
31 |
+ """close display""" |
|
32 |
+ self._socket.close() |
|
23 | 33 |
|
24 | 34 |
def get_size(self): |
25 | 35 |
"""get size of display as (width, height) in pixels""" |
... | ... |
@@ -27,18 +37,18 @@ class Display(object): |
27 | 37 |
|
28 | 38 |
def data_clear(self): |
29 | 39 |
"""clear image data, i.e. set entire image to black""" |
30 |
- # TODO |
|
31 |
- pass |
|
40 |
+ for distri in self._distris.values(): |
|
41 |
+ distri.data_clear() |
|
32 | 42 |
|
33 |
- def data_set(self, TODO): |
|
43 |
+ def data_image(self, image): |
|
34 | 44 |
"""set image data""" |
35 |
- # TODO |
|
36 |
- pass |
|
45 |
+ for distri in self._distris.values(): |
|
46 |
+ distri.data_image(image) |
|
37 | 47 |
|
38 | 48 |
def send(self): |
39 |
- """send image data to distributors""" |
|
40 |
- # TODO |
|
41 |
- pass |
|
49 |
+ """send image data to actual distributor modules using UDP""" |
|
50 |
+ for distri in self._distris.values(): |
|
51 |
+ distri.send(self._socket) |
|
42 | 52 |
|
43 | 53 |
def _proc_config_file(self, config_file): |
44 | 54 |
"""process config file |
... | ... |
@@ -1,3 +1,6 @@ |
1 |
+import socket |
|
2 |
+import struct |
|
3 |
+ |
|
1 | 4 |
from mapping import Mapping |
2 | 5 |
|
3 | 6 |
|
... | ... |
@@ -19,6 +22,11 @@ class Distributor(object): |
19 | 22 |
self._mappings.append(Mapping()) |
20 | 23 |
# pixel coordinates: all unknown |
21 | 24 |
self._pixel_coords = [[None] * self._pixels] * self._outputs |
25 |
+ # header for UDP packets |
|
26 |
+ self._udp_hdr = struct.pack("!I4H", 0x23542666, |
|
27 |
+ outputs, pixels, Mapping.CHANNELS, 255) |
|
28 |
+ # initial image data is cleared |
|
29 |
+ self.data_clear() |
|
22 | 30 |
|
23 | 31 |
def check_output_no(self, output_no): |
24 | 32 |
"""check output number, return True if okay, False if not okay""" |
... | ... |
@@ -36,6 +44,35 @@ class Distributor(object): |
36 | 44 |
"""set distributor address""" |
37 | 45 |
self._addr = addr |
38 | 46 |
|
47 |
+ def data_clear(self): |
|
48 |
+ """clear image data, i.e. set entire image to black""" |
|
49 |
+ # prepare message buffer with all pixels cleared (black) |
|
50 |
+ clr = "".join([self._mappings[channel].table[0] |
|
51 |
+ for channel in range(Mapping.CHANNELS)]) |
|
52 |
+ self._buffer = self._udp_hdr + (clr * (self._outputs * self._pixels)) |
|
53 |
+ |
|
54 |
+ def data_image(self, image): |
|
55 |
+ """set image data""" |
|
56 |
+ # collect pixels from image and assemble message in buffer |
|
57 |
+ clr = [0] * Mapping.CHANNELS |
|
58 |
+ data = [] |
|
59 |
+ for output_pixel_coords in self._pixel_coords: |
|
60 |
+ for pixel_coord in output_pixel_coords: |
|
61 |
+ if pixel_coord is None: |
|
62 |
+ pix = clr |
|
63 |
+ else: |
|
64 |
+ pix = (128, 128, 0) # TODO |
|
65 |
+ data += [self._mappings[channel].table[pix[channel]] |
|
66 |
+ for channel in range(Mapping.CHANNELS)] |
|
67 |
+ self._buffer = self._udp_hdr + "".join(data) |
|
68 |
+ |
|
69 |
+ def send(self, socket): |
|
70 |
+ """send image data to actual distributor module using UDP""" |
|
71 |
+ try: |
|
72 |
+ socket.sendto(self._buffer, self._addr) |
|
73 |
+ except: |
|
74 |
+ pass |
|
75 |
+ |
|
39 | 76 |
def set_pixel_coords(self, output_no, pixel_coords): |
40 | 77 |
"""set distributor address |
41 | 78 |
output_no: number of output |
... | ... |
@@ -1,6 +1,8 @@ |
1 | 1 |
#! /usr/bin/env python |
2 | 2 |
|
3 | 3 |
import sys |
4 |
+import time |
|
5 |
+ |
|
4 | 6 |
import pyetherpix |
5 | 7 |
|
6 | 8 |
|
... | ... |
@@ -10,6 +12,20 @@ def main(argv): |
10 | 12 |
return 2 |
11 | 13 |
config_file = argv[1] |
12 | 14 |
display = pyetherpix.Display(config_file) |
15 |
+ (width, height) = display.get_size() |
|
16 |
+ print "width %u, height %u" % (width, height) |
|
17 |
+ print "blink" |
|
18 |
+ for i in range(5): |
|
19 |
+ print "on" |
|
20 |
+ display.data_image("ON") # TODO |
|
21 |
+ display.send() |
|
22 |
+ time.sleep(0.5) |
|
23 |
+ print "off" |
|
24 |
+ display.data_clear() |
|
25 |
+ display.send() |
|
26 |
+ time.sleep(0.5) |
|
27 |
+ print "done" |
|
28 |
+ display.close() |
|
13 | 29 |
return 0 |
14 | 30 |
|
15 | 31 |
|
... | ... |
@@ -1,3 +1,6 @@ |
1 |
+from struct import Struct |
|
2 |
+ |
|
3 |
+ |
|
1 | 4 |
class Mapping(object): |
2 | 5 |
|
3 | 6 |
RED = 0 |
... | ... |
@@ -23,14 +26,16 @@ class Mapping(object): |
23 | 26 |
"""pre-compute mapping table""" |
24 | 27 |
# display_value := base + factor * input_value ^ (1 / gamma) |
25 | 28 |
gamma_1 = 1.0 / self._gamma |
29 |
+ s = Struct("!B") |
|
26 | 30 |
tab = [] |
27 | 31 |
for v in range(256): |
28 |
- val = self._base + self._factor * (v / 255.0) ** gamma_1 |
|
29 |
- if val < 0: |
|
30 |
- tab.append(0) |
|
31 |
- elif val > 1.0: |
|
32 |
- tab.append(255) |
|
32 |
+ display_val = self._base + self._factor * (v / 255.0) ** gamma_1 |
|
33 |
+ if display_val < 0: |
|
34 |
+ display_no = 0 |
|
35 |
+ elif display_val > 1.0: |
|
36 |
+ display_no = 255 |
|
33 | 37 |
else: |
34 |
- tab.append(int(round(val * 255.0))) |
|
35 |
- self._table = tuple(tab) |
|
38 |
+ display_no = int(round(display_val * 255.0)) |
|
39 |
+ tab.append(s.pack(display_no)) |
|
40 |
+ self.table = tuple(tab) |
|
36 | 41 |
|
37 | 42 |