Fix main function initialization (#1176)

I don't have a good way to ensure this always works, so this is going to be a documentation issue.
But initializeHardwareConfiguration is now reentrant, so we can just have all tests call it.
This commit is contained in:
Thad House
2018-07-08 15:41:31 -07:00
committed by Peter Johnson
parent f5b1028b5a
commit 89d15f061b
27 changed files with 86 additions and 729 deletions

View File

@@ -28,7 +28,7 @@ import edu.wpi.first.wpilibj.hal.PowerJNI;
@SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.ExcessiveClassLength",
"PMD.ExcessivePublicCount", "PMD.GodClass", "PMD.TooManyFields",
"PMD.TooManyMethods"})
public class DriverStation implements RobotState.Interface {
public class DriverStation {
/**
* Number of Joystick Ports.
*/
@@ -630,7 +630,6 @@ public class DriverStation implements RobotState.Interface {
*
* @return True if the robot is enabled, false otherwise.
*/
@Override
public boolean isEnabled() {
synchronized (m_controlWordMutex) {
updateControlWord(false);
@@ -643,7 +642,6 @@ public class DriverStation implements RobotState.Interface {
*
* @return True if the robot should be disabled, false otherwise.
*/
@Override
public boolean isDisabled() {
return !isEnabled();
}
@@ -654,7 +652,6 @@ public class DriverStation implements RobotState.Interface {
*
* @return True if autonomous mode should be enabled, false otherwise.
*/
@Override
public boolean isAutonomous() {
synchronized (m_controlWordMutex) {
updateControlWord(false);
@@ -668,7 +665,6 @@ public class DriverStation implements RobotState.Interface {
*
* @return True if operator-controlled mode should be enabled, false otherwise.
*/
@Override
public boolean isOperatorControl() {
return !(isAutonomous() || isTest());
}
@@ -679,7 +675,6 @@ public class DriverStation implements RobotState.Interface {
*
* @return True if test mode should be enabled, false otherwise.
*/
@Override
public boolean isTest() {
synchronized (m_controlWordMutex) {
updateControlWord(false);

View File

@@ -1,73 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj;
import edu.wpi.first.wpilibj.util.BaseSystemNotInitializedException;
/**
* Support for high level usage reporting.
*/
@SuppressWarnings("JavadocMethod")
public final class HLUsageReporting {
private static Interface impl;
@SuppressWarnings("MethodName")
public static void SetImplementation(Interface implementation) {
impl = implementation;
}
public static void reportScheduler() {
if (impl != null) {
impl.reportScheduler();
} else {
throw new BaseSystemNotInitializedException(Interface.class, HLUsageReporting.class);
}
}
public static void reportPIDController(int num) {
if (impl != null) {
impl.reportPIDController(num);
} else {
throw new BaseSystemNotInitializedException(Interface.class, HLUsageReporting.class);
}
}
public static void reportSmartDashboard() {
if (impl != null) {
impl.reportSmartDashboard();
} else {
throw new BaseSystemNotInitializedException(Interface.class, HLUsageReporting.class);
}
}
public interface Interface {
void reportScheduler();
void reportPIDController(int num);
void reportSmartDashboard();
}
public static class Null implements Interface {
@Override
public void reportScheduler() {
}
@Override
@SuppressWarnings("PMD.UnusedFormalParameter")
public void reportPIDController(int num) {
}
@Override
public void reportSmartDashboard() {
}
}
private HLUsageReporting() {
}
}

View File

@@ -10,6 +10,8 @@ package edu.wpi.first.wpilibj;
import java.util.concurrent.locks.ReentrantLock;
import edu.wpi.first.wpilibj.filters.LinearDigitalFilter;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
import edu.wpi.first.wpilibj.util.BoundaryException;
@@ -176,7 +178,7 @@ public class PIDBase extends SendableBase implements PIDInterface, PIDOutput {
m_pidOutput = output;
instances++;
HLUsageReporting.reportPIDController(instances);
HAL.report(tResourceType.kResourceType_PIDController, instances);
m_tolerance = new NullTolerance();
setName("PIDController", instances);
}

View File

@@ -21,8 +21,6 @@ import edu.wpi.first.wpilibj.hal.FRCNetComm.tInstances;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
import edu.wpi.first.wpilibj.hal.HALUtil;
import edu.wpi.first.wpilibj.internal.HardwareHLUsageReporting;
import edu.wpi.first.wpilibj.internal.HardwareTimer;
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
import edu.wpi.first.wpilibj.util.WPILibVersion;
@@ -84,7 +82,6 @@ public abstract class RobotBase implements AutoCloseable {
* to put this code into it's own task that loads on boot so ensure that it runs.
*/
protected RobotBase() {
initializeHardwareConfiguration();
NetworkTableInstance inst = NetworkTableInstance.getDefault();
setupCameraServerShared();
inst.setNetworkIdentity("Robot");
@@ -198,24 +195,6 @@ public abstract class RobotBase implements AutoCloseable {
}
}
/**
* Common initialization for all robot programs.
*/
public static void initializeHardwareConfiguration() {
if (!HAL.initialize(500, 0)) {
throw new IllegalStateException("Failed to initialize. Terminating");
}
// Set some implementations so that the static methods work properly
Timer.SetImplementation(new HardwareTimer());
HLUsageReporting.SetImplementation(new HardwareHLUsageReporting());
RobotState.SetImplementation(DriverStation.getInstance());
// Call a CameraServer JNI function to force OpenCV native library loading
// Needed because all the OpenCV JNI functions don't have built in loading
CameraServerJNI.enumerateSinks();
}
/**
* Starting point for the applications.
*/
@@ -226,6 +205,10 @@ public abstract class RobotBase implements AutoCloseable {
throw new IllegalStateException("Failed to initialize. Terminating");
}
// Call a CameraServer JNI function to force OpenCV native library loading
// Needed because all the OpenCV JNI functions don't have built in loading
CameraServerJNI.enumerateSinks();
HAL.report(tResourceType.kResourceType_Language, tInstances.kLanguage_Java);
String robotName = "";

View File

@@ -7,67 +7,26 @@
package edu.wpi.first.wpilibj;
import edu.wpi.first.wpilibj.util.BaseSystemNotInitializedException;
@SuppressWarnings("JavadocMethod")
public final class RobotState {
private static Interface m_impl;
@SuppressWarnings("MethodName")
public static void SetImplementation(Interface implementation) {
m_impl = implementation;
}
public static boolean isDisabled() {
if (m_impl != null) {
return m_impl.isDisabled();
} else {
throw new BaseSystemNotInitializedException(Interface.class, RobotState.class);
}
return DriverStation.getInstance().isDisabled();
}
public static boolean isEnabled() {
if (m_impl != null) {
return m_impl.isEnabled();
} else {
throw new BaseSystemNotInitializedException(Interface.class, RobotState.class);
}
return DriverStation.getInstance().isEnabled();
}
public static boolean isOperatorControl() {
if (m_impl != null) {
return m_impl.isOperatorControl();
} else {
throw new BaseSystemNotInitializedException(Interface.class, RobotState.class);
}
return DriverStation.getInstance().isOperatorControl();
}
public static boolean isAutonomous() {
if (m_impl != null) {
return m_impl.isAutonomous();
} else {
throw new BaseSystemNotInitializedException(Interface.class, RobotState.class);
}
return DriverStation.getInstance().isAutonomous();
}
public static boolean isTest() {
if (m_impl != null) {
return m_impl.isTest();
} else {
throw new BaseSystemNotInitializedException(Interface.class, RobotState.class);
}
}
interface Interface {
boolean isDisabled();
boolean isEnabled();
boolean isOperatorControl();
boolean isAutonomous();
boolean isTest();
return DriverStation.getInstance().isTest();
}
private RobotState() {

View File

@@ -7,16 +7,7 @@
package edu.wpi.first.wpilibj;
import edu.wpi.first.wpilibj.util.BaseSystemNotInitializedException;
public class Timer {
private static StaticInterface impl;
@SuppressWarnings("MethodName")
public static void SetImplementation(StaticInterface ti) {
impl = ti;
}
/**
* Return the system clock time in seconds. Return the time from the FPGA hardware clock in
* seconds since the FPGA started.
@@ -25,11 +16,7 @@ public class Timer {
*/
@SuppressWarnings("AbbreviationAsWordInName")
public static double getFPGATimestamp() {
if (impl != null) {
return impl.getFPGATimestamp();
} else {
throw new BaseSystemNotInitializedException(StaticInterface.class, Timer.class);
}
return RobotController.getFPGATime() / 1000000.0;
}
/**
@@ -42,11 +29,7 @@ public class Timer {
* @return Time remaining in current match period (auto or teleop) in seconds
*/
public static double getMatchTime() {
if (impl != null) {
return impl.getMatchTime();
} else {
throw new BaseSystemNotInitializedException(StaticInterface.class, Timer.class);
}
return DriverStation.getInstance().getMatchTime();
}
/**
@@ -58,34 +41,24 @@ public class Timer {
* @param seconds Length of time to pause
*/
public static void delay(final double seconds) {
if (impl != null) {
impl.delay(seconds);
} else {
throw new BaseSystemNotInitializedException(StaticInterface.class, Timer.class);
try {
Thread.sleep((long) (seconds * 1e3));
} catch (final InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
public interface StaticInterface {
@SuppressWarnings("AbbreviationAsWordInName")
double getFPGATimestamp();
double getMatchTime();
void delay(double seconds);
@SuppressWarnings("JavadocMethod")
Interface newTimer();
}
private final Interface m_timer;
private double m_startTime;
private double m_accumulatedTime;
private boolean m_running;
@SuppressWarnings("JavadocMethod")
public Timer() {
if (impl != null) {
m_timer = impl.newTimer();
} else {
throw new BaseSystemNotInitializedException(StaticInterface.class, Timer.class);
}
reset();
}
private double getMsClock() {
return RobotController.getFPGATime() / 1000.0;
}
/**
@@ -95,24 +68,30 @@ public class Timer {
*
* @return Current time value for this timer in seconds
*/
public double get() {
return m_timer.get();
public synchronized double get() {
if (m_running) {
return ((getMsClock() - m_startTime) + m_accumulatedTime) / 1000.0;
} else {
return m_accumulatedTime;
}
}
/**
* Reset the timer by setting the time to 0. Make the timer startTime the current time so new
* requests will be relative now
*/
public void reset() {
m_timer.reset();
public synchronized void reset() {
m_accumulatedTime = 0;
m_startTime = getMsClock();
}
/**
* Start the timer running. Just set the running flag to true indicating that all time requests
* should be relative to the system clock.
*/
public void start() {
m_timer.start();
public synchronized void start() {
m_startTime = getMsClock();
m_running = true;
}
/**
@@ -120,8 +99,10 @@ public class Timer {
* subsequent time requests to be read from the accumulated time rather than looking at the system
* clock.
*/
public void stop() {
m_timer.stop();
public synchronized void stop() {
final double temp = get();
m_accumulatedTime = temp;
m_running = false;
}
/**
@@ -132,48 +113,13 @@ public class Timer {
* @param period The period to check for (in seconds).
* @return If the period has passed.
*/
public boolean hasPeriodPassed(double period) {
return m_timer.hasPeriodPassed(period);
}
public interface Interface {
/**
* Get the current time from the timer. If the clock is running it is derived from the current
* system clock the start time stored in the timer class. If the clock is not running, then
* return the time when it was last stopped.
*
* @return Current time value for this timer in seconds
*/
double get();
/**
* Reset the timer by setting the time to 0. Make the timer startTime the current time so new
* requests will be relative now
*/
void reset();
/**
* Start the timer running. Just set the running flag to true indicating that all time requests
* should be relative to the system clock.
*/
void start();
/**
* Stop the timer. This computes the time as of now and clears the running flag, causing all
* subsequent time requests to be read from the accumulated time rather than looking at the
* system clock.
*/
void stop();
/**
* Check if the period specified has passed and if it has, advance the start time by that
* period. This is useful to decide if it's time to do periodic work without drifting later by
* the time it took to get around to checking.
*
* @param period The period to check for (in seconds).
* @return If the period has passed.
*/
boolean hasPeriodPassed(double period);
public synchronized boolean hasPeriodPassed(double period) {
if (get() > period) {
// Advance the start time by the period.
// Don't set it to the current time... we want to avoid drift.
m_startTime += period * 1000;
return true;
}
return false;
}
}

View File

@@ -12,9 +12,11 @@ import java.util.Hashtable;
import java.util.Vector;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.wpilibj.HLUsageReporting;
import edu.wpi.first.wpilibj.SendableBase;
import edu.wpi.first.wpilibj.buttons.Trigger.ButtonScheduler;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tInstances;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
/**
@@ -92,7 +94,7 @@ public final class Scheduler extends SendableBase {
* Instantiates a {@link Scheduler}.
*/
private Scheduler() {
HLUsageReporting.reportScheduler();
HAL.report(tResourceType.kResourceType_Command, tInstances.kCommand_Scheduler);
setName("Scheduler");
}

View File

@@ -1,30 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.internal;
import edu.wpi.first.wpilibj.HLUsageReporting;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tInstances;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
public class HardwareHLUsageReporting implements HLUsageReporting.Interface {
@Override
public void reportScheduler() {
HAL.report(tResourceType.kResourceType_Command, tInstances.kCommand_Scheduler);
}
@Override
public void reportPIDController(int num) {
HAL.report(tResourceType.kResourceType_PIDController, num);
}
@Override
public void reportSmartDashboard() {
HAL.report(tResourceType.kResourceType_SmartDashboard, 0);
}
}

View File

@@ -1,143 +0,0 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2008-2018 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.wpilibj.internal;
import edu.wpi.first.wpilibj.DriverStation;
import edu.wpi.first.wpilibj.RobotController;
import edu.wpi.first.wpilibj.Timer;
/**
* Timer objects measure accumulated time in milliseconds. The timer object functions like a
* stopwatch. It can be started, stopped, and cleared. When the timer is running its value counts
* up in milliseconds. When stopped, the timer holds the current value. The implementation simply
* records the time when started and subtracts the current time whenever the value is requested.
*/
public class HardwareTimer implements Timer.StaticInterface {
/**
* Pause the thread for a specified time. Pause the execution of the thread for a specified period
* of time given in seconds. Motors will continue to run at their last assigned values, and
* sensors will continue to update. Only the task containing the wait will pause until the wait
* time is expired.
*
* @param seconds Length of time to pause
*/
@Override
public void delay(final double seconds) {
try {
Thread.sleep((long) (seconds * 1e3));
} catch (final InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
/**
* Return the system clock time in seconds. Return the time from the FPGA hardware clock in
* seconds since the FPGA started.
*
* @return Robot running time in seconds.
*/
@Override
public double getFPGATimestamp() {
return RobotController.getFPGATime() / 1000000.0;
}
@Override
public double getMatchTime() {
return DriverStation.getInstance().getMatchTime();
}
@Override
public Timer.Interface newTimer() {
return new TimerImpl();
}
class TimerImpl implements Timer.Interface {
private double m_startTime;
private double m_accumulatedTime;
private boolean m_running;
/**
* Create a new timer object. Create a new timer object and reset the time to zero. The timer is
* initially not running and must be started.
*/
TimerImpl() {
reset();
}
private double getMsClock() {
return RobotController.getFPGATime() / 1000.0;
}
/**
* Get the current time from the timer. If the clock is running it is derived from the current
* system clock the start time stored in the timer class. If the clock is not running, then
* return the time when it was last stopped.
*
* @return Current time value for this timer in seconds
*/
@Override
public synchronized double get() {
if (m_running) {
return ((getMsClock() - m_startTime) + m_accumulatedTime) / 1000.0;
} else {
return m_accumulatedTime;
}
}
/**
* Reset the timer by setting the time to 0. Make the timer start time the current time so new
* requests will be relative now
*/
@Override
public synchronized void reset() {
m_accumulatedTime = 0;
m_startTime = getMsClock();
}
/**
* Start the timer running. Just set the running flag to true indicating that all time
* requests should be relative to the system clock.
*/
@Override
public synchronized void start() {
m_startTime = getMsClock();
m_running = true;
}
/**
* Stop the timer. This computes the time as of now and clears the running flag, causing all
* subsequent time requests to be read from the accumulated time rather than looking at the
* system clock.
*/
@Override
public synchronized void stop() {
final double temp = get();
m_accumulatedTime = temp;
m_running = false;
}
/**
* Check if the period specified has passed and if it has, advance the start time by that
* period. This is useful to decide if it's time to do periodic work without drifting later by
* the time it took to get around to checking.
*
* @param period The period to check for (in seconds).
* @return If the period has passed.
*/
@Override
public synchronized boolean hasPeriodPassed(double period) {
if (get() > period) {
// Advance the start time by the period.
// Don't set it to the current time... we want to avoid drift.
m_startTime += period * 1000;
return true;
}
return false;
}
}
}

View File

@@ -15,8 +15,10 @@ import java.util.Set;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.networktables.NetworkTableInstance;
import edu.wpi.first.wpilibj.HLUsageReporting;
import edu.wpi.first.wpilibj.NamedSendable;
import edu.wpi.first.wpilibj.Sendable;
import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
import edu.wpi.first.wpilibj.hal.HAL;
/**
* The {@link SmartDashboard} class is the bridge between robot programs and the SmartDashboard on
@@ -50,7 +52,7 @@ public class SmartDashboard {
private static final Map<String, Data> tablesToData = new HashMap<>();
static {
HLUsageReporting.reportSmartDashboard();
HAL.report(tResourceType.kResourceType_SmartDashboard, 0);
}
private SmartDashboard() {