Skip to content

[Tutorial 3.3] The Storage Framework

Colby Skeggs edited this page Nov 11, 2015 · 3 revisions

WARNING: THIS DOCUMENTATION IS FOR CCRE v2, NOT CCRE v3!

See the readme on the main page for the correct documentation.

The Storage Framework

[Back to the previous tutorial]([Tutorial 3.2] The Networking Framework)

As the CCRE attempts to run on multiple platforms, and these platforms have different methods of accessing their file systems. As such, it's useful to have a method of saving data that works across these platforms.

Basic I/O with StorageProvider

The CCRE provides most of its storage functionality through the StorageProvider class. This class has two primary methods for raw I/O: openInput(name) and openOutput(name). These are similar to the constructors for FileInputStream and FileOutputStream.

Writing to files

Imagine that we want to write the current autonomous mode to a file on the cRIO.

try {
    Writer output = new OutputStreamWriter(StorageProvider.openOutput("autonomous-mode.txt"));
    try {
        output.write("two-ball-autonomous\n");
    } finally {
        output.close();
    }
} catch (IOException ex) {
    Logger.warning("Could not save autonomous mode!", ex);
}

This should be fairly straightforward if you're familiar with Java's standard I/O. We open a reference to a file, write text, and then close the file. This includes exception handling, so the file will always be closed regardless of whether or not an error occurs while writing. (Don't forget this, especially on the cRIO!) If any exception occurs, this system uses the Logging subsystem to report it.

Reading from files

Let's try reading back the same data from the file again.

String mode = "default-mode";
try {
    BufferedReader reader = new BufferedReader(new InputStreamReader(StorageProvider.openInput("autonomous-mode.txt")));
    try {
        mode = reader.readLine();
    } finally {
        reader.close();
    }
} catch (IOException ex) {
    Logger.warning("Could not load autonomous mode. Defaulting to " + mode + ".", ex);
}

Again, this should be fairly straightforward if you understand reading from files in Java SE. Note that the cRIO has a different BufferedReader class than Java SE (in a different package), so you'll want to do this slightly differently on a real robot.

Of course, this is a lot of code to change an autonomous mode! Is there an easier way?

Storage Segments

The CCRE provides StorageSegments to save data in an easier way. Let's rewrite our previous chunks of code:

StorageSegment segment = StorageProvider.openStorage("autonomous_mode");
StringHolder currentAutonomousMode = new StringStorage("default-mode");
segment.attachStringholder("autonomous-mode", currentAutonomousMode);

You can now modify StringHolder's contents and the new values will be saved when you call the segment.flush() method.

StorageSegments are also behind TuningContexts as covered earlier. Getting a FloatStatus from a TuningContext is literally:

FloatStatus out = new FloatStatus(default_); // Get a new FloatStatus
segment.attachFloatHolder(name, out); // Attach it to the StorageSegment
CluckPublisher.publish(enc, name, out); // Publish it on the network
return out;

You can, of course, use StorageSegment directly if that's what floats your water-going vessel.

One of the key features of these methods is that they keep track of the "default" of the holder or status - so if the default changes, it overrides the saved value. This lets you update the values either via setting them in code or by changing the defaults.

Note that the only valid symbols in a StorageSegment name are abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$ - spaces, for example, are disallowed. This is for maximum platform compatibility.

Low-level access to StorageSegments

If you want to use a StorageSegment at a lower level than this, you can use getStringForKey(key) and setStringForKey(key) directly to read and write values directly:

String autonomousMode = segment.getStringForKey("autonomous-mode");
if (autonomousMode == null) { autonomousMode = "default-mode"; }
// ... later ...
segment.setStringForKey("autonomous-mode", newAutonomousMode);

These are saved as raw key/value pairs in the written file.

Next: another tutorial coming at some point in the future!