implemented more parts of config parser and socket handling in display class
Stefan Schuermans

Stefan Schuermans commited on 2011-09-11 09:25:44
Showing 5 changed files, with 286 additions and 35 deletions.

... ...
@@ -32,7 +32,8 @@ JAVA=java
32 32
 PKG_PATH=org/blinkenarea/JFlexiPix
33 33
 PKG_PATH_EX=$(PKG_PATH)/examples
34 34
 
35
-CLASSES=Config Constants Display Distri Mapping MessageIf MsgType Pixel
35
+CLASSES=AddrParser Config Constants Display Distri \
36
+        Mapping MessageIf MsgType Pixel PixelParser
36 37
 CLASSES_EX=Blink Msg
37 38
 CLASS_FILES=$(addprefix $(PKG_PATH)/,$(addsuffix .class,$(CLASSES)))
38 39
 CLASS_FILES_EX=$(addprefix $(PKG_PATH_EX)/,$(addsuffix .class,$(CLASSES_EX)))
... ...
@@ -44,16 +45,18 @@ CLASSPATH=.
44 45
 .SUFFIXES:
45 46
 .SECONDARY:
46 47
 
47
-all: jar
48
+all: jar $(CLASS_FILES_EX)
48 49
 
49 50
 clean:
50 51
 	rm -f $(PKG_PATH)/Version.java $(CLASS_FILES) JFlexiPix.jar
51 52
 
52
-jar: JFlexiPix.jar $(CLASS_FILES_EX)
53
+jar: JFlexiPix.jar
53 54
 
54 55
 blink: $(PKG_PATH_EX)/Blink.class
55 56
 	$(JAVA) -classpath . $(subst /,.,$(basename $<)) $(CONFIG_EX)
56 57
 
58
+$(CLASS_FILES_EX): $(CLASS_FILES)
59
+
57 60
 $(PKG_PATH)/Version.java: Makefile
58 61
 	echo "package org.blinkenarea.JFlexiPix;" >$@
59 62
 	echo "public class Version {" >>$@
... ...
@@ -0,0 +1,65 @@
1
+/* JFlexiPix - Java implementation of FlexiPix output library
2
+ *
3
+ * Copyright 2010-2011 Stefan Schuermans <stefan blinkenarea org>
4
+ *
5
+ * This program is free software: you can redistribute it and/or modify
6
+ * it under the terms of the GNU General Public License as published by
7
+ * the Free Software Foundation, version 3 of the License.
8
+ *
9
+ *
10
+ * This program is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
+ * GNU General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU Lesser General Public License
16
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+
19
+package org.blinkenarea.JFlexiPix;
20
+
21
+import java.net.*;
22
+import java.util.regex.*;
23
+
24
+/// parser for a socket address
25
+class AddrParser
26
+{
27
+  /**
28
+   * @brief parse address
29
+   * @param[in] text address in text form ("host:port")
30
+   * @return address or null
31
+   */
32
+  static InetSocketAddress parseAddr(String text)
33
+  {
34
+    Pattern pattern;
35
+    Matcher matcher;
36
+    String strHost, strPort;
37
+    InetAddress host;
38
+    int port;
39
+
40
+    // split text into host and port
41
+    pattern = Pattern.compile("^([-.a-zA-Z0-9_]+):([0-9]+)$");
42
+    matcher = pattern.matcher(text);
43
+    if (!matcher.find())
44
+      return null;
45
+    strHost = matcher.group(1);
46
+    strPort = matcher.group(2);
47
+
48
+    // parse host
49
+    try {
50
+      host = InetAddress.getByName(strHost);
51
+    } catch (UnknownHostException e) {
52
+      return null;
53
+    }
54
+
55
+    // parse port
56
+    try {
57
+      port = Integer.parseInt(strPort);
58
+    } catch (NumberFormatException e) {
59
+      return null;
60
+    }
61
+
62
+    return new InetSocketAddress(host, port);
63
+  }
64
+}
65
+
... ...
@@ -19,6 +19,7 @@
19 19
 package org.blinkenarea.JFlexiPix;
20 20
 
