From d2a324089bfbd62c649445e70c8cf14565f97733 Mon Sep 17 00:00:00 2001 From: Nicklas Gavelin Date: Mon, 5 Mar 2012 15:33:38 +0100 Subject: [PATCH] Shutdown hook, Configuration update Added a shutdown hook to Robot to send reset settings on disconnect. Also added a new Configuration type locateion in sphero.configuration --- .../experimental/test/Experimental_Main.java | 2 - .../configuration/ProjectProperties.java | 176 ++++++++++++++ .../configuration/project.properties | 26 ++ src/se/nicklasgavelin/log/Configuration.java | 46 ---- src/se/nicklasgavelin/log/Logging.java | 75 ++---- src/se/nicklasgavelin/sphero/Robot.java | 230 +++++++++++------- .../nicklasgavelin/sphero/RobotSetting.java | 55 +++++ 7 files changed, 427 insertions(+), 183 deletions(-) create mode 100644 src/se/nicklasgavelin/configuration/ProjectProperties.java create mode 100644 src/se/nicklasgavelin/configuration/project.properties delete mode 100644 src/se/nicklasgavelin/log/Configuration.java create mode 100644 src/se/nicklasgavelin/sphero/RobotSetting.java diff --git a/experimental/experimental/test/Experimental_Main.java b/experimental/experimental/test/Experimental_Main.java index f704234..34adcbf 100644 --- a/experimental/experimental/test/Experimental_Main.java +++ b/experimental/experimental/test/Experimental_Main.java @@ -19,7 +19,6 @@ import se.nicklasgavelin.sphero.Robot; import se.nicklasgavelin.sphero.RobotListener; import se.nicklasgavelin.sphero.command.CommandMessage; -import se.nicklasgavelin.sphero.command.RGBLEDCommand; import se.nicklasgavelin.sphero.command.RawMotorCommand; import se.nicklasgavelin.sphero.command.SetDataStreamingCommand; import se.nicklasgavelin.sphero.exception.InvalidRobotAddressException; @@ -27,7 +26,6 @@ import se.nicklasgavelin.sphero.macro.command.Delay; import se.nicklasgavelin.sphero.macro.MacroObject; import se.nicklasgavelin.sphero.macro.command.RawMotor; -import experimental.sphero.macro.Rotate; import se.nicklasgavelin.sphero.macro.command.*; import se.nicklasgavelin.sphero.response.ResponseMessage; import se.nicklasgavelin.sphero.response.information.DataResponse; diff --git a/src/se/nicklasgavelin/configuration/ProjectProperties.java b/src/se/nicklasgavelin/configuration/ProjectProperties.java new file mode 100644 index 0000000..33fdee7 --- /dev/null +++ b/src/se/nicklasgavelin/configuration/ProjectProperties.java @@ -0,0 +1,176 @@ +/* + * Please read the LICENSE file that is included with the source + * code. + */ + +package se.nicklasgavelin.configuration; + +import java.awt.Color; +import java.util.Properties; +import se.nicklasgavelin.log.Logging; +import se.nicklasgavelin.sphero.Robot; +import se.nicklasgavelin.sphero.RobotSetting; +import se.nicklasgavelin.sphero.command.RawMotorCommand; +import se.nicklasgavelin.util.Value; + +/** + * Used for returning current configuration settings + * Settings are stored in project.properties in the same packet as this class. + * + * @author Nicklas Gavelin, nicklas.gavelin@gmail.com, Luleå University of + * Technology + */ +public class ProjectProperties extends Properties +{ + private static ProjectProperties instance; + + + /** + * Create project properties + */ + private ProjectProperties() + { + super(); + + try + { + // Load the property file + this.load( ProjectProperties.class.getResourceAsStream( "project.properties" ) ); + } + catch ( Exception e ) + { + // Unable to load property file, sorry :( + } + } + + + /** + * Returns default robot settings + * + * @return Default robot settings + */ + public RobotSetting getRobotSetting() + { + return new RobotSetting( + new Color( + Integer.parseInt( this.getProperty( "sphero.color.rgb.red", "255" ) ), + Integer.parseInt( this.getProperty( "sphero.color.rgb.green", "255" ) ), + Integer.parseInt( this.getProperty( "sphero.color.rgb.blue", "255" ) ) + ), + Integer.parseInt( this.getProperty( "sphero.pinginterval", "255" ) ), + Float.parseFloat( this.getProperty( "sphero.color.brightness", "1" ) ), + Integer.parseInt( this.getProperty( "sphero.motor.heading", "0" ) ), + Integer.parseInt( this.getProperty( "sphero.motor.speed", "0" ) ), + Integer.parseInt( this.getProperty( "sphero.macro.size", "0" ) ), + Integer.parseInt( this.getProperty( "sphero.macro.storage", "0" ) ), + Integer.parseInt( this.getProperty( "sphero.macro.minsize", "128" ) ), + Boolean.parseBoolean( this.getProperty( "sphero.motor.stop", "true" ) ), + Float.parseFloat( this.getProperty( "sphero.macro.rotationrate", "0" ) ), + RawMotorCommand.MOTOR_MODE.valueOf( this.getProperty( "sphero.motor.motormode", RawMotorCommand.MOTOR_MODE.FORWARD.toString() ) ) + ); + } + + + /** + * Returns size of received buffer + * + * @return The size of the received buffer + */ + public int getBufferSize() + { + return Integer.parseInt( this.getProperty( "sphero.socket.buffersize", "256" ) ); + } + + /** + * Returns the current debug state + * + * @return True for on, false for off + */ + public boolean getDebugEnabled() + { + return Boolean.parseBoolean( this.getProperty( "debug.enabled", "false" ) ); + } + + + /** + * Set debug status + * + * @param enabled The new debug status (true for on, false otherwise) + */ + public void setDebugEnabled( boolean enabled ) + { + this.setProperty( "debug.enabled", Boolean.toString( enabled ) ); + } + + + /** + * Returns the current bluecove debug state + * + * @return The current bluecove debug state + */ + public boolean getBluecoveDebugEnabled() + { + return Boolean.parseBoolean( this.getProperty( "debug.bluecove.enabled", "false" ) ); + } + + + /** + * Set bluecove debug status + * + * @param enabled New debug status + */ + public void setBluecoveDebugEnabled( boolean enabled ) + { + this.setProperty( "debug.bluecove.enabled", Boolean.toString( enabled ) ); + } + + + /** + * Returns the logger name + * + * @return The logger name + */ + public String getLoggerName() + { + return this.getProperty( "debug.loggername", "se.nicklasgavelin" ); + } + + + /** + * Set the name of the logger + * WILL NOT WORK AFTER THE LOGGER HAVE BEEN INITIALIZED + * + * @param name The new name for the logger + */ + public void setLoggerName( String name ) + { + this.setProperty( "debug.loggername", name ); + } + + + /** + * Returns the current debug level, + * default level is Logging.Level.FATAL + * + * @return The set debug level + */ + public Logging.Level getDebugLevel() + { + return Logging.Level.valueOf( this.getProperty( "debug.level", Logging.Level.FATAL.toString() ) ); + } + + + /** + * Returns the properies instance + * + * @return The property instance + */ + public static ProjectProperties getInstance() + { + // Check if we have a previous instance + if ( ProjectProperties.instance == null ) + ProjectProperties.instance = new ProjectProperties(); + + return ProjectProperties.instance; + } +} diff --git a/src/se/nicklasgavelin/configuration/project.properties b/src/se/nicklasgavelin/configuration/project.properties new file mode 100644 index 0000000..da3ec68 --- /dev/null +++ b/src/se/nicklasgavelin/configuration/project.properties @@ -0,0 +1,26 @@ +# Debugging +debug.level = INFO +debug.enabled = true +debug.loggername = se.nicklasgavelin.se + +debug.bluecove.enabled = false + +# Spero +sphero.macro.size = 200 +sphero.macro.storage = 600 +sphero.macro.minsize = 150 +sphero.pinginterval = 60000 + +sphero.color.rgb.red = 255 +sphero.color.rgb.blue = 255 +sphero.color.rgb.green = 255 + +sphero.color.brightness = 1 + +sphero.motor.speed = 0 +sphero.motor.stop = true +sphero.motor.heading = 0 +sphero.motor.rotationrate = 0 + +# Other +sphero.socket.buffersize = 50 \ No newline at end of file diff --git a/src/se/nicklasgavelin/log/Configuration.java b/src/se/nicklasgavelin/log/Configuration.java deleted file mode 100644 index 1eb1d73..0000000 --- a/src/se/nicklasgavelin/log/Configuration.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - * - * @author Nicklas Gavelin, nicklas.gavelin@gmail.com, Luleå University of Technology - */ -package se.nicklasgavelin.log; - -import com.intel.bluetooth.DebugLog; - -/** - * Handles configuration such as debug level and debugging - * - * @author Nicklas Gavelin - */ -public class Configuration -{ - /* Debug settings */ - - /** - * Flag for turning on/off debugging - */ - public static boolean debugEnabled = true; - - /** - * Name of logger - */ - public static final String loggerName = "se.nicklasgavelin"; - - /** - * Value for turning on/off Bluecove library debugging - */ - public static boolean bluecoveDebugEnabled = false; - - /** - * The logging level during runtime - */ - public static Logging.Level debugLevel = Logging.Level.ERROR; - - static - { - // Set bluecove debugging - DebugLog.setDebugEnabled( Configuration.bluecoveDebugEnabled ); - Logging.info( "Turning " + (Configuration.bluecoveDebugEnabled ? "ON" : "OFF") + " bluecove debugger" ); - } -} diff --git a/src/se/nicklasgavelin/log/Logging.java b/src/se/nicklasgavelin/log/Logging.java index 7fbf292..f781083 100644 --- a/src/se/nicklasgavelin/log/Logging.java +++ b/src/se/nicklasgavelin/log/Logging.java @@ -1,11 +1,14 @@ package se.nicklasgavelin.log; -import java.io.PrintStream; -import java.util.*; +import com.intel.bluetooth.DebugLog; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; import java.util.logging.ConsoleHandler; import java.util.logging.Handler; import java.util.logging.Logger; +import se.nicklasgavelin.configuration.ProjectProperties; /** * Manages the logging of the application. @@ -28,7 +31,7 @@ public class Logging private static final String log4logger = "site.nicklas.log.Log4JLogger"; private static final String from = Logging.class.getName(); private static final Collection fromCollection = new ArrayList(); - private static final Logger logger = Logger.getLogger( Configuration.loggerName ); + private static final Logger logger = Logger.getLogger( ProjectProperties.getInstance().getLoggerName() );//Configuration.loggerName ); static @@ -166,8 +169,6 @@ private static void initialize() setLevel(); - Logging.logger.fine( "test " ); - Logging.debug( "[" + Logging.class.getCanonicalName() + "] Turning off debug as no log4j instance could be created" ); } } @@ -175,9 +176,14 @@ private static void initialize() private static void setLevel() { - //get the top Logger: - Logger topLogger = java.util.logging.Logger.getLogger( Configuration.loggerName ); - topLogger.setLevel( Configuration.debugLevel.getLevel() ); + // Fetch project settings + ProjectProperties pp = ProjectProperties.getInstance(); + + Logger topLogger = java.util.logging.Logger.getLogger( pp.getLoggerName() );//Configuration.loggerName ); + topLogger.setLevel( pp.getDebugLevel().getLevel() ); //Configuration.debugLevel.getLevel() ); + + // Set bluecove log status + DebugLog.setDebugEnabled( pp.getBluecoveDebugEnabled() ); // Handler for console (reuse it if it already exists) Handler consoleHandler = null; @@ -200,7 +206,7 @@ private static void setLevel() } //set the console handler to fine: - consoleHandler.setLevel( Configuration.debugLevel.getLevel() ); + consoleHandler.setLevel( pp.getDebugLevel().getLevel() );//Configuration.debugLevel.getLevel() ); } @@ -212,7 +218,8 @@ private static void setLevel() public static void setDebugEnabled( boolean enabled ) { initialize(); - Configuration.debugEnabled = enabled; + //Configuration.debugEnabled = enabled; + ProjectProperties.getInstance().setDebugEnabled( enabled ); } @@ -228,12 +235,14 @@ private static void callAppenders( Level l, String msg, Throwable t ) // Perform initialization if not already done initialize(); + ProjectProperties pp = ProjectProperties.getInstance(); + // Check if we have debug enabled or if the level is fatal - if ( (!Configuration.debugEnabled && !l.equals( Level.FATAL )) ) + if ( (!pp.getDebugEnabled() && !l.equals( Level.FATAL )) ) return; // Check if we want the messages of this level to be logged - if ( l.getValue() < Configuration.debugLevel.getValue() ) + if ( l.getValue() < pp.getDebugLevel().getValue() ) return; if ( !log4exists ) @@ -266,48 +275,8 @@ private static void nativeDebug( Level l, String msg, Throwable t ) { // Fetch location for the message UtilsJavaSE.StackTraceLocation s = UtilsJavaSE.getLocation( fromCollection ); -// boolean useError = (t == null && (!l.equals( Level.ERROR ) && !l.equals( Level.FATAL ))); -// PrintStream out = (useError ? System.out : System.err); - - logger.setLevel( Configuration.debugLevel.getLevel() ); + logger.setLevel( ProjectProperties.getInstance().getDebugLevel().getLevel() ); Logging.logger.logp( l.getLevel(), s.className, s.methodName, "\t" + msg + "\n", t ); - -// try -// { -// // Create our timestamp -// Calendar calendar = Calendar.getInstance(); -// calendar.setTime( new Date( System.currentTimeMillis() ) ); -// -// // Hours -// String hour = calendar.get( Calendar.HOUR_OF_DAY ) + ""; -// hour = (Integer.parseInt( hour ) < 10 ? "0" : "") + hour; -// -// // Minutes -// String minutes = calendar.get( Calendar.MINUTE ) + ""; -// minutes = (Integer.parseInt( minutes ) < 10 ? "0" : "") + minutes; -// -// // Seconds -// String seconds = calendar.get( Calendar.SECOND ) + ""; -// seconds = (Integer.parseInt( seconds ) < 10 ? "0" : "") + seconds; -// -// // Milliseconds -// String ms = calendar.get( Calendar.MILLISECOND ) + ""; -// -// // Now create our debug message -// String aMsg = "[ " + hour + ":" + minutes + ":" + seconds + "." + ms + " ]"; // Timestamp -// aMsg += "[ " + l + " ]"; // Level -// aMsg += " " + msg; -// -// // Print message -// out.println( aMsg ); -// } -// catch ( Throwable _ ) -// { -// } -// -// // Check if we have something throwable -// if ( s != null ) -// out.println( "\t " + fromLocation( s ) ); } diff --git a/src/se/nicklasgavelin/sphero/Robot.java b/src/se/nicklasgavelin/sphero/Robot.java index 04b9f28..94fe63b 100644 --- a/src/se/nicklasgavelin/sphero/Robot.java +++ b/src/se/nicklasgavelin/sphero/Robot.java @@ -1,16 +1,16 @@ package se.nicklasgavelin.sphero; -import se.nicklasgavelin.sphero.macro.command.RGB; -import se.nicklasgavelin.sphero.macro.command.Delay; -import se.nicklasgavelin.sphero.macro.command.Emit; import java.awt.Color; import java.io.IOException; import java.util.*; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; +import java.util.logging.Level; +import java.util.logging.Logger; import se.nicklasgavelin.bluetooth.BluetoothConnection; import se.nicklasgavelin.bluetooth.BluetoothDevice; +import se.nicklasgavelin.configuration.ProjectProperties; import se.nicklasgavelin.log.Logging; import se.nicklasgavelin.sphero.RobotListener.EVENT_CODE; import se.nicklasgavelin.sphero.command.RawMotorCommand.MOTOR_MODE; @@ -18,12 +18,14 @@ import se.nicklasgavelin.sphero.exception.InvalidRobotAddressException; import se.nicklasgavelin.sphero.exception.RobotBluetoothException; import se.nicklasgavelin.sphero.exception.RobotInitializeConnectionFailed; -import se.nicklasgavelin.sphero.macro.*; -import se.nicklasgavelin.sphero.response.regular.GetBluetoothInfoResponse; -import se.nicklasgavelin.sphero.response.ResponseMessage; +import se.nicklasgavelin.sphero.macro.MacroCommand; +import se.nicklasgavelin.sphero.macro.MacroObject; +import se.nicklasgavelin.sphero.macro.command.Delay; +import se.nicklasgavelin.sphero.macro.command.Emit; +import se.nicklasgavelin.sphero.macro.command.RGB; import se.nicklasgavelin.sphero.response.InformationResponseMessage; -import se.nicklasgavelin.sphero.response.information.EmitResponse; -import se.nicklasgavelin.util.Array; +import se.nicklasgavelin.sphero.response.ResponseMessage; +import se.nicklasgavelin.sphero.response.regular.GetBluetoothInfoResponse; import se.nicklasgavelin.util.ByteArrayBuffer; import se.nicklasgavelin.util.Pair; import se.nicklasgavelin.util.Value; @@ -52,6 +54,8 @@ */ public class Robot { + private RobotSetting rs; + /** * Manages sending of macro commands * @@ -64,7 +68,6 @@ private class MACRO_SETTINGS private final Collection sendingQueue; private final Collection ballMemory; private boolean macroRunning, macroStreamingEnabled; - private static final int maxMacroSize = 200, robotStorageSpace = 600, minSpaceToSend = 180; private int emits = 0; @@ -93,7 +96,7 @@ private void stopMacro() this.commands.clear(); this.ballMemory.clear(); - // Set stop flag + // Set motorStop flag this.macroRunning = false; } @@ -164,7 +167,7 @@ private void playMacro( MacroObject macro ) * Send a command after a CachedStreaming macro has run * * @param command The command to send after the macro is finished - * running + * running */ public void sendCommandAfterMacro( CommandMessage command ) { @@ -190,11 +193,11 @@ private synchronized void emptyMacroCommandQueue() { // Calculate number of free bytes that we have int ballSpace = freeBallMemory(), - freeBytes = (ballSpace > maxMacroSize ? maxMacroSize : ballSpace), + freeBytes = (ballSpace > rs.macroMaxSize ? rs.macroMaxSize : ballSpace), chunkSize = 0; // Check if we need or can create more commands - if ( this.commands.isEmpty() || ballSpace <= minSpaceToSend ) + if ( this.commands.isEmpty() || ballSpace <= rs.macroMinSpaceSize ) return; // Create our sending collection (stuff that we want to send) @@ -208,7 +211,7 @@ private synchronized void emptyMacroCommandQueue() for ( MacroCommand cmd : this.commands ) { // Check if we allow for the new command to be added (that we still got enough space left to add it) - if ( freeBytes - (chunkSize + cmd.getLength() + emitLength) <= 0 || (chunkSize + cmd.getLength() + emitLength) > maxMacroSize ) + if ( freeBytes - (chunkSize + cmd.getLength() + emitLength) <= 0 || (chunkSize + cmd.getLength() + emitLength) > rs.macroMaxSize ) break; // Add the command to the send queue and increase the space we've used @@ -246,7 +249,7 @@ private synchronized void emptyMacroCommandQueue() svc ); // Check if we can continue creating more messages to send - if ( !this.commands.isEmpty() && freeBallMemory() > minSpaceToSend ) + if ( !this.commands.isEmpty() && freeBallMemory() > rs.macroMinSpaceSize ) this.emptyMacroCommandQueue(); } @@ -262,7 +265,7 @@ private int freeBallMemory() for ( Iterator i = this.ballMemory.iterator(); i.hasNext(); ) bytesInUse = bytesInUse + i.next().intValue(); - return (robotStorageSpace - bytesInUse); + return (rs.macroRobotStorageSize - bytesInUse); } } @@ -281,7 +284,7 @@ public class RobotMovement rotationRate; private boolean stop = true; // The current drive algorithm that is used for calculating velocity - // and heading when running .drive no Robot + // and motorHeading when running .drive no Robot private DriveAlgorithm algorithm; @@ -295,9 +298,9 @@ private RobotMovement() /** - * Returns the current heading of the robot + * Returns the current motorHeading of the robot * - * @return The current heading of the robot (0-360) + * @return The current motorHeading of the robot (0-360) */ public float getHeading() { @@ -328,7 +331,7 @@ public float getRotationRate() /** - * Returns the current stop value of the robot. + * Returns the current motorStop value of the robot. * True means the robot is stopped, false means it's * moving with a certain velocity * @@ -342,7 +345,7 @@ public boolean getStop() /** * Returns the current drive algorithm that is used to - * calculate the velocity and heading when running .drive on Robot + * calculate the velocity and motorHeading when running .drive on Robot * * @return The current drive algorithm */ @@ -359,8 +362,10 @@ public DriveAlgorithm getDriveAlgorithm() */ private void reset() { - this.heading = this.velocity = this.rotationRate = 0F; - this.stop = true; + this.heading = rs.motorHeading; + this.velocity = rs.motorStartSpeed; + this.rotationRate = rs.motorRotationRate; + this.stop = rs.motorStop; this.algorithm = new RCDriveAlgorithm(); } } @@ -438,8 +443,8 @@ public MOTOR_MODE getRightMotorMode() */ private void reset() { - this.leftMotorSpeed = this.rightMotorSpeed = 0; - this.leftMotorMode = this.rightMotorMode = MOTOR_MODE.FORWARD; + this.leftMotorSpeed = this.rightMotorSpeed = rs.motorStartSpeed; + this.leftMotorMode = this.rightMotorMode = rs.motorMode; } } @@ -509,9 +514,9 @@ public Color getRGBColor() /** - * Returns the brightness of the front led (0-1) + * Returns the ledBrightness of the front led (0-1) * - * @return The brightness level of the front led + * @return The ledBrightness level of the front led */ public float getFrontLEDBrightness() { @@ -525,14 +530,16 @@ public float getFrontLEDBrightness() private void reset() { // Set white color (default for connected devices) - this.red = this.green = this.blue = 255; + this.red = rs.ledRGB.getRed(); + this.green = rs.ledRGB.getGreen(); + this.blue = rs.ledRGB.getBlue(); - // Reset the brightness to 0 (off) - this.brightness = 0.0F; + // Reset the ledBrightness to 0 (off) + this.brightness = rs.ledBrightness; } } // Bluetooth - private BluetoothDevice bt; + private final BluetoothDevice bt; private BluetoothConnection btc; private boolean connected = false; // Listener/writer @@ -548,7 +555,7 @@ private void reset() private Robot.RobotRawMovement rawMovement; private Robot.RobotLED led; // Pinger - private float PING_INTERVAL = 60000; // Time in milliseconds + private float PING_INTERVAL; // Time in milliseconds // Address /** * The start of the Bluetooth address that is describing if the address @@ -575,10 +582,27 @@ private void reset() * @param bt The Bluetooth device that represents the robot * * @throws InvalidRobotAddressException - * throws - * RobotBluetoothException + * throws + * RobotBluetoothException */ public Robot( BluetoothDevice bt ) throws InvalidRobotAddressException, RobotBluetoothException + { + this( bt, null ); + } + + + /** + * Create a robot from a Bluetooth device. You need to call Robot.connect + * after creating a robot to connect to it via the Bluetooth connection + * given. + * + * @param bt The Bluetooth device that represents the robot + * + * @throws InvalidRobotAddressException + * throws + * RobotBluetoothException + */ + public Robot( BluetoothDevice bt, RobotSetting rs ) throws InvalidRobotAddressException, RobotBluetoothException { this.bt = bt; @@ -593,6 +617,14 @@ public Robot( BluetoothDevice bt ) throws InvalidRobotAddressException, RobotBlu throw new InvalidRobotAddressException( msg ); } + if ( rs == null ) + this.rs = ProjectProperties.getInstance().getRobotSetting(); + else + this.rs = rs; + + // Set ping interval + PING_INTERVAL = this.rs.socketPingInterval; + // Initialize the position and LEDs this.movement = new Robot.RobotMovement(); this.rawMovement = new Robot.RobotRawMovement(); @@ -606,6 +638,27 @@ public Robot( BluetoothDevice bt ) throws InvalidRobotAddressException, RobotBlu this.listeners = new ArrayList(); Logging.debug( "Robot created successfully" ); + + // Add system hook + Runtime.getRuntime().addShutdownHook( new Thread( new Runnable() + { + @Override + public void run() + { + // Force disconnect asap! + + try + { + // Wait for disconnect event + Robot.this.disconnect( false ); + Robot.this.sendingTimer.w.join(); + } + catch ( InterruptedException ex ) + { + Logger.getLogger( Robot.class.getName() ).log( Level.SEVERE, null, ex ); + } + } + } ) ); } /* @@ -733,7 +786,7 @@ public boolean connect() * @param throwException True to throw exception, false otherwise * * @throws RobotInitializeConnectionFailed Thrown if throwException is set - * to true and initialization failed + * to true and initialization failed * @return True if connected, will throw exception if not connected */ public boolean connect( boolean throwException ) @@ -817,6 +870,7 @@ public void disconnect() { this.disconnect( true ); } + private boolean disconnecting = false; /** @@ -857,13 +911,16 @@ private void closeConnections() if ( this.connected ) { this.connected = false; + this.disconnecting = true; // Stop our transmission of commands this.sendingTimer.cancel(); - // Send a direct command to stop any movement (eludes the .cancel command) + // Send a direct command to motorStop any movement (eludes the .cancel command) + this.sendingTimer.forceCommand( new AbortMacroCommand() ); this.sendingTimer.forceCommand( new RollCommand( 0, 0, true ) ); this.sendingTimer.forceCommand( new FrontLEDCommand( 0 ) ); + this.sendingTimer.forceCommand( new RGBLEDCommand( Color.BLACK ) ); } } @@ -925,7 +982,7 @@ public void sendCommand( CommandMessage command, float delay ) * * @param command The command to send * @param initialDelay The initial delay before the first message is sent - * (in milliseconds) + * (in milliseconds) * @param periodLength The length between the transmissions */ public void sendPeriodicCommand( CommandMessage command, float initialDelay, float periodLength ) @@ -963,7 +1020,7 @@ private void sendSystemCommand( CommandMessage command, float delay ) * * @param command The command to send * @param initialDelay The initial delay before the first message is sent - * (in milliseconds) + * (in milliseconds) * @param periodLength The length between the transmissions */ private void sendSystemCommand( CommandMessage command, float initialDelay, float periodLength ) @@ -982,7 +1039,7 @@ private void sendSystemCommand( CommandMessage command, float initialDelay, floa private void updateInternalValues( CommandMessage command ) { // Disconnect event, we will disconnect if we are not connected and - // we have sent both a roll stop command and a front led turn off command + // we have sent both a roll motorStop command and a front led turn off command if ( !this.connected && (command instanceof FrontLEDCommand || command instanceof RollCommand) ) { if ( receivedFirstDisconnect ) @@ -1099,10 +1156,10 @@ private void updateInternalValues( CommandMessage command ) */ /** - * Roll the robot with a given heading and speed + * Roll the robot with a given motorHeading and speed * - * @param heading The heading (0-360) - * @param speed The speed (0-1) + * @param motorHeading The motorHeading (0-360) + * @param speed The speed (0-1) */ public void roll( float heading, float speed ) { @@ -1111,10 +1168,11 @@ public void roll( float heading, float speed ) /** - * Calibrate the heading to a specific heading (Will move the robot to this - * heading) + * Calibrate the motorHeading to a specific motorHeading (Will move the + * robot to this + * motorHeading) * - * @param heading The heading to calibrate to (0-359) + * @param motorHeading The motorHeading to calibrate to (0-359) */ public void calibrate( float heading ) { @@ -1137,7 +1195,7 @@ public void calibrate( float heading ) * @param from The color to go from * @param to The color to end up with * @param steps The number of steps to take between the change between the - * two colors + * two colors */ public void rgbTransition( Color from, Color to, int steps ) { @@ -1157,7 +1215,7 @@ public void rgbTransition( Color from, Color to, int steps ) * @param tGreen The final green color value * @param tBlue The final blue color value * @param steps Number of steps to take (The number of times to change - * color until reaching the final color) + * color until reaching the final color) */ public void rgbTransition( int fRed, int fGreen, int fBlue, int tRed, int tGreen, int tBlue, int steps ) { @@ -1172,7 +1230,7 @@ public void rgbTransition( int fRed, int fGreen, int fBlue, int tRed, int tGreen * @param from The color to go from * @param to The color to end up with * @param steps The number of steps to take between the change between the - * two colors + * two colors * @param dDelay Delay between the color shifts */ public void rgbTransition( Color from, Color to, int steps, int dDelay ) @@ -1192,7 +1250,7 @@ public void rgbTransition( Color from, Color to, int steps, int dDelay ) * @param tGreen The final green color value * @param tBlue The final blue color value * @param steps Number of steps to take (The number of times to change - * color until reaching the final color) + * color until reaching the final color) * @param dDelay Delay between the color shifts */ public void rgbTransition( int fRed, int fGreen, int fBlue, int tRed, int tGreen, int tBlue, int steps, int dDelay ) @@ -1200,8 +1258,8 @@ public void rgbTransition( int fRed, int fGreen, int fBlue, int tRed, int tGreen int tdelay = dDelay; // Hue, saturation, intensity - float[] fHSB = Color.RGBtoHSB( fRed, fGreen, fBlue, null ); - float[] tHSB = Color.RGBtoHSB( tRed, tGreen, tBlue, null ); + final float[] fHSB = Color.RGBtoHSB( fRed, fGreen, fBlue, null ); + final float[] tHSB = Color.RGBtoHSB( tRed, tGreen, tBlue, null ); float hDif = Math.abs( fHSB[0] - tHSB[0] ); float sDif = Math.abs( fHSB[1] - tHSB[1] ); @@ -1236,9 +1294,6 @@ public void rgbTransition( int fRed, int fGreen, int fBlue, int tRed, int tGreen // Add new RGB commands mo.addCommand( new RGB( c, 0 ) ); mo.addCommand( new Delay( tdelay ) ); - - // Send new values - //this.sendingTimer.enqueue( new RGBLEDCommand( c.getRed(), c.getGreen(), c.getBlue() ), tdelay * i ); } // Set streaming as we don't know if we can fit all macro commands in one message @@ -1252,7 +1307,7 @@ public void rgbTransition( int fRed, int fGreen, int fBlue, int tRed, int tGreen /** * Rotate the robot * - * @param heading The new heading, 0-360 + * @param motorHeading The new motorHeading, 0-360 */ public void rotate( float heading ) { @@ -1277,7 +1332,7 @@ public void jumpToBootloader() * The sleep time is given in seconds. * * @param time Number of seconds to sleep. The connection WILL be LOST to - * the robot and have to be re-initialized. + * the robot and have to be re-initialized. */ public void sleep( int time ) { @@ -1321,11 +1376,11 @@ public void setRGBLedColor( Color c ) /** - * Resets the robots heading. + * Resets the robots motorHeading. * - * Sends a roll command with current velocity and stop value and also a + * Sends a roll command with current velocity and motorStop value and also a * calibrate - * command to reset the heading. + * command to reset the motorHeading. */ public void resetHeading() { @@ -1335,9 +1390,9 @@ public void resetHeading() /** - * Update heading offset + * Update motorHeading offset * - * @param offset The heading offset + * @param offset The motorHeading offset */ public void setHeadingOffset( double offset ) { @@ -1346,9 +1401,9 @@ public void setHeadingOffset( double offset ) /** - * Set brightness of the front led. 0-1 + * Set ledBrightness of the front led. 0-1 * - * @param brightness The brightness value, 0-1 + * @param ledBrightness The ledBrightness value, 0-1 */ public void setFrontLEDBrightness( float brightness ) { @@ -1420,7 +1475,7 @@ public void boost( float timeInterval ) /** - * Send a command to stop the robot motors + * Send a command to motorStop the robot motors */ public void stopMotors() { @@ -1652,14 +1707,12 @@ public Robot.RobotRawMovement getRobotRawMovement() */ private class RobotStreamListener extends Thread { - // Thread stop/continue + // Thread motorStop/continue private boolean stop = false; // Bluetooth connection to use private BluetoothConnection btc; // Queue for commands that are waiting for responses private LinkedList> waitingForResponse; - // Buffers - private static final int BUFFER_SIZE = 256; /** @@ -1678,7 +1731,7 @@ public RobotStreamListener( BluetoothConnection btc ) * Enqueue a command that are waiting for a response from the device * * @param cmd The pair of the command and the flag that tells if it's a - * system command or not + * system command or not */ protected void enqueue( Pair cmd ) { @@ -1698,8 +1751,8 @@ public void stopThread() private byte[] linkedToArray( List list ) { byte[] d = new byte[ list.size() ]; - for( int i = 0; i < list.size(); i++ ) - d[ i ] = list.get( i ); + for ( int i = 0; i < list.size(); i++ ) + d[ i] = list.get( i ); // for ( int i = 0; list.size() > 0; i++ ) // d[ i] = list.remove( 0 ); @@ -1718,10 +1771,10 @@ public void run() // Create a data array that contains all our read // data. - byte[] data = new byte[ BUFFER_SIZE ]; + byte[] data = new byte[ ProjectProperties.getInstance().getBufferSize() ]; LinkedList buffer = new LinkedList(); - // Run until we manually stop the thread + // Run until we manually motorStop the thread while ( !this.stop ) { try @@ -1840,6 +1893,19 @@ public void run() name = gb.getName(); break; } + break; + case RGB_LED_OUTPUT: + if ( Robot.this.disconnecting ) + { + if ( cmd.getFirst().getCommand().equals( CommandMessage.COMMAND_MESSAGE_TYPE.RGB_LED_OUTPUT ) ) + { + // Notify + // We are disconnecting + Robot.this.disconnecting = false; + this.stopThread(); + } + } + break; } } else // Notify user @@ -1927,7 +1993,7 @@ public void run() // Add the remaining data to the buffer by reading // from our abandoned position - for( ; read2 < nData.length; read2++) + for ( ; read2 < nData.length; read2++ ) buffer.add( nData[read2] ); } catch ( NullPointerException e ) @@ -2009,7 +2075,7 @@ protected RobotSendingQueue( BluetoothConnection btc ) /** * Start the writer thread. - * The writer will stop at the same time as the RobotSendinQueue is + * The writer will motorStop at the same time as the RobotSendinQueue is * stopped. */ private void startWriter() @@ -2037,7 +2103,7 @@ public void forceCommand( CommandMessage command ) * * @param command The command to send * @param systemCommand True if the command is a system command, false - * otherwise + * otherwise */ public void enqueue( CommandMessage command, boolean systemCommand ) { @@ -2125,7 +2191,7 @@ private void enqueue( Robot.RobotSendingQueue.CommandTask task, float delay ) * @param command The command to send * @param delay The delay to send after (in ms) * @param systemCommand True if the command is a system command, false - * otherwise + * otherwise */ public void enqueue( CommandMessage command, float delay, boolean systemCommand ) { @@ -2172,7 +2238,7 @@ private class CommandTask extends TimerTask * Create a command task to send a command * * @param execute The command together with a boolean value - * describing if it's a system message or not + * describing if it's a system message or not */ private CommandTask( Pair execute ) { @@ -2186,7 +2252,7 @@ private CommandTask( Pair execute ) * @param execute The command to execute * @param delay The delay between the commands * @param repeat The number of repeats to perform (-1 for infinite - * repeats) + * repeats) */ private CommandTask( Pair execute, float delay, int repeat ) { @@ -2225,7 +2291,7 @@ public void run() { ByteArrayBuffer sendingBuffer = new ByteArrayBuffer( 256 ); - // Run until we manually stop the thread or + // Run until we manually motorStop the thread or // a connection error occurs. while ( !stop ) { @@ -2234,14 +2300,14 @@ public void run() // Try and fetch some message Pair p = sendingQueue.take(); - Collection> sent = new ArrayList>(); +// Collection> sent = new ArrayList>(); // Append message to sending buffer sendingBuffer.append( p.getFirst().getPacket(), 0, p.getFirst().getPacketLength() ); // Add command to listening queue listeningThread.enqueue( p ); - sent.add( p ); +// sent.add( p ); Logging.debug( "Queueing " + p.getFirst() ); @@ -2270,7 +2336,7 @@ public void run() // Enqueue the next command sendingBuffer.append( c.getFirst().getPacket(), 0, c.getFirst().getPacketLength() ); listeningThread.enqueue( c ); - sent.add( c ); +// sent.add( c ); sendingQueue.remove(); Logging.debug( "Queueing " + c.getFirst() ); diff --git a/src/se/nicklasgavelin/sphero/RobotSetting.java b/src/se/nicklasgavelin/sphero/RobotSetting.java new file mode 100644 index 0000000..c1195f9 --- /dev/null +++ b/src/se/nicklasgavelin/sphero/RobotSetting.java @@ -0,0 +1,55 @@ +/* + * Please read the LICENSE file that is included with the source + * code. + */ + +package se.nicklasgavelin.sphero; + +import java.awt.Color; +import se.nicklasgavelin.sphero.command.RawMotorCommand; +import se.nicklasgavelin.util.Value; + +/** + * + * @author Nicklas Gavelin, nicklas.gavelin@gmail.com, Luleå University of + * Technology + */ +public class RobotSetting +{ + protected Color ledRGB; + protected float ledBrightness, motorRotationRate; + protected int socketPingInterval, motorHeading, motorStartSpeed, macroMaxSize, macroRobotStorageSize, macroMinSpaceSize; + protected boolean motorStop; + protected RawMotorCommand.MOTOR_MODE motorMode; + + + /** + * Create a robot setting + * + * @param ledRGB Initial color + * @param socketPinginterval Ping interval + * @param ledBrightness Brightness level + * @param motorHeading Heading + * @param motorStartSpeed Start speed + * @param macroMaxMacroSize Max macro size + * @param macroRobotStorageSize Storage volume on robot for macro + * @param macroMinSpaceSendSize Min macro size to send + * @param motorStop True or false + * @param motorRotationrate Rotation rate + * @param motorMode Motor mode + */ + public RobotSetting( Color ledRGB, int socketPinginterval, float ledBrightness, int motorHeading, int motorStartSpeed, int macroMaxMacroSize, int macroRobotStorageSize, int macroMinSpaceSendSize, boolean motorStop, float motorRotationrate, RawMotorCommand.MOTOR_MODE motorMode ) + { + this.ledRGB = ledRGB; + this.socketPingInterval = Value.clamp( socketPinginterval, 1000, 120000 ); + this.ledBrightness = Value.clamp( ledBrightness, 0, 1 ); + this.motorHeading = Value.clamp( motorHeading, 0, 359 ); + this.motorStartSpeed = Value.clamp( motorStartSpeed, 0, 255 ); + this.macroMaxSize = Value.clamp( macroMaxMacroSize, 50, 240 ); + this.macroRobotStorageSize = Value.clamp( macroRobotStorageSize, 256, 1000 ); + this.macroMinSpaceSize = Value.clamp( macroMinSpaceSendSize, 50, 240 ); + this.motorStop = motorStop; + this.motorRotationRate = Value.clamp( motorRotationrate, 0, 1 ); + this.motorMode = motorMode; + } +}