Skip to content
This repository has been archived by the owner on Jan 13, 2025. It is now read-only.

add support for multiple PID slots in MotorController #49

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 78 additions & 75 deletions src/main/java/com/team766/config/AbstractConfigValue.java
Original file line number Diff line number Diff line change
@@ -1,95 +1,98 @@
package com.team766.config;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import com.team766.library.AbstractObservable;
import com.team766.library.SettableValueProvider;
import com.team766.logging.Category;
import com.team766.logging.Logger;
import com.team766.logging.LoggerExceptionUtils;
import com.team766.logging.Severity;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Optional;

public abstract class AbstractConfigValue<E> implements SettableValueProvider<E> {
protected String m_key;
private E m_cachedValue;
private boolean m_cachedHasValue;
private int m_cachedGeneration = -1;
public abstract class AbstractConfigValue<E> extends AbstractObservable<Optional<E>>
implements SettableValueProvider<E> {
protected String m_key;
private E m_cachedValue;
private boolean m_cachedHasValue;

private static ArrayList<AbstractConfigValue<?>> c_accessedValues = new ArrayList<AbstractConfigValue<?>>();
private static ArrayList<AbstractConfigValue<?>> c_accessedValues =
new ArrayList<AbstractConfigValue<?>>();

static Collection<AbstractConfigValue<?>> accessedValues() {
return Collections.unmodifiableCollection(c_accessedValues);
}
static Collection<AbstractConfigValue<?>> accessedValues() {
return Collections.unmodifiableCollection(c_accessedValues);
}

static void resetStatics() {
c_accessedValues.clear();
}
static void resetStatics() {
c_accessedValues.clear();
}

protected AbstractConfigValue(final String key) {
m_key = key;
c_accessedValues.add(this);
// Querying for this config setting's key will add a placeholder entry
// in the config file if this setting does not already exist there.
ConfigFileReader.instance.getRawValue(m_key);
}
protected AbstractConfigValue(final String key) {
m_key = key;
c_accessedValues.add(this);
// Querying for this config setting's key will add a placeholder entry
// in the config file if this setting does not already exist there.
ConfigFileReader.instance.getRawValue(m_key);
update();
}

private void sync() {
if (ConfigFileReader.instance.getGeneration() != m_cachedGeneration) {
m_cachedGeneration = ConfigFileReader.instance.getGeneration();
var rawValue = ConfigFileReader.instance.getRawValue(m_key);
m_cachedHasValue = rawValue != null;
if (m_cachedHasValue) {
try {
m_cachedValue = parseJsonValue(rawValue);
} catch (Exception ex) {
Logger.get(Category.CONFIGURATION).logRaw(Severity.ERROR,
"Failed to parse " + m_key + " from the config file: "
+ LoggerExceptionUtils.exceptionToString(ex));
m_cachedValue = null;
m_cachedHasValue = false;
}
}
}
}
void update() {
var rawValue = ConfigFileReader.instance.getRawValue(m_key);
m_cachedHasValue = rawValue != null;
if (m_cachedHasValue) {
try {
m_cachedValue = parseJsonValue(rawValue);
} catch (Exception ex) {
Logger.get(Category.CONFIGURATION)
.logRaw(
Severity.ERROR,
"Failed to parse "
+ m_key
+ " from the config file: "
+ LoggerExceptionUtils.exceptionToString(ex));
m_cachedValue = null;
m_cachedHasValue = false;
}
}
notifyObservers(m_cachedHasValue ? Optional.of(m_cachedValue) : Optional.empty());
}

public String getKey() {
return m_key;
}
public String getKey() {
return m_key;
}

@Override
public boolean hasValue() {
sync();
return m_cachedHasValue;
}
@Override
public boolean hasValue() {
return m_cachedHasValue;
}

@Override
public E get() {
sync();
if (!m_cachedHasValue) {
throw new IllegalArgumentException(m_key + " not found in the config file");
}
return m_cachedValue;
}
@Override
public E get() {
if (!m_cachedHasValue) {
throw new IllegalArgumentException(m_key + " not found in the config file");
}
return m_cachedValue;
}

public void set(final E value) {
ConfigFileReader.instance.setValue(m_key, value);
}
public void set(final E value) {
ConfigFileReader.instance.setValue(m_key, value);
}

public void clear() {
ConfigFileReader.instance.setValue(m_key, null);
}
public void clear() {
ConfigFileReader.instance.setValue(m_key, null);
}

protected abstract E parseJsonValue(Object configValue);
protected abstract E parseJsonValue(Object configValue);

@Override
public String toString() {
sync();
if (!m_cachedHasValue) {
return "<unset>";
}
if (m_cachedValue == null) {
return "<null>";
}
return m_cachedValue.toString();
}
}
@Override
public String toString() {
if (!m_cachedHasValue) {
return "<unset>";
}
if (m_cachedValue == null) {
return "<null>";
}
return m_cachedValue.toString();
}
}
30 changes: 20 additions & 10 deletions src/main/java/com/team766/config/ConfigFileReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import java.io.StringReader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.regex.Pattern;
import org.json.JSONObject;
import org.json.JSONTokener;
Expand All @@ -29,10 +30,6 @@ public class ConfigFileReader {

private static final String KEY_DELIMITER = ".";

// This is incremented each time the config file is reloaded to ensure that ConfigValues use the
// most recent setting.
private int m_generation = 0;

private String m_fileName;
private String m_backupFileName; // if set, will also save here
private JSONObject m_values = new JSONObject();
Expand Down Expand Up @@ -81,12 +78,11 @@ public void reloadFromJson(final String jsonString) {
"Could not parse config value for " + param.getKey(), ex);
}
}
// All values parsed successfully; now actually apply the new values.
m_values = newValues;
++m_generation;
}

public int getGeneration() {
return m_generation;
for (AbstractConfigValue<?> param : AbstractConfigValue.accessedValues()) {
param.update();
}
}

public boolean containsKey(final String key) {
Expand Down Expand Up @@ -126,6 +122,13 @@ public <E> void setValue(final String key, final E value) {
String[] keyParts = splitKey(key);
JSONObject parentObj = getParent(m_values, keyParts);
parentObj.putOpt(keyParts[keyParts.length - 1], value == null ? JSONObject.NULL : value);

for (AbstractConfigValue<?> otherValue : AbstractConfigValue.accessedValues()) {
String[] otherValueKeyParts = splitKey(otherValue.getKey());
if (isPrefix(keyParts, otherValueKeyParts) || isPrefix(otherValueKeyParts, keyParts)) {
otherValue.update();
}
}
}

Object getRawValue(final String key) {
Expand All @@ -152,10 +155,17 @@ private static Object getRawValue(final JSONObject obj, final String key) {
return rawValue;
}

private static String[] splitKey(final String key) {
static String[] splitKey(final String key) {
return key.split(Pattern.quote(KEY_DELIMITER));
}

static boolean isPrefix(final String[] a, final String[] b) {
if (a.length > b.length) {
return false;
}
return Arrays.equals(a, 0, a.length, b, 0, a.length);
}

private static JSONObject getParent(JSONObject obj, final String[] keyParts) {
for (int i = 0; i < keyParts.length - 1; ++i) {
JSONObject subObj;
Expand Down
Loading
Loading