21 21
 import java.io.*;
22
+import java.net.*;
22 23
 import java.util.*;
23 24
 import java.util.regex.*;
24 25
 
... ...
@@ -61,7 +62,43 @@ class Config
61 62
   void procDistri(String settingPart2, String value)
62 63
     throws Exception
63 64
   {
64
-    // TODO
65
+    int dist, out, pix;
66
+    Pixel px;
67
+
68
+    // get distributor number
69
+    try {
70
+      dist = Integer.parseInt(settingPart2);
71
+    } catch (NumberFormatException e) {
72
+      dist = Constants.distriMaxCnt; // force error in next line
73
+    }
74
+    if (dist >= Constants.distriMaxCnt)
75
+      error("invalid distributor number \"" + settingPart2 +
76
+            String.format(" in line %d of config file", m_lineNo));
77
+
78
+    // get number of outputs and pixels
79
+    px = PixelParser.parsePixel(value); // abuse for "outputs,pixels"
80
+    if (px == null)
81
+      error("invalid distributor size \"" + value +
82
+            String.format(" in line %d of config file", m_lineNo));
83
+    out = px.m_x;
84
+    if (out >= Constants.outputMaxCnt)
85
+      error(String.format("invalid number of outputs \"%d\"" +
86
+                          " in line %d of config file", out, m_lineNo));
87
+    pix = px.m_y;
88
+    if (pix >= Constants.pixelMaxCnt)
89
+      error(String.format("invalid number of pixels \"%d\"" +
90
+                          " in line %d of config file", pix, m_lineNo));
91
+
92
+    // check if distributor is already present
93
+    if (m_display.m_distris[dist] != null)
94
+      error(String.format("duplicate definition of distributor \"%d\"" +
95
+                          " in line %d of config file", dist, m_lineNo));
96
+
97
+    // create new distributor
98
+    m_display.m_distris[dist] = new Distri(dist, out, pix);
99
+
100
+    // count distributors
101
+    ++m_display.m_distriCnt;
65 102
   }
66 103
 
