From d1da2c2b09f2e4754dc89fdb89bbb1d7cb73e0f0 Mon Sep 17 00:00:00 2001 From: Christopher Baines Date: Thu, 15 Sep 2011 21:38:57 +0100 Subject: Lots of changes, began a dev branch. --- PunchingBag/src/PicHelper/ImagePanel.java | 118 ++++++ .../src/uk/ac/open/punchingbag/Arduino.java | 353 ++++++++--------- .../src/uk/ac/open/punchingbag/PunchingBag.java | 439 +++++++++++++-------- .../src/uk/ac/open/punchingbag/PunchingBagGUI.java | 195 +++++++-- .../uk/ac/open/punchingbag/examples/Giggle.java | 7 +- .../open/punchingbag/examples/SimpleKeyboard.java | 7 +- 6 files changed, 730 insertions(+), 389 deletions(-) create mode 100644 PunchingBag/src/PicHelper/ImagePanel.java diff --git a/PunchingBag/src/PicHelper/ImagePanel.java b/PunchingBag/src/PicHelper/ImagePanel.java new file mode 100644 index 0000000..099fcb8 --- /dev/null +++ b/PunchingBag/src/PicHelper/ImagePanel.java @@ -0,0 +1,118 @@ +/* + * ImagePanel.java + * + * Copyright (C) 2007 Scott Carpenter (scottc at movingtofreedom dot org) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + * Created on November 9, 2007, 4:07 PM + * + */ + +package PicHelper; + +import java.io.*; +import java.awt.*; +import javax.swing.*; +import javax.imageio.*; + +public class ImagePanel extends JPanel { + + private Image image; + private Image scaledImage; + private int imageWidth = 0; + private int imageHeight = 0; + + // private long paintCount = 0; + + // constructor + public ImagePanel() { + super(); + } + + public void loadImage(String file) throws IOException { + loadImage(new File(file)); + } + + public void loadImage(File file) throws IOException { + image = ImageIO.read(file); + // might be a situation where image isn't fully loaded, and + // should check for that before setting... + imageWidth = image.getWidth(this); + imageHeight = image.getHeight(this); + setScaledImage(); + } + + // e.g., containing frame might call this from formComponentResized + public void scaleImage() { + setScaledImage(); + } + + // override paintComponent + public void paintComponent(Graphics g) { + super.paintComponent(g); + if (scaledImage != null) { + // System.out.println("ImagePanel paintComponent " + ++paintCount); + g.drawImage(scaledImage, 0, 0, this); + } + } + + private void setScaledImage() { + if (image != null) { + + // use floats so division below won't round + float iw = imageWidth; + float ih = imageHeight; + float pw = this.getWidth(); // panel width + float ph = this.getHeight(); // panel height + + if (pw < iw || ph < ih) { + + /* + * compare some ratios and then decide which side of image to + * anchor to panel and scale the other side (this is all based + * on empirical observations and not at all grounded in theory) + */ + + // System.out.println("pw/ph=" + pw/ph + ", iw/ih=" + iw/ih); + + if ((pw / ph) > (iw / ih)) { + iw = -1; + ih = ph; + } else { + iw = pw; + ih = -1; + } + + // prevent errors if panel is 0 wide or high + if (iw == 0) { + iw = -1; + } + if (ih == 0) { + ih = -1; + } + + scaledImage = image.getScaledInstance(new Float(iw).intValue(), + new Float(ih).intValue(), Image.SCALE_DEFAULT); + + } else { + scaledImage = image; + } + + // System.out.println("iw = " + iw + ", ih = " + ih + ", pw = " + pw + // + ", ph = " + ph); + } + } + +} \ No newline at end of file diff --git a/PunchingBag/src/uk/ac/open/punchingbag/Arduino.java b/PunchingBag/src/uk/ac/open/punchingbag/Arduino.java index 78d6726..0421d0e 100644 --- a/PunchingBag/src/uk/ac/open/punchingbag/Arduino.java +++ b/PunchingBag/src/uk/ac/open/punchingbag/Arduino.java @@ -1,4 +1,5 @@ package uk.ac.open.punchingbag; + import java.util.Enumeration; import java.util.HashSet; @@ -16,10 +17,12 @@ import javax.swing.event.EventListenerList; import gnu.io.*; public class Arduino implements Runnable { + + private InputStream in; + private OutputStream out; - InputStream in; - OutputStream out; - + private boolean connected = false; + private EventListenerList readListenerList = new EventListenerList(); private EventListenerList writeListenerList = new EventListenerList(); @@ -30,189 +33,177 @@ public class Arduino implements Runnable { public void addSerialReadListener(SerialReadListener l) { readListenerList.add(SerialReadListener.class, l); } - - static void listPorts() - { - System.out.println("Listing Comm ports:"); - java.util.Enumeration portEnum = CommPortIdentifier.getPortIdentifiers(); - while ( portEnum.hasMoreElements() ) - { - CommPortIdentifier portIdentifier = portEnum.nextElement(); - System.out.println(portIdentifier.getName() + " - " + getPortTypeName(portIdentifier.getPortType()) ); - } - } - - static String getPortTypeName ( int portType ) - { - switch ( portType ) - { - case CommPortIdentifier.PORT_I2C: - return "I2C"; - case CommPortIdentifier.PORT_PARALLEL: - return "Parallel"; - case CommPortIdentifier.PORT_RAW: - return "Raw"; - case CommPortIdentifier.PORT_RS485: - return "RS485"; - case CommPortIdentifier.PORT_SERIAL: - return "Serial"; - default: - return "unknown type"; - } - } - - public String getID() throws IOException { - byte[] idBytes = {0x49, 0x44}; - this.write(idBytes); - try { + + static void listPorts() { + System.out.println("Listing Comm ports:"); + java.util.Enumeration portEnum = CommPortIdentifier + .getPortIdentifiers(); + while (portEnum.hasMoreElements()) { + CommPortIdentifier portIdentifier = portEnum.nextElement(); + System.out.println(portIdentifier.getName() + " - " + + getPortTypeName(portIdentifier.getPortType())); + } + } + + static String getPortTypeName(int portType) { + switch (portType) { + case CommPortIdentifier.PORT_I2C: + return "I2C"; + case CommPortIdentifier.PORT_PARALLEL: + return "Parallel"; + case CommPortIdentifier.PORT_RAW: + return "Raw"; + case CommPortIdentifier.PORT_RS485: + return "RS485"; + case CommPortIdentifier.PORT_SERIAL: + return "Serial"; + default: + return "unknown type"; + } + } + + public String getID() throws IOException { + byte[] idBytes = { 0x49, 0x44 }; + this.write(idBytes); + try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } - int id; - while ((id = this.read()) == -1) {} - if (id == 66) { - return "B"; - } else if (id == 76) { - return "L"; - } else { - return "ERROR " + id; - } - } - - /** - * @return A HashSet containing the CommPortIdentifier for all serial ports that are not currently being used. - */ - public static HashSet getAvailableSerialPorts() { - HashSet h = new HashSet(); - Enumeration thePorts = CommPortIdentifier.getPortIdentifiers(); - while (thePorts.hasMoreElements()) { - CommPortIdentifier com = (CommPortIdentifier) thePorts.nextElement(); - switch (com.getPortType()) { - case CommPortIdentifier.PORT_SERIAL: - try { - CommPort thePort = com.open("CommUtil", 50); - thePort.close(); - h.add(com); - //System.out.println("Found a port: " + com.getPortType()); - } catch (PortInUseException e) { - System.out.println("Port, " + com.getName() + ", is in use."); - } catch (Exception e) { - System.err.println("Failed to open port " + com.getName()); - e.printStackTrace(); - } - } - } - return h; - } - - void connect ( String portName ) throws Exception - { - CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName); - if ( portIdentifier.isCurrentlyOwned() ) - { - System.out.println("Error: Port is currently in use"); - } - else - { - CommPort commPort = portIdentifier.open(this.getClass().getName(),2000); - - if ( commPort instanceof SerialPort ) - { - SerialPort serialPort = (SerialPort) commPort; - serialPort.setSerialPortParams(9600,SerialPort.DATABITS_8,SerialPort.STOPBITS_1,SerialPort.PARITY_NONE); - - in = serialPort.getInputStream(); - out = serialPort.getOutputStream(); - - //(new Thread(this)).start(); - } - else - { - System.out.println("Error: Only serial ports are handled by this example."); - } - } - } - - /** */ - public class SerialReader implements Runnable - { - InputStream in; - - public SerialReader ( InputStream in ) - { - this.in = in; - } - - public void run () - { - byte[] buffer = new byte[1024]; - int len = -1; - try - { - while ( ( len = this.in.read(buffer)) > -1 ) - { - System.out.print(new String(buffer,0,len)); - input(new String(buffer,0,len)); - } - } - catch ( IOException e ) - { - e.printStackTrace(); - } - } - } - - public static void input(String string) { - - } - - /** */ - public class SerialWriter implements Runnable - { - OutputStream out; - - public SerialWriter ( OutputStream out ) - { - this.out = out; - } - - public void run () - { - try - { - int c = 0; - while ( ( c = System.in.read()) > -1 ) - { - this.out.write(c); - } - } - catch ( IOException e ) - { - e.printStackTrace(); - } - } - } + int id; + while ((id = this.read()) == -1) { + } + if (id == 66) { + return "B"; + } else if (id == 76) { + return "L"; + } else { + return "ERROR " + id; + } + } + + /** + * @return A HashSet containing the CommPortIdentifier for all serial ports + * that are not currently being used. + */ + public static HashSet getAvailableSerialPorts() { + HashSet h = new HashSet(); + Enumeration thePorts = CommPortIdentifier.getPortIdentifiers(); + while (thePorts.hasMoreElements()) { + CommPortIdentifier com = (CommPortIdentifier) thePorts + .nextElement(); + switch (com.getPortType()) { + case CommPortIdentifier.PORT_SERIAL: + try { + CommPort thePort = com.open("CommUtil", 50); + thePort.close(); + h.add(com); + // System.out.println("Found a port: " + com.getPortType()); + } catch (PortInUseException e) { + System.out.println("Port, " + com.getName() + + ", is in use."); + } catch (Exception e) { + System.err.println("Failed to open port " + com.getName()); + e.printStackTrace(); + } + } + } + return h; + } + + boolean connect(String portName) throws Exception { + CommPortIdentifier portIdentifier = CommPortIdentifier + .getPortIdentifier(portName); + if (portIdentifier.isCurrentlyOwned()) { + System.out.println("Error: Port is currently in use"); + return false; + } else { + CommPort commPort = portIdentifier.open(this.getClass().getName(), + 2000); + + if (commPort instanceof SerialPort) { + SerialPort serialPort = (SerialPort) commPort; + serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8, + SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); + + in = serialPort.getInputStream(); + out = serialPort.getOutputStream(); + + // (new Thread(this)).start(); + connected = true; + return true; + } else { + System.out + .println("Error: Only serial ports are handled by this example."); + return false; + } + } + } + + /** */ + public class SerialReader implements Runnable { + InputStream in; + + public SerialReader(InputStream in) { + this.in = in; + } + + public void run() { + byte[] buffer = new byte[1024]; + int len = -1; + try { + while ((len = this.in.read(buffer)) > -1) { + System.out.print(new String(buffer, 0, len)); + input(new String(buffer, 0, len)); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + public static void input(String string) { - public void run() { - byte[] buffer = new byte[1024]; - int len = -1; - try - { - while ( ( len = this.in.read(buffer)) > -1 ) - { - System.out.print(new String(buffer,0,len)); - //input(new String(buffer,0,len)); - } - } - catch ( IOException e ) - { - e.printStackTrace(); - } - } - + public boolean connected() { + return connected; + } + + /** */ + public class SerialWriter implements Runnable { + OutputStream out; + + public SerialWriter(OutputStream out) { + this.out = out; + } + + public void run() { + try { + int c = 0; + while ((c = System.in.read()) > -1) { + this.out.write(c); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + public void run() { + byte[] buffer = new byte[1024]; + int len = -1; + try { + while ((len = this.in.read(buffer)) > -1) { + System.out.print(new String(buffer, 0, len)); + // input(new String(buffer,0,len)); + } + } catch (IOException e) { + e.printStackTrace(); + } + + } + public void write(byte[] bytes) throws IOException { out.write(bytes); SerialWriteListener[] sListeners = writeListenerList @@ -221,7 +212,7 @@ public class Arduino implements Runnable { sListeners[i].serialWriteEvent(bytes); } } - + public void write(byte b) throws IOException { out.write(b); SerialWriteListener[] sListeners = writeListenerList @@ -230,7 +221,7 @@ public class Arduino implements Runnable { sListeners[i].serialWriteEvent(b); } } - + public int read() throws IOException { int read = in.read(); SerialReadListener[] sListeners = readListenerList diff --git a/PunchingBag/src/uk/ac/open/punchingbag/PunchingBag.java b/PunchingBag/src/uk/ac/open/punchingbag/PunchingBag.java index 70da436..1e710bc 100644 --- a/PunchingBag/src/uk/ac/open/punchingbag/PunchingBag.java +++ b/PunchingBag/src/uk/ac/open/punchingbag/PunchingBag.java @@ -16,95 +16,14 @@ import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; -// TODO: Loads of threads in this class, make sure everything is thread safe. - /** - * This class represents the punching bag, reads and sends data to and from the arduino's (using the Arduino class), - * controlling the led's and reading the state of the accelerometers and buttons. + * This class represents the punching bag, reads and sends data to and from the + * arduino's (using the Arduino class), controlling the led's and reading the + * state of the accelerometers and buttons. * * @author Christopher Baines * @author Adam Martindale */ -/** - * @author cb24367 - * - */ -/** - * @author cb24367 - * - */ -/** - * @author cb24367 - * - */ -/** - * @author cb24367 - * - */ -/** - * @author cb24367 - * - */ -/** - * @author cb24367 - * - */ -/** - * @author cb24367 - * - */ -/** - * @author cb24367 - * - */ -/** - * @author cb24367 - * - */ -/** - * @author cb24367 - * - */ -/** - * @author cb24367 - * - */ -/** - * @author cb24367 - * - */ -/** - * @author cb24367 - * - */ -/** - * @author cb24367 - * - */ -/** - * @author cb24367 - * - */ -/** - * @author cb24367 - * - */ -/** - * @author cb24367 - * - */ -/** - * @author cb24367 - * - */ -/** - * @author cb24367 - * - */ -/** - * @author cb24367 - * - */ public class PunchingBag implements Runnable { /** * Used by the run method to decide if to call the LEDListeners @@ -123,7 +42,8 @@ public class PunchingBag implements Runnable { */ private byte[] rawLeds = new byte[6 * 8]; /** - * The colour objects for each led, do not access directly as this does not properly set ledsChanged + * The colour objects for each led, do not access directly as this does not + * properly set ledsChanged */ private Color[][] leds = new Color[ledWidth][ledHeight]; @@ -183,13 +103,25 @@ public class PunchingBag implements Runnable { * Arduino managing the buttons and accelerometers */ Arduino buttonArduino = new Arduino(); + /** + * The device address of the button arduino (COM* on Windows, /dev/tty* on + * linux) + */ + String buttonArduinoDeviceAddress = ""; // TODO: This should be cached + // localy /** * The Arduino managing the led drivers */ Arduino ledArduino = new Arduino(); + /** + * The device address of the led arduino (COM* on Windows, /dev/tty* on + * linux) + */ + String ledArduinoDeviceAddress = ""; // TODO: This should be cached localy /** - * Turn on to activate the command line messages regarding the run loop timing stuff + * Turn on to activate the command line messages regarding the run loop + * timing stuff */ boolean debugTimings = false; /** @@ -268,8 +200,9 @@ public class PunchingBag implements Runnable { } /** - * Gets the Color of the led given by its x and y, it will be one of: Color.red - * Color.yellow Color.green Color.white + * Gets the Color of the led given by its x and y, it will be + * one of: Color.red Color.yellow + * Color.green Color.white * * @param x * The x coordinate of the led @@ -282,21 +215,28 @@ public class PunchingBag implements Runnable { } /** - * Used by methods in the PunchingBag class to change the led's array. To simplify things it will accept any Color - * object, but if it's not one of the supported (red,green,yellow), then it will just set it to white (the none colour). + * Used by methods in the PunchingBag class to change the led's array. To + * simplify things it will accept any Color object, but if it's not one of + * the supported (red,green,yellow), then it will just set it to white (the + * none colour). * * @param x * The x coordinate of the led * @param y * The y coordinate of the led * @param colour - * The desired colour of the led, as either Color.red, Color.yellow, Color.green or Color,white. + * The desired colour of the led, as either Color.red, + * Color.yellow, Color.green or Color,white. * @return true if something was changed, false if not */ private boolean setLEDInternal(int x, int y, Color colour) { - if (x >= 0 && x < ledWidth && y >= 0 && y < ledHeight) { - if (leds[x][y] != colour) { - if (!colour.equals(Color.red) && !colour.equals(Color.green) && !colour.equals(Color.yellow)) { + if (x >= 0 && x < ledWidth && y >= 0 && y < ledHeight) { // Check if the + // led being + // set + // exists + if (leds[x][y] != colour) { // Check if the led is being changed + if (!(colour == Color.red) && !(colour == Color.green) + && !(colour == Color.yellow)) { if (leds[x][y] != Color.white) { leds[x][y] = Color.white; ledsChanged = true; @@ -310,13 +250,14 @@ public class PunchingBag implements Runnable { } return true; } else { - return false; + return false; // If not, return false } } /** - * Sets a LED on the grid to the specified colour, either use this command again to change it, or use the - * clearLEDS() function to clear the entire grid. + * Sets a LED on the grid to the specified colour, either use this command + * again to change it, or use the clearLEDS() function to clear + * the entire grid. * * @param x * @param y @@ -329,62 +270,110 @@ public class PunchingBag implements Runnable { /** * Starts an expanding circle at x and y. * - * @param x The x coordinate of the centre of the circle. - * @param y The y coordinate of the centre of the circle. - * @param intensity This controls the intensity of the circle, including colour and (but not yet) weight. + * @param x + * The x coordinate of the centre of the circle. + * @param y + * The y coordinate of the centre of the circle. + * @param intensity + * This controls the intensity of the circle, including colour + * and (but not yet) weight. */ public void circleExpand(int x, int y, int intensity) { runningEffects.add(new CircleExpand(x, y, 100)); } /** - * This controls the intensity of the circle, including colour and (but not yet) weight. + * This controls the intensity of the circle, including colour and (but not + * yet) weight. * - * @param x The x coordinate of the centre of the square - * @param y The y coordinate of the centre of the square - * @param intensity AFAIK, this does nothing yet - * @param colour The colour of the square + * @param x + * The x coordinate of the centre of the square + * @param y + * The y coordinate of the centre of the square + * @param intensity + * AFAIK, this does nothing yet + * @param colour + * The colour of the square */ public void squareExpand(int x, int y, int intensity, Color colour) { runningEffects.add(new SquareExpand(x, y, intensity, colour)); } - + /** * This should fill in a rectangle * - * @param x The x coordinate of the top right of the rectangle - * @param y The y coordinate of the top right of the + * @param x + * The x coordinate of the top right of the rectangle + * @param y + * The y coordinate of the top right of the * @param width * @param height * @param colour * @param time */ - public void fillRect(int x, int y, int width, int height, Color colour, long time) { + public void fillRect(int x, int y, int width, int height, Color colour, + long time) { runningEffects.add(new FillRect(x, y, width, height, colour, time)); } + /** + * @param x + * @param y + * @param width + * @param height + * @param colour + */ public void rect(int x, int y, int width, int height, Color colour) { runningEffects.add(new Rect(x, y, width, height, colour)); } + /** + * @param rect + * @param time + */ public void noise(Rectangle rect, long time) { runningEffects.add(new Noise(rect, System.currentTimeMillis() + time)); } - abstract class Effect { + /** + * This represents an effect (a persistent visual artifact). The effects + * system is meant to provide a simple way of drawing to the screen without + * having to handle any of the refresh stuff. + * + * @author Christopher Baines + * + */ + private abstract class Effect { + /** + * The system time of the last refresh + */ long lastRefresh = 0; - boolean stop = false; - - // int refreshRate = 60; // Times per second to refresh + /** + * Set when the effect should stop (use stop() to set). + */ + private boolean stop = false; + /** + * Used to stop the effect, removing it from the list of effects + * (runningEffects) to be drawn. + */ public void stop() { stop = true; } + /** + * The draw method for each effect, called every iteration in run. + */ abstract public void draw(); } - class Point extends Effect { + /** + * Used by the setLED function, this draws a point on the screen. + * + * @author Christopher Baines + * + */ + private class Point extends Effect { final int x; final int y; final Color colour; @@ -408,7 +397,8 @@ public class PunchingBag implements Runnable { final Color colour; final long time; - public FillRect(int x, int y, int width, int height, Color colour, long time) { + public FillRect(int x, int y, int width, int height, Color colour, + long time) { this.x = x; this.y = y; this.width = width; @@ -460,7 +450,7 @@ public class PunchingBag implements Runnable { } public void draw() { - byte[] stringBytes = string.getBytes(); + // byte[] stringBytes = string.getBytes(); } } @@ -498,7 +488,7 @@ public class PunchingBag implements Runnable { // 10); if (!drawCircle(x, y, currentRadius, colour)) - stop = true; + stop(); } } @@ -523,7 +513,7 @@ public class PunchingBag implements Runnable { public void draw() { heightWidth += 0.1 + 0.1 + (heightWidth / 20); if (!drawRectCenter(x, y, heightWidth, heightWidth, colour)) - stop = true; + stop(); } @@ -561,7 +551,8 @@ public class PunchingBag implements Runnable { } } - public boolean drawRectCenter(int x, int y, int height, int width, Color colour) { + public boolean drawRectCenter(int x, int y, int height, int width, + Color colour) { if (height < 0) { height = 0; } @@ -577,16 +568,20 @@ public class PunchingBag implements Runnable { int heightEx = 0; do { - if (setLEDInternal((x - (height / 2)) + widthEx, y - (height / 2), colour)) { + if (setLEDInternal((x - (height / 2)) + widthEx, y - (height / 2), + colour)) { doneSomething = true; } - if (setLEDInternal(x - (height / 2), (y - (height / 2)) + heightEx, colour)) { + if (setLEDInternal(x - (height / 2), (y - (height / 2)) + heightEx, + colour)) { doneSomething = true; } - if (setLEDInternal((x - (height / 2)) + widthEx, y + (height / 2), colour)) { + if (setLEDInternal((x - (height / 2)) + widthEx, y + (height / 2), + colour)) { doneSomething = true; } - if (setLEDInternal(x + (height / 2), (y - (height / 2)) + heightEx, colour)) { + if (setLEDInternal(x + (height / 2), (y - (height / 2)) + heightEx, + colour)) { doneSomething = true; } if (heightEx < height) { @@ -601,7 +596,8 @@ public class PunchingBag implements Runnable { return doneSomething; } - public boolean drawRectInternal(int x, int y, int width, int height, Color colour) { + public boolean drawRectInternal(int x, int y, int width, int height, + Color colour) { if (height < 0) { height = 0; } @@ -706,7 +702,8 @@ public class PunchingBag implements Runnable { return drawnSomething; } - public boolean fillRectInternal(int x, int y, int height, int width, Color colour) { + public boolean fillRectInternal(int x, int y, int height, int width, + Color colour) { boolean doneSomething = false; for (int px = x; px < (x + height); px++) { @@ -729,34 +726,28 @@ public class PunchingBag implements Runnable { for (int x = 0; x < 8; x++) { for (int y = 0; y < 8; y++) { if ((y % 2) == 0) { - if (leds[1 + x][(grid * 4) + (y / 2)] == Color.green || leds[1 + x][(grid * 4) + (y / 2)] == Color.yellow) { - rawLeds[(grid * 8) + x] = (byte) (rawLeds[(grid * 8) + x] | (1 << (7 - y))); + if (leds[1 + x][(grid * 4) + (y / 2)] == Color.green + || leds[1 + x][(grid * 4) + (y / 2)] == Color.yellow) { + rawLeds[(grid * 8) + x] = (byte) (rawLeds[(grid * 8) + + x] | (1 << (7 - y))); } } else { - if (leds[1 + x][(grid * 4) + (y / 2)] == Color.red || leds[1 + x][(grid * 4) + (y / 2)] == Color.yellow) { - rawLeds[(grid * 8) + x] = (byte) (rawLeds[(grid * 8) + x] | (1 << (7 - y))); + if (leds[1 + x][(grid * 4) + (y / 2)] == Color.red + || leds[1 + x][(grid * 4) + (y / 2)] == Color.yellow) { + rawLeds[(grid * 8) + x] = (byte) (rawLeds[(grid * 8) + + x] | (1 << (7 - y))); } } } } } - /* - * for (int y = 0; y <= 18; y++) { for (int x = 0; x <= 6; x++) { if ((y % 2) == 0) { if (leds[x][y] == Colour.Green - * || leds[x][y] == Colour.Yellow) { rawLeds[(int) Math.floor(y / 4)] = (byte) (rawLeds[(int) Math .floor(y / 4)] | - * (1 << (7 - x))); } } else { if (leds[x][y] == Colour.Red || leds[x][y] == Colour.Yellow) { rawLeds[(int) - * Math.floor(y / 4)] = (byte) (rawLeds[(int) Math .floor(y / 4)] | (1 << (7 - x))); } } } } - */ - /* - * int x = 7; // TODO: Complete and test, or rethink the following? for (int startY = 0; startY <= 4; startY++) { for - * (int y = 0; y <= 3; y++) { if (leds[x][startY + (y * 4)] == Colour.Red || leds[x][startY + (y * 4)] == - * Colour.Yellow) { rawLeds[(5 * 8) + startY] = (byte) (rawLeds[(int) Math .floor(y / 4)] | (1 << (7 - x))); } if - * (leds[x][y] == Colour.Green || leds[x][y] == Colour.Yellow) { rawLeds[(int) Math.floor(y / 4)] = (byte) - * (rawLeds[(int) Math .floor(y / 4)] | (1 << (7 - x))); } } } - */ + // TODO: Add support for the wierd column } - /* Clears the led grid */ + /** + * Clears the led grid + */ private void clearLEDGrid() { for (int x = 0; x < ledWidth; x++) { for (int y = 0; y < ledHeight; y++) { @@ -765,6 +756,9 @@ public class PunchingBag implements Runnable { } } + /** + * Clears the button grid + */ private void clearButtonGrid() { for (int x = 0; x < buttonWidth; x++) { for (int y = 0; y < buttonHeight; y++) { @@ -773,49 +767,106 @@ public class PunchingBag implements Runnable { } } + /** + * Stops all effects, this will remove them from the runningEffects list on + * the next run iteration + */ private void clearEffects() { for (Iterator iter = runningEffects.iterator(); iter.hasNext();) { ((Effect) iter.next()).stop(); } } + /** + * Clears the LED grid. + */ public void clearLEDs() { clearLEDGrid(); clearEffects(); } + /** + * Each of the six grids (described at the top) can have an intensity set + * between 0 and 15. + * + * @param grid + * The number of the grid (0-5) + * @param intensity + * The desired intensity (0-15) + */ public void setLEDGridIntensity(byte grid, byte intensity) { ledGridIntensities[grid] = intensity; } + /** + * Sets the intensity of all the grids. + * + * @param intensity + * The desired intensity (0-15) + */ public void setLEDIntensities(byte intensity) { - Arrays.fill(ledGridIntensities, intensity); + if (intensity < 0) { + Arrays.fill(ledGridIntensities, (byte) 0); + } else if (intensity > 15) { + Arrays.fill(ledGridIntensities, (byte) 15); + } else { + Arrays.fill(ledGridIntensities, intensity); + } } + /** + * Generates a button pressed event + * + * @param x + * The x coordinate of the button + * @param y + * The y coordinate of the button + */ public void buttonPressed(int x, int y) { buttons[x][y] = true; buttonsChanged = true; } - public boolean connectToArduinos() { - try { - ledArduino.connect("COM6"); - buttonArduino.connect("COM7"); - } catch (Exception e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); - } - HashSet serialPorts = Arduino.getAvailableSerialPorts(); + /** + * Connect to both arduino's + * + * @return True if the connection to both was successful, false if not + * @throws Exception + */ + public boolean connectToArduinos() throws Exception { + return connectToButtonArduino() && connectToLEDArduino(); + } + + /** + * @return + * @throws Exception + */ + public boolean connectToButtonArduino() throws Exception { + return buttonArduino.connect(buttonArduinoDeviceAddress); + } + + /** + * @return + * @throws Exception + */ + public boolean connectToLEDArduino() throws Exception { + return ledArduino.connect(ledArduinoDeviceAddress); + } + + /** + * @return + */ + private boolean findArduinos() { + // TODO: Detect OS and continue appropiately + HashSet serialPorts = Arduino + .getAvailableSerialPorts(); for (Iterator iter = serialPorts.iterator(); iter.hasNext();) { CommPortIdentifier comPort = (CommPortIdentifier) iter.next(); // HACK FOR WINDOWS TO IDENIFY PORTS LIKELY TO CONTAIN ARDUINO // (COM10 for instance). TODO: FIX - if (comPort.getName().length() == 5) { - System.out.println(comPort.getName()); - } try { - System.out.println(comPort.getName()); + // TODO: Connect and check what arduino this is } catch (Exception e) { e.printStackTrace(); } @@ -823,12 +874,18 @@ public class PunchingBag implements Runnable { return true; } + /** + * Processes the serial data regarding accelerations + * + * @param data The data string to be processed + */ private void readAccelData(String data) { // System.out.println("Data: " + data); String[] nums = data.split(" "); for (int x = 1; x < nums.length; x++) { // Regex expression to strip newline at end (normally just 4th) - if (nums[x].replaceAll("[^0-9]", "").length() == 0 || nums[x].replaceAll("[^0-9]", "").length() > 4) { + if (nums[x].replaceAll("[^0-9]", "").length() == 0 + || nums[x].replaceAll("[^0-9]", "").length() > 4) { System.err.println("Accel Data Error: " + data); continue; } @@ -856,6 +913,11 @@ public class PunchingBag implements Runnable { } } + /** + * Processes the serial data regarding buttons + * + * @param data The data string to be processed + */ private void readButtonData(String data) { // System.out.println("Data: " + data); if (data.replaceAll("[^0-9]", "").length() > 0) { @@ -871,6 +933,11 @@ public class PunchingBag implements Runnable { } } + /** + * Debugging utility function to print in binary byte b + * + * @param b + */ private void printByte(byte b) { // System.out.println("Byte: " + b); String str; @@ -891,14 +958,22 @@ public class PunchingBag implements Runnable { System.out.println(""); } + /* + * The run method starts a loop which processes the serial data, effects and events + * + * @see java.lang.Runnable#run() + */ public void run() { - long timeToSleep = 10; + long timeToSleep = 10; // The time slept at the end of the loop (to maintain the refresh rate) while (true) { if (debugTimings) { - System.out.println("Time since last refresh: " + (System.currentTimeMillis() - lastRefresh)); + System.out.println("Time since last refresh: " + + (System.currentTimeMillis() - lastRefresh)); if ((System.currentTimeMillis() - lastRefresh) != 0) - System.out.println("FPS: " + (1000 / (System.currentTimeMillis() - lastRefresh))); + System.out + .println("FPS: " + + (1000 / (System.currentTimeMillis() - lastRefresh))); } if ((System.currentTimeMillis() - lastRefresh) > (1000 / 60)) { @@ -921,7 +996,8 @@ public class PunchingBag implements Runnable { // ConcurrentModificationException's // (havent managed to produce one // though - for (Iterator iter = runningEffects.iterator(); iter.hasNext();) { + for (Iterator iter = runningEffects.iterator(); iter + .hasNext();) { Effect ef = (Effect) iter.next(); if (ef.stop) { iter.remove(); @@ -940,7 +1016,7 @@ public class PunchingBag implements Runnable { long beginTimeButtonIn = System.currentTimeMillis(); boolean doneA = false; boolean doneB = false; - if (buttonArduino.in != null) { + if (buttonArduino.connected()) { try { int read; // System.out.println("Reading selector"); @@ -952,7 +1028,8 @@ public class PunchingBag implements Runnable { System.out.println("Outside " + (char) read); if ((char) read == 'B') { if (debugSerial) - System.out.println(" Got an B, begining reading the button data"); + System.out + .println(" Got an B, begining reading the button data"); String str = ""; // StringBuilder sb = new StringBuilder(20); while (true) { @@ -961,17 +1038,21 @@ public class PunchingBag implements Runnable { break; str = str + String.valueOf((char) read); if (debugSerial) - System.out.println("Reading button data: " + (char) read); + System.out.println("Reading button data: " + + (char) read); // sb.append((char) read); } if (debugSerial) - System.out.print("Finished reading button data because of newline " + (char) read); + System.out + .print("Finished reading button data because of newline " + + (char) read); // System.out.println(""); doneB = true; readButtonData(str); } else if ((char) read == 'A') { if (debugSerial) - System.out.println(" Got an A, begining reading the accel data"); + System.out + .println(" Got an A, begining reading the accel data"); String str = ""; // StringBuilder sb = new StringBuilder(20); while (true) { @@ -980,7 +1061,8 @@ public class PunchingBag implements Runnable { break; str = str + String.valueOf((char) read); if (debugSerial) - System.out.println("Reading accel data " + (char) read); + System.out.println("Reading accel data " + + (char) read); // sb.append((char) read); } // System.out.println(""); @@ -1000,7 +1082,8 @@ public class PunchingBag implements Runnable { } } if (debugTimings) - System.out.println("Button: " + (System.currentTimeMillis() - beginTimeButtonIn)); + System.out.println("Button: " + + (System.currentTimeMillis() - beginTimeButtonIn)); calculateRawLeds(); // String str; @@ -1011,7 +1094,7 @@ public class PunchingBag implements Runnable { // Arrays.fill(rawLeds, (byte) -42); long beginTimeLedOut = System.currentTimeMillis(); - if (ledArduino.out != null) { + if (ledArduino.connected()) { // calculateRawLeds(); try { ledArduino.write(((byte) 108)); @@ -1021,32 +1104,38 @@ public class PunchingBag implements Runnable { } } if (debugTimings) - System.out.println("Leds: " + (System.currentTimeMillis() - beginTimeLedOut)); + System.out.println("Leds: " + + (System.currentTimeMillis() - beginTimeLedOut)); // Arrays.fill(rawLeds, (byte) -42); long beginTimeListeners = System.currentTimeMillis(); if (ledsChanged) { - LEDListener[] LEDListeners = ledListenerList.getListeners(LEDListener.class); + LEDListener[] LEDListeners = ledListenerList + .getListeners(LEDListener.class); for (int i = 0; i < ledListenerList.getListenerCount(); i++) { LEDListeners[i].LEDchanged(); } } if (buttonsChanged) { - ButtonListener[] buttonListeners = buttonListenerList.getListeners(ButtonListener.class); + ButtonListener[] buttonListeners = buttonListenerList + .getListeners(ButtonListener.class); for (int i = 0; i < buttonListenerList.getListenerCount(); i++) { for (int x = 0; x < buttonWidth; x++) { for (int y = 0; y < buttonHeight; y++) { if (buttons[x][y]) { buttonListeners[i].buttonPressed(x, y); - buttonListeners[i].contact(new Contact(System.currentTimeMillis(), x, y, bottomAccelX)); + buttonListeners[i].contact(new Contact(System + .currentTimeMillis(), x, y, + bottomAccelX)); } } } } } if (debugTimings) - System.out.println("Listeners: " + (System.currentTimeMillis() - beginTimeListeners)); + System.out.println("Listeners: " + + (System.currentTimeMillis() - beginTimeListeners)); clearButtonGrid(); diff --git a/PunchingBag/src/uk/ac/open/punchingbag/PunchingBagGUI.java b/PunchingBag/src/uk/ac/open/punchingbag/PunchingBagGUI.java index d05016d..5cbc3f5 100644 --- a/PunchingBag/src/uk/ac/open/punchingbag/PunchingBagGUI.java +++ b/PunchingBag/src/uk/ac/open/punchingbag/PunchingBagGUI.java @@ -1,9 +1,13 @@ package uk.ac.open.punchingbag; + import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; +import java.awt.DisplayMode; import java.awt.Graphics; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; @@ -13,10 +17,16 @@ import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; +import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; +import java.util.ArrayList; +import javax.imageio.ImageIO; import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JComponent; @@ -43,16 +53,21 @@ import javax.sound.sampled.UnsupportedAudioFileException; import javax.sound.sampled.AudioFormat.Encoding; import javax.sound.sampled.Mixer.Info; +import PicHelper.ImagePanel; + public class PunchingBagGUI implements MouseListener, MouseMotionListener, ButtonListener, LEDListener { public static enum Mode { - Menu, Interactive, Game + Debug, Menu }; - Mode currentMode = Mode.Interactive; + Mode currentMode = Mode.Menu; - static JFrame frame; + JFrame frame; + + JPanel bagDebugingPanel = new JPanel(); + JPanel programOptionsPanel = new JPanel(); // Contact public enum Direction { @@ -67,13 +82,16 @@ public class PunchingBagGUI implements MouseListener, MouseMotionListener, new File(soundDir + "E5.wav"), new File(soundDir + "F5.wav"), new File(soundDir + "G5.wav") }; + String imageDirectory = System.getProperty("user.home"); + static PunchingBag bag = PunchingBag.getBag(); final boolean useDebugScreen = true; + boolean debugImages = true; + public static void main(String[] args) throws InterruptedException { new PunchingBagGUI(); - } PunchingBagGUI() throws InterruptedException { @@ -82,13 +100,18 @@ public class PunchingBagGUI implements MouseListener, MouseMotionListener, // System.out.println(AudioSystem.getMixerInfo()[0].getDescription()); // Mixer mix = AudioSystem.getMixer(AudioSystem.getMixerInfo()[0]); - bag.connectToArduinos(); + try { + // bag.connectToArduinos(); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } frame = new JFrame("Punching Bag GUI"); + frame.setUndecorated(true); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // frame.setSize(600, 600); - frame.setVisible(true); frame.addMouseListener(this); frame.addMouseMotionListener(this); @@ -106,34 +129,132 @@ public class PunchingBagGUI implements MouseListener, MouseMotionListener, tabbedPane.addTab("LED Control Panel", null, new LEDControlPanel(), "Allows control of individual LED's"); + tabbedPane.addTab("GUI Control Panel", null, new GUIControlPanel(), + "Allows control of the GUI"); + centerTopSplitPane.setLeftComponent(new PunchingBagSim()); centerTopSplitPane.setRightComponent(tabbedPane); bottomTopSplitPane.setTopComponent(centerTopSplitPane); bottomTopSplitPane.setBottomComponent(new SerialPanel()); - frame.add(bottomTopSplitPane, BorderLayout.CENTER); + bagDebugingPanel.add(bottomTopSplitPane, BorderLayout.CENTER); + + programOptionsPanel.add(new DisplayPanel()); + + //frame.add(bagDebugingPanel); + frame.add(programOptionsPanel); + + //setMode(currentMode); + + GraphicsDevice device; + device = GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice(); + if (device.isFullScreenSupported()) { + device.setFullScreenWindow(frame); + } else { + System.err.println("Full screen not supported"); + } + frame.setVisible(true); // frame.pack(); } - void playKey(int key) { - try { - AudioInputStream sound = AudioSystem.getAudioInputStream(keys[key]); - DataLine.Info dataLine = new DataLine.Info(Clip.class, - sound.getFormat()); - Clip clip = (Clip) AudioSystem.getLine(dataLine); - clip.open(sound); - clip.start(); - } catch (LineUnavailableException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (UnsupportedAudioFileException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + void setMode(Mode mode) { + this.currentMode = mode; + if (currentMode == Mode.Menu) { + bagDebugingPanel.setVisible(false); + programOptionsPanel.setVisible(true); + } else if (currentMode == Mode.Debug) { + bagDebugingPanel.setVisible(true); + programOptionsPanel.setVisible(false); + } + } + + class MenuPanel extends JPanel implements ActionListener { + MenuPanel() { + this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + + this.add(Box.createVerticalGlue()); + + JPanel bottom = new JPanel(); + bottom.setAlignmentX(1f); + bottom.setLayout(new BoxLayout(bottom, BoxLayout.X_AXIS)); + + JButton debugMode = new JButton("Debug Mode"); + debugMode.addActionListener(this); + + bottom.add(debugMode); + bottom.add(Box.createRigidArea(new Dimension(15, 0))); + + this.add(bottom); + this.add(Box.createRigidArea(new Dimension(0, 15))); + } + + @Override + public void actionPerformed(ActionEvent e) { + setMode(Mode.Debug); + } + } + + class DisplayPanel extends JPanel implements Runnable { + ArrayList files = new ArrayList(); + ImagePanel imagePanel = new ImagePanel(); + int image = 0; + + DisplayPanel() { + this.add(imagePanel); + new Thread(this).start(); + } + + /*public void paintComponent(Graphics g) { + if (images.size() != 0) { + if (debugImages) + System.out.println("Displaying Image"); + g.drawImage(images.get(image), 0, 0, frame.getSize().width, frame.getSize().height, null); + } + }*/ + + public void run() { + loadImages(); + while (true) { + try { + imagePanel.loadImage(files.get(image)); + } catch (IOException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + if (image == (files.size() - 1)) { + image = 0; + } else { + image++; + } + if (debugImages) + System.out.println("Moving to the next image "); + try { + Thread.sleep(10000); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + + public void loadImages() { + if (debugImages) + System.out.println("Loading images..."); + File imageDir = new File(imageDirectory); + System.out.println("Looking in " + imageDirectory); + File[] dirFiles = imageDir.listFiles(); + for (int i = 0; i < dirFiles.length; i++) { + if (dirFiles[i].getName().contains(".jpg")) { + if (debugImages) + System.out.println("Found .jpg " + dirFiles[i].getName()); + files.add(dirFiles[i]); + } + } + if (debugImages) + System.out.println("Finished loading images"); } } @@ -247,6 +368,21 @@ public class PunchingBagGUI implements MouseListener, MouseMotionListener, } } + class GUIControlPanel extends JPanel implements ActionListener { + public GUIControlPanel() { + JButton menuButton = new JButton("Menu"); + menuButton.addActionListener(this); + + this.add(menuButton); + } + + @Override + public void actionPerformed(ActionEvent e) { + setMode(Mode.Menu); + + } + } + class LEDControlPanel extends JPanel implements ActionListener { String[] colours = { " ", "R", "Y", "G" }; @@ -519,10 +655,7 @@ public class PunchingBagGUI implements MouseListener, MouseMotionListener, @Override public void mousePressed(MouseEvent me) { - if (currentMode == Mode.Interactive) { - // bag.buttonPressed(me.getX()/(buttonSize+ledSize), - // me.getY()/(buttonSize+ledSize)); - } + } @Override @@ -534,7 +667,7 @@ public class PunchingBagGUI implements MouseListener, MouseMotionListener, @Override public void contact(Contact c) { // TODO Auto-generated method stub - + } } @@ -589,8 +722,8 @@ public class PunchingBagGUI implements MouseListener, MouseMotionListener, @Override public void buttonPressed(int x, int y) { System.out.println("Button Pressed: " + x + " " + y); - //bag.circleExpand(x, y, 16); - //bag.setLED(x, y, Color.red); + // bag.circleExpand(x, y, 16); + // bag.setLED(x, y, Color.red); bag.noise(new Rectangle(0, 0, 9, 20), 5000); /* * for (int bx=0; bx