Project

General

Profile

Statistics
| Revision:

root / trunk / code / projects / colonet / ColonetGUI / BotGraph.java @ 396

History | View | Annotate | Download (20.1 KB)

1 32 gtress
/*
2
        BotGraph.java
3
        Colony Project
4
        Gregory Tress
5
*/
6
7
import javax.swing.*;
8
import java.awt.*;
9
import java.awt.image.*;
10
import java.awt.event.*;
11
import java.net.*;
12
import java.io.*;
13
import java.util.Random;
14
15
public class BotGraph extends JApplet implements ActionListener, MouseListener, Runnable
16
{
17
18
        final int CANVAS_SIZE = 550;  //don't make this too large, or the applet will be slow.
19
        final int BUFFER = 50;
20
        final int RADIUS = 30;
21
22
        JTextField txtHost;
23
        JTextField txtPort;
24
        JButton btnConnect;
25
        JButton btnGraph;
26
        JButton btnRandomize;
27
        JLabel lblNumRobots;
28
        JLabel lblHasToken;
29
        JLabel lblTokenPasses;
30
        JLabel lblConnectionStatus;
31
        JTextArea txtInput;  //sample matrix is entered in this area
32
        JTextArea txtInfo;
33
        JPanel panel;
34
        JPanel panelConnect;
35
        JPanel panelControl;
36
        JPanel panelStats;
37
38
        GraphicsConfiguration gc;
39
        volatile BufferedImage image;
40
        volatile Graphics2D canvas;
41
        int cx, cy;
42
43
        Socket socket;
44
        OutputStreamWriter out;                        //TODO: add a BufferedWriter
45
        DataListener datalistener;
46
47
        Font botFont;
48
        Random random = new Random();
49
        volatile int tokenLoc;  //the token is currently here
50
        volatile int numBots;
51
        volatile int selectedBot;  //the user has selected this bot
52
        volatile Rectangle[] botRect;  //contains boundary shapes around bots for click detection
53
54
        Thread drawThread;
55
        SelectionIndicator indicator;
56
        Simulator simulator;
57
        PacketMonitor packetMonitor;
58
59
        public void init ()
60
        {
61
                // We should invoke and wait to avoid browser display difficulties
62
                Runnable r = new Runnable() {
63
                        public void run() {
64
                                createAndShowGUI();
65
                        }
66
                };
67
                try {
68
                        SwingUtilities.invokeAndWait(r);
69
                } catch (InterruptedException e) {
70
                        //Not really sure why we would be in this situation
71
                        System.out.println(e);
72
                } catch (java.lang.reflect.InvocationTargetException e) {
73
                        //This should never happen. Seriously.
74
                        System.out.println(e);
75
                }
76
        }
77
78
        public void destroy ()
79
        {
80
                drawThread.interrupt();
81
                indicator.interrupt();
82
                simulator.interrupt();
83
                packetMonitor.interrupt();
84
        }
85
86
        private synchronized void createAndShowGUI ()
87
        {
88
                // init graphical elements
89
                panel = new JPanel(false);  //set automatic double-buffering to false. we are doing it manually.
90
91
                // Set up connection area
92
                txtHost = new JTextField("roboclub1.frc.ri.cmu.edu");
93
                txtPort = new JTextField("10123");
94
                btnConnect = new JButton("Connect");
95
                lblConnectionStatus = new JLabel("Status: Offline");
96
                panelConnect = new JPanel();
97
                panelConnect.setLayout(new GridLayout(2,3));
98
                panelConnect.add(new JLabel("Host"));
99
                panelConnect.add(new JLabel("Port"));
100
                panelConnect.add(lblConnectionStatus);
101
                panelConnect.add(txtHost);
102
                panelConnect.add(txtPort);
103
                panelConnect.add(btnConnect);
104
                panelConnect.setBorder(BorderFactory.createTitledBorder("Connection"));
105
106
                // Set up elements in the east
107
                panelControl = new JPanel();
108
                panelControl.setLayout(new GridLayout(5,1));
109
                lblNumRobots = new JLabel();
110
                lblHasToken = new JLabel();
111
                lblTokenPasses = new JLabel();
112
                panelStats = new JPanel();
113
                panelStats.setLayout(new GridLayout(3,2));
114
                panelStats.add(new JLabel("Number of Bots  "));
115
                panelStats.add(lblNumRobots);
116
                panelStats.add(new JLabel("Token At  "));
117
                panelStats.add(lblHasToken);
118
                panelStats.add(new JLabel("Token Passes / sec     "));
119
                panelStats.add(lblTokenPasses);
120
                txtInput = new JTextArea("- 9 3 - 1\n- - - 5 -\n4 - - - 2\n- - - - -\n1 - - 3 -");
121
                txtInput.setBorder(BorderFactory.createTitledBorder("Input Matrix"));
122
                txtInfo = new JTextArea();
123
                txtInfo.setBorder(BorderFactory.createTitledBorder("Info"));
124
                txtInfo.setEditable(false);
125
                btnGraph = new JButton("Run");
126
                btnRandomize = new JButton("Randomize");
127
                panelControl.add(panelStats);
128
                panelControl.add(txtInput);
129
                panelControl.add(txtInfo);
130
                panelControl.add(btnRandomize);
131
                panelControl.add(btnGraph);
132
133
134
                this.getContentPane().setLayout(new BorderLayout());
135
                this.getContentPane().add(panelConnect, BorderLayout.NORTH);
136
                this.getContentPane().add(panelControl, BorderLayout.EAST);
137
                this.getContentPane().add(panel, BorderLayout.CENTER);
138
                this.setVisible(true);
139
140
                btnGraph.addActionListener(this);
141
                btnRandomize.addActionListener(this);
142
                btnConnect.addActionListener(this);
143
                panel.addMouseListener(this);
144
145
146
                // Get the graphics configuration of the screen to create a buffer
147
                gc = GraphicsEnvironment.getLocalGraphicsEnvironment()
148
                        .getDefaultScreenDevice().getDefaultConfiguration();
149
                image = gc.createCompatibleImage(CANVAS_SIZE,CANVAS_SIZE);
150
                canvas = image.createGraphics();
151
                canvas.setStroke(new BasicStroke(2));  //set pen width
152
153
                // Calculate center of canvas
154
                cx = image.getWidth() / 2;
155
                cy = image.getHeight() / 2;
156
157
                botFont = new Font("Arial", Font.PLAIN, 30);
158
                tokenLoc = 0;
159
                numBots = 0;
160
                selectedBot = 0;
161
162
                // Set up dependent threads
163
                indicator = new SelectionIndicator(canvas);
164
                indicator.setRadius(RADIUS+3, 15);  //a tad more than the bot radius
165
                simulator = new Simulator();
166
                packetMonitor = new PacketMonitor();
167
                datalistener = new DataListener();
168
169
        }
170
171
        public synchronized void paint (Graphics g)
172
        {
173
                /*        First, redraw the graphical components in the applet.
174
                        This paint method overrides the built-in paint of the
175
                        JApplet, and we don't want to deal with redrawing the
176
                        components manually. Fuck that shit. */
177
                super.paint(g);
178
179
                // Place the buffered image on the screen, inside the panel
180
                panel.getGraphics().drawImage(image, 0, 0, Color.WHITE, this);
181
182
        }
183
184
        public synchronized void update (Graphics g)
185
        {
186
                paint(g);
187
        }
188
189
        public void actionPerformed (ActionEvent e)
190
        {
191
                Object source = e.getSource();
192
                if (source == btnGraph)
193
                {
194
                        btnGraph.setEnabled(false);
195
                        lblConnectionStatus.setText("Status: Simulation mode => running");
196
197
                        //Start dependent threads
198
                        drawThread = new Thread(this, "drawThread");
199
                        drawThread.start();
200
                        indicator.start();
201
                        simulator.start();
202
                        packetMonitor.start();
203
                }
204
                else if (source == btnConnect)
205
                {
206
                        doSocket();
207
                }
208
                else if (source == btnRandomize)
209
                {
210
                        randomize();
211
                }
212
        }
213
214
        private void randomize ()
215
        {
216
                Random r = new Random();
217
                StringBuilder s = new StringBuilder();
218
219
                int count = r.nextInt(8) + 1;
220
                for (int i = 0; i < count; i++)
221
                {
222
                        for (int j = 0; j < count; j++)
223
                        {
224
                                if (r.nextBoolean())
225
                                        s.append("" + (r.nextInt(16) + 1));
226
                                else
227
                                        s.append("-");
228
                                if (j != count-1)
229
                                        s.append(" ");
230
                        }
231
                        if (i != count-1) s.append("\n");
232
                }
233
234
                txtInput.setText(s.toString());
235
        }
236
237
        private void doSocket ()
238
        {
239
                //make sure hostname and port are valid
240
                if (txtHost.getText().equals("") || txtPort.getText().equals("")) {
241
                        err("Please enter a hostname and port.");
242
                        return;
243
                }
244
                int port = 0;
245
                try {
246
                        port = Integer.parseInt(txtPort.getText());
247
                } catch (Exception e) {
248
                        err("Invalid port");
249
                        return;
250
                }
251
252
                //make sure we aren't already connected. if so, disconnect first.
253
                if (socket != null && socket.isConnected()) {
254
                        try {
255
                                out.close();
256
                                socket.close();
257
                        } catch (IOException e) {}
258
                }
259
260
                try {
261
                        socket = new Socket(txtHost.getText(), port);
262
                } catch (UnknownHostException e) {
263
                        err("Unknown Host Exception");
264
                        return;
265
                } catch (IOException e) {
266
                        err("IO Exception\n\n" + e);
267
                        return;
268
                } catch (java.security.AccessControlException e) {
269
                        err("Permission denied by java.security.AccessControlException.\n\nYou may only connect to the server from which this applet was loaded.");
270
                        return;
271
                }
272
                if (socket == null || !socket.isConnected()) {
273
                        err("Connection failed. Try connecting again.");
274
                        return;
275
                }
276
                msg("Connected to " + txtHost.getText() + " on port " + port + "\n");
277
                lblConnectionStatus.setText("Status: ONLINE");
278
                try {
279
                        out = new OutputStreamWriter(socket.getOutputStream());
280
                } catch (IOException e) {
281
                        warn("Could not get OutputStream from socket connection.");
282
                }
283
284
        }
285
286
        public void drawRobot (int id, int x, int y)
287
        {
288
                //save the bot in memory, so we can tell if we click on it later
289
                botRect[id] = new Rectangle(x-RADIUS, y-RADIUS, 2*RADIUS, 2*RADIUS);
290
291
                //draw the bot on the canvas
292
                canvas.setColor(Color.BLACK);
293
                canvas.drawOval(x-RADIUS, y-RADIUS, RADIUS*2, RADIUS*2);
294
295
                //draw the label
296
                canvas.setFont(botFont);
297
                canvas.drawString("" + id, x-10, y+10);
298
        }
299
300
        public void drawConnection (int start, int end, int radius, Color color)
301
        {
302
                final int ARROW_LENGTH = 18;
303
304
                double angle = 2.0 * Math.PI / numBots;
305
                int startx, starty, endx, endy;
306
                startx = cx - (int)(radius * Math.cos(start * angle));
307
                starty = cy - (int)(radius * Math.sin(start * angle));
308
                endx = cx - (int)(radius * Math.cos(end * angle));
309
                endy = cy - (int)(radius * Math.sin(end * angle));
310
                canvas.setColor(color);
311
                canvas.drawLine(startx, starty, endx, endy);
312
313
                //create arrow
314
                if (color.equals(Color.BLACK)) return;
315
                int big_dy = starty - endy;
316
                int big_dx = endx - startx;
317
                double theta = 0;
318
                if (big_dx == 0 && starty > endy) //pointing up
319
                        theta = Math.PI/2;
320
                else if (big_dx == 0 && starty < endy) //pointing down
321
                        theta = 3*Math.PI/2;
322
                else if (big_dy == 0 && startx > endx) //pointing left
323
                        theta = Math.PI;
324
                else if (big_dy == 0 && startx < endx) //pointing right
325
                        theta = 0;
326
                else
327
                        theta = Math.atan(1.0 * big_dy / big_dx);
328
329
                //create ploygon
330
                Polygon poly = new Polygon();
331
                int dx_arrow = Math.abs((int)(ARROW_LENGTH * Math.cos(theta)));
332
                int dy_arrow = Math.abs((int)(ARROW_LENGTH * Math.sin(theta)));
333
                int dy_half = (int)(ARROW_LENGTH/2 * Math.cos(theta));
334
                int dx_half = (int)(ARROW_LENGTH/2 * Math.sin(theta));
335
                int rx = (big_dx > 0) ? endx - dx_arrow : endx + dx_arrow;
336
                int ry = (big_dy > 0) ? endy + dy_arrow : endy - dy_arrow;
337
                //System.out.println("" + start + "->" + end + " : dx=" + big_dx + ",dy=" + big_dy + ",dy_arrow=" + dy_arrow + ",dx_arrow=" + dx_arrow + ",theta=" + theta + ",endx=" + endx + ",endy=" + endy + ",rx=" + rx + ",ry=" + ry);
338
                poly.addPoint(endx, endy);
339
                poly.addPoint(rx - dx_half, ry - dy_half);
340
                poly.addPoint(rx + dx_half, ry + dy_half);
341
                canvas.fillPolygon(poly);
342
        }
343
344
        public void run ()
345
        {
346
                while (true)
347
                {
348
                        step();
349
                        repaint();
350
                        try { Thread.sleep(90); }
351
                                catch (InterruptedException e) { return; }
352
                }
353
        }
354
355
        public void step ()
356
        {
357
                final int DIAMETER = image.getWidth() - 2*BUFFER;
358
                final int BIGRADIUS = DIAMETER / 2;
359
                final int TOKENRADIUS = 40;
360
                boolean valid;
361
362
                // clear image
363
                canvas.setColor(Color.WHITE);
364
                canvas.fillRect(0, 0, image.getWidth(), image.getHeight());
365
366
                // parse the matrix, to see what robots exist
367
                String [] rows = txtInput.getText().split("\n");
368
                numBots = rows.length;
369
                String [][] entries = new String[numBots][numBots];
370
                valid = true;
371
                for (int i = 0; i < numBots; i++)
372
                {
373
                        entries[i] = rows[i].split(" ");
374
                        if (entries[i].length != rows.length) valid = false;
375
                }
376
377
                if (valid)
378
                {
379
                        lblNumRobots.setText("" + numBots);
380
                        lblHasToken.setText("" + tokenLoc);
381
                        this.showStatus("Matrix OK");
382
383
                        // draw outer ring
384
                        //canvas.setColor(Color.GREEN);
385
                        //canvas.drawOval(BUFFER, BUFFER, DIAMETER, DIAMETER);
386
387
                        // draw robots and find which one is seleced
388
                        double angle = 2.0 * Math.PI / numBots;
389
                        canvas.setColor(Color.BLACK);
390
                        botRect = new Rectangle[numBots];
391
                        int x, y;
392
                        if (selectedBot >= numBots) selectedBot = 0;
393
                        for (int i = 0; i < numBots; i++)
394
                        {
395
                                x = cx - (int)(BIGRADIUS * Math.cos(i * angle));
396
                                y = cy - (int)(BIGRADIUS * Math.sin(i * angle));
397
                                drawRobot(i, x, y);
398
                                if (i == selectedBot) indicator.setCenter(x, y);
399
                        }
400
401
                        // draw token marker
402
                        int tokenx, tokeny;
403
                        int tokenNum = tokenLoc;
404
                        tokenx = cx - (int)(BIGRADIUS * Math.cos(tokenNum * angle));
405
                        tokeny = cy - (int)(BIGRADIUS * Math.sin(tokenNum * angle));
406
                        canvas.setColor(Color.RED);
407
                        canvas.drawOval(tokenx-TOKENRADIUS, tokeny-TOKENRADIUS, 2*TOKENRADIUS, 2*TOKENRADIUS);
408
409
                        // create an inner circle along which the connections are made.
410
                        // let the diameter of this circle be 2*RADIUS less than the outerDiameter.
411
                        // see what connections exist
412
                        for (int row = 0; row < numBots; row++)
413
                        {
414
                                for(int col = 0; col < numBots; col++)
415
                                {
416
                                        if (! entries[row][col].equals("-") && entries[col][row].equals("-") && row != col) //one-way
417
                                        {
418
                                                //drawConnection(row, col, BIGRADIUS-RADIUS, Color.GRAY);
419
                                                drawConnection(row, col, BIGRADIUS-RADIUS, new Color(200,200,200));
420
                                        }
421
                                        else if (! entries[row][col].equals("-") && ! entries[col][row].equals("-") && row != col) //two-way
422
                                        {
423
                                                drawConnection(row, col, BIGRADIUS-RADIUS, Color.BLACK);
424
                                        }
425
                                }
426
                        }
427
428
                        // draw the selection indicator
429
                        indicator.draw();
430
                        txtInfo.setText("Bot " + selectedBot + " is selected.\n");
431
                        txtInfo.append("Battery: ???\n");
432
                        txtInfo.append("Packet statistics: ???");
433
434
                }
435
                else // if matrix is not valid
436
                {
437
                        this.showStatus("Error: Invalid matrix");
438
                }
439
440
        }
441
442
        /*        At this point, moveToken is only called by the simulator.
443
        *        In the future, it can be rewritten to account for non-standard
444
        *        token passing or deleted if the information can be retrieved
445
        *        directly from the Colonet server instead.
446
        */
447
        public void moveToken ()
448
        {
449
                try { tokenLoc = (tokenLoc+1)%numBots; }
450
                        catch (ArithmeticException e) { }  // in case numRobots is zero
451
452
                packetMonitor.addTokenPass();
453
        }
454
455
        //
456
        // MouseEvent methods
457
        //
458
        public void mouseExited(MouseEvent e) {}
459
        public void mouseEntered(MouseEvent e) {}
460
        public void mouseReleased(MouseEvent e) {}
461
        public void mouseClicked(MouseEvent e) {}
462
        public void mousePressed(MouseEvent e)
463
        {
464
                try {
465
                        for (int i = 0; i < numBots; i++)
466
                        {
467
                                if (botRect[i].contains(e.getPoint()))
468
                                        selectedBot = i;
469
                        }
470
                } catch (Exception ex) {
471
                        System.out.println(e);
472
                }
473
474
        }
475
476
        private void msg (String text) {JOptionPane.showMessageDialog(null, text, "Colonet", JOptionPane.INFORMATION_MESSAGE);}
477
        private void warn (String text) {JOptionPane.showMessageDialog(null, text, "Colonet", JOptionPane.WARNING_MESSAGE);}
478
        private void err (String text) {JOptionPane.showMessageDialog(null, text, "Colonet", JOptionPane.ERROR_MESSAGE);}
479
480
481
        /*
482
        *        SelectionIndicator thread.
483
        *        Graphical representation of the selection marker
484
        *
485
        *        step() and draw() are synchronized methods. step() is private and
486
        *        used to update the position of the crosshairs. draw() is called
487
        *        externally and should only run if all calculations in step() have
488
        *        been completed.
489
        */
490
        private class SelectionIndicator extends Thread
491
        {
492
493
                final int INDICATOR_DELAY = 100;
494
                final double DTHETA = 0.3;    //larger values make the marker rotate faster
495
                Graphics2D g;   //canvas to draw on
496
                boolean running;
497
498
                int sx, sy;                //center
499
                int r, dr;                //radius and width of marker
500
                double theta;   //current angle
501
502
                volatile Polygon poly1, poly2, poly3, poly4;
503
504
                int px1, py1;
505
                int rx1, ry1;
506
                int px2, py2;
507
                int rx2, ry2;
508
                int px3, py3;
509
                int rx3, ry3;
510
                int px4, py4;
511
                int rx4, ry4;
512
513
                int steps;
514
515
                public SelectionIndicator (Graphics2D g)
516
                {
517
                        super("SelectionIndicator");
518
                        this.g = g;
519
                        running = false;
520
                        steps = 0;
521
522
                        theta = 0;
523
                        rx1 = 0; ry1 = 0;
524
                        px1 = 0; py1 = 0;
525
                        rx2 = 0; ry2 = 0;
526
                        px2 = 0; py2 = 0;
527
                        rx3 = 0; ry3 = 0;
528
                        px3 = 0; py3 = 0;
529
                        rx4 = 0; ry4 = 0;
530
                        px4 = 0; py4 = 0;
531
                }
532
533
                public synchronized void setCenter (int sx, int sy)
534
                {
535
                        if (sx == this.sx && sy == this.sy) return;
536
                        this.sx = sx;
537
                        this.sy = sy;
538
                        steps = 0;
539
                }
540
541
                public synchronized void setRadius (int r, int dr)
542
                {
543
                        this.r = r;
544
                        this.dr = dr;
545
                        steps = 0;
546
                }
547
548
                public void run ()
549
                {
550
                        running = true;
551
                        while (running)
552
                        {
553
                                step();
554
                                try { Thread.sleep(INDICATOR_DELAY); }
555
                                        catch (InterruptedException e) {  running = false; return; }
556
                        }
557
                }
558
559
                private synchronized void step ()
560
                {
561
                        Polygon poly1_new = new Polygon();
562
                        Polygon poly2_new = new Polygon();
563
                        Polygon poly3_new = new Polygon();
564
                        Polygon poly4_new = new Polygon();
565
566
                        //the step
567
                        theta = (theta + DTHETA/Math.PI) % (Math.PI);
568
569
                        //the calculation
570
                        //let p be the point of the pointy thing toward the center
571
                        //let r be the point at the opposite side
572
573
                        //recalculate radius, if it will look cool, lolz
574
                        int newr = r;
575
                        if (steps < 100) newr = (int)( r + 200/(steps+1) );
576
577
                        //precompute values for dx and dy
578
                        int dx_inner = (int)(newr * Math.cos(theta));
579
                        int dy_inner = (int)(newr * Math.sin(theta));
580
                        int dx_outer = (int)((newr+dr) * Math.cos(theta));
581
                        int dy_outer = (int)((newr+dr) * Math.sin(theta));
582
583
                        //calculate polygon constants
584
                        int dy_poly = (int)(dr/2 * Math.cos(theta));
585
                        int dx_poly = (int)(dr/2 * Math.sin(theta));
586
587
                        //determine critical points
588
                        px1 = sx + dx_inner;
589
                        py1 = sy - dy_inner;
590
                        rx1 = sx + dx_outer;
591
                        ry1 = sy - dy_outer;
592
                        px2 = sx - dx_inner;
593
                        py2 = sy + dy_inner;
594
                        rx2 = sx - dx_outer;
595
                        ry2 = sy + dy_outer;
596
                        px3 = sx - dy_inner;
597
                        py3 = sy - dx_inner;
598
                        rx3 = sx - dy_outer;
599
                        ry3 = sy - dx_outer;
600
                        px4 = sx + dy_inner;
601
                        py4 = sy + dx_inner;
602
                        rx4 = sx + dy_outer;
603
                        ry4 = sy + dx_outer;
604
605
                        //create polygons
606
                        poly1_new.addPoint(px1, py1);
607
                        poly1_new.addPoint(rx1+dx_poly, ry1+dy_poly);
608
                        poly1_new.addPoint(rx1-dx_poly, ry1-dy_poly);
609
                        poly2_new.addPoint(px2, py2);
610
                        poly2_new.addPoint(rx2+dx_poly, ry2+dy_poly);
611
                        poly2_new.addPoint(rx2-dx_poly, ry2-dy_poly);
612
                        poly3_new.addPoint(px3, py3);
613
                        poly3_new.addPoint(rx3-dy_poly, ry3+dx_poly);
614
                        poly3_new.addPoint(rx3+dy_poly, ry3-dx_poly);
615
                        poly4_new.addPoint(px4, py4);
616
                        poly4_new.addPoint(rx4-dy_poly, ry4+dx_poly);
617
                        poly4_new.addPoint(rx4+dy_poly, ry4-dx_poly);
618
619
                        //reassign updated polygons
620
                        poly1 = poly1_new;
621
                        poly2 = poly2_new;
622
                        poly3 = poly3_new;
623
                        poly4 = poly4_new;
624
625
                        if (steps < 300) steps++;
626
                }
627
628
                public synchronized void draw ()
629
                {
630
                        if (!running) return;
631
                        g.setColor(Color.GRAY);
632
                        //draw polygons
633
                        g.fillPolygon(poly1);
634
                        g.fillPolygon(poly2);
635
                        g.fillPolygon(poly3);
636
                        g.fillPolygon(poly4);
637
                }
638
639
640
        }
641
642
        /*
643
        *        Simulator thread.
644
        *
645
        */
646
        private class Simulator extends Thread
647
        {
648
                final int SIMULATOR_DELAY = 300;
649
650
                boolean running;
651
652
                public Simulator ()
653
                {
654
                        super("Simulator");
655
                        running = false;
656
                }
657
658
                public void run ()
659
                {
660
                        running = true;
661
                        while (running)
662
                        {
663
                                step();
664
                                try { Thread.sleep(SIMULATOR_DELAY); }
665
                                        catch (InterruptedException e) { running = false; return; }
666
                        }
667
                }
668
669
                private void step ()
670
                {
671
                        // simulate passing the token
672
                        moveToken();
673
674
                }
675
676
        }
677
678
        /*
679
        *        PacketMonitor thread.
680
        *
681
        *        Currently, this counts the rate of token passes but will eventually
682
        *        be modified to keep more important statistics.
683
        */
684
        private class PacketMonitor extends Thread
685
        {
686
                final int PACKETMONITOR_DELAY = 1000;
687
688
                boolean running;
689
                int tokenPasses;
690
691
                public PacketMonitor ()
692
                {
693
                        super("PacketMonitor");
694
                        running = false;
695
                        tokenPasses = 0;
696
                }
697
698
                public void run ()
699
                {
700
                        running = true;
701
                        while (running)
702
                        {
703
                                displayTokenPasses();
704
                                try { Thread.sleep(PACKETMONITOR_DELAY); }
705
                                        catch (InterruptedException e) { running = false; return; }
706
                        }
707
                }
708
709
                public synchronized void addTokenPass ()
710
                {
711
                        tokenPasses++;
712
                }
713
714
                public synchronized void displayTokenPasses ()
715
                {
716
                        lblTokenPasses.setText("" + tokenPasses);
717
                        tokenPasses = 0;
718
                }
719
720
        }
721
722
        /*
723
        *        DataListener thread.
724
        *
725
        */
726
        class DataListener extends Thread
727
        {
728
                final int DATALISTENER_DELAY = 1000;
729
                BufferedReader reader;
730
731
                public DataListener ()
732
                {
733
                        super("Colonet DataListener");
734
                }
735
736
                public void run ()
737
                {
738
                        String line;
739
                        try {
740
                                reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
741
                        } catch (IOException e) {
742
                                warn("Could not open input stream from socket.\nTry relooding the applet.");
743
                        }
744
                        while (true)
745
                        {
746
                                try {
747
                                        if (reader.ready())
748
                                        {
749
                                                line = reader.readLine();
750
                                                if (line != null)
751
                                                {
752
                                                        msg("Incoming data: [" + line + "]");
753
                                                }
754
                                        }
755
                                        Thread.sleep(DATALISTENER_DELAY);
756
                                } catch (InterruptedException e) {
757
                                        return;
758
                                } catch (IOException e) {
759
                                        warn("IOException while reading incoming data.");
760
                                }
761
                        }
762
                }
763
764
        }
765
766
767
        /*
768
        *        Matrix class
769
        *        holds current sensor matrix data
770
        */
771
772
        /*
773
        private class Matrix
774
        {
775
                int [][] grid;
776

777
                public Matrix ()
778
                {
779
                        grid = new int[1][1];
780
                }
781

782
                public String toString ()
783
                {
784
                        StringBuilder s = new StringBuilder();
785
                        for (int j = 0; j < grid.length; j++)
786
                        {
787
                                for (int i = 0; i < grid[0].length; i++)
788
                                        s.append(grid[i][j]);
789
                                if (j < grid.length-1) s.append("\n");
790
                        }
791
                        return s.toString();
792
                }
793

794
        }
795
        */
796
797
798
799
}