package jaci.openrio.toast.core;
import edu.wpi.first.wpilibj.DriverStation;
import edu.wpi.first.wpilibj.RobotBase;
import jaci.openrio.toast.core.command.CommandBus;
import jaci.openrio.toast.core.loader.RobotLoader;
import jaci.openrio.toast.core.network.SocketManager;
import jaci.openrio.toast.core.script.js.JavaScript;
import jaci.openrio.toast.core.thread.Async;
import jaci.openrio.toast.core.thread.Heartbeat;
import jaci.openrio.toast.core.thread.HeartbeatListener;
import jaci.openrio.toast.lib.FRCHooks;
import jaci.openrio.toast.lib.crash.CrashHandler;
import jaci.openrio.toast.lib.log.Logger;
import jaci.openrio.toast.lib.profiler.Profiler;
import jaci.openrio.toast.lib.profiler.ProfilerSection;
import jaci.openrio.toast.lib.state.LoadPhase;
import java.util.Random;
/**
* The Toast Base Class. This is the base for the Toast API.
*
* @author Jaci
*/
public class Toast extends RobotBase {
private static String[] tastes = new String[] {"Delicious", "Yummy", "Like a buttery heaven", "Needs more salt", "Hot, Hot, HOT!!", "TOTE-aly delicious"};
private static Toast instance;
public Toast() {
super();
instance = this;
}
/**
* Get the instance of Toast. This is the instance that WPILib loads
*/
public static Toast getToast() {
return instance;
}
/**
* Get the {@link edu.wpi.first.wpilibj.DriverStation} instance
*/
public DriverStation station() {
return m_ds;
}
/**
* Get the default logger for the Toast API. This logger uses
* ATTR_DEFAULT, including Date, Time and current Thread.
*/
public static Logger log() {
return ToastBootstrap.toastLogger;
}
/**
* Yum
*/
public static String getRandomTaste() {
return tastes[new Random().nextInt(tastes.length)];
}
protected void prestart() {
try {
ProfilerSection section = Profiler.INSTANCE.section("Setup");
section.stop("WPILib");
// -------- NEW PHASE -------- //
LoadPhase.PRE_START.transition();
log().info("Buttering Bread...");
RobotLoader.init(Profiler.INSTANCE.section("RobotLoader"));
JavaScript.loaderInit();
section.start("CommandBus");
CommandBus.init();
section.stop("CommandBus");
RobotLoader.prestart(Profiler.INSTANCE.section("RobotLoader"));
FRCHooks.robotReady();
} catch (Exception e) {
CrashHandler.handle(e);
}
}
/**
* The robot is setup and ready to go. Let's rock.
*/
@Override
public void startCompetition() {
prestart();
try {
// -------- NEW PHASE -------- //
LoadPhase.START.transition();
ProfilerSection section = Profiler.INSTANCE.section("Setup");
log().info("Fabricating Sandwich...");
log().info("Verdict: " + getRandomTaste());
RobotLoader.start(Profiler.INSTANCE.section("RobotLoader"));
section.start("Delegate");
SocketManager.launch();
section.stop("Delegate");
if (ToastConfiguration.Property.OPTIMIZATION_GC.asBoolean()) {
registerGC(ToastConfiguration.Property.OPTIMIZATION_GC_TIME.asDouble());
}
LoadPhase.COMPLETE.transition();
ToastBootstrap.endTimeMS = System.currentTimeMillis();
log().info("Total Initiation Time: " + (double)(ToastBootstrap.endTimeMS - ToastBootstrap.startTimeMS) / 1000D + " seconds");
Profiler.INSTANCE.export();
StateTracker.init(this);
} catch (Exception e) {
CrashHandler.handle(e);
}
}
/**
* Register the Garbage Collector to trigger on a regular basis.
*/
void registerGC(final double time) {
Heartbeat.add(new HeartbeatListener() {
int count = 0;
@Override
public void onHeartbeat(int skipped) {
count++;
if (count >= 10 * time) {
System.gc();
count = 0;
}
}
});
}
/**
* Shutdown the robot safely with exit code 0. This will stop all motors and
* ensure all actions on the ThreadPool are completed
*/
public void shutdownSafely() {
log().info("Robot Shutting Down...");
Async.INSTANCE.finish();
shutdownCommon();
System.exit(0);
}
/**
* Shutdown the robot when the exit code should not be 0. This is usually when
* the robot has crashed or encountered and error. This will forcefully stop the ThreadPool,
* all motors and yield the exit code -1
*/
public void shutdownCrash() {
log().info("Robot Error Detected... Shutting Down...");
Async.INSTANCE.shutdownNow();
shutdownCommon();
System.exit(-1);
}
/**
* A common method called by both shutdownSafely() and shutdownCrash()
*/
public void shutdownCommon() { }
}