diff options
Diffstat (limited to 'PunchingBag/src/uk/ac/open/punchingbag/PunchingBag.java')
-rw-r--r-- | PunchingBag/src/uk/ac/open/punchingbag/PunchingBag.java | 439 |
1 files changed, 264 insertions, 175 deletions
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 <cbaines8@gmail.com> * @author Adam Martindale <awiamartindale@googlemail.com> */ -/** - * @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]; @@ -184,12 +104,24 @@ public class PunchingBag implements Runnable { */ 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 <code>Color</code> of the led given by its x and y, it will be one of: <code>Color.red</code> - * <code>Color.yellow</code> <code>Color.green</code> <code>Color.white</code> + * Gets the <code>Color</code> of the led given by its x and y, it will be + * one of: <code>Color.red</code> <code>Color.yellow</code> + * <code>Color.green</code> <code>Color.white</code> * * @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 - * <code>clearLEDS()</code> 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 <code>clearLEDS()</code> function to clear + * the entire grid. * * @param x * @param y @@ -329,62 +270,110 @@ public class PunchingBag implements Runnable { /** * Starts an expanding circle at <code>x</code> and <code>y</code>. * - * @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 <cbaines8@gmail.com> + * + */ + 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 <code>stop()</code> 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 <cbaines8@gmail.com> + * + */ + 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<Effect> 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<CommPortIdentifier> 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<CommPortIdentifier> 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<Effect> iter = runningEffects.iterator(); iter.hasNext();) { + for (Iterator<Effect> 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(); |