Stefan Schuermans commited on 2018-11-01 14:01:10
Showing 9 changed files, with 90 additions and 26 deletions.
... | ... |
@@ -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 |