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    }