implement UDP packet output
Stefan Schuermans

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