001 /*----------------------------------------------------------------------------*/ 002 /* Copyright (c) FIRST 2008-2012. All Rights Reserved. */ 003 /* Open Source Software - may be modified and shared by FRC teams. The code */ 004 /* must be accompanied by the FIRST BSD license file in the root directory of */ 005 /* the project. */ 006 /*----------------------------------------------------------------------------*/ 007 package edu.wpi.first.wpilibj; 008 009 import com.sun.squawk.microedition.io.FileConnection; 010 import edu.wpi.first.wpilibj.communication.FRCControl; 011 import edu.wpi.first.wpilibj.communication.UsageReporting; 012 import edu.wpi.first.wpilibj.networktables.NetworkTable; 013 import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; 014 import java.io.IOException; 015 import java.io.OutputStream; 016 import java.io.PrintStream; 017 import javax.microedition.io.Connector; 018 import javax.microedition.midlet.MIDlet; 019 import javax.microedition.midlet.MIDletStateChangeException; 020 021 /** 022 * Implement a Robot Program framework. The RobotBase class is intended to be 023 * subclassed by a user creating a robot program. Overridden autonomous() and 024 * operatorControl() methods are called at the appropriate time as the match 025 * proceeds. In the current implementation, the Autonomous code will run to 026 * completion before the OperatorControl code could start. In the future the 027 * Autonomous code might be spawned as a task, then killed at the end of the 028 * Autonomous period. 029 */ 030 public abstract class RobotBase extends MIDlet { 031 032 /** 033 * The VxWorks priority that robot code should work at (so Java code should 034 * run at) 035 */ 036 public static final int ROBOT_TASK_PRIORITY = 101; 037 /** 038 * Boolean System property. If true (default), send System.err messages to 039 * the driver station. 040 */ 041 public final static String ERRORS_TO_DRIVERSTATION_PROP = "first.driverstation.senderrors"; 042 /** 043 * name and contents of the version file that is read by the DS to determine 044 * the library version 045 */ 046 protected final static String FILE_NAME = "file:///FRC_Lib_Version.ini"; 047 protected final static String VERSION_CONTENTS = "Java 2014 Update 0"; 048 protected final DriverStation m_ds; 049 private final Watchdog m_watchdog = Watchdog.getInstance(); 050 051 /** 052 * Constructor for a generic robot program. User code should be placed in 053 * the constructor that runs before the Autonomous or Operator Control 054 * period starts. The constructor will run to completion before Autonomous 055 * is entered. 056 * 057 * This must be used to ensure that the communications code starts. In the 058 * future it would be nice to put this code into it's own task that loads on 059 * boot so ensure that it runs. 060 */ 061 protected RobotBase() { 062 // TODO: StartCAPI(); 063 // TODO: See if the next line is necessary 064 // Resource.RestartProgram(); 065 066 // if (getBooleanProperty(ERRORS_TO_DRIVERSTATION_PROP, true)) { 067 // Utility.sendErrorStreamToDriverStation(true); 068 // } 069 NetworkTable.setServerMode();//must be before b 070 m_ds = DriverStation.getInstance(); 071 m_watchdog.setEnabled(false); 072 NetworkTable.getTable(""); // forces network tables to initialize 073 NetworkTable.getTable("LiveWindow").getSubTable("~STATUS~").putBoolean("LW Enabled", false); 074 } 075 076 /** 077 * Free the resources for a RobotBase class. 078 */ 079 public void free() { 080 } 081 082 /** 083 * Check on the overall status of the system. 084 * 085 * @return Is the system active (i.e. PWM motor outputs, etc. enabled)? 086 */ 087 public boolean isSystemActive() { 088 return m_watchdog.isSystemActive(); 089 } 090 091 /** 092 * Return the instance of the Watchdog timer. Get the watchdog timer so the 093 * user program can either disable it or feed it when necessary. 094 * 095 * @return The Watchdog timer. 096 */ 097 public Watchdog getWatchdog() { 098 return m_watchdog; 099 } 100 101 /** 102 * @return If the robot is running in simulation. 103 */ 104 public static boolean isSimulation() { 105 return false; 106 } 107 108 /** 109 * @return If the robot is running in the real world. 110 */ 111 public static boolean isReal() { 112 return true; 113 } 114 115 /** 116 * Determine if the Robot is currently disabled. 117 * 118 * @return True if the Robot is currently disabled by the field controls. 119 */ 120 public boolean isDisabled() { 121 return m_ds.isDisabled(); 122 } 123 124 /** 125 * Determine if the Robot is currently enabled. 126 * 127 * @return True if the Robot is currently enabled by the field controls. 128 */ 129 public boolean isEnabled() { 130 return m_ds.isEnabled(); 131 } 132 133 /** 134 * Determine if the robot is currently in Autonomous mode. 135 * 136 * @return True if the robot is currently operating Autonomously as 137 * determined by the field controls. 138 */ 139 public boolean isAutonomous() { 140 return m_ds.isAutonomous(); 141 } 142 143 /** 144 * Determine if the robot is currently in Test mode 145 * 146 * @return True if the robot is currently operating in Test mode as 147 * determined by the driver station. 148 */ 149 public boolean isTest() { 150 return m_ds.isTest(); 151 } 152 153 /** 154 * Determine if the robot is currently in Operator Control mode. 155 * 156 * @return True if the robot is currently operating in Tele-Op mode as 157 * determined by the field controls. 158 */ 159 public boolean isOperatorControl() { 160 return m_ds.isOperatorControl(); 161 } 162 163 /** 164 * Indicates if new data is available from the driver station. 165 * 166 * @return Has new data arrived over the network since the last time this 167 * function was called? 168 */ 169 public boolean isNewDataAvailable() { 170 return m_ds.isNewControlData(); 171 } 172 173 /** 174 * Provide an alternate "main loop" via startCompetition(). 175 */ 176 public abstract void startCompetition(); 177 178 public static boolean getBooleanProperty(String name, boolean defaultValue) { 179 String propVal = System.getProperty(name); 180 if (propVal == null) { 181 return defaultValue; 182 } 183 if (propVal.equalsIgnoreCase("false")) { 184 return false; 185 } else if (propVal.equalsIgnoreCase("true")) { 186 return true; 187 } else { 188 throw new IllegalStateException(propVal); 189 } 190 } 191 192 /** 193 * Write the version string to the root directory 194 */ 195 protected void writeVersionString() { 196 FileConnection file = null; 197 try { 198 file = (FileConnection) Connector.open(FILE_NAME, Connector.WRITE); 199 200 file.create(); 201 202 OutputStream output = file.openOutputStream(); 203 PrintStream ps = new PrintStream(output); 204 205 ps.println(VERSION_CONTENTS); 206 } catch (IOException ex) { 207 ex.printStackTrace(); 208 } finally { 209 if (file != null) { 210 try { 211 file.close(); 212 } catch (IOException ex) { 213 } 214 } 215 } 216 } 217 218 /** 219 * Starting point for the applications. Starts the OtaServer and then runs 220 * the robot. 221 * 222 * @throws javax.microedition.midlet.MIDletStateChangeException 223 */ 224 protected final void startApp() throws MIDletStateChangeException { 225 boolean errorOnExit = false; 226 227 Watchdog.getInstance().setExpiration(0.1); 228 Watchdog.getInstance().setEnabled(false); 229 FRCControl.observeUserProgramStarting(); 230 UsageReporting.report(UsageReporting.kResourceType_Language, UsageReporting.kLanguage_Java); 231 232 writeVersionString(); 233 234 try { 235 this.startCompetition(); 236 } catch (Throwable t) { 237 t.printStackTrace(); 238 errorOnExit = true; 239 } finally { 240 // startCompetition never returns unless exception occurs.... 241 System.err.println("WARNING: Robots don't quit!"); 242 if (errorOnExit) { 243 System.err.println("---> The startCompetition() method (or methods called by it) should have handled the exception above."); 244 } else { 245 System.err.println("---> Unexpected return from startCompetition() method."); 246 } 247 } 248 } 249 250 /** 251 * Pauses the application 252 */ 253 protected final void pauseApp() { 254 // This is not currently called by the Squawk VM 255 } 256 257 /** 258 * Called if the MIDlet is terminated by the system. I.e. if startApp throws 259 * any exception other than MIDletStateChangeException, if the isolate 260 * running the MIDlet is killed with Isolate.exit(), or if VM.stopVM() is 261 * called. 262 * 263 * It is not called if MIDlet.notifyDestroyed() was called. 264 * 265 * @param unconditional If true when this method is called, the MIDlet must 266 * cleanup and release all resources. If false the MIDlet may throw 267 * MIDletStateChangeException to indicate it does not want to be destroyed 268 * at this time. 269 * @throws MIDletStateChangeException if there is an exception in 270 * terminating the midlet 271 */ 272 protected final void destroyApp(boolean unconditional) throws MIDletStateChangeException { 273 } 274 }