add support for monochrome distributors
Stefan Schuermans

Stefan Schuermans commited on 2018-08-14 19:31:25
Showing 15 changed files, with 179 additions and 25 deletions.

... ...
@@ -17,7 +17,7 @@
17 17
 
18 18
 LIBTARGET := libetherpix
19 19
 VER_MAJ   := 1
20
-VER_MIN   := 2
20
+VER_MIN   := 3
21 21
 VER_REV   := 0
22 22
 VERSION   := $(VER_MAJ).$(VER_MIN).$(VER_REV)
23 23
 
... ...
@@ -12,8 +12,8 @@ are sent for one frame - a single MCUF frame to every distributor.
12 12
 The coordinates of the pixels in the MCUF packets do not correspond to pixel
13 13
 locations, but to pixel addresses. The y coordinate is the number of the
14 14
 output of the distributor and the x coordinate is the number of the pixel
15
-in the chain. The number of channels is always 3 (RGB) and the maximum value
16
-is always 255 (8 bit per channel).
15
+in the chain. The number of channels is always 1 (monochrome)  or 3 (RGB) and
16
+the maximum value is always 255 (8 bit per channel).
17 17
 
18 18
 This library can be used to send the required UDP packets to the EtherPix
19 19
 display to make it show images and/or videos.
... ...
@@ -41,8 +41,9 @@ distributorAddr 0 = 192.168.0.111:2323
41 41
 # and the values transmitted to the display
42 42
 # a mapping is configured per distributor and applies to all pixels
43 43
 # connected to it
44
+# RGB distributors use red, green and blue, monochrone distributors use white
44 45
 # syntax:
45
-#   mapping <distno> (red|green|blue) = <base> <factor> <gamma>
46
+#   mapping <distno> (red|green|blue|white) = <base> <factor> <gamma>
46 47
 # description:
47 48
 #   distno: number of distributor
48 49
 #   base, factor, gamma: floating-point values used in formula
