Project

General

Profile

Statistics
| Revision:

root / trunk / code / projects / colonet / client / ColonetServerInterface.java @ 531

History | View | Annotate | Download (19 KB)

1 32 gtress
/*
2
*        ColonetServerInterface.java
3
*        Gregory Tress
4
*/
5
6
import java.net.*;
7
import java.io.*;
8
import javax.swing.JOptionPane;
9
import javax.swing.JTextArea;
10
11 333 gtress
/**
12
* The Colonet server interface class. This class handles direct communication with the Colonet server. The general
13 527 emarinel
* contract is that this class will encapsulate the process of sending commands and requests to the server and
14
* receiving responses. This class should provide methods to send specific commands and requests so that the
15
* Colonet can easily communicate with the server. When data is received from the server, the ColonetServerInterface
16
* decides how to handle it and in many cases this means simply passing it to the Colonet.
17 333 gtress
* <p>
18
* The motivation is that any number of Colonet-type classes could be designed for different purposes if needed, with
19 527 emarinel
* this class being used by each one for communication.
20 333 gtress
* For instance, if an application is designed which only monitors sensor data, or that only has access to
21
* the task queue, etc., the application could easily plug in to this interface.
22 527 emarinel
* The Colonet should generally not contain communication-specific code or Strings of command and request data.
23 333 gtress
* If additional commands and requests are needed for permanent implementation, it is suggested that convenience
24
* classes be created in the ColonetServerInterface and called from the Colonet.
25
*
26 527 emarinel
* @author Gregory Tress
27 333 gtress
*/
28 527 emarinel
public class ColonetServerInterface
29 32 gtress
{
30 531 emarinel
/*        Old packet structure:
31 527 emarinel

32 107 gtress
    COMMAND PACKET STRUCTURE
33 32 gtress
        1:  SEND_TO_ROBOT
34
        2:  # of robot, or GLOBAL_DEST
35
        3:  COLONET_COMMMAND
36
        4:  message code (i.e. ORB_SET)
37
        5:  any data, as many that fit in the packet
38 527 emarinel

39 32 gtress
        REQUEST PACKET STRUCTURE
40 67 gtress
        1:  REQUEST_FROM_SERVER
41 32 gtress
        2:  # of robot
42
        3:  COLONET_REQUEST
43
        4:  ???
44 527 emarinel

45 38 gtress
  9/12/07 New server interface structure
46
    Client will no longer send full robot packets to the server.
47
    Commands will be defined as necessary.
48 32 gtress
        */
49 527 emarinel
50 76 gtress
        //General Colonet Interface
51 32 gtress
        public static final String SEND_TO_ROBOT = "0";
52 67 gtress
        public static final String REQUEST_FROM_SERVER = "1";
53 32 gtress
        public static final String RESPONSE_TO_CLIENT_REQUEST = "2";
54 76 gtress
        public static final String REQUEST_BOM_MATRIX = "144";
55 155 gtress
        public static final String REQUEST_XBEE_IDS = "145";
56 527 emarinel
57 32 gtress
        public static final String COLONET_COMMAND = "13"; //0x0D
58
        public static final String COLONET_REQUEST = "14"; //0x0E
59
        public static final String CORONET_RESPONSE = "15"; //0x0F
60 76 gtress
        public static final String GLOBAL_DEST = "200";
61 459 gtress
        public static final String CLIENT_REQUEST_ROBOT_POSITIONS = "86";
62
        public static final String CLIENT_ASSIGN_ROBOT_ID = "87";
63 470 gtress
        public static final String MOVE_TO_ABSOLUTE_POSITION = "83"; //0x53
64 527 emarinel
65 107 gtress
        //Queue instructions
66
        public static final String COLONET_QUEUE = "100";
67 527 emarinel
        public static final String QUEUE_UPDATE = "101";
68 107 gtress
        public static final String QUEUE_ADD = "102";
69
        public static final String QUEUE_REMOVE = "103";
70
        public static final String QUEUE_REORDER = "104";
71 527 emarinel
72 32 gtress
        //Use BATTERY to request battery level
73
        public static final String BATTERY = "56"; //0x38
74 527 emarinel
75 32 gtress
        //MOTORS
76
        public static final String MOTORS_INIT = "23"; //0x17
77
        public static final String MOTOR1_SET = "24"; //0x18
78
        public static final String MOTOR2_SET = "25"; //0x19
79
        public static final String MOTORS_OFF = "26"; //0x1A
80
        public static final String MOVE = "27"; //0x1B
81 39 gtress
        public static final String MOVE_AVOID = "28"; //0x1C
82 527 emarinel
83 32 gtress
        //BUZZER
84
        public static final String BUZZER_INIT = "0"; //0x00
85
        public static final String BUZZER_SET_VAL = "1"; //0x01
86
        public static final String BUZZER_SET_FREQ = "2"; //0x02
87
        public static final String BUZZER_CHIRP = "3"; //0x03
88
        public static final String BUZZER_OFF = "4"; //0x04
89
90
        //ORB
91
        public static final String ORB_INIT = "12"; //0x0C
92
        public static final String ORB_SET = "13"; //0x0D
93
        public static final String ORB_SET_COLOR = "14"; //0x0E
94
        public static final String ORB_DISABLE = "15"; //0x0F
95
        public static final String ORB_ENABLE = "16"; //0x10
96
        public static final String ORB_SET_DIO = "17"; //0x11
97
        public static final String LED_INIT = "18"; //0x12
98
        public static final String LED_USER = "19"; //0x13
99
        public static final String ORB_SET_NUM_NS = "20"; //0x14
100
        public static final String ORB_SET_NUM = "21"; //0x15
101
        public static final String ORB_SEND = "22"; //0x16
102
103 333 gtress
        Colonet colonet;  //save reference to the entire applet locally
104 32 gtress
        Socket socket;
105
        OutputStreamWriter out;
106
        BufferedReader reader;
107 76 gtress
        DataListener dataListener;
108
        JTextArea log, txtMatrix;
109 527 emarinel
110 32 gtress
        /*
111
        *        FUNCTION IMPLEMENTATIONS
112
        */
113
114 333 gtress
        /**
115
        * Constructs a new ColonetServerInterface. When constructing a ColonetServerInterface, a valid Colonet object
116 527 emarinel
        * reference must be provided to ensure that data is routed correctly.
117 333 gtress
        *
118 527 emarinel
        * @param colonet The Colonet object to save locally. This reference cannot be changed once the
119 531 emarinel
        *   ColonetSreverInterface has been contsructed.
120 333 gtress
        * @throws NullPointerException if colonet is null
121
        *
122
        */
123 136 gtress
        public ColonetServerInterface (Colonet colonet) {
124
                this.colonet = colonet;
125
                this.log = colonet.getLog();
126
                this.txtMatrix = colonet.getMatrixInput();
127 76 gtress
                dataListener = new DataListener();
128 32 gtress
        }
129
130
        public Socket getSocket () {
131
                return socket;
132
        }
133 527 emarinel
134 32 gtress
        public OutputStreamWriter getOutputStreamWriter () {
135
                return out;
136
        }
137 527 emarinel
138 32 gtress
        public BufferedReader getBufferedReader () {
139
                return reader;
140
        }
141 527 emarinel
142 32 gtress
        public boolean isReady () {
143 333 gtress
                if (socket == null || out == null || reader == null)
144
                        return false;
145
                if (!socket.isConnected() || socket.isClosed() || socket.isInputShutdown() || socket.isOutputShutdown())
146
                        return false;
147 32 gtress
                return true;
148
        }
149 527 emarinel
150 32 gtress
        public boolean isInputReady () {
151
                try {
152
                        if (reader.ready()) return true;
153
                } catch (Exception e) {
154
                        return false;
155
                }
156
                return false;
157
        }
158 527 emarinel
159 420 gtress
        public String getLine () throws IOException {
160
                return reader.readLine();
161 39 gtress
        }
162 527 emarinel
163 32 gtress
        /**
164
         * Create socket connection to Colonet server.
165 333 gtress
         * If successful, start thread for listening for incoming data.
166 32 gtress
         */
167
        public void connect (String strHost, String strPort) {
168
                //make sure hostname and port are valid
169
                if (strHost.equals("") || strPort.equals("")) {
170
                        err("Please enter a hostname and port.");
171
                        return;
172
                }
173
                int port = 0;
174
                try {
175
                        port = Integer.parseInt(strPort);
176
                } catch (Exception e) {
177
                        err("Invalid port");
178
                        return;
179
                }
180 527 emarinel
181 181 gtress
                //make sure we aren't already connected.
182 32 gtress
                if (socket != null && socket.isConnected()) {
183 181 gtress
                        return;
184 32 gtress
                }
185 527 emarinel
186 32 gtress
                try {
187
                        socket = new Socket(strHost, port);
188 420 gtress
                        socket.setKeepAlive(true);
189 32 gtress
                } catch (UnknownHostException e) {
190
                        log.append("Unknown host exception.\n");
191
                        err("Unknown Host Exception");
192
                        return;
193
                } catch (IOException e) {
194
                        log.append("IO Exception.\n");
195 402 gtress
                        err("Could not create socket to " + strHost + ".\n" + e);
196 32 gtress
                        return;
197
                } catch (java.security.AccessControlException e) {
198
                        log.append("Access Control Exception.\n");
199 67 gtress
                        err("Permission denied by java.security.AccessControlException.\n\n"
200
                                +"You may only connect to the server from which this applet was loaded.");
201 32 gtress
                        return;
202
                }
203
                if (socket == null || !socket.isConnected()) {
204 273 gtress
                        log.append("Connection is not ready. Try connecting again.\n");
205 32 gtress
                        return;
206
                }
207
                try {
208
                        out = new OutputStreamWriter(socket.getOutputStream());
209
                        reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
210
                } catch (IOException e) {
211
                        warn("Could not get transfer streams from socket connection.");
212
                }
213 76 gtress
                dataListener.start();
214 527 emarinel
215 32 gtress
        }
216 527 emarinel
217 420 gtress
        public void disconnect () {
218 517 gtress
            try {
219
                reader.close();
220
                out.close();
221
            } catch (IOException e) {
222
            }
223 420 gtress
        }
224 527 emarinel
225 107 gtress
        /*
226 517 gtress
        * Send a general String to the OutputStream.
227 107 gtress
        */
228 333 gtress
        private void sendString (String s) {
229 32 gtress
                //make sure we can send
230
                if (!this.isReady()) {
231 273 gtress
                        log.append("Could not send data.\n");
232 32 gtress
                        return;
233
                }
234
                //send packet
235
                try {
236 181 gtress
                        Thread.sleep(50);  //pause to be safe
237 107 gtress
                        out.write(s);
238 32 gtress
                        out.flush();
239 273 gtress
                        //log.append("Sent: " + s + "\n");
240 32 gtress
                } catch (IOException e) {
241 172 gtress
                        log.setText("Could not send data.\n");
242 107 gtress
                } catch (InterruptedException e) {
243 172 gtress
                        log.setText("Thread InterruptedException in sendData\n");
244 67 gtress
                }
245 32 gtress
        }
246 527 emarinel
247 333 gtress
        /**
248
        * General send-to-server method. This method is used by other command methods, which are usually convenience
249 527 emarinel
        * methods that simply specify arguments to this method. A command consists of a String which holds integers
250
        * separated by spaces. This method should not be used directly unless you know the format of the particular
251
        * command you are sending. If implementing a particular command for permanent use, it is recommended that
252 333 gtress
        * you create a new wrapper method specific to that command in the ColonetServerInterface file.
253
        *
254
        * Note that no checking is performed in this method to ensure the correct formatting of the String arguments.
255
        * If malformed commands or robot numbers are specified, the behavior of the request at the server will be
256 527 emarinel
        * undefined and could result in server failure.
257 333 gtress
        *
258
        * @param s The command String in its correct format. The format of a command String is ultimately specified
259 527 emarinel
        * by the Colonet server application and may change.
260
        * @param robotNumber The number of the robot that is the subject of the command, if any. The robot number
261
        * is specified as a single integer in a String. If the command does not have a single robot subject, this
262
        * argument can be null or an empty String, whichever is convenient.
263 333 gtress
        */
264 527 emarinel
        public void sendData (String s, String robotNumber) {
265 107 gtress
                //create packet
266
                String packet = "";
267
                packet += ColonetServerInterface.SEND_TO_ROBOT;
268 333 gtress
                if (robotNumber != null)
269 517 gtress
                        packet += " " + robotNumber;
270 107 gtress
                packet += " " + ColonetServerInterface.COLONET_COMMAND;
271
                packet += " " + s;  //add  the command code here
272
                packet += "\n";
273
                sendString(packet);
274 510 gtress
                //txtMatrix.append("S:" + packet);
275 107 gtress
        }
276 527 emarinel
277 333 gtress
        /**
278
        * General request-from-server method. This method is used by other request methods, which are usually convenience
279 527 emarinel
        * methods that simply specify arguments to this method. A request consists of a String which holds integers
280
        * separated by spaces. This method should not be used directly unless you know the format of the particular
281 333 gtress
        * request you are making. If implementing a particular request, it is recommended that you create a new method
282
        * specific to that request in the ColonetServerInterface file.
283
        *
284
        */
285
        private void sendRequest (String s, String robotNumber) {
286 32 gtress
                //create packet
287 107 gtress
                String packet = "";
288
                packet += ColonetServerInterface.REQUEST_FROM_SERVER;
289 270 gtress
                packet += " " + robotNumber;
290 32 gtress
                packet += " " + s;  //add  the command code here
291
                packet += "\n";
292 107 gtress
                sendString(packet);
293 32 gtress
        }
294 527 emarinel
295
        /**
296
        * Sends a request to the server to report the entire BOM sensor matrix. The server will reply at its convenience.
297 333 gtress
        * No guarantee is made (end-to-end or otherwise) that the server will respond in a timely manner or at all
298
        * to any individual request.
299
        */
300 107 gtress
        public void sendSensorDataRequest () {
301
                sendRequest(ColonetServerInterface.REQUEST_BOM_MATRIX, "");
302
        }
303 527 emarinel
304 333 gtress
        /**
305 527 emarinel
        * Sends a request to the server to report a list of XBee IDs. The server will reply at its convenience.
306 333 gtress
        * The purpose of having this list is to ensure that robots are properly identified for control purposes.
307 527 emarinel
        * This keeps robot identification consistent between sessions and prevents arbitrary assignment.
308 333 gtress
        * No guarantee is made (end-to-end or otherwise) that the server will respond in a timely manner or at all
309
        * to any individual request.
310
        *
311
        * @see Colonet#parseXBeeIDs(String)
312
        */
313 136 gtress
        public void sendXBeeIDRequest () {
314
                sendRequest(ColonetServerInterface.REQUEST_XBEE_IDS, "");
315
        }
316 527 emarinel
317 333 gtress
        /**
318 527 emarinel
        * Sends a battery request for a specific robot to the server. The server will reply at its convenience.
319
        * Behavior is undefined if an invalid robot number is specified. The server will probably not respond in
320 333 gtress
        * this case.
321
        * No guarantee is made (end-to-end or otherwise) that the server will respond in a timely manner or at all
322
        * to any individual request.
323
        *
324
        * @param robotNum The number of the robot for which we are requesting the battery. Note that this value
325
        * is sent as-is to the server. No mapping to or from XBee IDs is performed. The contract for this is
326
        * currently undefined.
327
        * @see Colonet#parseBattery(String)
328
        */
329 270 gtress
        public void sendBatteryRequest (int robotNum) {
330 425 gtress
                //create packet
331
                String packet = "";
332
                packet += ColonetServerInterface.SEND_TO_ROBOT;
333
                packet += " " + robotNum;
334
                packet += " " + ColonetServerInterface.COLONET_REQUEST;
335
                packet += " " + ColonetServerInterface.BATTERY;  //add  the command code here
336
                packet += "\n";
337
                sendString(packet);
338 270 gtress
        }
339 527 emarinel
340 459 gtress
        /**
341
        * Requests a list of all robot positions and correspondind robot IDs.
342
        */
343
        public void sendPositionRequest () {
344
                sendRequest(ColonetServerInterface.CLIENT_REQUEST_ROBOT_POSITIONS, "");
345
        }
346 527 emarinel
347 459 gtress
        /**
348
        * Send a robot ID assignment update to store on the server.
349
        */
350
        public void sendIDAssignment (int oldID, int newID) {
351
                String packet = "";
352
                packet += ColonetServerInterface.REQUEST_FROM_SERVER;
353 522 gtress
                packet += " " + CLIENT_ASSIGN_ROBOT_ID;
354 459 gtress
                packet += " " + oldID + " " + newID;
355
                packet += "\n";
356
                sendString(packet);
357
        }
358 527 emarinel
359
        /**
360 470 gtress
        * Order a robot to move to an absolute coordinate point.
361
        */
362
        public void sendAbsoluteMove (int id, int x, int y) {
363
            sendData(MOVE_TO_ABSOLUTE_POSITION + " " + x + " " + y, "" + id);
364
        }
365 527 emarinel
366 107 gtress
        /*
367
        *        Queue management
368
        */
369 333 gtress
        private void sendQueueInstruction (String inst) {
370 107 gtress
                String packet = "";
371
                packet += ColonetServerInterface.COLONET_QUEUE;
372
                packet += " " + inst;
373
                packet += "\n";
374
                sendString(packet);
375
        }
376 527 emarinel
377 333 gtress
        /**
378 527 emarinel
        * Notifies the Colonet server to add a task to the current task queue. The Colonet server holds the canonical
379 333 gtress
        * task queue. Any applet can send tasks to add to the queue. Local copies of the queue in the applet are for
380
        * display purposes only, and are not authoritative when adding tasks. All clients send additions asynchronously,
381 527 emarinel
        * and as a result no guarantee is made that a task will be added in the specificed location in the queue or at
382 333 gtress
        * all. If an invalid position is specified, the task will probably not be added to the queue and may cause
383
        * server failure. Due to the asynchronous nature of the queue, we cannot easily account for concurrent
384
        * modification failures on the client side.
385
        *
386 527 emarinel
        * @param pos The position in the queue at which we would like the task to be placed. Note that this is not
387 333 gtress
        * guaranteed. Invalid positions may cause the task to be discarded at the server.
388 527 emarinel
        * @param data The String containing the command code(s) for the task and any arguments necessary to fully
389 333 gtress
        * define the behavior of the task. This format is currently not specified. In the future, the canonical format
390
        * of the data String will ultimately be defined by the Colonet server.
391
        * @param description A String that contains a description of the task. This will be the message displayed to
392 527 emarinel
        * the user when information about the task is requested.
393 333 gtress
        */
394 107 gtress
        public void sendQueueAdd (int pos, String data, String description) {
395
                String packet = "";
396
                packet += ColonetServerInterface.QUEUE_ADD;
397
                packet += " " + pos;
398
                packet += " " + data;
399
                packet += " [" + description + "]";
400
                packet += "\n";
401
                sendQueueInstruction(packet);
402
        }
403 527 emarinel
404 333 gtress
        /**
405 527 emarinel
        * Notifies the Colonet server to remove a task from the current task queue. The Colonet server holds the canonical
406 333 gtress
        * task queue. Any applet can remove a task from the queue. Local copies of the queue in the applet are for
407
        * display purposes only, and are not authoritative when removing tasks. All clients remove tasks asynchronously,
408 527 emarinel
        * and as a result no guarantee is made that the correct task will actually be removed.
409 333 gtress
        * If an invalid position is specified, the state of the queue is undefined and server failure may result.
410
        * Due to the asynchronous nature of the queue, we cannot easily account for concurrent
411
        * modification failures on the client side.
412
        *
413 527 emarinel
        * @param pos The position in the queue at which we would like the task to be removed. Note that this is not
414 333 gtress
        * guaranteed. Invalid positions may result in a corrupted queue.
415
        */
416 107 gtress
        public void sendQueueRemove (int pos) {
417
                String packet = "";
418
                packet += ColonetServerInterface.QUEUE_REMOVE;
419
                packet += " " + pos;
420
                packet += "\n";
421
                sendQueueInstruction(packet);
422
        }
423 32 gtress
424 333 gtress
        /**
425 527 emarinel
        * Notifies the Colonet server to reorder tasks in the current task queue. The Colonet server holds the canonical
426 333 gtress
        * task queue. Any applet can reorder tasks in the queue. Local copies of the queue in the applet are for
427
        * display purposes only, and are not authoritative when reordering tasks. All clients reorder tasks asynchronously,
428 527 emarinel
        * and as a result no guarantee is made that the correct tasks will actually be reordered.
429 333 gtress
        * If an invalid position is specified, the state of the queue is undefined and server failure may result.
430
        * Due to the asynchronous nature of the queue, we cannot easily account for concurrent
431
        * modification failures on the client side.
432
        *
433
        * @param pos1 The queue position of a task which we would like to reorder.
434
        * @param pos2 The queue position of a task which we would like to reorder.
435
        */
436 107 gtress
        public void sendQueueReorder (int pos1, int pos2) {
437
                String packet = "";
438
                packet += ColonetServerInterface.QUEUE_REORDER;
439
                packet += " " + pos1;
440
                packet += " " + pos2;
441
                packet += "\n";
442
                sendQueueInstruction(packet);
443
        }
444 32 gtress
445 136 gtress
        public void sendQueueUpdate () {
446
                sendQueueInstruction(ColonetServerInterface.QUEUE_UPDATE);
447
        }
448 527 emarinel
449 32 gtress
        /**
450
         * Display informational message box on the screen. Used for casual communicaton to the user.
451
         * @param text Text to display
452
         */
453 35 gtress
        public void msg (String text) {
454 470 gtress
                JOptionPane.showMessageDialog(colonet, text, "Colonet", JOptionPane.INFORMATION_MESSAGE);
455 32 gtress
        }
456 527 emarinel
457 32 gtress
        /**
458
         * Display warning message box on the screen. Used for minor alerts or exceptions.
459
         * @param text Text to display
460
         */
461 35 gtress
        public void warn (String text) {
462 470 gtress
                JOptionPane.showMessageDialog(colonet, text, "Colonet", JOptionPane.WARNING_MESSAGE);
463 32 gtress
        }
464 527 emarinel
465 32 gtress
        /**
466
         * Display error message box on the screen. Used for major errors or exceptions in the program.
467
         * @param text Text to display
468
         */
469 35 gtress
        public void err (String text) {
470 470 gtress
                JOptionPane.showMessageDialog(colonet, text, "Colonet", JOptionPane.ERROR_MESSAGE);
471 32 gtress
        }
472 527 emarinel
473
474 76 gtress
        /*
475
        *        DataListener thread.
476
        *
477
        */
478
        class DataListener extends Thread {
479
                final int DATALISTENER_DELAY = 222;
480 527 emarinel
481 76 gtress
                public DataListener () {
482
                        super("Colonet DataListener");
483
                }
484 527 emarinel
485 76 gtress
                public void run () {
486
                        String line;
487 527 emarinel
                        while (true) {
488 76 gtress
                                try {
489 420 gtress
                                        line = reader.readLine();
490
                                        if (line == null)
491
                                            throw new IOException();
492
                                        parseData(line);
493 76 gtress
                                        Thread.sleep(DATALISTENER_DELAY);
494
                                } catch (InterruptedException e) {
495
                                        return;
496 420 gtress
                                } catch (IOException e) {
497
                                disconnect();
498
                                    colonet.disconnect();
499
                                    return;
500
                                }
501 76 gtress
                        }
502
                }
503 527 emarinel
504 76 gtress
                public void parseData (String line) {
505 333 gtress
                        // Sensor Matrix
506 136 gtress
                        if (line.startsWith(ColonetServerInterface.RESPONSE_TO_CLIENT_REQUEST + " " +
507
                                ColonetServerInterface.REQUEST_BOM_MATRIX))
508
                                colonet.parseMatrix(line);
509 270 gtress
                        // Task Queue
510 155 gtress
                        else if (line.startsWith(ColonetServerInterface.COLONET_QUEUE))
511 136 gtress
                                colonet.parseQueue(line);
512 270 gtress
                        // XBee IDs
513 155 gtress
                        else if (line.startsWith(ColonetServerInterface.RESPONSE_TO_CLIENT_REQUEST + " " +
514 136 gtress
                                ColonetServerInterface.REQUEST_XBEE_IDS))
515
                                colonet.parseXBeeIDs(line);
516 270 gtress
                        // Battery
517
                        else if (line.startsWith(ColonetServerInterface.RESPONSE_TO_CLIENT_REQUEST + " " +
518
                                ColonetServerInterface.BATTERY))
519
                                colonet.parseBattery(line);
520 459 gtress
                        // Robot Positions
521
                        else if (line.startsWith(ColonetServerInterface.RESPONSE_TO_CLIENT_REQUEST + " " +
522
                                ColonetServerInterface.CLIENT_REQUEST_ROBOT_POSITIONS))
523
                                colonet.parsePositions(line);
524 333 gtress
                        // Unknown type
525 510 gtress
                        else {
526
                                //txtMatrix.setText("Got unknown data: " + line + "\n");
527
                        }
528 76 gtress
                }
529 32 gtress
530 76 gtress
        }
531
532 420 gtress
}