001/*----------------------------------------------------------------------------*/
002/* Copyright (c) 2008-2018 FIRST. 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
008package edu.wpi.first.wpilibj;
009
010import java.io.File;
011import java.io.FileOutputStream;
012import java.io.IOException;
013import java.net.URL;
014import java.util.Enumeration;
015import java.util.jar.Manifest;
016
017import edu.wpi.cscore.CameraServerJNI;
018import edu.wpi.first.networktables.NetworkTableInstance;
019import edu.wpi.first.wpilibj.hal.FRCNetComm.tInstances;
020import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
021import edu.wpi.first.wpilibj.hal.HAL;
022import edu.wpi.first.wpilibj.hal.HALUtil;
023import edu.wpi.first.wpilibj.internal.HardwareHLUsageReporting;
024import edu.wpi.first.wpilibj.internal.HardwareTimer;
025import edu.wpi.first.wpilibj.livewindow.LiveWindow;
026import edu.wpi.first.wpilibj.util.WPILibVersion;
027
028/**
029 * Implement a Robot Program framework. The RobotBase class is intended to be subclassed by a user
030 * creating a robot program. Overridden autonomous() and operatorControl() methods are called at the
031 * appropriate time as the match proceeds. In the current implementation, the Autonomous code will
032 * run to completion before the OperatorControl code could start. In the future the Autonomous code
033 * might be spawned as a task, then killed at the end of the Autonomous period.
034 */
035public abstract class RobotBase {
036  /**
037   * The VxWorks priority that robot code should work at (so Java code should run at).
038   */
039  public static final int ROBOT_TASK_PRIORITY = 101;
040
041  /**
042   * The ID of the main Java thread.
043   */
044  // This is usually 1, but it is best to make sure
045  public static final long MAIN_THREAD_ID = Thread.currentThread().getId();
046
047  protected final DriverStation m_ds;
048
049  /**
050   * Constructor for a generic robot program. User code should be placed in the constructor that
051   * runs before the Autonomous or Operator Control period starts. The constructor will run to
052   * completion before Autonomous is entered.
053   *
054   * <p>This must be used to ensure that the communications code starts. In the future it would be
055   * nice
056   * to put this code into it's own task that loads on boot so ensure that it runs.
057   */
058  protected RobotBase() {
059    NetworkTableInstance inst = NetworkTableInstance.getDefault();
060    inst.setNetworkIdentity("Robot");
061    inst.startServer("/home/lvuser/networktables.ini");
062    m_ds = DriverStation.getInstance();
063    inst.getTable("LiveWindow").getSubTable(".status").getEntry("LW Enabled").setBoolean(false);
064
065    LiveWindow.setEnabled(false);
066  }
067
068  /**
069   * Free the resources for a RobotBase class.
070   */
071  public void free() {
072  }
073
074  /**
075   * Get if the robot is a simulation.
076   *
077   * @return If the robot is running in simulation.
078   */
079  public static boolean isSimulation() {
080    return !isReal();
081  }
082
083  /**
084   * Get if the robot is real.
085   *
086   * @return If the robot is running in the real world.
087   */
088  public static boolean isReal() {
089    return HALUtil.getHALRuntimeType() == 0;
090  }
091
092  /**
093   * Determine if the Robot is currently disabled.
094   *
095   * @return True if the Robot is currently disabled by the field controls.
096   */
097  public boolean isDisabled() {
098    return m_ds.isDisabled();
099  }
100
101  /**
102   * Determine if the Robot is currently enabled.
103   *
104   * @return True if the Robot is currently enabled by the field controls.
105   */
106  public boolean isEnabled() {
107    return m_ds.isEnabled();
108  }
109
110  /**
111   * Determine if the robot is currently in Autonomous mode as determined by the field
112   * controls.
113   *
114   * @return True if the robot is currently operating Autonomously.
115   */
116  public boolean isAutonomous() {
117    return m_ds.isAutonomous();
118  }
119
120  /**
121   * Determine if the robot is currently in Test mode as determined by the driver
122   * station.
123   *
124   * @return True if the robot is currently operating in Test mode.
125   */
126  public boolean isTest() {
127    return m_ds.isTest();
128  }
129
130  /**
131   * Determine if the robot is currently in Operator Control mode as determined by the field
132   * controls.
133   *
134   * @return True if the robot is currently operating in Tele-Op mode.
135   */
136  public boolean isOperatorControl() {
137    return m_ds.isOperatorControl();
138  }
139
140  /**
141   * Indicates if new data is available from the driver station.
142   *
143   * @return Has new data arrived over the network since the last time this function was called?
144   */
145  public boolean isNewDataAvailable() {
146    return m_ds.isNewControlData();
147  }
148
149  /**
150   * Provide an alternate "main loop" via startCompetition().
151   */
152  public abstract void startCompetition();
153
154  @SuppressWarnings("JavadocMethod")
155  public static boolean getBooleanProperty(String name, boolean defaultValue) {
156    String propVal = System.getProperty(name);
157    if (propVal == null) {
158      return defaultValue;
159    }
160    if (propVal.equalsIgnoreCase("false")) {
161      return false;
162    } else if (propVal.equalsIgnoreCase("true")) {
163      return true;
164    } else {
165      throw new IllegalStateException(propVal);
166    }
167  }
168
169  /**
170   * Common initialization for all robot programs.
171   */
172  public static void initializeHardwareConfiguration() {
173    if (!HAL.initialize(500, 0)) {
174      throw new IllegalStateException("Failed to initialize. Terminating");
175    }
176
177    // Set some implementations so that the static methods work properly
178    Timer.SetImplementation(new HardwareTimer());
179    HLUsageReporting.SetImplementation(new HardwareHLUsageReporting());
180    RobotState.SetImplementation(DriverStation.getInstance());
181
182    // Call a CameraServer JNI function to force OpenCV native library loading
183    // Needed because all the OpenCV JNI functions don't have built in loading
184    CameraServerJNI.enumerateSinks();
185  }
186
187  /**
188   * Starting point for the applications.
189   */
190  @SuppressWarnings("PMD.UnusedFormalParameter")
191  public static void main(String... args) {
192    initializeHardwareConfiguration();
193
194    HAL.report(tResourceType.kResourceType_Language, tInstances.kLanguage_Java);
195
196    String robotName = "";
197    Enumeration<URL> resources = null;
198    try {
199      resources = RobotBase.class.getClassLoader().getResources("META-INF/MANIFEST.MF");
200    } catch (IOException ex) {
201      ex.printStackTrace();
202    }
203    while (resources != null && resources.hasMoreElements()) {
204      try {
205        Manifest manifest = new Manifest(resources.nextElement().openStream());
206        robotName = manifest.getMainAttributes().getValue("Robot-Class");
207      } catch (IOException ex) {
208        ex.printStackTrace();
209      }
210    }
211
212    System.out.println("********** Robot program starting **********");
213
214    RobotBase robot;
215    try {
216      robot = (RobotBase) Class.forName(robotName).newInstance();
217    } catch (Throwable throwable) {
218      Throwable cause = throwable.getCause();
219      if (cause != null) {
220        throwable = cause;
221      }
222      DriverStation.reportError("Unhandled exception instantiating robot " + robotName + " "
223          + throwable.toString(), throwable.getStackTrace());
224      DriverStation.reportWarning("Robots should not quit, but yours did!", false);
225      DriverStation.reportError("Could not instantiate robot " + robotName + "!", false);
226      System.exit(1);
227      return;
228    }
229
230    try {
231      final File file = new File("/tmp/frc_versions/FRC_Lib_Version.ini");
232
233      if (file.exists()) {
234        file.delete();
235      }
236
237      file.createNewFile();
238
239      try (FileOutputStream output = new FileOutputStream(file)) {
240        output.write("Java ".getBytes());
241        output.write(WPILibVersion.Version.getBytes());
242      }
243
244    } catch (IOException ex) {
245      ex.printStackTrace();
246    }
247
248    boolean errorOnExit = false;
249    try {
250      robot.startCompetition();
251    } catch (Throwable throwable) {
252      Throwable cause = throwable.getCause();
253      if (cause != null) {
254        throwable = cause;
255      }
256      DriverStation.reportError("Unhandled exception: " + throwable.toString(),
257          throwable.getStackTrace());
258      errorOnExit = true;
259    } finally {
260      // startCompetition never returns unless exception occurs....
261      DriverStation.reportWarning("Robots should not quit, but yours did!", false);
262      if (errorOnExit) {
263        DriverStation.reportError(
264            "The startCompetition() method (or methods called by it) should have "
265                + "handled the exception above.", false);
266      } else {
267        DriverStation.reportError("Unexpected return from startCompetition() method.", false);
268      }
269    }
270    System.exit(1);
271  }
272}