67 104
   /**
... ...
@@ -111,10 +148,58 @@ class Config
111 148
   void procSetting(String setting, String value)
112 149
     throws Exception
113 150
   {
114
-    // TODO
151
+    InetSocketAddress addr;
152
+    Pixel pix;
153
+
154
+    // replace all whitespace in setting with spaces
155
+    setting = setting.replace('\t', ' ').replace('\r', ' ')
156
+                     .replace('\n', ' ').replace('\f', ' ');
157
+
158
+    // bind address of UDP output
159
+    if (setting.equals("bindAddr")) {
160
+      addr = AddrParser.parseAddr(value);
161
+      if (addr == null) {
162
+        error("invalid addess \"" + value + "\" for \"" + setting +
163
+              String.format(" in line %d of config file", m_lineNo));
164
+      }
165
+      info("bind address: " + addr.toString());
166
+      m_display.m_bindAddr = addr;
167
+      return;
168
+    }
169
+
170
+    // size of display
171
+    if (setting.equals("size")) {
172
+      pix = PixelParser.parsePixel(value);
173
+      if (pix == null || pix.m_x <= 0 || pix.m_y <= 0) {
174
+        error("invalid value \"" + value + "\" for \"" + setting +
175
+              String.format(" in line %d of config file", m_lineNo));
176
+      }
177
+      m_display.m_size = pix;
178
+      return;
179
+    }
180
+
181
+    // distributor
182
+    if (setting.startsWith("distributor ")) {
183
+      procDistri(setting.substring(12), value);
184
+      return;
185
+    }
186
+
187
+    // mapping
188
+    if (setting.startsWith("mapping ")) {
189
+      procMapping(setting.substring(8), value);
190
+      return;
191
+    }
115 192
 
116
-    // DEBUG
117
-    System.out.println("setting=" + setting + " value=" + value + "\n");
193
+    // distributor
194
+    if (setting.startsWith("output ")) {
195
+      procOutput(setting.substring(7), value);
196
+      return;
197
+    }
198
+
199
+    // unknown setting
200
+    warning("unknown setting \"" + setting +
201
+            String.format(" in line %d of config file", m_lineNo) +
202
+            ", ignored");
118 203
   }
119 204
 
120 205
   /**
... ...
@@ -158,32 +243,23 @@ class Config
158 243
   void procFile(String configFileName)
159 244
     throws Exception
160 245
   {
161
-    FileReader fr;
162
-    BufferedReader br;
246
+    FileReader fr = null;
247
+    BufferedReader br = null;
163 248
     String line;
164 249
 
165 250
     // check file name
166
-    if (configFileName.length() == 0) {
167
-      String txt = "no config file specified";
168
-      if (m_messageIf != null)
169
-        m_messageIf.message(MsgType.Err, txt + "\n");
170
-      throw new Exception(txt);
171
-    }
251
+    if (configFileName.length() == 0)
252
+      error("no config file specified");
172 253
 
173
-    if (m_messageIf != null)
174
-      m_messageIf.message(MsgType.Info,
175
-                          "using config file \"" + configFileName + "\"\n");
254
+    info("using config file \"" + configFileName + "\"");
176 255
 
177 256
     // open file
178 257
     try {
179 258
       fr = new FileReader(configFileName);
180 259
       br = new BufferedReader(fr);
181 260
     } catch (FileNotFoundException e) {
182
-      String txt = "cannot open config file \"" + configFileName +
183
-                   "\" for reading: " + e.getMessage() + "\n";
184
-      if (m_messageIf != null)
185
-        m_messageIf.message(MsgType.Err, txt + "\n");
186
-      throw new Exception(txt);
261
+      error("cannot open config file \"" + configFileName +
262
+            "\" for reading", e);
187 263
     }
188 264
 
189 265
     // read lines and process them
... ...
@@ -197,19 +273,59 @@ class Config
197 273
     br.close();
198 274
     fr.close();
199 275
 
200
-    if (m_messageIf != null)
201
-      m_messageIf.message(MsgType.Info,
202
-                          String.format("%dx%d input format, ",
203
-                                        m_display.m_size.m_x, m_display.m_size.m_y) +
204
-                          String.format("%d distributors, ",
205
-                                        m_display.m_distriCnt ) +
206
-                          String.format("%d outputs, ",
207
-                                        m_display.m_outputCnt ) +
208
-                          String.format("%d pixels, ",
209
-                                        m_display.m_pixelCnt) +
276
+    info(String.format("%dx%d input format, ", m_display.m_size.m_x,
277
+                                               m_display.m_size.m_y) +
278
+         String.format("%d distributors, ",    m_display.m_distriCnt ) +
279
+         String.format("%d outputs, ",         m_display.m_outputCnt ) +
280
+         String.format("%d pixels, ",          m_display.m_pixelCnt) +
210 281
          "\n");
211 282
   }
212 283
 
284
+  /**
285
+   * @brief report error message and throw exception
286
+   * @param[in] txt error text
287
+   */
288
+  private void error(String txt)
289
+    throws Exception
290
+  {
291
+    if (m_messageIf != null)
292
+      m_messageIf.message(MsgType.Err, txt + "\n");
293
+    throw new Exception(txt);
294
+  }
295
+
296
+  /**
297
+   * @brief report error message and throw exception
298
+   * @param[in] txt error text
299
+   * @param[in] e reason for error
300
+   */
301
+  private void error(String txt, Exception e)
302
+    throws Exception
303
+  {
304
+    if (m_messageIf != null)
305
+      m_messageIf.message(MsgType.Err, txt + ": " + e.getMessage() + "\n");
306
+    throw new Exception(txt, e);
307
+  }
308
+
309
+  /**
310
+   * @brief report warning message
311
+   * @param[in] txt warning text
312
+   */
313
+  private void warning(String txt)
314
+  {
315
+    if (m_messageIf != null)
316
+      m_messageIf.message(MsgType.Warn, txt + "\n");
317
+  }
318
+
319
+  /**
320
+   * @brief report information message
321
+   * @param[in] txt information text
322
+   */
323
+  private void info(String txt)
324
+  {
325
+    if (m_messageIf != null)
326
+      m_messageIf.message(MsgType.Info, txt + "\n");
327
+  }
328
+
213 329
   Display   m_display;      ///< display to configure
