/*
* Copyright 2013-2015 Cel Skeggs
*
* This file is part of the CCRE, the Common Chicken Runtime Engine.
*
* The CCRE is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* The CCRE is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the CCRE. If not, see <http://www.gnu.org/licenses/>.
*/
package ccre.tuning;
import ccre.channel.BooleanCell;
import ccre.channel.EventOutput;
import ccre.channel.FloatCell;
import ccre.cluck.Cluck;
import ccre.cluck.CluckNode;
import ccre.cluck.CluckPublisher;
import ccre.log.Logger;
import ccre.storage.Storage;
import ccre.storage.StorageSegment;
import ccre.util.UniqueIds;
import ccre.verifier.SetupPhase;
import ccre.verifier.SuppressPhaseWarnings;
/**
* A TuningContext represents a context in which variables can be saved and
* published to the network.
*
* @author skeggsc
*/
public final class TuningContext {
/**
* The node to publish the values to.
*/
private final CluckNode node;
/**
* The segment to store the values in.
*/
private final StorageSegment segment;
/**
* Create a new TuningContext from a specified CluckNode and name of storage
* (used to find the StorageSegment)
*
* @param node the CluckNode to share values over.
* @param storageName the storage name to save values to.
*/
public TuningContext(CluckNode node, String storageName) {
this(node, Storage.openStorage(storageName));
}
/**
* Create a new TuningContext from a specified CluckNode and a specified
* StorageSegment.
*
* @param enc the CluckNode to share values over.
* @param seg the segment to save values to.
*/
public TuningContext(CluckNode enc, StorageSegment seg) {
this.node = enc;
this.segment = seg;
}
/**
* Create a new TuningContext from the global CluckNode and name of storage
* (used to find the StorageSegment)
*
* @param storageName the storage name to save values to.
*/
public TuningContext(String storageName) {
this(Cluck.getNode(), Storage.openStorage(storageName));
}
/**
* Create a new TuningContext from the global CluckNode and a specified
* StorageSegment.
*
* @param seg the segment to save values to.
*/
public TuningContext(StorageSegment seg) {
this(Cluck.getNode(), seg);
}
/**
* Get the attached Cluck node.
*
* @return the CluckNode behind this TuningContext.
*/
public CluckNode getNode() {
return node;
}
/**
* Get the attached storage segment.
*
* @return the storage segment behind this TuningContext.
*/
public StorageSegment getSegment() {
return segment;
}
/**
* Get a FloatCell with the specified name and default value. This will be
* tunable over the network and saved on the roboRIO once flush() is called.
*
* @param name the name of the tunable value.
* @param default_ the default value.
* @return the FloatCell representing the current value.
*/
@SetupPhase
public FloatCell getFloat(String name, float default_) {
FloatCell out = new FloatCell(default_);
segment.attachFloatHolder(name, out);
CluckPublisher.publish(node, name, out);
return out;
}
/**
* Get a BooleanCell with the specified name and default value. This will be
* tunable over the network and saved on the roboRIO once flush() is called.
*
* @param name the name of the tunable value.
* @param default_ the default value.
* @return the BooleanCell representing the current value.
*/
@SetupPhase
public BooleanCell getBoolean(String name, boolean default_) {
BooleanCell out = new BooleanCell(default_);
segment.attachBooleanHolder(name, out);
CluckPublisher.publish(node, name, out);
return out;
}
/**
* Flush the StorageSegment - save the current value.
*/
@SetupPhase
public void flush() {
segment.flush();
Logger.info("Flushed storage segment " + segment.getName());
}
/**
* Get an event that flushes this object.
*
* @return the EventOutput that will flush this object.
* @see #flush()
*/
@SetupPhase
public EventOutput getFlushEvent() {
return new EventOutput() {
@Override
@SuppressPhaseWarnings // TODO: rather than ignoring this issue,
// have a worker thread take care of it.
public void event() {
flush();
}
};
}
/**
* Publish an EventOutput that can be used to save the tuning variables on
* this context.
*
* @param name The name for the EventOutput to be published under. (Prefixed
* by "Save Tuning for ".)
* @return This TuningContext. Returned for method chaining purposes.
*/
@SetupPhase
public TuningContext publishSavingEvent(String name) {
CluckPublisher.publish(node, "Save Tuning for " + name, getFlushEvent());
return this;
}
/**
* Publish an EventOutput that can be used to save the tuning variables on
* this context. The name will be "Save Tuning for " followed by the name of
* the StorageSegment that this context uses. If no name is available,
* "anonymous-N" will be used instead, where N is an arbitrary number.
*
* @return This TuningContext. Returned for method chaining purposes.
*/
@SetupPhase
public TuningContext publishSavingEvent() {
String name = segment.getName();
return publishSavingEvent(name == null ? UniqueIds.global.nextHexId("anonymous") : name);
}
}