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 }