Skip to content
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package org.rocketproplab.marginalstability.flightcomputer;

import java.io.PrintStream;

import org.rocketproplab.marginalstability.flightcomputer.subsystems.Telemetry;

import java.io.PrintStream;

/**
* A class to report errors which are encountered during the operation of the
* flight computer. Errors get logged to a printstream and to the Telemetry
Expand All @@ -13,17 +13,16 @@
* along with a copy of that print stream writing to stderr. That was
* interactive applications can report errors instantly while all errors will be
* recorded.
*
* @author Max Apodaca
*
* @author Max Apodaca
*/
public class ErrorReporter {

private static ErrorReporter instance;

/**
* Instantiate the singleton if not already and return it.
*
*
* @return A singleton of type ErrorReporter
*/
public static ErrorReporter getInstance() {
Expand All @@ -36,7 +35,7 @@ public static ErrorReporter getInstance() {
/**
* Sets the singleton in case you want to output to a particular stream. This
* should be called before any calls to {@link #getInstance()}.
*
*
* @param reporter the new singleton
*/
public static void setInstance(ErrorReporter reporter) {
Expand All @@ -57,7 +56,7 @@ public ErrorReporter() {
/**
* Error reporter that should print to the given print stream and send telemetry
* to the given telemetry.
*
*
* @param stream the stream to print to
* @param telemetry the telemetry object to use to send telemetry.
*/
Expand Down Expand Up @@ -112,7 +111,7 @@ public void reportError(Exception exception, String extraInfo) {
* Reports a given error, exception and extra info. The String gets sent to the
* printstream along with the exception if present. The Errors enum gets
* reported to telemetry. All parameters may be null.
*
*
* @param error What error should be reported to the telemetry, may be null.
* @param exception What exception caused the error, may be null.
* @param extraInfo Additional useful text related to the error, may be null.
Expand All @@ -122,15 +121,15 @@ public void reportError(Errors error, Exception exception, String extraInfo) {
stream.print(extraInfo);
stream.print("\n");
}

if (error != null) {
stream.print(error);
stream.print("\n");
if (telemetry != null) {
telemetry.reportError(error);
}
}

if (exception != null) {
exception.printStackTrace(stream);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,26 @@
public enum Errors {

UNKNOWN_ERROR("Unexpected error occured!"),
TOP_LEVEL_EXCEPTION("Exception in main loop occured"),
TOP_LEVEL_EXCEPTION("Exception in main loop occured"),
IMU_IO_ERROR("Unable to read IMU over SPI"),
MAX14830_IO_ERROR("Unable to access /dev/spix.x via Pi4J"),
LPS22HD_INITIALIZATION_ERROR("Unable to write from i2cDevice IO Exception"),
LPS22HD_PRESSURE_IO_ERROR("Unable to read Pressure from i2cDevice IO Exception");

private String errorMessage;

/**
* Sets the error message in the error
*
* @param errorMessage
*/
Errors(String errorMessage) {
this.errorMessage = errorMessage;
}

@Override
public String toString() {
return this.errorMessage;
}

}
Original file line number Diff line number Diff line change
@@ -1,27 +1,120 @@
package org.rocketproplab.marginalstability.flightcomputer;

import org.rocketproplab.marginalstability.flightcomputer.comm.PacketRouter;
import org.rocketproplab.marginalstability.flightcomputer.comm.PacketSources;
import org.rocketproplab.marginalstability.flightcomputer.comm.SCMPacket;
import org.rocketproplab.marginalstability.flightcomputer.looper.Looper;
import org.rocketproplab.marginalstability.flightcomputer.subsystems.Subsystem;
import org.rocketproplab.marginalstability.flightcomputer.subsystems.Telemetry;
import org.rocketproplab.marginalstability.flightcomputer.subsystems.*;

import java.util.logging.Logger;

public class FlightComputer {
private Telemetry telemetry;
private Time time;
private Looper looper;
private static FlightComputer instance;

/**
* Creates a FlightComputer instance, which can only be created once.
*
* @param args arguments to configure FightComputer settings
* @return new FlightComputer instance
*/
public static FlightComputer create(String[] args) {
if (instance != null) {
throw new RuntimeException("FlightComputer has already been created.");
}
instance = new FlightComputer(args);
return instance;
}

public FlightComputer(Telemetry telemetry, Time time) {
this.telemetry = telemetry;
this.time = time;
this.looper = new Looper(time);
/**
* Convenient method to create a FlightComputer instance without any arguments.
*
* @return new FlightComputer instance
*/
public static FlightComputer create() {
return create(new String[0]);
}

/**
* Time used by all objects created in the FC.
*/
private final Time time;

/**
* Looper used by objects created in the FC, e.g. subsystems.
*/
private final Looper looper;

private PacketRouter packetRouter = new PacketRouter();
private Telemetry telemetry = new Telemetry(Logger.getLogger("Telemetry"), packetRouter);

/**
* Providers to provide singleton objects to higher level management objects.
*/
private SensorProvider sensorProvider;

/**
* Private FlightComputer constructor to avoid multiple initializations.
*
* @param args arguments to configure FlightComputer settings
*/
private FlightComputer(String[] args) {
this.time = new Time();
this.looper = new Looper(this.time);
initWithArgs(args);
}

/**
* Initialize input/output devices and other settings based on arguments.
*
* @param args arguments for configuration
*/
private void initWithArgs(String[] args) {
ParseCmdLine cmd = new ParseCmdLine(args);

// use real/fake sensors
sensorProvider = SensorProvider.create(cmd.useRealSensors);
}

/**
* Allows subsystems to register events and callbacks with the looper.
*
* @param subsystem subsystem to register
*/
public void registerSubsystem(Subsystem subsystem) {
subsystem.prepare(this.looper);
}

public Time getTime() {
return time;
/**
* After all input/output devices and settings are initialized, higher level objects can be created.
* Use objects provided by the providers, and simply inject all objects needed to create any higher level object.
*/
public void initHighLevelObjects() {

// PacketRouter
PacketRouter packetRouter = new PacketRouter();

// Telemetry
Telemetry telemetry = new Telemetry(Logger.getLogger("Telemetry"), packetRouter);

telemetry.logInfo(Info.INIT_SUBSYSTEMS_START);

// ParachuteSubsystem
registerSubsystem(new ParachuteSubsystem(null, null, null, null));

// SensorSubsystem
SensorSubsystem sensorSubsystem = new SensorSubsystem(this.time);
// add sensors
telemetry.logInfo(Info.DONE_CREATING_SENSORS);
registerSubsystem(sensorSubsystem);

// SCMCommandSubsystem
registerSubsystem(new SCMCommandSubsystem()); // TODO: should listen to PacketRouter

// ValveStateSubsystem
packetRouter.addListener(new ValveStateSubsystem(packetRouter), SCMPacket.class,
PacketSources.EngineControllerUnit);

telemetry.logInfo(Info.FINISH_SUBSYSTEM_START);
}

public void tick() {
Expand All @@ -34,4 +127,113 @@ public void tick() {
}
});
}

/**
* Builder class to create FlightComputer objects with more customization.
*/
public static class Builder {
private Telemetry telemetry;
private final FlightComputer fc;

/**
* Creates a new Builder instance, which can be used to customize the FC.
*
* @param args arguments to configure FlightComputer settings.
*/
public Builder(String[] args) {
fc = FlightComputer.create(args);
}

/**
* Convenient method to create a Builder instance without any arguments.
*/
public Builder() {
this(new String[0]);
}

/**
* Set custom telemetry.
*
* @param telemetry customized telemetry
* @return this Builder
*/
public Builder withTelemetry(Telemetry telemetry) {
this.telemetry = telemetry;
return this;
}

/**
* Customizations set programmatically in the Builder will override defaults and arguments.
*
* @return customized FlightComputer
*/
public FlightComputer build() {
if (telemetry != null) fc.telemetry = this.telemetry;
return fc;
}
}

/**
* Defines command line options and possible arguments.
* Also prints help and exits if invalid arguments are detected.
*/
private static class ParseCmdLine {
/**
* CLI argument names and descriptions
*/
private static final String
HELP = "--help",
HELP_DESC = "print help menu",
REAL_SENSORS = "--real-sensors",
REAL_SENSORS_DESC = "use real sensors";

/**
* Real sensor flag
*/
private boolean useRealSensors = false;

/**
* Constructs a new object to parse CLI arguments
*
* @param args arguments to parse
*/
private ParseCmdLine(String[] args) {
parse(args);
}

/**
* Checks arguments against each setting
*
* @param args
*/
private void parse(String[] args) {
// help
if (args.length == 1 && args[0].equals("--help")) {
printHelp();
System.exit(0);
}

// settings
int i = 0;
while (i < args.length) {
String arg = args[i];
if (arg.equals(REAL_SENSORS)) {
useRealSensors = true;
System.out.println(REAL_SENSORS_DESC);
} else {
System.out.println("Invalid argument: " + arg);
printHelp();
System.exit(1);
}
i++;
}
}

private void printHelp() {
System.out.println("Usage:\n"
+ HELP + ": " + HELP_DESC + "\n"
+ REAL_SENSORS + ": " + REAL_SENSORS_DESC
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ public enum Info {
INIT_SUBSYSTEMS_START("Starting Subsystems."),
FINISH_SUBSYSTEM_START("Subsystems started."),
DONE_CREATING_SENSORS("Finished creating sensors.");

private String description;
Info(String description){

Info(String description) {
this.description = description;
}

public String getDescription() {
return this.description;
}
Expand Down
Loading