214 330
   MessageIf m_messageIf;    ///< message interface to report messages to or null
215 331
   int       m_lineNo;       ///< current line in config file
... ...
@@ -38,7 +38,7 @@ public class Display
38 38
       InetAddress ip = InetAddress.getByAddress(Constants.bindIp);
39 39
       m_bindAddr = new InetSocketAddress(ip, Constants.bindPort);
40 40
     } catch (java.net.UnknownHostException e) {
41
-      String txt = "internal error: bad default bin address";
41
+      String txt = "internal error: bad default bind address";
42 42
       if (messageIf != null)
43 43
         messageIf.message(MsgType.Err, txt + "\n");
44 44
       throw new Exception(txt, e);
... ...
@@ -68,7 +68,14 @@ public class Display
68 68
     config = null;
69 69
 
70 70
     // create socket and bind it
71
-    // TODO
71
+    try {
72
+      m_sock = new DatagramSocket(m_bindAddr);
73
+    } catch (SocketException e) {
74
+      String txt = "creating and binding socket failed\n";
75
+      if (messageIf != null)
76
+        messageIf.message(MsgType.Err, txt + "\n");
77
+      throw new Exception(txt, e);
78
+    }
72 79
 
73 80
     // clear display
74 81
     dataClear();
... ...
@@ -126,6 +133,7 @@ public class Display
126 133
         for (out = 0, i = 0; out < distri.m_outputCnt; ++out) {
127 134
           for (pix = 0; pix < distri.m_pixelCnt; ++pix) {
128 135
             pixel = distri.m_pixels[i];
136
+            if (pixel != null) {
129 137
 
130 138
               // get pixel coordinates relative to rectangular area of image
131 139
               rx = pixel.m_x - x;
... ...
@@ -139,6 +147,7 @@ public class Display
139 147
                 distri.m_msgBuf[dest+2] = distri.m_mapBlue.m_table[data[src+2]];
140 148
               }
141 149
 
150
+            } // if pixel
142 151
             dest += 3;
143 152
           } // for pix
144 153
         } // for out
... ...
@@ -0,0 +1,58 @@
1
+/* JFlexiPix - Java implementation of FlexiPix output library
2
+ *
3
+ * Copyright 2010-2011 Stefan Schuermans <stefan blinkenarea org>
4
+ *
5
+ * This program is free software: you can redistribute it and/or modify
6
+ * it under the terms of the GNU General Public License as published by
7
+ * the Free Software Foundation, version 3 of the License.
8
+ *
9
+ *
10
+ * This program is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
+ * GNU General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU Lesser General Public License
16
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ */
18
+
19
+package org.blinkenarea.JFlexiPix;
20
+
21
+import java.util.regex.*;
22
+
23
+/// parser for a pixel ("x,y") - also abused for similar things
24
+class PixelParser
25
+{
26
+  /**
27
+   * @brief parse pixel - or similar thing
28
+   * @param[in] text pixel coordinates in text form ("x,y")
29
+   * @return pixel or null
30
+   */
31
+  static Pixel parsePixel(String text)
32
+  {
33
+    Pattern pattern;
34
+    Matcher matcher;
35
+    String strX, strY;
36
+    Pixel pixel;
37
+
38
+    // split text at comma
39
+    pattern = Pattern.compile("^([0-9]+),([0-9]+)$");
40
+    matcher = pattern.matcher(text);
41
+    if (!matcher.find())
42
+      return null;
43
+    strX = matcher.group(1);
44
+    strY = matcher.group(2);
45
+
46
+    // parse numbers
47
+    pixel = new Pixel();
48
+    try {
49
+      pixel.m_x = Integer.parseInt(strX);
50
+      pixel.m_y = Integer.parseInt(strY);
51
+    } catch (NumberFormatException e) {
52
+      return null;
53
+    }
54
+
55
+    return pixel;
56
+  }
57
+}
58
+
0 59