add support for monochrome distributors
Stefan Schuermans

Stefan Schuermans commited on 2018-11-01 14:01:10
Showing 9 changed files, with 90 additions and 26 deletions.

... ...
@@ -16,7 +16,7 @@
16 16
 # along with this program. If not, see <http://www.gnu.org/licenses/>.
17 17
 
18 18
 VERSION_MAJOR=1
19
-VERSION_MINOR=2
19
+VERSION_MINOR=3
20 20
 VERSION_REVISION=0
21 21
 
22 22
 JAVAC=javac
... ...
@@ -1,6 +1,6 @@
1 1
 JEtherPix - Java implementation of EtherPix output library
2 2
 
3
-EtherPix is a large scale display architecure that is driven using UDP/IP.
3
+EtherPix is a large scale display architecture that is driven using UDP/IP.
4 4
 It consists of single pixels that are connected to chains. A number of those
5 5
 pixel chains is then connected to a so called distributor module that
6 6
 receives data over ethernet and distributes it to the pixel chains.
... ...
@@ -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.
... ...
@@ -169,7 +169,7 @@ class Config
169 169
     Pattern pattern;
170 170
     Matcher matcher;
171 171
     String strDistri, strChannel, strBase, strFactor, strGamma;
172
-    int dist;
172
+    int dist, prev_channels;
173 173
     Distri distri;
174 174
     Mapping mapping = null;
175 175
     double base = 0.0, factor = 1.0, gamma = 1.0;
... ...
@@ -199,16 +199,24 @@ class Config
199 199
       errorExc(String.format("no distributor with number \"%d\"" +
200 200
                              " in line %d of config file", dist, m_lineNo));
201 201
 
202
-    // get channel
203
-    if (strChannel.equals("red"))
204
-      mapping = distri.m_mapRed;
205
-    else if (strChannel.equals("green"))
202
+    // get channel (and implicitly number of channels)
203
+    prev_channels = distri.m_channels;
204
+    if (strChannel.equals("red")) {
205
+      distri.m_channels = 3;
206
+      mapping = distri.m_mapRedWhite;
207
+    } else if (strChannel.equals("green")) {
208
+      distri.m_channels = 3;
206 209
       mapping = distri.m_mapGreen;
207
-    else if (strChannel.equals("blue"))
210
+    } else if (strChannel.equals("blue")) {
211
+      distri.m_channels = 3;
208 212
       mapping = distri.m_mapBlue;
209
-    else
213
+    } else if (strChannel.equals("white")) {
214
+      distri.m_channels = 1;
215
+      mapping = distri.m_mapRedWhite;
216
+    } else {
210 217
       errorExc("invalid channel \"" + strChannel + "\"" +
211 218
                String.format(" in line %d of config file", m_lineNo));
219
+    }
212 220
 
213 221
     // split mapping parameters
214 222
     pattern = Pattern.compile("^([-+.eE0-9]+) +([-+.eE0-9]+) +([-+.eE0-9]+)$");
... ...
@@ -235,6 +243,11 @@ class Config
235 243
 
236 244
     // update mapping parameters
237 245
     mapping.set(base, factor, gamma);
246
+
247
+    // update message buffer if channel count changed
248
+    if (distri.m_channels != prev_channels) {
249
+      distri.allocMsgBuf();
250
+    }
238 251
   }
239 252
 
240 253
   /**
... ...
@@ -38,10 +38,11 @@ class Constants
38 38
   static byte [] mcufHdr    = {  ///< data of MCUF header
39 39
     (byte)0x23, (byte)0x54, (byte)0x26, (byte)0x66,
40 40
     (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
41
-    (byte)0x00, (byte)0x03, (byte)0x00, (byte)0xFF
41
+    (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xFF
42 42
   };
43 43
   static int mcufOfsOutputsU16  = 4; /**< offset of output count in MCUF data */
44 44
   static int mcufOfsPixelsU16   = 6; /**< offset of pixel count in MCUF data */
45
+  static int mcufOfsChannelsU16 = 8; /**< offset of chan count in MCUF data */
45 46
 
46 47
   // fixed settings constants