... ...
@@ -0,0 +1,72 @@
1
+# EtherPix configuration file for screen with 2x2 panels of 8x12 pixels each
2
+
3
+# address of local output socket
4
+# all distributors must be reachable from this address
5
+# syntax:
6
+#   bindAddr = <IPv4>:<port>
7
+# description:
8
+#   IPv4: IPv4 address, 0.0.0.0 for all local interfaces
9
+#   port: UDP port number, 0 for automatic selection
10
+bindAddr = 0.0.0.0:0
11
+
12
+# size of the (virtual) rectangluar display
13
+# syntax:
14
+#   size = <width>,<height>
15
+# description:
16
+#   width: width in pixels
17
+#   height: height in pixels
18
+size = 16,24
19
+
20
+# configure distributors
21
+# syntax:
22
+#   distributor <distno> = <outputs>,<pixels>
23
+# description:
24
+#   distno: number of distributor
25
+#   outputs: number of outputs per distributor
26
+#   pixels: number of pixels per output
27
+distributor 0 = 32,96
28
+
29
+# set address of distributor
30
+# if address is not set, default IP/UDP configuration is used:
31
+#   IPv4: 10.70.80.<distno>
32
+#   UDP port: 2323
33
+# syntax:
34
+#   distributorAddr = <IPv4>:<port>
35
+# description:
36
+#   IPv4: IPv4 address
37
+#   port: UDP port number
38
+distributorAddr 0 = 192.168.0.111:2323
39
+
40
+# configure mapping between the color channel values in the video
41
+# and the values transmitted to the display
42
+# a mapping is configured per distributor and applies to all pixels
43
+# connected to it
44
+# RGB distributors use red, green and blue, monochrone distributors use white
45
+# syntax:
46
+#   mapping <distno> (red|green|blue|white) = <base> <factor> <gamma>
47
+# description:
48
+#   distno: number of distributor
49
+#   base, factor, gamma: floating-point values used in formula
50
+# mapping formula:
51
+#   display := base + factor * video ** (1.0 / gamma)
52
+# description:
53
+#   display: the value sent to the actual pixel connected to the distributor
54
+#   video: the color channel value taken from the video
55
+mapping 0 white = 0.0 1.0 1.0
56
+
57
+# specify logical positions of the pixels at distributor outputs
58
+# for each physical pixel, the source pixel in the video is specified
59
+# in video coordinates
60
+# syntax:
61
+#   output <distno>,<outno> = <px 1 x>,<px 1 y> <px 2 x>,<px 2 y> ...
62
+#   <pixel N>
63
+# description:
64
+#   distno: number of distributor
65
+#   outno: number of output of distributor
66
+#   px i x/y: the x/y cordinate of the video pixel whose color is to be sent
67
+#             to the i-th pixel connected to the output of the distributor
68
+output 0,0 = 0,11 0,10 0,9 0,8 0,7 0,6 0,5 0,4 0,3 0,2 0,1 0,0 1,0 1,1 1,2 1,3 1,4 1,5 1,6 1,7 1,8 1,9 1,10 1,11 2,11 2,10 2,9 2,8 2,7 2,6 2,5 2,4 2,3 2,2 2,1 2,0 3,0 3,1 3,2 3,3 3,4 3,5 3,6 3,7 3,8 3,9 3,10 3,11 4,11 4,10 4,9 4,8 4,7 4,6 4,5 4,4 4,3 4,2 4,1 4,0 5,0 5,1 5,2 5,3 5,4 5,5 5,6 5,7 5,8 5,9 5,10 5,11 6,11 6,10 6,9 6,8 6,7 6,6 6,5 6,4 6,3 6,2 6,1 6,0 7,0 7,1 7,2 7,3 7,4 7,5 7,6 7,7 7,8 7,9 7,10 7,11
69
+output 0,1 = 0,23 0,22 0,21 0,20 0,19 0,18 0,17 0,16 0,15 0,14 0,13 0,12 1,12 1,13 1,14 1,15 1,16 1,17 1,18 1,19 1,20 1,21 1,22 1,23 2,23 2,22 2,21 2,20 2,19 2,18 2,17 2,16 2,15 2,14 2,13 2,12 3,12 3,13 3,14 3,15 3,16 3,17 3,18 3,19 3,20 3,21 3,22 3,23 4,23 4,22 4,21 4,20 4,19 4,18 4,17 4,16 4,15 4,14 4,13 4,12 5,12 5,13 5,14 5,15 5,16 5,17 5,18 5,19 5,20 5,21 5,22 5,23 6,23 6,22 6,21 6,20 6,19 6,18 6,17 6,16 6,15 6,14 6,13 6,12 7,12 7,13 7,14 7,15 7,16 7,17 7,18 7,19 7,20 7,21 7,22 7,23
70
+output 0,2 = 8,11 8,10 8,9 8,8 8,7 8,6 8,5 8,4 8,3 8,2 8,1 8,0 9,0 9,1 9,2 9,3 9,4 9,5 9,6 9,7 9,8 9,9 9,10 9,11 10,11 10,10 10,9 10,8 10,7 10,6 10,5 10,4 10,3 10,2 10,1 10,0 11,0 11,1 11,2 11,3 11,4 11,5 11,6 11,7 11,8 11,9 11,10 11,11 12,11 12,10 12,9 12,8 12,7 12,6 12,5 12,4 12,3 12,2 12,1 12,0 13,0 13,1 13,2 13,3 13,4 13,5 13,6 13,7 13,8 13,9 13,10 13,11 14,11 14,10 14,9 14,8 14,7 14,6 14,5 14,4 14,3 14,2 14,1 14,0 15,0 15,1 15,2 15,3 15,4 15,5 15,6 15,7 15,8 15,9 15,10 15,11
71
+output 0,3 = 8,23 8,22 8,21 8,20 8,19 8,18 8,17 8,16 8,15 8,14 8,13 8,12 9,12 9,13 9,14 9,15 9,16 9,17 9,18 9,19 9,20 9,21 9,22 9,23 10,23 10,22 10,21 10,20 10,19 10,18 10,17 10,16 10,15 10,14 10,13 10,12 11,12 11,13 11,14 11,15 11,16 11,17 11,18 11,19 11,20 11,21 11,22 11,23 12,23 12,22 12,21 12,20 12,19 12,18 12,17 12,16 12,15 12,14 12,13 12,12 13,12 13,13 13,14 13,15 13,16 13,17 13,18 13,19 13,20 13,21 13,22 13,23 14,23 14,22 14,21 14,20 14,19 14,18 14,17 14,16 14,15 14,14 14,13 14,12 15,12 15,13 15,14 15,15 15,16 15,17 15,18 15,19 15,20 15,21 15,22 15,23
72
+
... ...
@@ -41,8 +41,9 @@ distributorAddr 0 = 192.168.0.111:2323
41 41
 # and the values transmitted to the display
