[ntcore] NetworkTables 4 (#3217)

This commit is contained in:
Peter Johnson
2022-10-08 10:01:31 -07:00
committed by GitHub
parent 90cfa00115
commit 77301b126c
380 changed files with 34573 additions and 22095 deletions

View File

@@ -0,0 +1,15 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.networktables;
/**
* NetworkTables {{ TypeName }} entry.
*
* <p>Unlike NetworkTableEntry, the entry goes away when close() is called.
*/
public interface {{ TypeName }}Entry extends {{ TypeName }}Subscriber, {{ TypeName }}Publisher {
/** Stops publishing the entry if it's published. */
void unpublish();
}

View File

@@ -0,0 +1,75 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.networktables;
/** NetworkTables {{ TypeName }} implementation. */
@SuppressWarnings("PMD.ArrayIsStoredDirectly")
final class {{ TypeName }}EntryImpl extends EntryBase implements {{ TypeName }}Entry {
/**
* Constructor.
*
* @param topic Topic
* @param handle Native handle
* @param defaultValue Default value for get()
*/
{{ TypeName }}EntryImpl({{ TypeName }}Topic topic, int handle, {{ java.ValueType }} defaultValue) {
super(handle);
m_topic = topic;
m_defaultValue = defaultValue;
}
@Override
public {{ TypeName }}Topic getTopic() {
return m_topic;
}
@Override
public {{ java.ValueType }} get() {
return NetworkTablesJNI.get{{ TypeName }}(m_handle, m_defaultValue);
}
@Override
public {{ java.ValueType }} get({{ java.ValueType }} defaultValue) {
return NetworkTablesJNI.get{{TypeName}}(m_handle, defaultValue);
}
@Override
public Timestamped{{ TypeName }} getAtomic() {
return NetworkTablesJNI.getAtomic{{ TypeName }}(m_handle, m_defaultValue);
}
@Override
public Timestamped{{ TypeName }} getAtomic({{ java.ValueType }} defaultValue) {
return NetworkTablesJNI.getAtomic{{ TypeName }}(m_handle, defaultValue);
}
@Override
public Timestamped{{ TypeName }}[] readQueue() {
return NetworkTablesJNI.readQueue{{ TypeName }}(m_handle);
}
@Override
public {{ java.ValueType }}[] readQueueValues() {
return NetworkTablesJNI.readQueueValues{{ TypeName }}(m_handle);
}
@Override
public void set({{ java.ValueType }} value, long time) {
NetworkTablesJNI.set{{ TypeName }}(m_handle, time, value);
}
@Override
public void setDefault({{ java.ValueType }} value) {
NetworkTablesJNI.setDefault{{ TypeName }}(m_handle, 0, value);
}
@Override
public void unpublish() {
NetworkTablesJNI.unpublish(m_handle);
}
private final {{ TypeName }}Topic m_topic;
private final {{ java.ValueType }} m_defaultValue;
}

View File

@@ -0,0 +1,317 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.networktables;
/** NetworkTables generic implementation. */
final class GenericEntryImpl extends EntryBase implements GenericEntry {
/**
* Constructor.
*
* @param topic Topic
* @param handle Native handle
*/
GenericEntryImpl(Topic topic, int handle) {
super(handle);
m_topic = topic;
}
@Override
public Topic getTopic() {
return m_topic;
}
@Override
public NetworkTableValue get() {
return NetworkTablesJNI.getValue(m_handle);
}
{% for t in types %}
/**
* Gets the entry's value as a {{ t.java.ValueType }}. If the entry does not exist or is of different type, it
* will return the default value.
*
* @param defaultValue the value to be returned if no value is found
* @return the entry's value or the given default value
*/
@Override
public {{ t.java.ValueType }} get{{ t.TypeName }}({{ t.java.ValueType }} defaultValue) {
return NetworkTablesJNI.get{{ t.TypeName }}(m_handle, defaultValue);
}
{% if t.java.WrapValueType %}
/**
* Gets the entry's value as a boolean array. If the entry does not exist or is of different type,
* it will return the default value.
*
* @param defaultValue the value to be returned if no value is found
* @return the entry's value or the given default value
*/
@Override
public {{ t.java.WrapValueType }} get{{ t.TypeName }}({{ t.java.WrapValueType }} defaultValue) {
return NetworkTableValue.fromNative{{ t.TypeName }}(
get{{ t.TypeName }}(NetworkTableValue.toNative{{ t.TypeName }}(defaultValue)));
}
{% endif -%}
{% endfor %}
@Override
public NetworkTableValue[] readQueue() {
return NetworkTablesJNI.readQueueValue(m_handle);
}
@Override
public boolean set(NetworkTableValue value) {
long time = value.getTime();
Object otherValue = value.getValue();
switch (value.getType()) {
case kBoolean:
return NetworkTablesJNI.setBoolean(m_handle, time, (Boolean) otherValue);
case kInteger:
return NetworkTablesJNI.setInteger(
m_handle, time, ((Number) otherValue).longValue());
case kFloat:
return NetworkTablesJNI.setFloat(
m_handle, time, ((Number) otherValue).floatValue());
case kDouble:
return NetworkTablesJNI.setDouble(
m_handle, time, ((Number) otherValue).doubleValue());
case kString:
return NetworkTablesJNI.setString(m_handle, time, (String) otherValue);
case kRaw:
return NetworkTablesJNI.setRaw(m_handle, time, (byte[]) otherValue);
case kBooleanArray:
return NetworkTablesJNI.setBooleanArray(m_handle, time, (boolean[]) otherValue);
case kIntegerArray:
return NetworkTablesJNI.setIntegerArray(m_handle, time, (long[]) otherValue);
case kFloatArray:
return NetworkTablesJNI.setFloatArray(m_handle, time, (float[]) otherValue);
case kDoubleArray:
return NetworkTablesJNI.setDoubleArray(m_handle, time, (double[]) otherValue);
case kStringArray:
return NetworkTablesJNI.setStringArray(m_handle, time, (String[]) otherValue);
default:
return true;
}
}
/**
* Sets the entry's value.
*
* @param value the value that will be assigned
* @return False if the table key already exists with a different type
* @throws IllegalArgumentException if the value is not a known type
*/
@Override
public boolean setValue(Object value, long time) {
if (value instanceof NetworkTableValue) {
return set((NetworkTableValue) value);
} else if (value instanceof Boolean) {
return setBoolean((Boolean) value, time);
} else if (value instanceof Long) {
return setInteger((Long) value, time);
} else if (value instanceof Float) {
return setFloat((Float) value, time);
} else if (value instanceof Number) {
return setNumber((Number) value, time);
} else if (value instanceof String) {
return setString((String) value, time);
} else if (value instanceof byte[]) {
return setRaw((byte[]) value, time);
} else if (value instanceof boolean[]) {
return setBooleanArray((boolean[]) value, time);
} else if (value instanceof long[]) {
return setIntegerArray((long[]) value, time);
} else if (value instanceof float[]) {
return setFloatArray((float[]) value, time);
} else if (value instanceof double[]) {
return setDoubleArray((double[]) value, time);
} else if (value instanceof Boolean[]) {
return setBooleanArray((Boolean[]) value, time);
} else if (value instanceof Long[]) {
return setIntegerArray((Long[]) value, time);
} else if (value instanceof Float[]) {
return setFloatArray((Float[]) value, time);
} else if (value instanceof Number[]) {
return setNumberArray((Number[]) value, time);
} else if (value instanceof String[]) {
return setStringArray((String[]) value, time);
} else {
throw new IllegalArgumentException(
"Value of type " + value.getClass().getName() + " cannot be put into a table");
}
}
{% for t in types %}
/**
* Sets the entry's value.
*
* @param value the value to set
* @return False if the entry exists with a different type
*/
@Override
public boolean set{{ t.TypeName }}({{ t.java.ValueType }} value, long time) {
return NetworkTablesJNI.set{{ t.TypeName }}(m_handle, time, value);
}
{% if t.java.WrapValueType %}
/**
* Sets the entry's value.
*
* @param value the value to set
* @return False if the entry exists with a different type
*/
@Override
public boolean set{{ t.TypeName }}({{ t.java.WrapValueType }} value, long time) {
return set{{ t.TypeName }}(NetworkTableValue.toNative{{ t.TypeName }}(value), time);
}
{% endif -%}
{% endfor %}
/**
* Sets the entry's value.
*
* @param value the value to set
* @return False if the entry exists with a different type
*/
public boolean setNumber(Number value, long time) {
return setDouble(value.doubleValue(), time);
}
/**
* Sets the entry's value.
*
* @param value the value to set
* @return False if the entry exists with a different type
*/
public boolean setNumberArray(Number[] value, long time) {
return setDoubleArray(NetworkTableValue.toNativeDoubleArray(value), time);
}
@Override
public boolean setDefault(NetworkTableValue defaultValue) {
long time = defaultValue.getTime();
Object otherValue = defaultValue.getValue();
switch (defaultValue.getType()) {
case kBoolean:
return NetworkTablesJNI.setDefaultBoolean(m_handle, time, (Boolean) otherValue);
case kInteger:
return NetworkTablesJNI.setDefaultInteger(
m_handle, time, ((Number) otherValue).longValue());
case kFloat:
return NetworkTablesJNI.setDefaultFloat(
m_handle, time, ((Number) otherValue).floatValue());
case kDouble:
return NetworkTablesJNI.setDefaultDouble(
m_handle, time, ((Number) otherValue).doubleValue());
case kString:
return NetworkTablesJNI.setDefaultString(m_handle, time, (String) otherValue);
case kRaw:
return NetworkTablesJNI.setDefaultRaw(m_handle, time, (byte[]) otherValue);
case kBooleanArray:
return NetworkTablesJNI.setDefaultBooleanArray(m_handle, time, (boolean[]) otherValue);
case kIntegerArray:
return NetworkTablesJNI.setDefaultIntegerArray(m_handle, time, (long[]) otherValue);
case kFloatArray:
return NetworkTablesJNI.setDefaultFloatArray(m_handle, time, (float[]) otherValue);
case kDoubleArray:
return NetworkTablesJNI.setDefaultDoubleArray(m_handle, time, (double[]) otherValue);
case kStringArray:
return NetworkTablesJNI.setDefaultStringArray(m_handle, time, (String[]) otherValue);
default:
return true;
}
}
/**
* Sets the entry's value if it does not exist.
*
* @param defaultValue the default value to set
* @return False if the entry exists with a different type
* @throws IllegalArgumentException if the value is not a known type
*/
@Override
public boolean setDefaultValue(Object defaultValue) {
if (defaultValue instanceof NetworkTableValue) {
return setDefault((NetworkTableValue) defaultValue);
} else if (defaultValue instanceof Boolean) {
return setDefaultBoolean((Boolean) defaultValue);
} else if (defaultValue instanceof Integer) {
return setDefaultInteger((Integer) defaultValue);
} else if (defaultValue instanceof Float) {
return setDefaultFloat((Float) defaultValue);
} else if (defaultValue instanceof Number) {
return setDefaultNumber((Number) defaultValue);
} else if (defaultValue instanceof String) {
return setDefaultString((String) defaultValue);
} else if (defaultValue instanceof byte[]) {
return setDefaultRaw((byte[]) defaultValue);
} else if (defaultValue instanceof boolean[]) {
return setDefaultBooleanArray((boolean[]) defaultValue);
} else if (defaultValue instanceof long[]) {
return setDefaultIntegerArray((long[]) defaultValue);
} else if (defaultValue instanceof float[]) {
return setDefaultFloatArray((float[]) defaultValue);
} else if (defaultValue instanceof double[]) {
return setDefaultDoubleArray((double[]) defaultValue);
} else if (defaultValue instanceof Boolean[]) {
return setDefaultBooleanArray((Boolean[]) defaultValue);
} else if (defaultValue instanceof Long[]) {
return setDefaultIntegerArray((Long[]) defaultValue);
} else if (defaultValue instanceof Float[]) {
return setDefaultFloatArray((Float[]) defaultValue);
} else if (defaultValue instanceof Number[]) {
return setDefaultNumberArray((Number[]) defaultValue);
} else if (defaultValue instanceof String[]) {
return setDefaultStringArray((String[]) defaultValue);
} else {
throw new IllegalArgumentException(
"Value of type " + defaultValue.getClass().getName() + " cannot be put into a table");
}
}
{% for t in types %}
/**
* Sets the entry's value if it does not exist.
*
* @param defaultValue the default value to set
* @return False if the entry exists with a different type
*/
@Override
public boolean setDefault{{ t.TypeName }}({{ t.java.ValueType }} defaultValue) {
return NetworkTablesJNI.setDefault{{ t.TypeName }}(m_handle, 0, defaultValue);
}
{% if t.java.WrapValueType %}
/**
* Sets the entry's value if it does not exist.
*
* @param defaultValue the default value to set
* @return False if the entry exists with a different type
*/
@Override
public boolean setDefault{{ t.TypeName }}({{ t.java.WrapValueType }} defaultValue) {
return setDefault{{ t.TypeName }}(NetworkTableValue.toNative{{ t.TypeName }}(defaultValue));
}
{% endif -%}
{% endfor %}
/**
* Sets the entry's value if it does not exist.
*
* @param defaultValue the default value to set
* @return False if the entry exists with a different type
*/
public boolean setDefaultNumber(Number defaultValue) {
return setDefaultDouble(defaultValue.doubleValue());
}
/**
* Sets the entry's value if it does not exist.
*
* @param defaultValue the default value to set
* @return False if the entry exists with a different type
*/
public boolean setDefaultNumberArray(Number[] defaultValue) {
return setDefaultDoubleArray(NetworkTableValue.toNativeDoubleArray(defaultValue));
}
@Override
public void unpublish() {
NetworkTablesJNI.unpublish(m_handle);
}
private final Topic m_topic;
}

View File

@@ -0,0 +1,119 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.networktables;
import java.util.function.Consumer;
/** NetworkTables generic publisher. */
public interface GenericPublisher extends Publisher, Consumer<NetworkTableValue> {
/**
* Get the corresponding topic.
*
* @return Topic
*/
@Override
Topic getTopic();
/**
* Publish a new value.
*
* @param value value to publish
* @return False if the topic already exists with a different type
*/
boolean set(NetworkTableValue value);
/**
* Publish a new value.
*
* @param value value to publish
* @return False if the topic already exists with a different type
* @throws IllegalArgumentException if the value is not a known type
*/
default boolean setValue(Object value) {
return setValue(value, 0);
}
/**
* Publish a new value.
*
* @param value value to publish
* @param time timestamp; 0 indicates current NT time should be used
* @return False if the topic already exists with a different type
* @throws IllegalArgumentException if the value is not a known type
*/
boolean setValue(Object value, long time);
{% for t in types %}
/**
* Publish a new value.
*
* @param value value to publish
* @return False if the topic already exists with a different type
*/
default boolean set{{ t.TypeName }}({{ t.java.ValueType }} value) {
return set{{ t.TypeName }}(value, 0);
}
/**
* Publish a new value.
*
* @param value value to publish
* @param time timestamp; 0 indicates current NT time should be used
* @return False if the topic already exists with a different type
*/
boolean set{{ t.TypeName }}({{ t.java.ValueType }} value, long time);
{% if t.java.WrapValueType %}
/**
* Publish a new value.
*
* @param value value to publish
* @return False if the topic already exists with a different type
*/
default boolean set{{ t.TypeName }}({{ t.java.WrapValueType }} value) {
return set{{ t.TypeName }}(value, 0);
}
/**
* Publish a new value.
*
* @param value value to publish
* @param time timestamp; 0 indicates current NT time should be used
* @return False if the topic already exists with a different type
*/
boolean set{{ t.TypeName }}({{ t.java.WrapValueType }} value, long time);
{% endif -%}
{% endfor %}
/**
* Sets the entry's value if it does not exist.
*
* @param defaultValue the default value to set
* @return False if the entry exists with a different type
*/
boolean setDefault(NetworkTableValue defaultValue);
/**
* Sets the entry's value if it does not exist.
*
* @param defaultValue the default value to set
* @return False if the entry exists with a different type
* @throws IllegalArgumentException if the value is not a known type
*/
boolean setDefaultValue(Object defaultValue);
{% for t in types %}
/**
* Sets the entry's value if it does not exist.
*
* @param defaultValue the default value to set
* @return False if the entry exists with a different type
*/
boolean setDefault{{ t.TypeName }}({{ t.java.ValueType }} defaultValue);
{% if t.java.WrapValueType %}
boolean setDefault{{ t.TypeName }}({{ t.java.WrapValueType }} defaultValue);
{% endif -%}
{% endfor %}
@Override
default void accept(NetworkTableValue value) {
set(value);
}
}

View File

@@ -0,0 +1,58 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.networktables;
import java.util.function.Supplier;
/** NetworkTables generic subscriber. */
@SuppressWarnings("PMD.MissingOverride")
public interface GenericSubscriber extends Subscriber, Supplier<NetworkTableValue> {
/**
* Get the corresponding topic.
*
* @return Topic
*/
@Override
Topic getTopic();
/**
* Get the last published value.
* If no value has been published, returns a value with type NetworkTableType.kUnassigned.
*
* @return value
*/
NetworkTableValue get();
{% for t in types %}
/**
* Gets the entry's value as a {{ t.java.ValueType }}. If the entry does not exist or is of different type, it
* will return the default value.
*
* @param defaultValue the value to be returned if no value is found
* @return the entry's value or the given default value
*/
{{ t.java.ValueType }} get{{ t.TypeName }}({{ t.java.ValueType }} defaultValue);
{% if t.java.WrapValueType %}
/**
* Gets the entry's value as a boolean array. If the entry does not exist or is of different type,
* it will return the default value.
*
* @param defaultValue the value to be returned if no value is found
* @return the entry's value or the given default value
*/
{{ t.java.WrapValueType }} get{{ t.TypeName }}({{ t.java.WrapValueType }} defaultValue);
{% endif -%}
{% endfor %}
/**
* Get an array of all value changes since the last call to readQueue.
* Also provides a timestamp for each value.
*
* <p>The "poll storage" subscribe option can be used to set the queue
* depth.
*
* @return Array of timestamped values; empty array if no new changes have
* been published since the previous call.
*/
NetworkTableValue[] readQueue();
}

View File

@@ -0,0 +1,537 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.networktables;
/**
* NetworkTables Entry.
*
* <p>For backwards compatibility, the NetworkTableEntry close() does not release the entry.
*/
@SuppressWarnings("UnnecessaryParentheses")
public final class NetworkTableEntry implements Publisher, Subscriber {
/**
* Flag values (as returned by {@link #getFlags()}).
*
* @deprecated Use isPersistent() instead.
*/
@Deprecated(since = "2022", forRemoval = true)
public static final int kPersistent = 0x01;
/**
* Construct from native handle.
*
* @param inst Instance
* @param handle Native handle
*/
public NetworkTableEntry(NetworkTableInstance inst, int handle) {
this(new Topic(inst, NetworkTablesJNI.getTopicFromHandle(handle)), handle);
}
/**
* Construct from native handle.
*
* @param topic Topic
* @param handle Native handle
*/
public NetworkTableEntry(Topic topic, int handle) {
m_topic = topic;
m_handle = handle;
}
@Override
public void close() {}
/**
* Determines if the native handle is valid.
*
* @return True if the native handle is valid, false otherwise.
*/
@Override
public boolean isValid() {
return m_handle != 0;
}
/**
* Gets the native handle for the entry.
*
* @return Native handle
*/
@Override
public int getHandle() {
return m_handle;
}
/**
* Gets the subscribed-to / published-to topic.
*
* @return Topic
*/
@Override
public Topic getTopic() {
return m_topic;
}
/**
* Gets the instance for the entry.
*
* @return Instance
*/
public NetworkTableInstance getInstance() {
return m_topic.getInstance();
}
/**
* Determines if the entry currently exists.
*
* @return True if the entry exists, false otherwise.
*/
@Override
public boolean exists() {
return NetworkTablesJNI.getType(m_handle) != 0;
}
/**
* Gets the name of the entry (the key).
*
* @return the entry's name
*/
public String getName() {
return NetworkTablesJNI.getEntryName(m_handle);
}
/**
* Gets the type of the entry.
*
* @return the entry's type
*/
public NetworkTableType getType() {
return NetworkTableType.getFromInt(NetworkTablesJNI.getType(m_handle));
}
/**
* Returns the flags.
*
* @return the flags (bitmask)
* @deprecated Use isPersistent() or topic properties instead
*/
@Deprecated(since = "2022", forRemoval = true)
public int getFlags() {
return NetworkTablesJNI.getEntryFlags(m_handle);
}
/**
* Gets the last time the entry's value was changed.
*
* @return Entry last change time
*/
@Override
public long getLastChange() {
return NetworkTablesJNI.getEntryLastChange(m_handle);
}
/**
* Gets the entry's value. Returns a value with type NetworkTableType.kUnassigned if the value
* does not exist.
*
* @return the entry's value
*/
public NetworkTableValue getValue() {
return NetworkTablesJNI.getValue(m_handle);
}
{% for t in types %}
/**
* Gets the entry's value as a {{ t.java.ValueType }}. If the entry does not exist or is of different type, it
* will return the default value.
*
* @param defaultValue the value to be returned if no value is found
* @return the entry's value or the given default value
*/
public {{ t.java.ValueType }} get{{ t.TypeName }}({{ t.java.ValueType }} defaultValue) {
return NetworkTablesJNI.get{{ t.TypeName }}(m_handle, defaultValue);
}
{% if t.java.WrapValueType %}
/**
* Gets the entry's value as a boolean array. If the entry does not exist or is of different type,
* it will return the default value.
*
* @param defaultValue the value to be returned if no value is found
* @return the entry's value or the given default value
*/
public {{ t.java.WrapValueType }} get{{ t.TypeName }}({{ t.java.WrapValueType }} defaultValue) {
return NetworkTableValue.fromNative{{ t.TypeName }}(
get{{ t.TypeName }}(NetworkTableValue.toNative{{ t.TypeName }}(defaultValue)));
}
{% endif -%}
{% endfor %}
/**
* Gets the entry's value as a double. If the entry does not exist or is of different type, it
* will return the default value.
*
* @param defaultValue the value to be returned if no value is found
* @return the entry's value or the given default value
*/
public Number getNumber(Number defaultValue) {
return getDouble(defaultValue.doubleValue());
}
/**
* Gets the entry's value as a double array. If the entry does not exist or is of different type,
* it will return the default value.
*
* @param defaultValue the value to be returned if no value is found
* @return the entry's value or the given default value
*/
public Number[] getNumberArray(Number[] defaultValue) {
return NetworkTableValue.fromNativeDoubleArray(
getDoubleArray(NetworkTableValue.toNativeDoubleArray(defaultValue)));
}
/**
* Get an array of all value changes since the last call to readQueue.
*
* <p>The "poll storage" subscribe option can be used to set the queue
* depth.
*
* @return Array of values; empty array if no new changes have been
* published since the previous call.
*/
public NetworkTableValue[] readQueue() {
return NetworkTablesJNI.readQueueValue(m_handle);
}
/**
* Checks if a data value is of a type that can be placed in a NetworkTable entry.
*
* @param data the data to check
* @return true if the data can be placed in an entry, false if it cannot
*/
public static boolean isValidDataType(Object data) {
return data instanceof Number
|| data instanceof Boolean
|| data instanceof String
|| data instanceof long[]
|| data instanceof Long[]
|| data instanceof float[]
|| data instanceof Float[]
|| data instanceof double[]
|| data instanceof Double[]
|| data instanceof Number[]
|| data instanceof boolean[]
|| data instanceof Boolean[]
|| data instanceof String[]
|| data instanceof byte[]
|| data instanceof Byte[];
}
/**
* Sets the entry's value if it does not exist.
*
* @param defaultValue the default value to set
* @return False if the entry exists with a different type
* @throws IllegalArgumentException if the value is not a known type
*/
public boolean setDefaultValue(Object defaultValue) {
if (defaultValue instanceof NetworkTableValue) {
long time = ((NetworkTableValue) defaultValue).getTime();
Object otherValue = ((NetworkTableValue) defaultValue).getValue();
switch (((NetworkTableValue) defaultValue).getType()) {
case kBoolean:
return NetworkTablesJNI.setDefaultBoolean(m_handle, time, (Boolean) otherValue);
case kInteger:
return NetworkTablesJNI.setDefaultInteger(
m_handle, time, ((Number) otherValue).longValue());
case kFloat:
return NetworkTablesJNI.setDefaultFloat(
m_handle, time, ((Number) otherValue).floatValue());
case kDouble:
return NetworkTablesJNI.setDefaultDouble(
m_handle, time, ((Number) otherValue).doubleValue());
case kString:
return NetworkTablesJNI.setDefaultString(m_handle, time, (String) otherValue);
case kRaw:
return NetworkTablesJNI.setDefaultRaw(m_handle, time, (byte[]) otherValue);
case kBooleanArray:
return NetworkTablesJNI.setDefaultBooleanArray(m_handle, time, (boolean[]) otherValue);
case kIntegerArray:
return NetworkTablesJNI.setDefaultIntegerArray(m_handle, time, (long[]) otherValue);
case kFloatArray:
return NetworkTablesJNI.setDefaultFloatArray(m_handle, time, (float[]) otherValue);
case kDoubleArray:
return NetworkTablesJNI.setDefaultDoubleArray(m_handle, time, (double[]) otherValue);
case kStringArray:
return NetworkTablesJNI.setDefaultStringArray(m_handle, time, (String[]) otherValue);
default:
return true;
}
} else if (defaultValue instanceof Boolean) {
return setDefaultBoolean((Boolean) defaultValue);
} else if (defaultValue instanceof Integer) {
return setDefaultInteger((Integer) defaultValue);
} else if (defaultValue instanceof Float) {
return setDefaultFloat((Float) defaultValue);
} else if (defaultValue instanceof Number) {
return setDefaultNumber((Number) defaultValue);
} else if (defaultValue instanceof String) {
return setDefaultString((String) defaultValue);
} else if (defaultValue instanceof byte[]) {
return setDefaultRaw((byte[]) defaultValue);
} else if (defaultValue instanceof boolean[]) {
return setDefaultBooleanArray((boolean[]) defaultValue);
} else if (defaultValue instanceof long[]) {
return setDefaultIntegerArray((long[]) defaultValue);
} else if (defaultValue instanceof float[]) {
return setDefaultFloatArray((float[]) defaultValue);
} else if (defaultValue instanceof double[]) {
return setDefaultDoubleArray((double[]) defaultValue);
} else if (defaultValue instanceof Boolean[]) {
return setDefaultBooleanArray((Boolean[]) defaultValue);
} else if (defaultValue instanceof Long[]) {
return setDefaultIntegerArray((Long[]) defaultValue);
} else if (defaultValue instanceof Float[]) {
return setDefaultFloatArray((Float[]) defaultValue);
} else if (defaultValue instanceof Number[]) {
return setDefaultNumberArray((Number[]) defaultValue);
} else if (defaultValue instanceof String[]) {
return setDefaultStringArray((String[]) defaultValue);
} else {
throw new IllegalArgumentException(
"Value of type " + defaultValue.getClass().getName() + " cannot be put into a table");
}
}
{% for t in types %}
/**
* Sets the entry's value if it does not exist.
*
* @param defaultValue the default value to set
* @return False if the entry exists with a different type
*/
public boolean setDefault{{ t.TypeName }}({{ t.java.ValueType }} defaultValue) {
return NetworkTablesJNI.setDefault{{ t.TypeName }}(m_handle, 0, defaultValue);
}
{% if t.java.WrapValueType %}
/**
* Sets the entry's value if it does not exist.
*
* @param defaultValue the default value to set
* @return False if the entry exists with a different type
*/
public boolean setDefault{{ t.TypeName }}({{ t.java.WrapValueType }} defaultValue) {
return setDefault{{ t.TypeName }}(NetworkTableValue.toNative{{ t.TypeName }}(defaultValue));
}
{% endif -%}
{% endfor %}
/**
* Sets the entry's value if it does not exist.
*
* @param defaultValue the default value to set
* @return False if the entry exists with a different type
*/
public boolean setDefaultNumber(Number defaultValue) {
return setDefaultDouble(defaultValue.doubleValue());
}
/**
* Sets the entry's value if it does not exist.
*
* @param defaultValue the default value to set
* @return False if the entry exists with a different type
*/
public boolean setDefaultNumberArray(Number[] defaultValue) {
return setDefaultDoubleArray(NetworkTableValue.toNativeDoubleArray(defaultValue));
}
/**
* Sets the entry's value.
*
* @param value the value that will be assigned
* @return False if the table key already exists with a different type
* @throws IllegalArgumentException if the value is not a known type
*/
public boolean setValue(Object value) {
if (value instanceof NetworkTableValue) {
long time = ((NetworkTableValue) value).getTime();
Object otherValue = ((NetworkTableValue) value).getValue();
switch (((NetworkTableValue) value).getType()) {
case kBoolean:
return NetworkTablesJNI.setBoolean(m_handle, time, (Boolean) otherValue);
case kInteger:
return NetworkTablesJNI.setInteger(
m_handle, time, ((Number) otherValue).longValue());
case kFloat:
return NetworkTablesJNI.setFloat(
m_handle, time, ((Number) otherValue).floatValue());
case kDouble:
return NetworkTablesJNI.setDouble(
m_handle, time, ((Number) otherValue).doubleValue());
case kString:
return NetworkTablesJNI.setString(m_handle, time, (String) otherValue);
case kRaw:
return NetworkTablesJNI.setRaw(m_handle, time, (byte[]) otherValue);
case kBooleanArray:
return NetworkTablesJNI.setBooleanArray(m_handle, time, (boolean[]) otherValue);
case kIntegerArray:
return NetworkTablesJNI.setIntegerArray(m_handle, time, (long[]) otherValue);
case kFloatArray:
return NetworkTablesJNI.setFloatArray(m_handle, time, (float[]) otherValue);
case kDoubleArray:
return NetworkTablesJNI.setDoubleArray(m_handle, time, (double[]) otherValue);
case kStringArray:
return NetworkTablesJNI.setStringArray(m_handle, time, (String[]) otherValue);
default:
return true;
}
} else if (value instanceof Boolean) {
return setBoolean((Boolean) value);
} else if (value instanceof Long) {
return setInteger((Long) value);
} else if (value instanceof Float) {
return setFloat((Float) value);
} else if (value instanceof Number) {
return setNumber((Number) value);
} else if (value instanceof String) {
return setString((String) value);
} else if (value instanceof byte[]) {
return setRaw((byte[]) value);
} else if (value instanceof boolean[]) {
return setBooleanArray((boolean[]) value);
} else if (value instanceof long[]) {
return setIntegerArray((long[]) value);
} else if (value instanceof float[]) {
return setFloatArray((float[]) value);
} else if (value instanceof double[]) {
return setDoubleArray((double[]) value);
} else if (value instanceof Boolean[]) {
return setBooleanArray((Boolean[]) value);
} else if (value instanceof Long[]) {
return setIntegerArray((Long[]) value);
} else if (value instanceof Float[]) {
return setFloatArray((Float[]) value);
} else if (value instanceof Number[]) {
return setNumberArray((Number[]) value);
} else if (value instanceof String[]) {
return setStringArray((String[]) value);
} else {
throw new IllegalArgumentException(
"Value of type " + value.getClass().getName() + " cannot be put into a table");
}
}
{% for t in types %}
/**
* Sets the entry's value.
*
* @param value the value to set
* @return False if the entry exists with a different type
*/
public boolean set{{ t.TypeName }}({{ t.java.ValueType }} value) {
return NetworkTablesJNI.set{{ t.TypeName }}(m_handle, 0, value);
}
{% if t.java.WrapValueType %}
/**
* Sets the entry's value.
*
* @param value the value to set
* @return False if the entry exists with a different type
*/
public boolean set{{ t.TypeName }}({{ t.java.WrapValueType }} value) {
return set{{ t.TypeName }}(NetworkTableValue.toNative{{ t.TypeName }}(value));
}
{% endif -%}
{% endfor %}
/**
* Sets the entry's value.
*
* @param value the value to set
* @return False if the entry exists with a different type
*/
public boolean setNumber(Number value) {
return setDouble(value.doubleValue());
}
/**
* Sets the entry's value.
*
* @param value the value to set
* @return False if the entry exists with a different type
*/
public boolean setNumberArray(Number[] value) {
return setDoubleArray(NetworkTableValue.toNativeDoubleArray(value));
}
/**
* Sets flags.
*
* @param flags the flags to set (bitmask)
* @deprecated Use setPersistent() or topic properties instead
*/
@Deprecated(since = "2022", forRemoval = true)
public void setFlags(int flags) {
NetworkTablesJNI.setEntryFlags(m_handle, getFlags() | flags);
}
/**
* Clears flags.
*
* @param flags the flags to clear (bitmask)
* @deprecated Use setPersistent() or topic properties instead
*/
@Deprecated(since = "2022", forRemoval = true)
public void clearFlags(int flags) {
NetworkTablesJNI.setEntryFlags(m_handle, getFlags() & ~flags);
}
/** Make value persistent through program restarts. */
public void setPersistent() {
NetworkTablesJNI.setTopicPersistent(m_topic.getHandle(), true);
}
/** Stop making value persistent through program restarts. */
public void clearPersistent() {
NetworkTablesJNI.setTopicPersistent(m_topic.getHandle(), false);
}
/**
* Returns whether the value is persistent through program restarts.
*
* @return True if the value is persistent.
*/
public boolean isPersistent() {
return NetworkTablesJNI.getTopicPersistent(m_topic.getHandle());
}
/** Stops publishing the entry if it's been published. */
public void unpublish() {
NetworkTablesJNI.unpublish(m_handle);
}
/**
* Deletes the entry.
*
* @deprecated Use unpublish() instead.
*/
@Deprecated(since = "2022", forRemoval = true)
public void delete() {
unpublish();
}
@Override
public boolean equals(Object other) {
if (other == this) {
return true;
}
if (!(other instanceof NetworkTableEntry)) {
return false;
}
return m_handle == ((NetworkTableEntry) other).m_handle;
}
@Override
public int hashCode() {
return m_handle;
}
private final Topic m_topic;
protected int m_handle;
}

View File

@@ -0,0 +1,852 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.networktables;
import edu.wpi.first.util.WPIUtilJNI;
import edu.wpi.first.util.datalog.DataLog;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
/**
* NetworkTables Instance.
*
* <p>Instances are completely independent from each other. Table operations on one instance will
* not be visible to other instances unless the instances are connected via the network. The main
* limitation on instances is that you cannot have two servers on the same network port. The main
* utility of instances is for unit testing, but they can also enable one program to connect to two
* different NetworkTables networks.
*
* <p>The global "default" instance (as returned by {@link #getDefault()}) is always available, and
* is intended for the common case when there is only a single NetworkTables instance being used in
* the program.
*
* <p>Additional instances can be created with the {@link #create()} function. A reference must be
* kept to the NetworkTableInstance returned by this function to keep it from being garbage
* collected.
*/
public final class NetworkTableInstance implements AutoCloseable {
/**
* Client/server mode flag values (as returned by {@link #getNetworkMode()}). This is a bitmask.
*/
public static final int kNetModeNone = 0x00;
public static final int kNetModeServer = 0x01;
public static final int kNetModeClient3 = 0x02;
public static final int kNetModeClient4 = 0x04;
public static final int kNetModeStarting = 0x08;
public static final int kNetModeLocal = 0x10;
/** The default port that network tables operates on for NT3. */
public static final int kDefaultPort3 = 1735;
/** The default port that network tables operates on for NT4. */
public static final int kDefaultPort4 = 5810;
/**
* Construct from native handle.
*
* @param handle Native handle
*/
private NetworkTableInstance(int handle) {
m_owned = false;
m_handle = handle;
}
/** Destroys the instance (if created by {@link #create()}). */
@Override
public synchronized void close() {
if (m_owned && m_handle != 0) {
NetworkTablesJNI.destroyInstance(m_handle);
}
}
/**
* Determines if the native handle is valid.
*
* @return True if the native handle is valid, false otherwise.
*/
public boolean isValid() {
return m_handle != 0;
}
/* The default instance. */
private static NetworkTableInstance s_defaultInstance;
/**
* Get global default instance.
*
* @return Global default instance
*/
public static synchronized NetworkTableInstance getDefault() {
if (s_defaultInstance == null) {
s_defaultInstance = new NetworkTableInstance(NetworkTablesJNI.getDefaultInstance());
}
return s_defaultInstance;
}
/**
* Create an instance. Note: A reference to the returned instance must be retained to ensure the
* instance is not garbage collected.
*
* @return Newly created instance
*/
public static NetworkTableInstance create() {
NetworkTableInstance inst = new NetworkTableInstance(NetworkTablesJNI.createInstance());
inst.m_owned = true;
return inst;
}
/**
* Gets the native handle for the instance.
*
* @return Native handle
*/
public int getHandle() {
return m_handle;
}
/**
* Get (generic) topic.
*
* @param name topic name
* @return Topic
*/
public Topic getTopic(String name) {
Topic topic = m_topics.get(name);
if (topic == null) {
int handle = NetworkTablesJNI.getTopic(m_handle, name);
topic = new Topic(this, handle);
Topic oldTopic = m_topics.putIfAbsent(name, topic);
if (oldTopic != null) {
topic = oldTopic;
}
// also cache by handle
m_topicsByHandle.putIfAbsent(handle, topic);
}
return topic;
}
{% for t in types %}
/**
* Get {{ t.java.ValueType }} topic.
*
* @param name topic name
* @return {{ t.TypeName }}Topic
*/
public {{ t.TypeName }}Topic get{{ t.TypeName }}Topic(String name) {
Topic topic = m_topics.get(name);
if (topic instanceof {{ t.TypeName }}Topic) {
return ({{ t.TypeName }}Topic) topic;
}
int handle;
if (topic == null) {
handle = NetworkTablesJNI.getTopic(m_handle, name);
} else {
handle = topic.getHandle();
}
topic = new {{ t.TypeName }}Topic(this, handle);
m_topics.put(name, topic);
// also cache by handle
m_topicsByHandle.put(handle, topic);
return ({{ t.TypeName }}Topic) topic;
}
{% endfor %}
private Topic[] topicHandlesToTopics(int[] handles) {
Topic[] topics = new Topic[handles.length];
for (int i = 0; i < handles.length; i++) {
topics[i] = getCachedTopic(handles[i]);
}
return topics;
}
/**
* Get all published topics.
*
* @return Array of topics.
*/
public Topic[] getTopics() {
return topicHandlesToTopics(NetworkTablesJNI.getTopics(m_handle, "", 0));
}
/**
* Get published topics starting with the given prefix. The results are optionally filtered by
* string prefix to only return a subset of all topics.
*
* @param prefix topic name required prefix; only topics whose name starts with this string are
* returned
* @return Array of topic information.
*/
public Topic[] getTopics(String prefix) {
return topicHandlesToTopics(NetworkTablesJNI.getTopics(m_handle, prefix, 0));
}
/**
* Get published topics starting with the given prefix. The results are optionally filtered by
* string prefix and data type to only return a subset of all topics.
*
* @param prefix topic name required prefix; only topics whose name starts with this string are
* returned
* @param types bitmask of data types; 0 is treated as a "don't care"
* @return Array of topic information.
*/
public Topic[] getTopics(String prefix, int types) {
return topicHandlesToTopics(NetworkTablesJNI.getTopics(m_handle, prefix, types));
}
/**
* Get published topics starting with the given prefix. The results are optionally filtered by
* string prefix and data type to only return a subset of all topics.
*
* @param prefix topic name required prefix; only topics whose name starts with this string are
* returned
* @param types array of data type strings
* @return Array of topic information.
*/
public Topic[] getTopics(String prefix, String[] types) {
return topicHandlesToTopics(NetworkTablesJNI.getTopicsStr(m_handle, prefix, types));
}
/**
* Get information about all topics.
*
* @return Array of topic information.
*/
public TopicInfo[] getTopicInfo() {
return NetworkTablesJNI.getTopicInfos(this, m_handle, "", 0);
}
/**
* Get information about topics starting with the given prefix. The results are optionally
* filtered by string prefix to only return a subset of all topics.
*
* @param prefix topic name required prefix; only topics whose name starts with this string are
* returned
* @return Array of topic information.
*/
public TopicInfo[] getTopicInfo(String prefix) {
return NetworkTablesJNI.getTopicInfos(this, m_handle, prefix, 0);
}
/**
* Get information about topics starting with the given prefix. The results are optionally
* filtered by string prefix and data type to only return a subset of all topics.
*
* @param prefix topic name required prefix; only topics whose name starts with this string are
* returned
* @param types bitmask of data types; 0 is treated as a "don't care"
* @return Array of topic information.
*/
public TopicInfo[] getTopicInfo(String prefix, int types) {
return NetworkTablesJNI.getTopicInfos(this, m_handle, prefix, types);
}
/**
* Get information about topics starting with the given prefix. The results are optionally
* filtered by string prefix and data type to only return a subset of all topics.
*
* @param prefix topic name required prefix; only topics whose name starts with this string are
* returned
* @param types array of data type strings
* @return Array of topic information.
*/
public TopicInfo[] getTopicInfo(String prefix, String[] types) {
return NetworkTablesJNI.getTopicInfosStr(this, m_handle, prefix, types);
}
/* Cache of created entries. */
private final ConcurrentMap<String, NetworkTableEntry> m_entries = new ConcurrentHashMap<>();
/**
* Gets the entry for a key.
*
* @param name Key
* @return Network table entry.
*/
public NetworkTableEntry getEntry(String name) {
NetworkTableEntry entry = m_entries.get(name);
if (entry == null) {
entry = new NetworkTableEntry(this, NetworkTablesJNI.getEntry(m_handle, name));
NetworkTableEntry oldEntry = m_entries.putIfAbsent(name, entry);
if (oldEntry != null) {
entry = oldEntry;
}
}
return entry;
}
/* Cache of created topics. */
private final ConcurrentMap<String, Topic> m_topics = new ConcurrentHashMap<>();
private final ConcurrentMap<Integer, Topic> m_topicsByHandle = new ConcurrentHashMap<>();
Topic getCachedTopic(String name) {
Topic topic = m_topics.get(name);
if (topic == null) {
int handle = NetworkTablesJNI.getTopic(m_handle, name);
topic = new Topic(this, handle);
Topic oldTopic = m_topics.putIfAbsent(name, topic);
if (oldTopic != null) {
topic = oldTopic;
}
// also cache by handle
m_topicsByHandle.putIfAbsent(handle, topic);
}
return topic;
}
Topic getCachedTopic(int handle) {
Topic topic = m_topicsByHandle.get(handle);
if (topic == null) {
topic = new Topic(this, handle);
Topic oldTopic = m_topicsByHandle.putIfAbsent(handle, topic);
if (oldTopic != null) {
topic = oldTopic;
}
}
return topic;
}
/* Cache of created tables. */
private final ConcurrentMap<String, NetworkTable> m_tables = new ConcurrentHashMap<>();
/**
* Gets the table with the specified key.
*
* @param key the key name
* @return The network table
*/
public NetworkTable getTable(String key) {
// prepend leading / if not present
String theKey;
if (key.isEmpty() || "/".equals(key)) {
theKey = "";
} else if (key.charAt(0) == NetworkTable.PATH_SEPARATOR) {
theKey = key;
} else {
theKey = NetworkTable.PATH_SEPARATOR + key;
}
// cache created tables
NetworkTable table = m_tables.get(theKey);
if (table == null) {
table = new NetworkTable(this, theKey);
NetworkTable oldTable = m_tables.putIfAbsent(theKey, table);
if (oldTable != null) {
table = oldTable;
}
}
return table;
}
/*
* Callback Creation Functions
*/
private final ReentrantLock m_connectionListenerLock = new ReentrantLock();
private final Map<Integer, Consumer<ConnectionNotification>> m_connectionListeners =
new HashMap<>();
private int m_connectionListenerPoller;
@SuppressWarnings("PMD.AvoidCatchingThrowable")
private void startConnectionListenerThread() {
var connectionListenerThread =
new Thread(
() -> {
boolean wasInterrupted = false;
while (!Thread.interrupted()) {
try {
WPIUtilJNI.waitForObject(m_connectionListenerPoller);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
// don't try to destroy poller, as its handle is likely no longer valid
wasInterrupted = true;
break;
}
ConnectionNotification[] events =
NetworkTablesJNI.readConnectionListenerQueue(this, m_connectionListenerPoller);
for (ConnectionNotification event : events) {
Consumer<ConnectionNotification> listener;
m_connectionListenerLock.lock();
try {
listener = m_connectionListeners.get(event.listener);
} finally {
m_connectionListenerLock.unlock();
}
if (listener != null) {
try {
listener.accept(event);
} catch (Throwable throwable) {
System.err.println(
"Unhandled exception during connection listener callback: "
+ throwable.toString());
throwable.printStackTrace();
}
}
}
}
m_connectionListenerLock.lock();
try {
if (!wasInterrupted) {
NetworkTablesJNI.destroyConnectionListenerPoller(m_connectionListenerPoller);
}
m_connectionListenerPoller = 0;
} finally {
m_connectionListenerLock.unlock();
}
},
"NTConnectionListener");
connectionListenerThread.setDaemon(true);
connectionListenerThread.start();
}
/**
* Add a connection listener.
*
* @param listener Listener to add
* @param immediateNotify Notify listener of all existing connections
* @return Listener handle
*/
public int addConnectionListener(
Consumer<ConnectionNotification> listener, boolean immediateNotify) {
m_connectionListenerLock.lock();
try {
if (m_connectionListenerPoller == 0) {
m_connectionListenerPoller = NetworkTablesJNI.createConnectionListenerPoller(m_handle);
startConnectionListenerThread();
}
int handle =
NetworkTablesJNI.addPolledConnectionListener(m_connectionListenerPoller, immediateNotify);
m_connectionListeners.put(handle, listener);
return handle;
} finally {
m_connectionListenerLock.unlock();
}
}
/**
* Remove a connection listener.
*
* @param listener Listener handle to remove
*/
public void removeConnectionListener(int listener) {
m_connectionListenerLock.lock();
try {
m_connectionListeners.remove(listener);
} finally {
m_connectionListenerLock.unlock();
}
NetworkTablesJNI.removeConnectionListener(listener);
}
/*
* Client/Server Functions
*/
/**
* Set the network identity of this node. This is the name used during the initial connection
* handshake, and is visible through ConnectionInfo on the remote node.
*
* @param name identity to advertise
*/
public void setNetworkIdentity(String name) {
NetworkTablesJNI.setNetworkIdentity(m_handle, name);
}
/**
* Get the current network mode.
*
* @return Bitmask of NetworkMode.
*/
public int getNetworkMode() {
return NetworkTablesJNI.getNetworkMode(m_handle);
}
/**
* Starts local-only operation. Prevents calls to startServer or startClient from taking effect.
* Has no effect if startServer or startClient has already been called.
*/
public void startLocal() {
NetworkTablesJNI.startLocal(m_handle);
}
/**
* Stops local-only operation. startServer or startClient can be called after this call to start a
* server or client.
*/
public void stopLocal() {
NetworkTablesJNI.stopLocal(m_handle);
}
/**
* Starts a server using the networktables.json as the persistent file, using the default
* listening address and port.
*/
public void startServer() {
startServer("networktables.json");
}
/**
* Starts a server using the specified persistent filename, using the default listening address
* and port.
*
* @param persistFilename the name of the persist file to use
*/
public void startServer(String persistFilename) {
startServer(persistFilename, "");
}
/**
* Starts a server using the specified filename and listening address, using the default port.
*
* @param persistFilename the name of the persist file to use
* @param listenAddress the address to listen on, or empty to listen on any address
*/
public void startServer(String persistFilename, String listenAddress) {
startServer(persistFilename, listenAddress, kDefaultPort3, kDefaultPort4);
}
/**
* Starts a server using the specified filename, listening address, and port.
*
* @param persistFilename the name of the persist file to use
* @param listenAddress the address to listen on, or empty to listen on any address
* @param port3 port to communicate over (NT3)
*/
public void startServer(String persistFilename, String listenAddress, int port3) {
startServer(persistFilename, listenAddress, port3, kDefaultPort4);
}
/**
* Starts a server using the specified filename, listening address, and port.
*
* @param persistFilename the name of the persist file to use
* @param listenAddress the address to listen on, or empty to listen on any address
* @param port3 port to communicate over (NT3)
* @param port4 port to communicate over (NT4)
*/
public void startServer(String persistFilename, String listenAddress, int port3, int port4) {
NetworkTablesJNI.startServer(m_handle, persistFilename, listenAddress, port3, port4);
}
/** Stops the server if it is running. */
public void stopServer() {
NetworkTablesJNI.stopServer(m_handle);
}
/** Starts a NT3 client. Use SetServer or SetServerTeam to set the server name and port. */
public void startClient3() {
NetworkTablesJNI.startClient3(m_handle);
}
/** Starts a NT4 client. Use SetServer or SetServerTeam to set the server name and port. */
public void startClient4() {
NetworkTablesJNI.startClient4(m_handle);
}
/** Stops the client if it is running. */
public void stopClient() {
NetworkTablesJNI.stopClient(m_handle);
}
/**
* Sets server address and port for client (without restarting client). Changes the port to the
* default port.
*
* @param serverName server name
*/
public void setServer(String serverName) {
setServer(serverName, 0);
}
/**
* Sets server address and port for client (without restarting client).
*
* @param serverName server name
* @param port port to communicate over (0=default)
*/
public void setServer(String serverName, int port) {
NetworkTablesJNI.setServer(m_handle, serverName, port);
}
/**
* Sets server addresses and port for client (without restarting client). Changes the port to the
* default port. The client will attempt to connect to each server in round robin fashion.
*
* @param serverNames array of server names
*/
public void setServer(String[] serverNames) {
setServer(serverNames, 0);
}
/**
* Sets server addresses and port for client (without restarting client). The client will attempt
* to connect to each server in round robin fashion.
*
* @param serverNames array of server names
* @param port port to communicate over (0=default)
*/
public void setServer(String[] serverNames, int port) {
int[] ports = new int[serverNames.length];
for (int i = 0; i < serverNames.length; i++) {
ports[i] = port;
}
setServer(serverNames, ports);
}
/**
* Sets server addresses and ports for client (without restarting client). The client will attempt
* to connect to each server in round robin fashion.
*
* @param serverNames array of server names
* @param ports array of port numbers (0=default)
*/
public void setServer(String[] serverNames, int[] ports) {
NetworkTablesJNI.setServer(m_handle, serverNames, ports);
}
/**
* Sets server addresses and port for client (without restarting client). Changes the port to the
* default port. The client will attempt to connect to each server in round robin fashion.
*
* @param team team number
*/
public void setServerTeam(int team) {
setServerTeam(team, 0);
}
/**
* Sets server addresses and port for client (without restarting client). Connects using commonly
* known robot addresses for the specified team.
*
* @param team team number
* @param port port to communicate over (0=default)
*/
public void setServerTeam(int team, int port) {
NetworkTablesJNI.setServerTeam(m_handle, team, port);
}
/**
* Starts requesting server address from Driver Station. This connects to the Driver Station
* running on localhost to obtain the server IP address, and connects with the default port.
*/
public void startDSClient() {
startDSClient(0);
}
/**
* Starts requesting server address from Driver Station. This connects to the Driver Station
* running on localhost to obtain the server IP address.
*
* @param port server port to use in combination with IP from DS (0=default)
*/
public void startDSClient(int port) {
NetworkTablesJNI.startDSClient(m_handle, port);
}
/** Stops requesting server address from Driver Station. */
public void stopDSClient() {
NetworkTablesJNI.stopDSClient(m_handle);
}
/**
* Flushes all updated values immediately to the local client/server. This does not flush to the
* network.
*/
public void flushLocal() {
NetworkTablesJNI.flushLocal(m_handle);
}
/**
* Flushes all updated values immediately to the network. Note: This is rate-limited to protect
* the network from flooding. This is primarily useful for synchronizing network updates with user
* code.
*/
public void flush() {
NetworkTablesJNI.flush(m_handle);
}
/**
* Gets information on the currently established network connections. If operating as a client,
* this will return either zero or one values.
*
* @return array of connection information
*/
public ConnectionInfo[] getConnections() {
return NetworkTablesJNI.getConnections(m_handle);
}
/**
* Return whether or not the instance is connected to another node.
*
* @return True if connected.
*/
public boolean isConnected() {
return NetworkTablesJNI.isConnected(m_handle);
}
/**
* Starts logging entry changes to a DataLog.
*
* @param log data log object; lifetime must extend until StopEntryDataLog is called or the
* instance is destroyed
* @param prefix only store entries with names that start with this prefix; the prefix is not
* included in the data log entry name
* @param logPrefix prefix to add to data log entry names
* @return Data logger handle
*/
public int startEntryDataLog(DataLog log, String prefix, String logPrefix) {
return NetworkTablesJNI.startEntryDataLog(m_handle, log, prefix, logPrefix);
}
/**
* Stops logging entry changes to a DataLog.
*
* @param logger data logger handle
*/
public static void stopEntryDataLog(int logger) {
NetworkTablesJNI.stopEntryDataLog(logger);
}
/**
* Starts logging connection changes to a DataLog.
*
* @param log data log object; lifetime must extend until StopConnectionDataLog is called or the
* instance is destroyed
* @param name data log entry name
* @return Data logger handle
*/
public int startConnectionDataLog(DataLog log, String name) {
return NetworkTablesJNI.startConnectionDataLog(m_handle, log, name);
}
/**
* Stops logging connection changes to a DataLog.
*
* @param logger data logger handle
*/
public static void stopConnectionDataLog(int logger) {
NetworkTablesJNI.stopConnectionDataLog(logger);
}
private final ReentrantLock m_loggerLock = new ReentrantLock();
private final Map<Integer, Consumer<LogMessage>> m_loggers = new HashMap<>();
private int m_loggerPoller;
@SuppressWarnings("PMD.AvoidCatchingThrowable")
private void startLogThread() {
var loggerThread =
new Thread(
() -> {
boolean wasInterrupted = false;
while (!Thread.interrupted()) {
try {
WPIUtilJNI.waitForObject(m_loggerPoller);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
// don't try to destroy poller, as its handle is likely no longer valid
wasInterrupted = true;
break;
}
LogMessage[] events = NetworkTablesJNI.readLoggerQueue(this, m_loggerPoller);
for (LogMessage event : events) {
Consumer<LogMessage> logger;
m_loggerLock.lock();
try {
logger = m_loggers.get(event.logger);
} finally {
m_loggerLock.unlock();
}
if (logger != null) {
try {
logger.accept(event);
} catch (Throwable throwable) {
System.err.println(
"Unhandled exception during logger callback: " + throwable.toString());
throwable.printStackTrace();
}
}
}
}
m_loggerLock.lock();
try {
if (!wasInterrupted) {
NetworkTablesJNI.destroyLoggerPoller(m_loggerPoller);
}
} finally {
m_loggerLock.unlock();
}
},
"NTLogger");
loggerThread.setDaemon(true);
loggerThread.start();
}
/**
* Add logger callback function. By default, log messages are sent to stderr; this function sends
* log messages with the specified levels to the provided callback function instead. The callback
* function will only be called for log messages with level greater than or equal to minLevel and
* less than or equal to maxLevel; messages outside this range will be silently ignored.
*
* @param func log callback function
* @param minLevel minimum log level
* @param maxLevel maximum log level
* @return Logger handle
*/
public int addLogger(Consumer<LogMessage> func, int minLevel, int maxLevel) {
m_loggerLock.lock();
try {
if (m_loggerPoller == 0) {
m_loggerPoller = NetworkTablesJNI.createLoggerPoller(m_handle);
startLogThread();
}
int handle = NetworkTablesJNI.addPolledLogger(m_loggerPoller, minLevel, maxLevel);
m_loggers.put(handle, func);
return handle;
} finally {
m_loggerLock.unlock();
}
}
/**
* Remove a logger.
*
* @param logger Logger handle to remove
*/
public void removeLogger(int logger) {
m_loggerLock.lock();
try {
m_loggers.remove(logger);
} finally {
m_loggerLock.unlock();
}
NetworkTablesJNI.removeLogger(logger);
}
@Override
public boolean equals(Object other) {
if (other == this) {
return true;
}
if (!(other instanceof NetworkTableInstance)) {
return false;
}
return m_handle == ((NetworkTableInstance) other).m_handle;
}
@Override
public int hashCode() {
return m_handle;
}
private boolean m_owned;
private final int m_handle;
}

View File

@@ -0,0 +1,248 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.networktables;
import java.util.Objects;
/** A network table entry value. */
@SuppressWarnings({"UnnecessaryParentheses", "PMD.MethodReturnsInternalArray"})
public final class NetworkTableValue {
NetworkTableValue(NetworkTableType type, Object value, long time, long serverTime) {
m_type = type;
m_value = value;
m_time = time;
m_serverTime = serverTime;
}
NetworkTableValue(NetworkTableType type, Object value, long time) {
this(type, value, time, time == 0 ? 0 : 1);
}
NetworkTableValue(NetworkTableType type, Object value) {
this(type, value, NetworkTablesJNI.now(), 1);
}
NetworkTableValue(int type, Object value, long time, long serverTime) {
this(NetworkTableType.getFromInt(type), value, time, serverTime);
}
/**
* Get the data type.
*
* @return The type.
*/
public NetworkTableType getType() {
return m_type;
}
/**
* Get the data value stored.
*
* @return The type.
*/
public Object getValue() {
return m_value;
}
/**
* Get the creation time of the value in local time.
*
* @return The time, in the units returned by NetworkTablesJNI.now().
*/
public long getTime() {
return m_time;
}
/**
* Get the creation time of the value in server time.
*
* @return The server time.
*/
public long getServerTime() {
return m_serverTime;
}
/*
* Type Checkers
*/
/**
* Determine if entry value contains a value or is unassigned.
*
* @return True if the entry value contains a value.
*/
public boolean isValid() {
return m_type != NetworkTableType.kUnassigned;
}
{% for t in types %}
/**
* Determine if entry value contains a {{ t.java.ValueType }}.
*
* @return True if the entry value is of {{ t.java.ValueType }} type.
*/
public boolean is{{ t.TypeName }}() {
return m_type == NetworkTableType.k{{ t.TypeName }};
}
{% endfor %}
/*
* Type-Safe Getters
*/
{% for t in types %}
/**
* Get the {{ t.java.ValueType }} value.
*
* @return The {{ t.java.ValueType }} value.
* @throws ClassCastException if the entry value is not of {{ t.java.ValueType }} type.
*/
public {{ t.java.ValueType }} get{{ t.TypeName }}() {
if (m_type != NetworkTableType.k{{ t.TypeName }}) {
throw new ClassCastException("cannot convert " + m_type + " to {{ t.java.ValueType }}");
}
return {{ t.java.FromStorageBegin }}m_value{{ t.java.FromStorageEnd }};
}
{% endfor %}
/*
* Factory functions.
*/
{% for t in types %}
/**
* Creates a {{ t.java.ValueType }} value.
*
* @param value the value
* @return The entry value
*/
public static NetworkTableValue make{{ t.TypeName }}({{ t.java.ValueType }} value) {
return new NetworkTableValue(NetworkTableType.k{{ t.TypeName }}, {{ t.java.ToWrapObject }}(value));
}
/**
* Creates a {{ t.java.ValueType }} value.
*
* @param value the value
* @param time the creation time to use (instead of the current time)
* @return The entry value
*/
public static NetworkTableValue make{{ t.TypeName }}({{ t.java.ValueType }} value, long time) {
return new NetworkTableValue(NetworkTableType.k{{ t.TypeName }}, {{ t.java.ToWrapObject }}(value), time);
}
{% if t.java.WrapValueType %}
/**
* Creates a {{ t.java.ValueType }} value.
*
* @param value the value
* @return The entry value
*/
public static NetworkTableValue make{{ t.TypeName }}({{ t.java.WrapValueType }} value) {
return new NetworkTableValue(NetworkTableType.k{{ t.TypeName }}, toNative{{ t.TypeName }}(value));
}
/**
* Creates a {{ t.java.ValueType }} value.
*
* @param value the value
* @param time the creation time to use (instead of the current time)
* @return The entry value
*/
public static NetworkTableValue make{{ t.TypeName }}({{ t.java.WrapValueType }} value, long time) {
return new NetworkTableValue(NetworkTableType.k{{ t.TypeName }}, toNative{{ t.TypeName }}(value), time);
}
{% endif -%}
{% endfor %}
@Override
public boolean equals(Object other) {
if (other == this) {
return true;
}
if (!(other instanceof NetworkTableValue)) {
return false;
}
NetworkTableValue ntOther = (NetworkTableValue) other;
return m_type == ntOther.m_type && m_value.equals(ntOther.m_value);
}
@Override
public int hashCode() {
return Objects.hash(m_type, m_value);
}
// arraycopy() doesn't know how to unwrap boxed values; this is a false positive in PMD
// (see https://sourceforge.net/p/pmd/bugs/804/)
@SuppressWarnings("PMD.AvoidArrayLoops")
static boolean[] toNativeBooleanArray(Boolean[] arr) {
boolean[] out = new boolean[arr.length];
for (int i = 0; i < arr.length; i++) {
out[i] = arr[i];
}
return out;
}
@SuppressWarnings("PMD.AvoidArrayLoops")
static double[] toNativeDoubleArray(Number[] arr) {
double[] out = new double[arr.length];
for (int i = 0; i < arr.length; i++) {
out[i] = arr[i].doubleValue();
}
return out;
}
@SuppressWarnings("PMD.AvoidArrayLoops")
static long[] toNativeIntegerArray(Number[] arr) {
long[] out = new long[arr.length];
for (int i = 0; i < arr.length; i++) {
out[i] = arr[i].longValue();
}
return out;
}
@SuppressWarnings("PMD.AvoidArrayLoops")
static float[] toNativeFloatArray(Number[] arr) {
float[] out = new float[arr.length];
for (int i = 0; i < arr.length; i++) {
out[i] = arr[i].floatValue();
}
return out;
}
@SuppressWarnings("PMD.AvoidArrayLoops")
static Boolean[] fromNativeBooleanArray(boolean[] arr) {
Boolean[] out = new Boolean[arr.length];
for (int i = 0; i < arr.length; i++) {
out[i] = arr[i];
}
return out;
}
@SuppressWarnings("PMD.AvoidArrayLoops")
static Long[] fromNativeIntegerArray(long[] arr) {
Long[] out = new Long[arr.length];
for (int i = 0; i < arr.length; i++) {
out[i] = arr[i];
}
return out;
}
@SuppressWarnings("PMD.AvoidArrayLoops")
static Float[] fromNativeFloatArray(float[] arr) {
Float[] out = new Float[arr.length];
for (int i = 0; i < arr.length; i++) {
out[i] = arr[i];
}
return out;
}
@SuppressWarnings("PMD.AvoidArrayLoops")
static Double[] fromNativeDoubleArray(double[] arr) {
Double[] out = new Double[arr.length];
for (int i = 0; i < arr.length; i++) {
out[i] = arr[i];
}
return out;
}
private NetworkTableType m_type;
private Object m_value;
private long m_time;
private long m_serverTime;
}

View File

@@ -0,0 +1,301 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.networktables;
import edu.wpi.first.util.RuntimeLoader;
import edu.wpi.first.util.datalog.DataLog;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicBoolean;
public final class NetworkTablesJNI {
static boolean libraryLoaded = false;
static RuntimeLoader<NetworkTablesJNI> loader = null;
public static class Helper {
private static AtomicBoolean extractOnStaticLoad = new AtomicBoolean(true);
public static boolean getExtractOnStaticLoad() {
return extractOnStaticLoad.get();
}
public static void setExtractOnStaticLoad(boolean load) {
extractOnStaticLoad.set(load);
}
}
static {
if (Helper.getExtractOnStaticLoad()) {
try {
loader =
new RuntimeLoader<>(
"ntcorejni", RuntimeLoader.getDefaultExtractionRoot(), NetworkTablesJNI.class);
loader.loadLibrary();
} catch (IOException ex) {
ex.printStackTrace();
System.exit(1);
}
libraryLoaded = true;
}
}
/**
* Force load the library.
*
* @throws IOException if the library fails to load
*/
public static synchronized void forceLoad() throws IOException {
if (libraryLoaded) {
return;
}
loader =
new RuntimeLoader<>(
"ntcorejni", RuntimeLoader.getDefaultExtractionRoot(), NetworkTablesJNI.class);
loader.loadLibrary();
libraryLoaded = true;
}
private static int[] pubSubOptionTypes(PubSubOption... options) {
int[] rv = new int[options.length];
for (int i = 0; i < options.length; i++) {
rv[i] = options[i].m_type;
}
return rv;
}
private static double[] pubSubOptionValues(PubSubOption... options) {
double[] rv = new double[options.length];
for (int i = 0; i < options.length; i++) {
rv[i] = options[i].m_value;
}
return rv;
}
public static native int getDefaultInstance();
public static native int createInstance();
public static native void destroyInstance(int inst);
public static native int getInstanceFromHandle(int handle);
public static native int getEntry(int inst, String key);
private static native int getEntry(
int topic, int type, String typeStr, int[] optionTypes, double[] optionValues);
public static int getEntry(int topic, int type, String typeStr, PubSubOption... options) {
return getEntry(topic, type, typeStr, pubSubOptionTypes(options), pubSubOptionValues(options));
}
public static native String getEntryName(int entry);
public static native long getEntryLastChange(int entry);
public static native int getType(int entry);
/* Topic functions */
public static native int[] getTopics(int inst, String prefix, int types);
public static native int[] getTopicsStr(int inst, String prefix, String[] types);
public static native TopicInfo[] getTopicInfos(
NetworkTableInstance instObject, int inst, String prefix, int types);
public static native TopicInfo[] getTopicInfosStr(
NetworkTableInstance instObject, int inst, String prefix, String[] types);
public static native int getTopic(int inst, String name);
public static native String getTopicName(int topic);
public static native int getTopicType(int topic);
public static native void setTopicPersistent(int topic, boolean value);
public static native boolean getTopicPersistent(int topic);
public static native void setTopicRetained(int topic, boolean value);
public static native boolean getTopicRetained(int topic);
public static native String getTopicTypeString(int topic);
public static native boolean getTopicExists(int topic);
public static native String getTopicProperty(int topic, String name);
public static native void setTopicProperty(int topic, String name, String value);
public static native void deleteTopicProperty(int topic, String name);
public static native String getTopicProperties(int topic);
public static native void setTopicProperties(int topic, String properties);
private static native int subscribe(
int topic, int type, String typeStr, int[] optionTypes, double[] optionValues);
public static int subscribe(int topic, int type, String typeStr, PubSubOption... options) {
return subscribe(topic, type, typeStr, pubSubOptionTypes(options), pubSubOptionValues(options));
}
public static native void unsubscribe(int sub);
private static native int publish(
int topic, int type, String typeStr, int[] optionTypes, double[] optionValues);
public static int publish(int topic, int type, String typeStr, PubSubOption... options) {
return publish(topic, type, typeStr, pubSubOptionTypes(options), pubSubOptionValues(options));
}
private static native int publishEx(
int topic, int type, String typeStr, String properties, int[] optionTypes, double[] optionValues);
public static int publishEx(int topic, int type, String typeStr, String properties, PubSubOption... options) {
return publishEx(topic, type, typeStr, properties, pubSubOptionTypes(options), pubSubOptionValues(options));
}
public static native void unpublish(int pubentry);
public static native void releaseEntry(int entry);
public static native void release(int pubsubentry);
public static native int getTopicFromHandle(int pubsubentry);
private static native int subscribeMultiple(
int inst, String[] prefixes, int[] optionTypes, double[] optionValues);
public static int subscribeMultiple(int inst, String[] prefixes, PubSubOption... options) {
return subscribeMultiple(
inst, prefixes, pubSubOptionTypes(options), pubSubOptionValues(options));
}
public static native void unsubscribeMultiple(int sub);
{% for t in types %}
public static native Timestamped{{ t.TypeName }} getAtomic{{ t.TypeName }}(
int subentry, {{ t.java.ValueType }} defaultValue);
public static native Timestamped{{ t.TypeName }}[] readQueue{{ t.TypeName }}(int subentry);
public static native {{ t.java.ValueType }}[] readQueueValues{{ t.TypeName }}(int subentry);
public static native boolean set{{ t.TypeName }}(int entry, long time, {{ t.java.ValueType }} value);
public static native {{ t.java.ValueType }} get{{ t.TypeName }}(int entry, {{ t.java.ValueType }} defaultValue);
public static native boolean setDefault{{ t.TypeName }}(int entry, long time, {{ t.java.ValueType }} defaultValue);
{% endfor %}
public static native NetworkTableValue[] readQueueValue(int subentry);
public static native NetworkTableValue getValue(int entry);
public static native void setEntryFlags(int entry, int flags);
public static native int getEntryFlags(int entry);
public static native TopicInfo getTopicInfo(NetworkTableInstance inst, int topic);
public static native int createTopicListenerPoller(int inst);
public static native void destroyTopicListenerPoller(int poller);
public static native int addPolledTopicListener(int poller, String[] prefixes, int flags);
public static native int addPolledTopicListener(int poller, int handle, int flags);
public static native TopicNotification[] readTopicListenerQueue(
NetworkTableInstance inst, int poller);
public static native void removeTopicListener(int topicListener);
public static native int createValueListenerPoller(int inst);
public static native void destroyValueListenerPoller(int poller);
public static native int addPolledValueListener(int poller, int subentry, int flags);
public static native ValueNotification[] readValueListenerQueue(
NetworkTableInstance inst, int poller);
public static native void removeValueListener(int valueListener);
public static native int createConnectionListenerPoller(int inst);
public static native void destroyConnectionListenerPoller(int poller);
public static native int addPolledConnectionListener(int poller, boolean immediateNotify);
public static native ConnectionNotification[] readConnectionListenerQueue(
NetworkTableInstance inst, int poller);
public static native void removeConnectionListener(int connListener);
public static native void setNetworkIdentity(int inst, String name);
public static native int getNetworkMode(int inst);
public static native void startLocal(int inst);
public static native void stopLocal(int inst);
public static native void startServer(
int inst, String persistFilename, String listenAddress, int port3, int port4);
public static native void stopServer(int inst);
public static native void startClient3(int inst);
public static native void startClient4(int inst);
public static native void stopClient(int inst);
public static native void setServer(int inst, String serverName, int port);
public static native void setServer(int inst, String[] serverNames, int[] ports);
public static native void setServerTeam(int inst, int team, int port);
public static native void startDSClient(int inst, int port);
public static native void stopDSClient(int inst);
public static native void flushLocal(int inst);
public static native void flush(int inst);
public static native ConnectionInfo[] getConnections(int inst);
public static native boolean isConnected(int inst);
public static native long now();
private static native int startEntryDataLog(int inst, long log, String prefix, String logPrefix);
public static int startEntryDataLog(int inst, DataLog log, String prefix, String logPrefix) {
return startEntryDataLog(inst, log.getImpl(), prefix, logPrefix);
}
public static native void stopEntryDataLog(int logger);
private static native int startConnectionDataLog(int inst, long log, String name);
public static int startConnectionDataLog(int inst, DataLog log, String name) {
return startConnectionDataLog(inst, log.getImpl(), name);
}
public static native void stopConnectionDataLog(int logger);
public static native int createLoggerPoller(int inst);
public static native void destroyLoggerPoller(int poller);
public static native int addPolledLogger(int poller, int minLevel, int maxLevel);
public static native LogMessage[] readLoggerQueue(NetworkTableInstance inst, int poller);
public static native void removeLogger(int logger);
}

View File

@@ -0,0 +1,49 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.networktables;
import {{ java.ConsumerFunctionPackage|default('java.util.function') }}.{{ java.FunctionTypePrefix }}Consumer;
/** NetworkTables {{ TypeName }} publisher. */
public interface {{ TypeName }}Publisher extends Publisher, {{ java.FunctionTypePrefix }}Consumer{{ java.FunctionTypeSuffix }} {
/**
* Get the corresponding topic.
*
* @return Topic
*/
@Override
{{ TypeName }}Topic getTopic();
/**
* Publish a new value using current NT time.
*
* @param value value to publish
*/
default void set({{ java.ValueType }} value) {
set(value, 0);
}
/**
* Publish a new value.
*
* @param value value to publish
* @param time timestamp; 0 indicates current NT time should be used
*/
void set({{ java.ValueType }} value, long time);
/**
* Publish a default value.
* On reconnect, a default value will never be used in preference to a
* published value.
*
* @param value value
*/
void setDefault({{ java.ValueType }} value);
@Override
default void accept({{ java.ValueType }} value) {
set(value);
}
}

View File

@@ -0,0 +1,83 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.networktables;
import {{ java.SupplierFunctionPackage|default('java.util.function') }}.{{ java.FunctionTypePrefix }}Supplier;
/** NetworkTables {{ TypeName }} subscriber. */
@SuppressWarnings("PMD.MissingOverride")
public interface {{ TypeName }}Subscriber extends Subscriber, {{ java.FunctionTypePrefix }}Supplier{{ java.FunctionTypeSuffix }} {
/**
* Get the corresponding topic.
*
* @return Topic
*/
@Override
{{ TypeName }}Topic getTopic();
/**
* Get the last published value.
* If no value has been published, returns the stored default value.
*
* @return value
*/
{{ java.ValueType }} get();
/**
* Get the last published value.
* If no value has been published, returns the passed defaultValue.
*
* @param defaultValue default value to return if no value has been published
* @return value
*/
{{ java.ValueType }} get({{ java.ValueType }} defaultValue);
{% if java.FunctionTypePrefix %}
@Override
default {{ java.ValueType }} getAs{{ java.FunctionTypePrefix }}() {
return get();
}
{% endif %}
/**
* Get the last published value along with its timestamp
* If no value has been published, returns the stored default value and a
* timestamp of 0.
*
* @return timestamped value
*/
Timestamped{{ TypeName }} getAtomic();
/**
* Get the last published value along with its timestamp
* If no value has been published, returns the passed defaultValue and a
* timestamp of 0.
*
* @param defaultValue default value to return if no value has been published
* @return timestamped value
*/
Timestamped{{ TypeName }} getAtomic({{ java.ValueType }} defaultValue);
/**
* Get an array of all value changes since the last call to readQueue.
* Also provides a timestamp for each value.
*
* <p>The "poll storage" subscribe option can be used to set the queue
* depth.
*
* @return Array of timestamped values; empty array if no new changes have
* been published since the previous call.
*/
Timestamped{{ TypeName }}[] readQueue();
/**
* Get an array of all value changes since the last call to readQueue.
*
* <p>The "poll storage" subscribe option can be used to set the queue
* depth.
*
* @return Array of values; empty array if no new changes have been
* published since the previous call.
*/
{{ java.ValueType }}[] readQueueValues();
}

View File

@@ -0,0 +1,40 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.networktables;
/** NetworkTables timestamped {{ TypeName }}. */
@SuppressWarnings("PMD.ArrayIsStoredDirectly")
public final class Timestamped{{ TypeName }} {
/**
* Create a timestamped value.
*
* @param timestamp timestamp in local time base
* @param serverTime timestamp in server time base
* @param value value
*/
public Timestamped{{ TypeName }}(long timestamp, long serverTime, {{ java.ValueType }} value) {
this.timestamp = timestamp;
this.serverTime = serverTime;
this.value = value;
}
/**
* Timestamp in local time base.
*/
@SuppressWarnings("MemberName")
public final long timestamp;
/**
* Timestamp in server time base. May be 0 or 1 for locally set values.
*/
@SuppressWarnings("MemberName")
public final long serverTime;
/**
* Value.
*/
@SuppressWarnings("MemberName")
public final {{ java.ValueType }} value;
}

View File

@@ -0,0 +1,222 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.networktables;
/** NetworkTables {{ TypeName }} topic. */
public final class {{ TypeName }}Topic extends Topic {
{%- if TypeString %}
/** The default type string for this topic type. */
public static final String kTypeString = {{ TypeString }};
{% endif %}
/**
* Construct from a generic topic.
*
* @param topic Topic
*/
public {{ TypeName }}Topic(Topic topic) {
super(topic.m_inst, topic.m_handle);
}
/**
* Constructor; use NetworkTableInstance.get{{TypeName}}Topic() instead.
*
* @param inst Instance
* @param handle Native handle
*/
public {{ TypeName }}Topic(NetworkTableInstance inst, int handle) {
super(inst, handle);
}
/**
* Create a new subscriber to the topic.
*
* <p>The subscriber is only active as long as the returned object
* is not closed.
*
* <p>Subscribers that do not match the published data type do not return
* any values. To determine if the data type matches, use the appropriate
* Topic functions.
*
{%- if not TypeString %}
* @param typeString type string
{% endif %}
* @param defaultValue default value used when a default is not provided to a
* getter function
* @param options subscribe options
* @return subscriber
*/
public {{ TypeName }}Subscriber subscribe(
{%- if not TypeString %}
String typeString,
{% endif %}
{{ java.ValueType }} defaultValue,
PubSubOption... options) {
return new {{ TypeName }}EntryImpl(
this,
NetworkTablesJNI.subscribe(
m_handle, NetworkTableType.k{{ TypeName }}.getValue(),
{{ TypeString|default('typeString') }}, options),
defaultValue);
}
{% if TypeString %}
/**
* Create a new subscriber to the topic, with specified type string.
*
* <p>The subscriber is only active as long as the returned object
* is not closed.
*
* <p>Subscribers that do not match the published data type do not return
* any values. To determine if the data type matches, use the appropriate
* Topic functions.
*
* @param typeString type string
* @param defaultValue default value used when a default is not provided to a
* getter function
* @param options subscribe options
* @return subscriber
*/
public {{ TypeName }}Subscriber subscribeEx(
String typeString,
{{ java.ValueType }} defaultValue,
PubSubOption... options) {
return new {{ TypeName }}EntryImpl(
this,
NetworkTablesJNI.subscribe(
m_handle, NetworkTableType.k{{ TypeName }}.getValue(),
typeString, options),
defaultValue);
}
{% endif %}
/**
* Create a new publisher to the topic.
*
* <p>The publisher is only active as long as the returned object
* is not closed.
*
* <p>It is not possible to publish two different data types to the same
* topic. Conflicts between publishers are typically resolved by the server on
* a first-come, first-served basis. Any published values that do not match
* the topic's data type are dropped (ignored). To determine if the data type
* matches, use the appropriate Topic functions.
*
{%- if not TypeString %}
* @param typeString type string
{% endif %}
* @param options publish options
* @return publisher
*/
public {{ TypeName }}Publisher publish(
{%- if not TypeString %}
String typeString,
{% endif %}
PubSubOption... options) {
return new {{ TypeName }}EntryImpl(
this,
NetworkTablesJNI.publish(
m_handle, NetworkTableType.k{{ TypeName }}.getValue(),
{{ TypeString|default('typeString') }}, options),
{{ java.EmptyValue }});
}
/**
* Create a new publisher to the topic, with type string and initial properties.
*
* <p>The publisher is only active as long as the returned object
* is not closed.
*
* <p>It is not possible to publish two different data types to the same
* topic. Conflicts between publishers are typically resolved by the server on
* a first-come, first-served basis. Any published values that do not match
* the topic's data type are dropped (ignored). To determine if the data type
* matches, use the appropriate Topic functions.
*
* @param typeString type string
* @param properties JSON properties
* @param options publish options
* @return publisher
*/
public {{ TypeName }}Publisher publishEx(
String typeString,
String properties,
PubSubOption... options) {
return new {{ TypeName }}EntryImpl(
this,
NetworkTablesJNI.publishEx(
m_handle, NetworkTableType.k{{ TypeName }}.getValue(),
typeString, properties, options),
{{ java.EmptyValue }});
}
/**
* Create a new entry for the topic.
*
* <p>Entries act as a combination of a subscriber and a weak publisher. The
* subscriber is active as long as the entry is not closed. The publisher is
* created when the entry is first written to, and remains active until either
* unpublish() is called or the entry is closed.
*
* <p>It is not possible to use two different data types with the same
* topic. Conflicts between publishers are typically resolved by the server on
* a first-come, first-served basis. Any published values that do not match
* the topic's data type are dropped (ignored), and the entry will show no new
* values if the data type does not match. To determine if the data type
* matches, use the appropriate Topic functions.
*
{%- if not TypeString %}
* @param typeString type string
{% endif %}
* @param defaultValue default value used when a default is not provided to a
* getter function
* @param options publish and/or subscribe options
* @return entry
*/
public {{ TypeName }}Entry getEntry(
{%- if not TypeString %}
String typeString,
{% endif %}
{{ java.ValueType }} defaultValue,
PubSubOption... options) {
return new {{ TypeName }}EntryImpl(
this,
NetworkTablesJNI.getEntry(
m_handle, NetworkTableType.k{{ TypeName }}.getValue(),
{{ TypeString|default('typeString') }}, options),
defaultValue);
}
{% if TypeString %}
/**
* Create a new entry for the topic, with specified type string.
*
* <p>Entries act as a combination of a subscriber and a weak publisher. The
* subscriber is active as long as the entry is not closed. The publisher is
* created when the entry is first written to, and remains active until either
* unpublish() is called or the entry is closed.
*
* <p>It is not possible to use two different data types with the same
* topic. Conflicts between publishers are typically resolved by the server on
* a first-come, first-served basis. Any published values that do not match
* the topic's data type are dropped (ignored), and the entry will show no new
* values if the data type does not match. To determine if the data type
* matches, use the appropriate Topic functions.
*
* @param typeString type string
* @param defaultValue default value used when a default is not provided to a
* getter function
* @param options publish and/or subscribe options
* @return entry
*/
public {{ TypeName }}Entry getEntryEx(
String typeString,
{{ java.ValueType }} defaultValue,
PubSubOption... options) {
return new {{ TypeName }}EntryImpl(
this,
NetworkTablesJNI.getEntry(
m_handle, NetworkTableType.k{{ TypeName }}.getValue(),
typeString, options),
defaultValue);
}
{% endif %}
}