47 48
   static int destIpBase   = 0x0A465000; /**< base IP address of distributors,
... ...
@@ -143,13 +143,23 @@ public class Display
143 143
               if (rx >= 0 && rx < width && ry >= 0 && ry < height) {
144 144
                 // get pixel data and map it
145 145
                 src = rx * strideX + ry * strideY + base;
146
-                distri.m_msgBuf[dest+0] = distri.m_mapRed.m_table[data[src+0] & 0xFF];
146
+                // monochrome (convert, emphasize green)
147
+                if (distri.m_channels == 1) {
148
+                  distri.m_msgBuf[dest] = (byte)(
149
+                    (distri.m_mapRedWhite.m_table[data[src+0] & 0xFF] +
150
+                     (distri.m_mapGreen.m_table[data[src+1] & 0xFF] << 1) +
151
+                     distri.m_mapBlue.m_table[data[src+2] & 0xFF] + 2) >> 2);
152
+                }
153
+                // RGB
154
+                else if (distri.m_channels == 3) {
155
+                  distri.m_msgBuf[dest+0] = distri.m_mapRedWhite.m_table[data[src+0] & 0xFF];
147 156
                   distri.m_msgBuf[dest+1] = distri.m_mapGreen.m_table[data[src+1] & 0xFF];
148 157
                   distri.m_msgBuf[dest+2] = distri.m_mapBlue.m_table[data[src+2] & 0xFF];
149 158
                 }
159
+              }
150 160
 
151 161
             } // if pixel
152
-            dest += 3;
162
+            dest += distri.m_channels;
153 163
           } // for pix
154 164
         } // for out
155 165
 
... ...
@@ -36,9 +36,10 @@ class Distri
36 36
     m_distri    = distri;
37 37
     m_outputCnt = outputCnt;
38 38
     m_pixelCnt  = pixelCnt;
39
+    m_channels  = 3; // RGB by default
39 40
 
40 41
     // allocate default mappings
41
-    m_mapRed   = new Mapping();
42
+    m_mapRedWhite = new Mapping();
42 43
     m_mapGreen    = new Mapping();
43 44
     m_mapBlue     = new Mapping();
44 45
 
... ...
@@ -46,13 +47,7 @@ class Distri
46 47
     m_pixels = new Pixel [m_outputCnt * m_pixelCnt];
47 48
 
48 49
     // allocate and initialize message buffer
49
-    m_msgBuf = Arrays.copyOf(Constants.mcufHdr,
50
-                             Constants.mcufHdr.length +
51
-                             m_outputCnt * m_pixelCnt * 3);
52
-    m_msgBuf[Constants.mcufOfsOutputsU16 + 0] = (byte)(m_outputCnt >> 8);
53
-    m_msgBuf[Constants.mcufOfsOutputsU16 + 1] = (byte)m_outputCnt;
54
-    m_msgBuf[Constants.mcufOfsPixelsU16 + 0]  = (byte)(m_pixelCnt >> 8);
55
-    m_msgBuf[Constants.mcufOfsPixelsU16 + 1]  = (byte)m_pixelCnt;
50
+    allocMsgBuf();
56 51
   }
57 52
 
58 53
   /**
... ...
@@ -79,14 +74,31 @@ class Distri
79 74
     }
80 75
   }
81 76
 
77
+  /**
78
+   * @brief allocate and initialize message buffer
79
+   */
80
+  void allocMsgBuf()
81
+  {
82
+    m_msgBuf = Arrays.copyOf(Constants.mcufHdr,
83
+                             Constants.mcufHdr.length +
84
+                             m_outputCnt * m_pixelCnt * m_channels);
85
+    m_msgBuf[Constants.mcufOfsOutputsU16 + 0] = (byte)(m_outputCnt >> 8);
86
+    m_msgBuf[Constants.mcufOfsOutputsU16 + 1] = (byte)m_outputCnt;
87
+    m_msgBuf[Constants.mcufOfsPixelsU16 + 0]  = (byte)(m_pixelCnt >> 8);
88
+    m_msgBuf[Constants.mcufOfsPixelsU16 + 1]  = (byte)m_pixelCnt;
89
+    m_msgBuf[Constants.mcufOfsChannelsU16 + 0]  = (byte)(m_channels >> 8);
90
+    m_msgBuf[Constants.mcufOfsChannelsU16 + 1]  = (byte)m_channels;
91
+  }
92
+
82 93
   int               m_distri;      ///< number of this distributor
83 94
   int               m_outputCnt;   ///< number of outputs
84 95
   int               m_pixelCnt;    ///< number pixels connected to every output
85 96
   InetSocketAddress [] m_addrs;    /**< network address(es) of distributor,
86 97
                                         multiple addresses mean the packets are
87 98
                                         sent to each address */
88
-  Mapping           m_mapRed;    ///< mapping information for red channel
89
-  Mapping           m_mapGreen;  ///< mapping information for Green channel
99
+  int               m_channels;    ///< number of channels: 1 (mono)or 3 (RGB)
100
+  Mapping           m_mapRedWhite; ///< mapping information for red/white chan
101
+  Mapping           m_mapGreen;    ///< mapping information for green channel
90 102
   Mapping           m_mapBlue;     ///< mapping information for blue channel
91 103
   Pixel []          m_pixels;      /**< information about pixels of this
92 104
                                         distributor,
... ...
@@ -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
21 22