42 42
 # a mapping is configured per distributor and applies to all pixels
43 43
 # connected to it
44
+# RGB distributors use red, green and blue, monochrone distributors use white
44 45
 # syntax:
45
-#   mapping <distno> (red|green|blue) = <base> <factor> <gamma>
46
+#   mapping <distno> (red|green|blue|white) = <base> <factor> <gamma>
46 47
 # description:
47 48
 #   distno: number of distributor
48 49
 #   base, factor, gamma: floating-point values used in formula
... ...
@@ -42,8 +42,9 @@ distributorAddr 0 = 127.0.0.1:23000 # simulator
42 42
 # and the values transmitted to the display
43 43
 # a mapping is configured per distributor and applies to all pixels
44 44
 # connected to it
45
+# RGB distributors use red, green and blue, monochrone distributors use white
45 46
 # syntax:
46
-#   mapping <distno> (red|green|blue) = <base> <factor> <gamma>
47
+#   mapping <distno> (red|green|blue|white) = <base> <factor> <gamma>
47 48
 # description:
48 49
 #   distno: number of distributor
49 50
 #   base, factor, gamma: floating-point values used in formula
... ...
@@ -41,8 +41,9 @@ distributorAddr 0 = 127.0.0.1:23000 # simulator
41 41
 # and the values transmitted to the display
42 42
 # a mapping is configured per distributor and applies to all pixels
43 43
 # connected to it
44
+# RGB distributors use red, green and blue, monochrone distributors use white
44 45
 # syntax:
45
-#   mapping <distno> (red|green|blue) = <base> <factor> <gamma>
46
+#   mapping <distno> (red|green|blue|white) = <base> <factor> <gamma>
46 47
 # description:
47 48
 #   distno: number of distributor
48 49
 #   base, factor, gamma: floating-point values used in formula
... ...
@@ -29,7 +29,8 @@ distributor 15 = 6,64
29 29
 
30 30
 # those lines introduce a mapping between the channel values in the video and the values transmitted to the display
31 31
 #  - mapping is done per distributor and applies to all pixels connected to it
32
-#  - the general format is: mapping <distributor number> (red|green|blue) = <base> <factor> <gamma>
32
+#  - RGB distributors use red, green and blue, monochrone distributors use white
33
+#  - the general format is: mapping <distributor number> (red|green|blue|white) = <base> <factor> <gamma>
33 34
 #  - the mapping formula is: <display value> := <base> + <factor> * <original value> ^ (1 / <gamma>)
34 35
 mapping 0 red = 0.005 0.99 1.0
35 36
 mapping 0 green = 0.005 0.99 1.0
... ...
@@ -0,0 +1,26 @@
1
+# EtherPix configuration file
2
+
3
+# the address to bind the local socket to
4
+#  - the EtherPix network 10.70.80.0/16 must be reachable from this address
5
+bindAddr = 0.0.0.0:0
6
+
7
+# the size of the display
8
+#  - <width>,<height> in pixels
9
+size = 8,8
10
+
11
+# this line adds a new distributor
12
+#  - the general format is: distributor <distributor number> = <number of outputs>,<number of pixel per output>
13
+distributor 0 = 6,64
14
+
15
+# those lines introduce a mapping between the channel values in the video and the values transmitted to the display
16
+#  - mapping is done per distributor and applies to all pixels connected to it
17
+#  - RGB distributors use red, green and blue, monochrone distributors use white
18
+#  - the general format is: mapping <distributor number> (red|green|blue|white) = <base> <factor> <gamma>
19
+#  - the mapping formula is: <display value> := <base> + <factor> * <original value> ^ (1 / <gamma>)
20
+mapping 0 white = 0.0 1.0 1.0
21
+
22
+# these lines specify the logical positions of the pixels at an output in movie coordinates
23
+#  - the general format is: output <distributor number>,<output number> = <pixel x>,<pixel y> ...
24
+#  - the order of the pixels is the order they are connected in the chain
25
+output 0,0 = 0,0 1,0 2,0 3,0 4,0 5,0 6,0 7,0 7,1 6,1 5,1 4,1 3,1 2,1 1,1 0,1 0,2 1,2 2,2 3,2 4,2 5,2 6,2 7,2 7,3 6,3 5,3 4,3 3,3 2,3 1,3 0,3 0,4 1,4 2,4 3,4 4,4 5,4 6,4 7,4 7,5 6,5 5,5 4,5 3,5 2,5 1,5 0,5 0,6 1,6 2,6 3,6 4,6 5,6 6,6 7,6 7,7 6,7 5,7 4,7 3,7 2,7 1,7 0,7
26
+
... ...
@@ -14,7 +14,8 @@ distributor 0 = 6,64
14 14
 
15 15
 # those lines introduce a mapping between the channel values in the video and the values transmitted to the display
16 16
 #  - mapping is done per distributor and applies to all pixels connected to it
17
-#  - the general format is: mapping <distributor number> (red|green|blue) = <base> <factor> <gamma>
17
+#  - RGB distributors use red, green and blue, monochrone distributors use white
18
+#  - the general format is: mapping <distributor number> (red|green|blue|white) = <base> <factor> <gamma>
18 19
 #  - the mapping formula is: <display value> := <base> + <factor> * <original value> ^ (1 / <gamma>)
19 20
 mapping 0 red = 0.0 1.0 1.0
20 21
 mapping 0 green = 0.0 1.0 1.0
... ...
@@ -32,6 +32,7 @@ typedef struct etp_display_s etp_display_t;
32 32
 typedef enum etp_pixfmt_e {
33 33
   etp_pixfmt_rgb24, /**< 24 bit RGB data, 3 bytes: red, green, blue */
34 34
   etp_pixfmt_bgr24, /**< 24 bit BGR data, 3 bytes: blue, green, red */
35
+  etp_pixfmt_mono8, /**< 8 bit monochrome data, 1 byte: white */
35 36
 } etp_pixfmt_t;
36 37
 
37 38
 /**
... ...
@@ -110,6 +110,8 @@ int etp_config_proc_distri(etp_config_ctx_t *p_ctx, char *p_setting_part2,
110 110
   p_distri->pixel_cnt = pix;
111 111
   /* no network address yet */
112 112
   p_distri->addr_cnt = 0;
113
+  /* RGB by default */
114
+  p_distri->channels = 3;
113 115
   /* initialize mapping information */
114 116
   for (i = 0; i < 3; i++) {
115 117
     p_distri->mapping[i].base = 0.0;
... ...
@@ -130,9 +132,9 @@ int etp_config_proc_distri(etp_config_ctx_t *p_ctx, char *p_setting_part2,
130 132
     p_distri->p_pixels[i].x = -1;
131 133
     p_distri->p_pixels[i].y = -1;
132 134
   }
133
-  /* create and initialize message buffer */
134
-  p_distri->msg_len = ETP_MCUF_HDR_LEN + out * pix * 3;
135
-  p_distri->p_msg_buf = (etp_u8_t *)malloc(p_distri->msg_len);
135
+  /* create and initialize message buffer (for up to 3 channels) */
136
+  p_distri->msg_buf_len = ETP_MCUF_HDR_LEN + out * pix * 3;
137
+  p_distri->p_msg_buf = (etp_u8_t *)malloc(p_distri->msg_buf_len);
136 138
   if (!p_distri->p_msg_buf) {
137 139
     free(p_distri->p_pixels);
138 140
     free(p_distri);
... ...
@@ -140,7 +142,7 @@ int etp_config_proc_distri(etp_config_ctx_t *p_ctx, char *p_setting_part2,
140 142
       p_ctx->p_msg_func(p_ctx->p_msg_ctx, etp_msg_type_err, "out of memory\n");
141 143
     return -1;
142 144
   }
143
-  memset(p_distri->p_msg_buf, 0, p_distri->msg_len);
145
+  memset(p_distri->p_msg_buf, 0, p_distri->msg_buf_len);
144 146
   memcpy(p_distri->p_msg_buf, etp_mcuf_hdr, ETP_MCUF_HDR_LEN);
145 147
   p_distri->p_msg_buf[ETP_MCUF_HDR_OFS_OUTPUTS_U16 + 0] = (etp_u8_t)(out >> 8);
146 148
   p_distri->p_msg_buf[ETP_MCUF_HDR_OFS_OUTPUTS_U16 + 1] = (etp_u8_t)out;
... ...
@@ -239,7 +241,7 @@ int etp_config_proc_mapping(etp_config_ctx_t *p_ctx, char *p_setting_part2,
239 241
 {
240 242
   char *ptr, *ptr2;
241 243
   unsigned long val;
242
-  unsigned int distri, chan;
244
+  unsigned int distri, channels, chan;
243 245
   etp_distri_t *p_distri;
244 246
   double base, factor, gamma;
245 247
 
... ...
@@ -268,13 +270,19 @@ int etp_config_proc_mapping(etp_config_ctx_t *p_ctx, char *p_setting_part2,
268 270
   /* get channel */
269 271
   while (*ptr == ' ' || *ptr == '\t' || *ptr == '\r' || *ptr == '\n')
270 272
     ptr++;
271
-  if (!strcmp(ptr, "red"))
273
+  if (!strcmp(ptr, "red")) {
274
+    channels = 3;
272 275
     chan = 0;
273
-  else if (!strcmp(ptr, "green"))
276
+  } else if (!strcmp(ptr, "green")) {
277
+    channels = 3;
274 278
     chan = 1;
275
-  else if (!strcmp(ptr, "blue"))
279
+  } else if (!strcmp(ptr, "blue")) {
280
+    channels = 3;
276 281
     chan = 2;
277
-  else {
282
+  } else if (!strcmp(ptr, "white")) {
283
+    channels = 1;
284
+    chan = 0;
285
+  } else {
278 286
     if (p_ctx->p_msg_func)
279 287
       p_ctx->p_msg_func(p_ctx->p_msg_ctx, etp_msg_type_err,
280 288
                         "invalid channel \"%s\""
... ...
@@ -337,12 +345,22 @@ int etp_config_proc_mapping(etp_config_ctx_t *p_ctx, char *p_setting_part2,
337 345
     return -1;
338 346
   }
339 347
 
340
-  /* store new mapping parameters and re-calculate mapping table */
348
+  /* store number of channels as well as new mapping parameters
349
+   * and re-calculate mapping table */
350
+  p_distri->channels = channels;
341 351
   p_distri->mapping[chan].base = base;
342 352
   p_distri->mapping[chan].factor = factor;
343 353
   p_distri->mapping[chan].gamma = gamma;
344 354
   etp_mapping_precalc(&p_distri->mapping[chan]);
345 355
 
356
+  /* update channel count in message buffer and message length
357
+   * (buffer is allocated for 3 channels on distri creation, so this is ok) */
358
+  p_distri->p_msg_buf[ETP_MCUF_HDR_OFS_CHANNELS_U16 + 0]
359
+                                                  = (etp_u8_t)(channels >> 8);
360
+  p_distri->p_msg_buf[ETP_MCUF_HDR_OFS_CHANNELS_U16 + 1] = (etp_u8_t)channels;
361
+  p_distri->msg_len = ETP_MCUF_HDR_LEN +
362
+                      p_distri->output_cnt * p_distri->pixel_cnt * channels;
363
+
346 364
   return 0;
347 365
 }
348 366
 
... ...
@@ -42,6 +42,8 @@
42 42
                                                *   in MCUF data */
43 43
 #define ETP_MCUF_HDR_OFS_PIXELS_U16   (6)     /**< offset of pixel count
44 44
                                                *   in MCUF data */
45
+#define ETP_MCUF_HDR_OFS_CHANNELS_U16 (8)     /**< offset of channel count
46
+                                               *   in MCUF data */
45 47
 #define ETP_MCUF_MAX_FRAME_INTERVAL_MS (1000) /**< maximum interval between
46 48
                                                    two MCUF frames */
47 49
 
... ...
@@ -213,6 +213,7 @@ void etp_display_data_fmt(etp_display_t *p_display, etp_u8_t *p_data,
213 213
   etp_u8_t *dest, *src;
214 214
   etp_pixel_t *p_pixel;
215 215
   int rx, ry;
216
+  etp_u8_t val;
216 217
 
217 218
   /* set data for all distributors */
218 219
   for (distri = 0; distri < ETP_DISTRI_MAX_CNT; distri++) {
... ...
@@ -236,6 +237,25 @@ void etp_display_data_fmt(etp_display_t *p_display, etp_u8_t *p_data,
236 237
               && ry >= 0 && (unsigned int)ry < height) {
237 238
             /* get pixel data and map it */
238 239
             src = (p_data + rx * stride_x + ry * stride_y);
240
+            switch (p_distri->channels) {
241
+              case 1:
242
+                switch (pixfmt) {
243
+                  case etp_pixfmt_rgb24:
244
+                  case etp_pixfmt_bgr24:
245
+                    /* RGB/BGR -> monochrome, emphasize green */
246
+                    val = (etp_u8_t)(((unsigned int)src[0] +
247
+                                      ((unsigned int)src[1] << 1) +
248
+                                      (unsigned int)src[2] + 2) >> 2);
249
+                    dest[0] = p_distri->mapping[0].table[val];
250
+                    break;
251
+                  case etp_pixfmt_mono8:
252
+                    dest[0] = p_distri->mapping[0].table[src[0]];
253
+                    break;
254
+                  default:
255
+                    dest[0] = 0;
256
+                }
257
+                break;
258
+              case 3:
239 259
                 switch (pixfmt) {
240 260
                   case etp_pixfmt_rgb24:
241 261
                     dest[0] = p_distri->mapping[0].table[src[0]];
... ...
@@ -247,14 +267,22 @@ void etp_display_data_fmt(etp_display_t *p_display, etp_u8_t *p_data,
247 267
                     dest[1] = p_distri->mapping[1].table[src[1]];
248 268
                     dest[2] = p_distri->mapping[2].table[src[0]];
249 269
                     break;
270
+                  case etp_pixfmt_mono8:
271
+                    val = p_distri->mapping[0].table[src[0]];
272
+                    dest[0] = val;
273
+                    dest[1] = val;
274
+                    dest[2] = val;
275
+                    break;
250 276
                   default:
251 277
                     dest[0] = 0;
252 278
                     dest[1] = 0;
253 279
                     dest[2] = 0;
254 280
                 }
255
-          }
281
+                break;
282
+            } /* switch channels */
283
+          } /* if */
256 284
 
257
-          dest += 3;
285
+          dest += p_distri->channels;
258 286
         } /* for (pix ...) */
259 287
       } /* for (out ...) */
260 288
 
... ...
@@ -54,16 +54,17 @@ typedef struct etp_distri_s {
54 54
       [ETP_DISTRI_MAX_ADDRS]; /**< network address(es) of distributor,
55 55
                                *   multiple addresses mean the packets are
56 56
                                *   sent to each address */
57
-  etp_mapping_t mapping[3];   /**< mapping information for red, green
57
+  unsigned int channels;      /**< number of chanels: 1 (mono) or 3 (RGB) */
58
+  etp_mapping_t mapping[3];   /**< mapping information for red/white, green
58 59
                                *   and blue channel */
59 60
   etp_pixel_t *p_pixels;      /**< array with information about pixels
60 61
                                *   of this distributor,
61 62
                                *   index = output * pixel_cnt + pixel,
62 63
                                *   malloc-ed */
63
-  unsigned int msg_len;       /**< size of a message to send to distributor */
64
+  unsigned int msg_buf_len;   /**< size of buffer for message */
64 65
   etp_u8_t *p_msg_buf;        /**< buffer for current message to send
65
-                               *   to distributor,
66
-                               *   malloc-ed */
66
+                               *   to distributor, malloc-ed */
67
+  unsigned int msg_len;       /**< size of a message to send to distributor */
67 68
 } etp_distri_t;
68 69
 
69 70
 /** information about a display */
70 71