diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..97b12d00e3 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "networktables/ntcore"] + path = networktables/ntcore + url = ../ntcore diff --git a/CMakeLists.txt b/CMakeLists.txt index 45bc24cb53..9c66469d0e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,3 +57,4 @@ include_directories("build") add_subdirectory(simulation/gz_msgs) add_subdirectory(wpilibc/wpilibC++Sim) add_subdirectory(simulation/frc_gazebo_plugins) +add_subdirectory(networktables/ntcore) diff --git a/networktables/OutlineViewer/build.gradle b/networktables/OutlineViewer/build.gradle index 6bcbe75891..57df0727d8 100644 --- a/networktables/OutlineViewer/build.gradle +++ b/networktables/OutlineViewer/build.gradle @@ -34,6 +34,6 @@ sourceSets { } dependencies { - compile project(":networktables:java") + compile project(":networktables:ntcore") compile 'uk.gov.nationalarchives.thirdparty.netbeans:org-netbeans-swing-outline:7.2' } diff --git a/networktables/OutlineViewer/src/main/java/edu/wpi/first/tableviewer/AbstractTreeNode.java b/networktables/OutlineViewer/src/main/java/edu/wpi/first/tableviewer/AbstractTreeNode.java index f491d47aed..00d0697ff2 100644 --- a/networktables/OutlineViewer/src/main/java/edu/wpi/first/tableviewer/AbstractTreeNode.java +++ b/networktables/OutlineViewer/src/main/java/edu/wpi/first/tableviewer/AbstractTreeNode.java @@ -5,8 +5,7 @@ package edu.wpi.first.tableviewer; import edu.wpi.first.wpilibj.tables.ITable; -import edu.wpi.first.wpilibj.networktables.NetworkTableProvider; -import edu.wpi.first.wpilibj.networktables2.NetworkTableNode; +import edu.wpi.first.wpilibj.networktables.NetworkTable; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import org.netbeans.swing.outline.Outline; @@ -30,13 +29,13 @@ public abstract class AbstractTreeNode extends DefaultMutableTreeNode { AbstractTreeNode.outline = outline; } - public AbstractTreeNode(NetworkTableNode node, String key, TableEntryData data) { + public AbstractTreeNode(String key, TableEntryData data) { super(data); this.data = data; if (treeModel != null) { treeModel.reload(this); } - table = new NetworkTableProvider(node).getTable(key); + table = NetworkTable.getTable(key); } /** diff --git a/networktables/OutlineViewer/src/main/java/edu/wpi/first/tableviewer/BranchNode.java b/networktables/OutlineViewer/src/main/java/edu/wpi/first/tableviewer/BranchNode.java index eafce855c1..601d0ea904 100644 --- a/networktables/OutlineViewer/src/main/java/edu/wpi/first/tableviewer/BranchNode.java +++ b/networktables/OutlineViewer/src/main/java/edu/wpi/first/tableviewer/BranchNode.java @@ -8,7 +8,6 @@ import edu.wpi.first.tableviewer.dialog.AddArrayDialog; import edu.wpi.first.tableviewer.dialog.AddBooleanDialog; import edu.wpi.first.tableviewer.dialog.AddNumberDialog; import edu.wpi.first.tableviewer.dialog.AddStringDialog; -import edu.wpi.first.wpilibj.networktables2.NetworkTableNode; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JMenuItem; @@ -25,8 +24,8 @@ public class BranchNode extends AbstractTreeNode { private final String name; - public BranchNode(NetworkTableNode node, String key, String name) { - super(node, key, new TableEntryData(name, null)); + public BranchNode(String key, String name) { + super(key, new TableEntryData(name, null)); this.name = name; } diff --git a/networktables/OutlineViewer/src/main/java/edu/wpi/first/tableviewer/LeafNode.java b/networktables/OutlineViewer/src/main/java/edu/wpi/first/tableviewer/LeafNode.java index 9d7bf44239..561b677a75 100644 --- a/networktables/OutlineViewer/src/main/java/edu/wpi/first/tableviewer/LeafNode.java +++ b/networktables/OutlineViewer/src/main/java/edu/wpi/first/tableviewer/LeafNode.java @@ -4,8 +4,7 @@ */ package edu.wpi.first.tableviewer; -import edu.wpi.first.wpilibj.networktables.NetworkTableProvider; -import edu.wpi.first.wpilibj.networktables2.NetworkTableNode; +import edu.wpi.first.wpilibj.networktables.NetworkTable; import javax.swing.event.TableModelEvent; /** @@ -16,9 +15,9 @@ import javax.swing.event.TableModelEvent; */ public class LeafNode extends AbstractTreeNode { - public LeafNode(NetworkTableNode node, String key, TableEntryData data) { - super(node, key, data); - table = new NetworkTableProvider(node).getTable(key.substring(0, key.lastIndexOf('/'))); + public LeafNode(String key, TableEntryData data) { + super(key, data); + table = NetworkTable.getTable(key.substring(0, key.lastIndexOf('/'))); } /** diff --git a/networktables/OutlineViewer/src/main/java/edu/wpi/first/tableviewer/OutlineFrame.java b/networktables/OutlineViewer/src/main/java/edu/wpi/first/tableviewer/OutlineFrame.java index ec5f2eba4e..d635a0ad3e 100644 --- a/networktables/OutlineViewer/src/main/java/edu/wpi/first/tableviewer/OutlineFrame.java +++ b/networktables/OutlineViewer/src/main/java/edu/wpi/first/tableviewer/OutlineFrame.java @@ -6,7 +6,7 @@ package edu.wpi.first.tableviewer; import edu.wpi.first.tableviewer.TableEntryData.EntryType; import edu.wpi.first.tableviewer.dialog.AbstractAddDialog; -import edu.wpi.first.wpilibj.networktables2.NetworkTableNode; +import edu.wpi.first.wpilibj.networktables.NetworkTable; import edu.wpi.first.wpilibj.tables.ITable; import edu.wpi.first.wpilibj.tables.ITableListener; import java.awt.BorderLayout; @@ -29,18 +29,16 @@ public class OutlineFrame extends JFrame implements ITableListener { private final Outline outline; private final BranchNode rootBranch; - private final NetworkTableNode node; private final boolean showMetadata; private final Preferences prefs = Preferences.userNodeForPackage(getClass()); - public OutlineFrame(String title, NetworkTableNode node, boolean showMetadata) { - this.node = node; + public OutlineFrame(String title, boolean showMetadata) { this.showMetadata = showMetadata; setTitle(title); setDefaultCloseOperation(EXIT_ON_CLOSE); - rootBranch = new BranchNode(node, "", "Root"); + rootBranch = new BranchNode("", "Root"); DefaultTreeModel outlineTreeModel = new DefaultTreeModel(rootBranch); OutlineModel outlineModel = DefaultOutlineModel.createOutlineModel( @@ -99,7 +97,7 @@ public class OutlineFrame extends JFrame implements ITableListener { scrollPane.setViewportView(outline); add(scrollPane, BorderLayout.CENTER); - node.addTableListener(this, true); + NetworkTable.getTable("").addTableListener(this, true); } @@ -125,7 +123,7 @@ public class OutlineFrame extends JFrame implements ITableListener { key += "/" + name; if (subTableNames.getLast() == name) { // leaf if (currentNode == null) { - currentNode = new LeafNode(node, key, new TableEntryData(name, value)); + currentNode = new LeafNode(key, new TableEntryData(name, value)); if (currentNode.data.isMetadata() && !showMetadata) { // don't show metadata directly // instead, show the value in the branch's "Type" field @@ -140,7 +138,7 @@ public class OutlineFrame extends JFrame implements ITableListener { } } else if (currentNode == null) { - currentNode = new BranchNode(node, key, name); + currentNode = new BranchNode(key, name); parentNode.add(currentNode); } } diff --git a/networktables/OutlineViewer/src/main/java/edu/wpi/first/tableviewer/dialog/AddArrayDialog.java b/networktables/OutlineViewer/src/main/java/edu/wpi/first/tableviewer/dialog/AddArrayDialog.java index 6a139a9597..842d96814f 100644 --- a/networktables/OutlineViewer/src/main/java/edu/wpi/first/tableviewer/dialog/AddArrayDialog.java +++ b/networktables/OutlineViewer/src/main/java/edu/wpi/first/tableviewer/dialog/AddArrayDialog.java @@ -4,12 +4,8 @@ */ package edu.wpi.first.tableviewer.dialog; -import edu.wpi.first.wpilibj.networktables.NetworkTable; -import edu.wpi.first.wpilibj.networktables2.type.ArrayData; -import edu.wpi.first.wpilibj.networktables2.type.BooleanArray; -import edu.wpi.first.wpilibj.networktables2.type.NumberArray; -import edu.wpi.first.wpilibj.networktables2.type.StringArray; import edu.wpi.first.wpilibj.tables.ITable; +import java.util.ArrayList; import javax.swing.DefaultCellEditor; import javax.swing.JComboBox; import javax.swing.JOptionPane; @@ -219,60 +215,78 @@ public class AddArrayDialog extends AbstractAddDialog { } /** - * Creates a new {@code ArrayData} object containing the values in the - * table, which will then be put into the {@link NetworkTable} associated + * Creates a new array object containing the values in the + * table, which will then be put into the Network Table associated * with this dialog. * * @param arrayType The type of array: Boolean, Number, or String. - * @return An {@link ArrayData} object containing the data in the table, or + * @return An array object containing the data in the table, or * null if an error is present in the table (such as an invalid double * value). */ - private ArrayData createArrayData(String arrayType) { - ArrayData ad; + private Object createArrayData(String arrayType) { + int n = 0; + for (int i = 0; i < valueTable.getRowCount(); i++) { + Object data = valueTable.getValueAt(i, 0); + if (data != null) { + n++; + } + } switch (arrayType) { case "Boolean": - ad = new BooleanArray(); - for (int i = 0; i < valueTable.getRowCount(); i++) { - Object data = valueTable.getValueAt(i, 0); - if (data != null) { - ((BooleanArray) ad).add(data.toString().equalsIgnoreCase("true")); - } - } - break; - case "Number": - ad = new NumberArray(); - for (int i = 0; i < valueTable.getRowCount(); i++) { - Object data = valueTable.getValueAt(i, 0); - try { + { + boolean[] arr = new boolean[n]; + n = 0; + for (int i = 0; i < valueTable.getRowCount(); i++) { + Object data = valueTable.getValueAt(i, 0); if (data != null) { - Double d = Double.parseDouble(data.toString()); - ((NumberArray) ad).add(d); + arr[n] = data.toString().equalsIgnoreCase("true"); + n++; } - } catch (NumberFormatException e) { - JOptionPane.showMessageDialog( - this, - "Invalid double value \"" + data + "\" in row " + (i + 1), - "Invalid number", - JOptionPane.ERROR_MESSAGE); - return null; } + return arr; + } + + case "Number": + { + double[] arr = new double[n]; + n = 0; + for (int i = 0; i < valueTable.getRowCount(); i++) { + Object data = valueTable.getValueAt(i, 0); + try { + if (data != null) { + arr[n] = Double.parseDouble(data.toString()); + n++; + } + } catch (NumberFormatException e) { + JOptionPane.showMessageDialog( + this, + "Invalid double value \"" + data + "\" in row " + (i + 1), + "Invalid number", + JOptionPane.ERROR_MESSAGE); + return null; + } + } + return arr; } - break; case "String": - ad = new StringArray(); - for (int i = 0; i < valueTable.getRowCount(); i++) { - Object data = valueTable.getValueAt(i, 0); - if (data != null) { - ((StringArray) ad).add(data.toString()); + { + String[] arr = new String[n]; + n = 0; + for (int i = 0; i < valueTable.getRowCount(); i++) { + Object data = valueTable.getValueAt(i, 0); + if (data != null) { + arr[n] = data.toString(); + n++; + } } + return arr; } - break; + default: throw new IllegalArgumentException(arrayType + " is not a valid array type"); } - return ad; } // Variables declaration - do not modify private javax.swing.JButton addRowButton; diff --git a/networktables/OutlineViewer/src/main/java/edu/wpi/first/tableviewer/dialog/PreferencesDialog.java b/networktables/OutlineViewer/src/main/java/edu/wpi/first/tableviewer/dialog/PreferencesDialog.java index 5f3e729cfe..591b020ef5 100644 --- a/networktables/OutlineViewer/src/main/java/edu/wpi/first/tableviewer/dialog/PreferencesDialog.java +++ b/networktables/OutlineViewer/src/main/java/edu/wpi/first/tableviewer/dialog/PreferencesDialog.java @@ -2,12 +2,8 @@ package edu.wpi.first.tableviewer.dialog; import edu.wpi.first.tableviewer.OutlineFrame; -import edu.wpi.first.wpilibj.networktables2.NetworkTableNode; -import edu.wpi.first.wpilibj.networktables2.client.NetworkTableClient; -import edu.wpi.first.wpilibj.networktables2.server.NetworkTableServer; -import edu.wpi.first.wpilibj.networktables2.stream.IOStreamFactory; -import edu.wpi.first.wpilibj.networktables2.stream.IOStreamProvider; -import edu.wpi.first.wpilibj.networktables2.stream.SocketStreams; +import edu.wpi.first.wpilibj.networktables.NetworkTable; +import edu.wpi.first.wpilibj.networktables.NetworkTablesJNI; import java.util.prefs.Preferences; import javax.swing.JOptionPane; @@ -114,24 +110,28 @@ public class PreferencesDialog extends javax.swing.JDialog { private void startButtonPressed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_startButtonPressed try { - NetworkTableNode node; + NetworkTablesJNI.setLogger(new NetworkTablesJNI.LoggerFunction() { + public void apply(int level, String file, int line, String msg) { + System.err.println(msg); + } + }, 0); if (evt.getSource() == clientButton) { // start client String host = hostField.getText(); if (host.isEmpty()) { return; } - IOStreamFactory streamFactory = SocketStreams.newStreamFactory(host, 1735); - NetworkTableClient client = new NetworkTableClient(streamFactory); - client.reconnect(); - node = client; + NetworkTable.setIPAddress(host); + NetworkTable.setClientMode(); + NetworkTable.initialize(); prefs.put("host", host); } else { // start server - IOStreamProvider streamProvider = SocketStreams.newStreamProvider(1735); - node = new NetworkTableServer(streamProvider); + NetworkTable.setIPAddress(""); + NetworkTable.setServerMode(); + NetworkTable.initialize(); prefs.put("host", ""); } prefs.putBoolean("metadata", metadataBox.isSelected()); - new OutlineFrame("Network Table Viewer", node, metadataBox.isSelected()).setVisible(true); + new OutlineFrame("Network Table Viewer", metadataBox.isSelected()).setVisible(true); dispose(); } catch (Exception e) { JOptionPane.showMessageDialog(null, e.getClass() + ": " + e.getMessage(), "Error creating table node", JOptionPane.ERROR_MESSAGE); diff --git a/networktables/ntcore b/networktables/ntcore new file mode 160000 index 0000000000..e42f9b0603 --- /dev/null +++ b/networktables/ntcore @@ -0,0 +1 @@ +Subproject commit e42f9b060315a9d5e29b0105813a620133754eca diff --git a/ni-libraries/libwpi_2015.so b/ni-libraries/libwpi_2015.so index 3589af2ceb..06dcbe4c85 100644 --- a/ni-libraries/libwpi_2015.so +++ b/ni-libraries/libwpi_2015.so @@ -1,3 +1,3 @@ /* GNU ld script */ OUTPUT_FORMAT(elf32-littlearm) -GROUP ( AS_NEEDED ( -lwpilib_nonshared -lHALAthena -lNetworkTables -lFRC_NetworkCommunication -li2c -lni_emb -lNiFpgaLv -lNiFpga -lnirio_emb_can -lNiRioSrv -lni_rtlog -lRoboRIO_FRC_ChipObject -lspi -lvisa -ldl -lpthread -lrt -lGCBase_gcc-4.4-arm_v2_3 -lGenApi_gcc-4.4-arm_v2_3 -lLog_gcc-4.4-arm_v2_3 -lMathParser_gcc-4.4-arm_v2_3 -llog4cpp_gcc-4.4-arm_v2_3 -lniimaqdx -lnivision -lnivissvc ) ) +GROUP ( AS_NEEDED ( -lwpilib_nonshared -lHALAthena -lntcore -lFRC_NetworkCommunication -li2c -lni_emb -lNiFpgaLv -lNiFpga -lnirio_emb_can -lNiRioSrv -lni_rtlog -lRoboRIO_FRC_ChipObject -lspi -lvisa -ldl -lpthread -lrt -lGCBase_gcc-4.4-arm_v2_3 -lGenApi_gcc-4.4-arm_v2_3 -lLog_gcc-4.4-arm_v2_3 -lMathParser_gcc-4.4-arm_v2_3 -llog4cpp_gcc-4.4-arm_v2_3 -lniimaqdx -lnivision -lnivissvc ) ) diff --git a/settings.gradle b/settings.gradle index 0b8394c4a3..1edf81a743 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,5 +1,4 @@ -include 'networktables:java', - 'networktables:cpp', +include 'networktables:ntcore', 'networktables:OutlineViewer', 'hal', 'wpilibj', @@ -7,4 +6,4 @@ include 'networktables:java', 'simulation:JavaGazebo', 'simulation:SimDS', 'jenkins', - 'driver-station' \ No newline at end of file + 'driver-station' diff --git a/wpilibc/build.gradle b/wpilibc/build.gradle index cb5881e76e..4cb6f8aa2b 100644 --- a/wpilibc/build.gradle +++ b/wpilibc/build.gradle @@ -18,7 +18,7 @@ def sim = 'wpilibC++Sim' // Ensure that both hal and networktables are evaluated, so that they have the binaries property. We need this to // properly copy their archives into the final zip evaluationDependsOn(':hal') -evaluationDependsOn(':networktables:cpp') +evaluationDependsOn(':networktables:ntcore') publishing { publications { @@ -57,7 +57,7 @@ model { includes = ['**/*.h'] } lib project: ':hal', library: 'HALAthena', linkage: 'static' - lib project: ':networktables:cpp', library: 'NetworkTables', linkage: 'static' + lib project: ':networktables:ntcore', library: 'ntcore', linkage: 'static' } } } @@ -86,12 +86,12 @@ model { include 'gtest-all.cc', 'gtest_main.cc' } exportedHeaders { - srcDirs = ["${dir}/include", "${dir}/src/gtest", "${dir}/src/gtest/include", "${devices}/include", "${shared}/include", '../hal/include/HAL', '../networktables/cpp/include'] + srcDirs = ["${dir}/include", "${dir}/src/gtest", "${dir}/src/gtest/include", "${devices}/include", "${shared}/include", '../hal/include/HAL', '../networktables/ntcore/include'] include '**/*.h' } lib library: 'wpilib_nonshared', linkage: 'static' - lib project: ':networktables:cpp', library: 'NetworkTables', linkage: 'static' + lib project: ':networktables:ntcore', library: 'ntcore', linkage: 'static' lib project: ':hal', library: 'HALAthena', linkage: 'static' } } @@ -104,7 +104,7 @@ doxygen { source file("${shared}/include") source file("${devices}/src") source file("${devices}/include") - def netTablesLoc = '../networktables/cpp' + def netTablesLoc = '../networktables/ntcore' source file("${netTablesLoc}/include") source file("${netTablesLoc}/lib/Athena") source file("${netTablesLoc}/lib/share") @@ -139,7 +139,7 @@ task wpilibcZip(type: Zip) { } // Include the static library file and header files from the networktables project - def netTables = project(':networktables:cpp') + def netTables = project(':networktables:ntcore') netTables.binaries.withType(StaticLibraryBinarySpec) { spec -> spec.headerDirs.each { from(it) { @@ -190,7 +190,7 @@ task wpilibcSimZip(type: Zip) { from "${sim}/include" from "${shared}/include" from "../build/simulation/gz_msgs/generated" - from '../networktables/cpp/include' + from '../networktables/ntcore/include' from '../hal/include' } @@ -204,7 +204,7 @@ tasks.whenTaskAdded { task -> } // Add the networktables static library as a dependency -project(':networktables:cpp').tasks.whenTaskAdded { task -> +project(':networktables:ntcore').tasks.whenTaskAdded { task -> if (task.name == 'networkTablesStaticLibrary') { wpilibcZip.dependsOn task } diff --git a/wpilibc/wpilibC++/include/Commands/Command.h b/wpilibc/wpilibC++/include/Commands/Command.h index 815399d711..5497701109 100644 --- a/wpilibc/wpilibC++/include/Commands/Command.h +++ b/wpilibc/wpilibC++/include/Commands/Command.h @@ -10,6 +10,7 @@ #include "ErrorBase.h" #include "SmartDashboard/NamedSendable.h" +#include "tables/ITableListener.h" #include #include #include @@ -179,8 +180,8 @@ class Command : public ErrorBase, public NamedSendable, public ITableListener { virtual void InitTable(std::shared_ptr table); virtual std::shared_ptr GetTable() const; virtual std::string GetSmartDashboardType() const; - virtual void ValueChanged(std::shared_ptr source, const std::string &key, - EntryValue value, bool isNew); + virtual void ValueChanged(ITable* source, llvm::StringRef key, + std::shared_ptr value, bool isNew); protected: std::shared_ptr m_table = nullptr; diff --git a/wpilibc/wpilibC++/include/Commands/Scheduler.h b/wpilibc/wpilibC++/include/Commands/Scheduler.h index 200c9517e2..1bd4affc03 100644 --- a/wpilibc/wpilibC++/include/Commands/Scheduler.h +++ b/wpilibc/wpilibC++/include/Commands/Scheduler.h @@ -12,13 +12,12 @@ #include "ErrorBase.h" #include "SmartDashboard/NamedSendable.h" #include "networktables/NetworkTable.h" -#include "networktables2/type/NumberArray.h" -#include "networktables2/type/StringArray.h" #include "SmartDashboard/SmartDashboard.h" #include #include #include #include +#include #include #include "HAL/cpp/priority_mutex.h" @@ -62,9 +61,9 @@ class Scheduler : public ErrorBase, public NamedSendable { CommandSet m_commands; bool m_adding = false; bool m_enabled = true; - StringArray *commands = nullptr; - NumberArray *ids = nullptr; - NumberArray *toCancel = nullptr; + std::vector commands; + std::vector ids; + std::vector toCancel; std::shared_ptr m_table = nullptr; bool m_runningCommandsChanged = false; }; diff --git a/wpilibc/wpilibC++/include/LiveWindow/LiveWindowStatusListener.h b/wpilibc/wpilibC++/include/LiveWindow/LiveWindowStatusListener.h index 6f06c0e220..4fa3eb7f60 100644 --- a/wpilibc/wpilibC++/include/LiveWindow/LiveWindowStatusListener.h +++ b/wpilibc/wpilibC++/include/LiveWindow/LiveWindowStatusListener.h @@ -6,8 +6,8 @@ class LiveWindowStatusListener : public ITableListener { public: - virtual void ValueChanged(std::shared_ptr source, const std::string& key, - EntryValue value, bool isNew); + virtual void ValueChanged(ITable* source, llvm::StringRef key, + std::shared_ptr value, bool isNew); }; #endif diff --git a/wpilibc/wpilibC++/include/PIDController.h b/wpilibc/wpilibC++/include/PIDController.h index 2994216d73..cc20c457a0 100644 --- a/wpilibc/wpilibC++/include/PIDController.h +++ b/wpilibc/wpilibC++/include/PIDController.h @@ -36,7 +36,7 @@ class PIDController : public LiveWindowSendable, float period = 0.05); PIDController(float p, float i, float d, float f, PIDSource *source, PIDOutput *output, float period = 0.05); - virtual ~PIDController() = default; + virtual ~PIDController(); PIDController(const PIDController&) = delete; PIDController& operator=(const PIDController) = delete; @@ -124,8 +124,9 @@ class PIDController : public LiveWindowSendable, virtual std::shared_ptr GetTable() const override; virtual std::string GetSmartDashboardType() const override; - virtual void ValueChanged(std::shared_ptr source, const std::string &key, - EntryValue value, bool isNew) override; + virtual void ValueChanged(ITable *source, llvm::StringRef key, + std::shared_ptr value, + bool isNew) override; virtual void UpdateTable() override; virtual void StartLiveWindowMode() override; virtual void StopLiveWindowMode() override; diff --git a/wpilibc/wpilibC++/include/SmartDashboard/SmartDashboard.h b/wpilibc/wpilibC++/include/SmartDashboard/SmartDashboard.h index 1b7e6840ec..a1cfb22d25 100644 --- a/wpilibc/wpilibC++/include/SmartDashboard/SmartDashboard.h +++ b/wpilibc/wpilibC++/include/SmartDashboard/SmartDashboard.h @@ -19,25 +19,23 @@ class SmartDashboard : public SensorBase { public: static void init(); - static void PutData(std::string key, Sendable *data); + static void PutData(llvm::StringRef key, Sendable *data); static void PutData(NamedSendable *value); - static Sendable *GetData(std::string keyName); + static Sendable *GetData(llvm::StringRef keyName); - static void PutBoolean(std::string keyName, bool value); - static bool GetBoolean(std::string keyName); - static bool GetBoolean(std::string keyName, bool defaultValue); + static void PutBoolean(llvm::StringRef keyName, bool value); + static bool GetBoolean(llvm::StringRef keyName, bool defaultValue); - static void PutNumber(std::string keyName, double value); - static double GetNumber(std::string keyName); - static double GetNumber(std::string keyName, double defaultValue); + static void PutNumber(llvm::StringRef keyName, double value); + static double GetNumber(llvm::StringRef keyName, double defaultValue); - static void PutString(std::string keyName, std::string value); - static int GetString(std::string keyName, char *value, unsigned int valueLen); - static std::string GetString(std::string keyName); - static std::string GetString(std::string keyName, std::string defaultValue); + static void PutString(llvm::StringRef keyName, llvm::StringRef value); + static std::string GetString(llvm::StringRef keyName, + llvm::StringRef defaultValue); - static void PutValue(std::string keyName, ComplexData &value); - static void RetrieveValue(std::string keyName, ComplexData &value); + static void PutValue(llvm::StringRef keyName, + std::shared_ptr value); + static std::shared_ptr GetValue(llvm::StringRef keyName); private: virtual ~SmartDashboard() = default; diff --git a/wpilibc/wpilibC++/src/Buttons/NetworkButton.cpp b/wpilibc/wpilibC++/src/Buttons/NetworkButton.cpp index 1e90ced31b..858703cf49 100644 --- a/wpilibc/wpilibC++/src/Buttons/NetworkButton.cpp +++ b/wpilibc/wpilibC++/src/Buttons/NetworkButton.cpp @@ -21,5 +21,5 @@ bool NetworkButton::Get() { return m_netTable->GetBoolean(m_field.c_str()); else return false;*/ - return m_netTable->GetBoolean(m_field); + return m_netTable->GetBoolean(m_field, false); } diff --git a/wpilibc/wpilibC++/src/Buttons/Trigger.cpp b/wpilibc/wpilibC++/src/Buttons/Trigger.cpp index 5a17645af5..54a1eba08e 100644 --- a/wpilibc/wpilibC++/src/Buttons/Trigger.cpp +++ b/wpilibc/wpilibC++/src/Buttons/Trigger.cpp @@ -18,7 +18,7 @@ bool Trigger::Grab() { return true; else if (m_table != nullptr) { // if (m_table->isConnected())//TODO is connected on button? - return m_table->GetBoolean("pressed"); + return m_table->GetBoolean("pressed", false); /*else return false;*/ } else diff --git a/wpilibc/wpilibC++/src/Commands/Command.cpp b/wpilibc/wpilibC++/src/Commands/Command.cpp index 38c2f26598..37effbe5b7 100644 --- a/wpilibc/wpilibC++/src/Commands/Command.cpp +++ b/wpilibc/wpilibC++/src/Commands/Command.cpp @@ -60,10 +60,8 @@ Command::Command(const std::string &name, double timeout) { } } -Command::~Command() { // TODO deal with cleaning up all listeners - /*if (m_table != nullptr){ - m_table->RemoveChangeListener(kRunning, this); - }*/ +Command::~Command() { + if (m_table != nullptr) m_table->RemoveTableListener(this); } /** @@ -383,9 +381,10 @@ void Command::InitTable(std::shared_ptr table) { std::shared_ptr Command::GetTable() const { return m_table; } -void Command::ValueChanged(std::shared_ptr source, const std::string &key, - EntryValue value, bool isNew) { - if (value.b) { +void Command::ValueChanged(ITable* source, llvm::StringRef key, + std::shared_ptr value, bool isNew) { + if (!value->IsBoolean()) return; + if (value->GetBoolean()) { if (!IsRunning()) Start(); } else { if (IsRunning()) Cancel(); diff --git a/wpilibc/wpilibC++/src/Commands/Scheduler.cpp b/wpilibc/wpilibC++/src/Commands/Scheduler.cpp index caeeff273e..2980f233a0 100644 --- a/wpilibc/wpilibC++/src/Commands/Scheduler.cpp +++ b/wpilibc/wpilibC++/src/Commands/Scheduler.cpp @@ -217,37 +217,41 @@ void Scheduler::UpdateTable() { CommandSet::iterator commandIter; if (m_table != nullptr) { // Get the list of possible commands to cancel - m_table->RetrieveValue("Cancel", *toCancel); + auto new_toCancel = m_table->GetValue("Cancel"); + if (new_toCancel) + toCancel = new_toCancel->GetDoubleArray(); + else + toCancel.resize(0); // m_table->RetrieveValue("Ids", *ids); // cancel commands that have had the cancel buttons pressed // on the SmartDashboad - if (toCancel->size() > 0) { + if (!toCancel.empty()) { for (commandIter = m_commands.begin(); commandIter != m_commands.end(); ++commandIter) { - for (unsigned i = 0; i < toCancel->size(); i++) { + for (unsigned i = 0; i < toCancel.size(); i++) { Command *c = *commandIter; - if (c->GetID() == toCancel->get(i)) { + if (c->GetID() == toCancel[i]) { c->Cancel(); } } } - toCancel->setSize(0); - m_table->PutValue("Cancel", *toCancel); + toCancel.resize(0); + m_table->PutValue("Cancel", nt::Value::MakeDoubleArray(toCancel)); } // Set the running commands if (m_runningCommandsChanged) { - commands->setSize(0); - ids->setSize(0); + commands.resize(0); + ids.resize(0); for (commandIter = m_commands.begin(); commandIter != m_commands.end(); ++commandIter) { Command *c = *commandIter; - commands->add(c->GetName()); - ids->add(c->GetID()); + commands.push_back(c->GetName()); + ids.push_back(c->GetID()); } - m_table->PutValue("Names", *commands); - m_table->PutValue("Ids", *ids); + m_table->PutValue("Names", nt::Value::MakeStringArray(commands)); + m_table->PutValue("Ids", nt::Value::MakeDoubleArray(ids)); } } } @@ -260,13 +264,10 @@ std::string Scheduler::GetSmartDashboardType() const { return "Scheduler"; } void Scheduler::InitTable(std::shared_ptr subTable) { m_table = subTable; - commands = new StringArray(); - ids = new NumberArray(); - toCancel = new NumberArray(); - m_table->PutValue("Names", *commands); - m_table->PutValue("Ids", *ids); - m_table->PutValue("Cancel", *toCancel); + m_table->PutValue("Names", nt::Value::MakeStringArray(commands)); + m_table->PutValue("Ids", nt::Value::MakeDoubleArray(ids)); + m_table->PutValue("Cancel", nt::Value::MakeDoubleArray(toCancel)); } std::shared_ptr Scheduler::GetTable() const { return m_table; } diff --git a/wpilibc/wpilibC++/src/LiveWindow/LiveWindow.cpp b/wpilibc/wpilibC++/src/LiveWindow/LiveWindow.cpp index 0d89620551..6984e48b7d 100644 --- a/wpilibc/wpilibC++/src/LiveWindow/LiveWindow.cpp +++ b/wpilibc/wpilibC++/src/LiveWindow/LiveWindow.cpp @@ -19,8 +19,8 @@ LiveWindow *LiveWindow::GetInstance() { * Allocate the necessary tables. */ LiveWindow::LiveWindow() : m_scheduler(Scheduler::GetInstance()) { - m_liveWindowTable.reset(NetworkTable::GetTable("LiveWindow")); - m_statusTable.reset(m_liveWindowTable->GetSubTable("~STATUS~")); + m_liveWindowTable = NetworkTable::GetTable("LiveWindow"); + m_statusTable = m_liveWindowTable->GetSubTable("~STATUS~"); } /** diff --git a/wpilibc/wpilibC++/src/LiveWindow/LiveWindowStatusListener.cpp b/wpilibc/wpilibC++/src/LiveWindow/LiveWindowStatusListener.cpp index 1d49ad909e..021798d76a 100644 --- a/wpilibc/wpilibC++/src/LiveWindow/LiveWindowStatusListener.cpp +++ b/wpilibc/wpilibC++/src/LiveWindow/LiveWindowStatusListener.cpp @@ -1,6 +1,6 @@ #include "LiveWindow/LiveWindowStatusListener.h" #include "Commands/Scheduler.h" -void LiveWindowStatusListener::ValueChanged(std::shared_ptr source, - const std::string& key, - EntryValue value, bool isNew) {} +void LiveWindowStatusListener::ValueChanged(ITable *source, llvm::StringRef key, + std::shared_ptr value, + bool isNew) {} diff --git a/wpilibc/wpilibC++/src/SmartDashboard/SendableChooser.cpp b/wpilibc/wpilibC++/src/SmartDashboard/SendableChooser.cpp index 49cb3e0c3d..255cc3af21 100644 --- a/wpilibc/wpilibC++/src/SmartDashboard/SendableChooser.cpp +++ b/wpilibc/wpilibC++/src/SmartDashboard/SendableChooser.cpp @@ -6,7 +6,6 @@ /*----------------------------------------------------------------------------*/ #include "SmartDashboard/SendableChooser.h" -#include "networktables2/type/StringArray.h" #include @@ -54,14 +53,14 @@ void *SendableChooser::GetSelected() { } void SendableChooser::InitTable(std::shared_ptr subtable) { - StringArray keys; + std::vector keys; m_table = subtable; if (m_table != nullptr) { std::map::iterator iter; for (iter = m_choices.begin(); iter != m_choices.end(); iter++) { - keys.add(iter->first); + keys.push_back(iter->first); } - m_table->PutValue(kOptions, keys); + m_table->PutValue(kOptions, nt::Value::MakeStringArray(std::move(keys))); m_table->PutString(kDefault, m_defaultChoice); } } diff --git a/wpilibc/wpilibC++/src/SmartDashboard/SmartDashboard.cpp b/wpilibc/wpilibC++/src/SmartDashboard/SmartDashboard.cpp index af4ed5f2dd..b6a38ae020 100644 --- a/wpilibc/wpilibC++/src/SmartDashboard/SmartDashboard.cpp +++ b/wpilibc/wpilibC++/src/SmartDashboard/SmartDashboard.cpp @@ -17,7 +17,7 @@ std::shared_ptr SmartDashboard::m_table = nullptr; std::map , Sendable *> SmartDashboard::m_tablesToData; void SmartDashboard::init() { - m_table.reset(NetworkTable::GetTable("SmartDashboard")); + m_table = NetworkTable::GetTable("SmartDashboard"); HLUsageReporting::ReportSmartDashboard(); } @@ -30,7 +30,7 @@ void SmartDashboard::init() { * @param keyName the key * @param value the value */ -void SmartDashboard::PutData(std::string key, Sendable *data) { +void SmartDashboard::PutData(llvm::StringRef key, Sendable *data) { if (data == nullptr) { wpi_setGlobalWPIErrorWithContext(NullParameter, "value"); return; @@ -62,11 +62,11 @@ void SmartDashboard::PutData(NamedSendable *value) { * @param keyName the key * @return the value */ -Sendable *SmartDashboard::GetData(std::string key) { +Sendable *SmartDashboard::GetData(llvm::StringRef key) { std::shared_ptr subtable(m_table->GetSubTable(key)); Sendable *data = m_tablesToData[subtable]; if (data == nullptr) { - wpi_setGlobalWPIErrorWithContext(SmartDashboardMissingKey, key.c_str()); + wpi_setGlobalWPIErrorWithContext(SmartDashboardMissingKey, key); return nullptr; } return data; @@ -81,7 +81,8 @@ Sendable *SmartDashboard::GetData(std::string key) { * @param keyName the key * @param value the value */ -void SmartDashboard::PutValue(std::string keyName, ComplexData &value) { +void SmartDashboard::PutValue(llvm::StringRef keyName, + std::shared_ptr value) { m_table->PutValue(keyName, value); } @@ -92,8 +93,8 @@ void SmartDashboard::PutValue(std::string keyName, ComplexData &value) { * @param keyName the key * @param value the object to retrieve the value into */ -void SmartDashboard::RetrieveValue(std::string keyName, ComplexData &value) { - m_table->RetrieveValue(keyName, value); +std::shared_ptr SmartDashboard::GetValue(llvm::StringRef keyName) { + return m_table->GetValue(keyName); } /** @@ -104,27 +105,17 @@ void SmartDashboard::RetrieveValue(std::string keyName, ComplexData &value) { * @param keyName the key * @param value the value */ -void SmartDashboard::PutBoolean(std::string keyName, bool value) { +void SmartDashboard::PutBoolean(llvm::StringRef keyName, bool value) { m_table->PutBoolean(keyName, value); } -/** - * Returns the value at the specified key. Throws an exception if the key is not - * found in the table - * @param keyName the key - * @return the value - */ -bool SmartDashboard::GetBoolean(std::string keyName) { - return m_table->GetBoolean(keyName); -} - /** * Returns the value at the specified key. If the key is not found, returns the * default value. * @param keyName the key * @return the value */ -bool SmartDashboard::GetBoolean(std::string keyName, bool defaultValue) { +bool SmartDashboard::GetBoolean(llvm::StringRef keyName, bool defaultValue) { return m_table->GetBoolean(keyName, defaultValue); } @@ -136,27 +127,17 @@ bool SmartDashboard::GetBoolean(std::string keyName, bool defaultValue) { * @param keyName the key * @param value the value */ -void SmartDashboard::PutNumber(std::string keyName, double value) { +void SmartDashboard::PutNumber(llvm::StringRef keyName, double value) { m_table->PutNumber(keyName, value); } -/** - * Returns the value at the specified key. Throws an exception if the key is not - * found in the table. - * @param keyName the key - * @return the value - */ -double SmartDashboard::GetNumber(std::string keyName) { - return m_table->GetNumber(keyName); -} - /** * Returns the value at the specified key. If the key is not found, returns the * default value. * @param keyName the key * @return the value */ -double SmartDashboard::GetNumber(std::string keyName, double defaultValue) { +double SmartDashboard::GetNumber(llvm::StringRef keyName, double defaultValue) { return m_table->GetNumber(keyName, defaultValue); } @@ -168,44 +149,17 @@ double SmartDashboard::GetNumber(std::string keyName, double defaultValue) { * @param keyName the key * @param value the value */ -void SmartDashboard::PutString(std::string keyName, std::string value) { +void SmartDashboard::PutString(llvm::StringRef keyName, llvm::StringRef value) { m_table->PutString(keyName, value); } -/** - * Returns the value at the specified key. - * @param keyName the key - * @param value the buffer to fill with the value - * @param valueLen the size of the buffer pointed to by value - * @return the length of the string - */ -int SmartDashboard::GetString(std::string keyName, char *outBuffer, - unsigned int bufferLen) { - std::string value = m_table->GetString(keyName); - unsigned int i; - for (i = 0; i < bufferLen - 1 && i < value.length(); ++i) - outBuffer[i] = (char)value.at(i); - outBuffer[i] = '\0'; - return i; -} - -/** - * Returns the value at the specified key. Throws an exception if the key is not - * found in the table - * @param keyName the key - * @return the value - */ -std::string SmartDashboard::GetString(std::string keyName) { - return m_table->GetString(keyName); -} - /** * Returns the value at the specified key. If the key is not found, returns the * default value. * @param keyName the key * @return the value */ -std::string SmartDashboard::GetString(std::string keyName, - std::string defaultValue) { +std::string SmartDashboard::GetString(llvm::StringRef keyName, + llvm::StringRef defaultValue) { return m_table->GetString(keyName, defaultValue); } diff --git a/wpilibc/wpilibC++Devices/CMakeLists.txt b/wpilibc/wpilibC++Devices/CMakeLists.txt index f73522cc50..22fe30aa02 100644 --- a/wpilibc/wpilibC++Devices/CMakeLists.txt +++ b/wpilibc/wpilibC++Devices/CMakeLists.txt @@ -4,7 +4,7 @@ project(WPILibC++Devices) file(GLOB_RECURSE SRC_FILES src/*.cpp) include_directories(include/ ${WPILIB_INCLUDES} ${HAL_API_INCLUDES} ${NWT_API_INCLUDES}) add_library(wpilib_nonshared STATIC ${SRC_FILES} ${COM_SRC_FILES}) -target_link_libraries(wpilib_nonshared HALAthena NetworkTables ${NI_LIBS}) +target_link_libraries(wpilib_nonshared HALAthena ntcore ${NI_LIBS}) INSTALL(TARGETS wpilib_nonshared ARCHIVE DESTINATION lib COMPONENT lib) INSTALL(DIRECTORY include DESTINATION ${CMAKE_INSTALL_PREFIX} COMPONENT headers) # lib/ c m gcc_s ld-linux diff --git a/wpilibc/wpilibC++Devices/include/CANJaguar.h b/wpilibc/wpilibC++Devices/include/CANJaguar.h index 6678933c2a..555557d338 100644 --- a/wpilibc/wpilibC++Devices/include/CANJaguar.h +++ b/wpilibc/wpilibC++Devices/include/CANJaguar.h @@ -14,7 +14,7 @@ #include "HAL/cpp/Semaphore.hpp" #include "HAL/HAL.hpp" #include "LiveWindow/LiveWindowSendable.h" -#include "tables/ITable.h" +#include "tables/ITableListener.h" #include "NetworkCommunication/CANSessionMux.h" #include "CAN/can_proto.h" @@ -232,8 +232,8 @@ class CANJaguar : public MotorSafety, std::unique_ptr m_safetyHelper; - void ValueChanged(std::shared_ptr source, const std::string &key, EntryValue value, - bool isNew) override; + void ValueChanged(ITable* source, llvm::StringRef key, + std::shared_ptr value, bool isNew) override; void UpdateTable() override; void StartLiveWindowMode() override; void StopLiveWindowMode() override; diff --git a/wpilibc/wpilibC++Devices/include/CANTalon.h b/wpilibc/wpilibC++Devices/include/CANTalon.h index 0c7ab779ec..3263174958 100644 --- a/wpilibc/wpilibC++Devices/include/CANTalon.h +++ b/wpilibc/wpilibC++Devices/include/CANTalon.h @@ -157,8 +157,8 @@ class CANTalon : public MotorSafety, double GetSetpoint() const override; // LiveWindow stuff. - void ValueChanged(std::shared_ptr source, const std::string &key, EntryValue value, - bool isNew) override; + void ValueChanged(ITable* source, llvm::StringRef key, + std::shared_ptr value, bool isNew) override; void UpdateTable() override; void StartLiveWindowMode() override; void StopLiveWindowMode() override; diff --git a/wpilibc/wpilibC++Devices/include/Compressor.h b/wpilibc/wpilibC++Devices/include/Compressor.h index 4afce9db84..7c3d73723e 100644 --- a/wpilibc/wpilibC++Devices/include/Compressor.h +++ b/wpilibc/wpilibC++Devices/include/Compressor.h @@ -50,8 +50,8 @@ class Compressor : public SensorBase, std::string GetSmartDashboardType() const override; void InitTable(std::shared_ptr subTable) override; std::shared_ptr GetTable() const override; - void ValueChanged(std::shared_ptr source, const std::string &key, EntryValue value, - bool isNew) override; + void ValueChanged(ITable* source, llvm::StringRef key, + std::shared_ptr value, bool isNew) override; protected: void *m_pcm_pointer; diff --git a/wpilibc/wpilibC++Devices/include/DigitalOutput.h b/wpilibc/wpilibC++Devices/include/DigitalOutput.h index 6236cd1631..1c0790caee 100644 --- a/wpilibc/wpilibC++Devices/include/DigitalOutput.h +++ b/wpilibc/wpilibC++Devices/include/DigitalOutput.h @@ -38,8 +38,8 @@ class DigitalOutput : public DigitalSource, virtual uint32_t GetModuleForRouting() const; virtual bool GetAnalogTriggerForRouting() const; - virtual void ValueChanged(std::shared_ptr source, const std::string &key, - EntryValue value, bool isNew); + virtual void ValueChanged(ITable* source, llvm::StringRef key, + std::shared_ptr value, bool isNew); void UpdateTable(); void StartLiveWindowMode(); void StopLiveWindowMode(); diff --git a/wpilibc/wpilibC++Devices/include/DoubleSolenoid.h b/wpilibc/wpilibC++Devices/include/DoubleSolenoid.h index 885880759e..949c1b40a5 100644 --- a/wpilibc/wpilibC++Devices/include/DoubleSolenoid.h +++ b/wpilibc/wpilibC++Devices/include/DoubleSolenoid.h @@ -34,8 +34,8 @@ class DoubleSolenoid : public SolenoidBase, bool IsFwdSolenoidBlackListed() const; bool IsRevSolenoidBlackListed() const; - void ValueChanged(std::shared_ptr source, const std::string& key, EntryValue value, - bool isNew); + void ValueChanged(ITable* source, llvm::StringRef key, + std::shared_ptr value, bool isNew); void UpdateTable(); void StartLiveWindowMode(); void StopLiveWindowMode(); diff --git a/wpilibc/wpilibC++Devices/include/PWM.h b/wpilibc/wpilibC++Devices/include/PWM.h index 578ed4013b..b99c61acfb 100644 --- a/wpilibc/wpilibC++Devices/include/PWM.h +++ b/wpilibc/wpilibC++Devices/include/PWM.h @@ -99,8 +99,8 @@ class PWM : public SensorBase, int32_t m_deadbandMinPwm; int32_t m_minPwm; - void ValueChanged(std::shared_ptr source, const std::string& key, EntryValue value, - bool isNew) override; + void ValueChanged(ITable* source, llvm::StringRef key, + std::shared_ptr value, bool isNew) override; void UpdateTable() override; void StartLiveWindowMode() override; void StopLiveWindowMode() override; diff --git a/wpilibc/wpilibC++Devices/include/Preferences.h b/wpilibc/wpilibC++Devices/include/Preferences.h index 118a968d38..525ae210ce 100644 --- a/wpilibc/wpilibC++Devices/include/Preferences.h +++ b/wpilibc/wpilibC++Devices/include/Preferences.h @@ -23,72 +23,41 @@ *

This class loads and saves from a file * inside the RoboRIO. The user can not access the file directly, but may * modify values at specific - * fields which will then be saved to the file when {@link Preferences#Save() - * Save()} is called.

+ * fields which will then be automatically periodically saved to the file + * by the NetworkTable server.

* *

This class is thread safe.

* *

This will also interact with {@link NetworkTable} by creating a table - * called "Preferences" with all the - * key-value pairs. To save using {@link NetworkTable}, simply set the boolean - * at position "~S A V E~" to true. - * Also, if the value of any variable is " in the {@link NetworkTable}, then - * that represents non-existence in the - * {@link Preferences} table

+ * called "Preferences" with all the key-value pairs.

*/ -class Preferences : public ErrorBase, public ITableListener { +class Preferences : public ErrorBase { public: static Preferences *GetInstance(); std::vector GetKeys(); - std::string GetString(const char *key, const char *defaultValue = ""); - int GetString(const char *key, char *value, int valueSize, - const char *defaultValue = ""); - int GetInt(const char *key, int defaultValue = 0); - double GetDouble(const char *key, double defaultValue = 0.0); - float GetFloat(const char *key, float defaultValue = 0.0); - bool GetBoolean(const char *key, bool defaultValue = false); - int64_t GetLong(const char *key, int64_t defaultValue = 0); - void PutString(const char *key, const char *value); - void PutInt(const char *key, int value); - void PutDouble(const char *key, double value); - void PutFloat(const char *key, float value); - void PutBoolean(const char *key, bool value); - void PutLong(const char *key, int64_t value); + std::string GetString(llvm::StringRef key, llvm::StringRef defaultValue = ""); + int GetInt(llvm::StringRef key, int defaultValue = 0); + double GetDouble(llvm::StringRef key, double defaultValue = 0.0); + float GetFloat(llvm::StringRef key, float defaultValue = 0.0); + bool GetBoolean(llvm::StringRef key, bool defaultValue = false); + int64_t GetLong(llvm::StringRef key, int64_t defaultValue = 0); + void PutString(llvm::StringRef key, llvm::StringRef value); + void PutInt(llvm::StringRef key, int value); + void PutDouble(llvm::StringRef key, double value); + void PutFloat(llvm::StringRef key, float value); + void PutBoolean(llvm::StringRef key, bool value); + void PutLong(llvm::StringRef key, int64_t value); + [[deprecated( + "Saving is now automatically performed by the NetworkTables server.")]] void Save(); - bool ContainsKey(const char *key); - void Remove(const char *key); - - void ValueChanged(std::shared_ptr source, const std::string &key, EntryValue value, - bool isNew) override; + bool ContainsKey(llvm::StringRef key); + void Remove(llvm::StringRef key); protected: Preferences(); virtual ~Preferences() = default; private: - std::string Get(const char *key); - void Put(const char *key, std::string value); - - void ReadTaskRun(); - void WriteTaskRun(); - - /** The semaphore for accessing the file */ - priority_recursive_mutex m_fileLock; - /** The semaphore for beginning reads and writes to the file */ - Semaphore m_fileOpStarted{Semaphore::kEmpty}; - /** The semaphore for reading from the table */ - priority_recursive_mutex m_tableLock; - typedef std::map StringMap; - /** The actual values (String->String) */ - StringMap m_values; - /** The keys in the order they were read from the file */ - std::vector m_keys; - /** The comments that were in the file sorted by which key they appeared over - * (String->Comment) */ - StringMap m_comments; - /** The comment at the end of the file */ - std::string m_endComment; - Task m_readTask; - Task m_writeTask; + std::shared_ptr m_table; }; diff --git a/wpilibc/wpilibC++Devices/include/Relay.h b/wpilibc/wpilibC++Devices/include/Relay.h index edf8eb3f6a..de21f0764a 100644 --- a/wpilibc/wpilibC++Devices/include/Relay.h +++ b/wpilibc/wpilibC++Devices/include/Relay.h @@ -40,8 +40,8 @@ class Relay : public SensorBase, void Set(Value value); Value Get() const; - void ValueChanged(std::shared_ptr source, const std::string& key, EntryValue value, - bool isNew) override; + void ValueChanged(ITable* source, llvm::StringRef key, + std::shared_ptr value, bool isNew) override; void UpdateTable() override; void StartLiveWindowMode() override; void StopLiveWindowMode() override; diff --git a/wpilibc/wpilibC++Devices/include/Servo.h b/wpilibc/wpilibC++Devices/include/Servo.h index 821a0caa4e..4669835932 100644 --- a/wpilibc/wpilibC++Devices/include/Servo.h +++ b/wpilibc/wpilibC++Devices/include/Servo.h @@ -30,8 +30,8 @@ class Servo : public SafePWM { static float GetMaxAngle() { return kMaxServoAngle; } static float GetMinAngle() { return kMinServoAngle; } - void ValueChanged(std::shared_ptr source, const std::string& key, - EntryValue value, bool isNew) override; + void ValueChanged(ITable* source, llvm::StringRef key, + std::shared_ptr value, bool isNew) override; void UpdateTable() override; void StartLiveWindowMode() override; void StopLiveWindowMode() override; diff --git a/wpilibc/wpilibC++Devices/include/Solenoid.h b/wpilibc/wpilibC++Devices/include/Solenoid.h index 897bc67355..fd550037a1 100644 --- a/wpilibc/wpilibC++Devices/include/Solenoid.h +++ b/wpilibc/wpilibC++Devices/include/Solenoid.h @@ -30,8 +30,8 @@ class Solenoid : public SolenoidBase, virtual bool Get() const; bool IsBlackListed() const; - void ValueChanged(std::shared_ptr source, const std::string& key, EntryValue value, - bool isNew); + void ValueChanged(ITable* source, llvm::StringRef key, + std::shared_ptr value, bool isNew); void UpdateTable(); void StartLiveWindowMode(); void StopLiveWindowMode(); diff --git a/wpilibc/wpilibC++Devices/src/CANJaguar.cpp b/wpilibc/wpilibC++Devices/src/CANJaguar.cpp index ddfba620f2..8f7a4aeada 100644 --- a/wpilibc/wpilibC++Devices/src/CANJaguar.cpp +++ b/wpilibc/wpilibC++Devices/src/CANJaguar.cpp @@ -216,6 +216,8 @@ CANJaguar::~CANJaguar() { FRC_NetworkCommunication_CANSessionMux_sendMessage( m_deviceNumber | LM_API_VCOMP_T_SET, nullptr, 0, CAN_SEND_PERIOD_STOP_REPEATING, &status); + + if (m_table != nullptr) m_table->RemoveTableListener(this); } /** @@ -1935,9 +1937,9 @@ uint8_t CANJaguar::GetDeviceID() const { return m_deviceNumber; } */ void CANJaguar::StopMotor() { DisableControl(); } -void CANJaguar::ValueChanged(std::shared_ptr source, const std::string &key, - EntryValue value, bool isNew) { - Set(value.f); +void CANJaguar::ValueChanged(ITable* source, llvm::StringRef key, + std::shared_ptr value, bool isNew) { + if (value->type() == NT_DOUBLE) Set(value->GetDouble()); } void CANJaguar::UpdateTable() { diff --git a/wpilibc/wpilibC++Devices/src/CANTalon.cpp b/wpilibc/wpilibC++Devices/src/CANTalon.cpp index a7bc529d59..509d7a9e49 100644 --- a/wpilibc/wpilibC++Devices/src/CANTalon.cpp +++ b/wpilibc/wpilibC++Devices/src/CANTalon.cpp @@ -44,6 +44,7 @@ CANTalon::CANTalon(int deviceNumber, int controlPeriodMs) } CANTalon::~CANTalon() { + if (m_table != nullptr) m_table->RemoveTableListener(this); if (m_hasBeenMoved) return; Disable(); } @@ -1275,9 +1276,10 @@ bool CANTalon::GetInverted() const { return m_isInverted; } */ void CANTalon::StopMotor() { Disable(); } -void CANTalon::ValueChanged(std::shared_ptr source, const std::string& key, - EntryValue value, bool isNew) { - Set(value.f); +void CANTalon::ValueChanged(ITable* source, llvm::StringRef key, + std::shared_ptr value, bool isNew) { + if (!value->IsDouble()) return; + Set(value->GetDouble()); } void CANTalon::UpdateTable() { diff --git a/wpilibc/wpilibC++Devices/src/Compressor.cpp b/wpilibc/wpilibC++Devices/src/Compressor.cpp index 5435b32b20..9ab89e0584 100644 --- a/wpilibc/wpilibC++Devices/src/Compressor.cpp +++ b/wpilibc/wpilibC++Devices/src/Compressor.cpp @@ -267,9 +267,10 @@ void Compressor::InitTable(std::shared_ptr subTable) { std::shared_ptr Compressor::GetTable() const { return m_table; } -void Compressor::ValueChanged(std::shared_ptr source, const std::string& key, - EntryValue value, bool isNew) { - if (value.b) +void Compressor::ValueChanged(ITable* source, llvm::StringRef key, + std::shared_ptr value, bool isNew) { + if (!value->IsBoolean()) return; + if (value->GetBoolean()) Start(); else Stop(); diff --git a/wpilibc/wpilibC++Devices/src/DigitalOutput.cpp b/wpilibc/wpilibC++Devices/src/DigitalOutput.cpp index b1692b8074..3cbb39fe67 100644 --- a/wpilibc/wpilibC++Devices/src/DigitalOutput.cpp +++ b/wpilibc/wpilibC++Devices/src/DigitalOutput.cpp @@ -40,6 +40,7 @@ DigitalOutput::DigitalOutput(uint32_t channel) { * Free the resources associated with a digital output. */ DigitalOutput::~DigitalOutput() { + if (m_table != nullptr) m_table->RemoveTableListener(this); if (StatusIsFatal()) return; // Disable the PWM in case it was running. DisablePWM(); @@ -196,9 +197,10 @@ uint32_t DigitalOutput::GetModuleForRouting() const { return 0; } */ bool DigitalOutput::GetAnalogTriggerForRouting() const { return false; } -void DigitalOutput::ValueChanged(std::shared_ptr source, const std::string &key, - EntryValue value, bool isNew) { - Set(value.b); +void DigitalOutput::ValueChanged(ITable* source, llvm::StringRef key, + std::shared_ptr value, bool isNew) { + if (!value->IsBoolean()) return; + Set(value->GetBoolean()); } void DigitalOutput::UpdateTable() {} diff --git a/wpilibc/wpilibC++Devices/src/DoubleSolenoid.cpp b/wpilibc/wpilibC++Devices/src/DoubleSolenoid.cpp index 1ef56916db..56f180c589 100644 --- a/wpilibc/wpilibC++Devices/src/DoubleSolenoid.cpp +++ b/wpilibc/wpilibC++Devices/src/DoubleSolenoid.cpp @@ -91,6 +91,7 @@ DoubleSolenoid::~DoubleSolenoid() { m_allocated->Free(m_moduleNumber * kSolenoidChannels + m_forwardChannel); m_allocated->Free(m_moduleNumber * kSolenoidChannels + m_reverseChannel); } + if (m_table != nullptr) m_table->RemoveTableListener(this); } /** @@ -155,13 +156,14 @@ bool DoubleSolenoid::IsRevSolenoidBlackListed() const { return (blackList & m_reverseMask) ? 1 : 0; } -void DoubleSolenoid::ValueChanged(std::shared_ptr source, const std::string &key, - EntryValue value, bool isNew) { +void DoubleSolenoid::ValueChanged(ITable* source, llvm::StringRef key, + std::shared_ptr value, + bool isNew) { + if (!value->IsString()) return; Value lvalue = kOff; - std::string *val = (std::string *)value.ptr; - if (*val == "Forward") + if (value->GetString() == "Forward") lvalue = kForward; - else if (*val == "Reverse") + else if (value->GetString() == "Reverse") lvalue = kReverse; Set(lvalue); } diff --git a/wpilibc/wpilibC++Devices/src/PIDController.cpp b/wpilibc/wpilibC++Devices/src/PIDController.cpp index 6fb55f1484..e9a25f752a 100644 --- a/wpilibc/wpilibC++Devices/src/PIDController.cpp +++ b/wpilibc/wpilibC++Devices/src/PIDController.cpp @@ -73,6 +73,10 @@ void PIDController::Initialize(float Kp, float Ki, float Kd, float Kf, HALReport(HALUsageReporting::kResourceType_PIDController, instances); } +PIDController::~PIDController() { + if (m_table != nullptr) m_table->RemoveTableListener(this); +} + /** * Call the Calculate method as a non-static method. This avoids having to * prepend @@ -551,18 +555,22 @@ void PIDController::InitTable(std::shared_ptr table) { std::shared_ptr PIDController::GetTable() const { return m_table; } -void PIDController::ValueChanged(std::shared_ptr source, const std::string &key, - EntryValue value, bool isNew) { +void PIDController::ValueChanged(ITable* source, llvm::StringRef key, + std::shared_ptr value, bool isNew) { if (key == kP || key == kI || key == kD || key == kF) { - if (m_P != m_table->GetNumber(kP) || m_I != m_table->GetNumber(kI) || - m_D != m_table->GetNumber(kD) || m_F != m_table->GetNumber(kF)) { + if (m_P != m_table->GetNumber(kP, 0.0) || + m_I != m_table->GetNumber(kI, 0.0) || + m_D != m_table->GetNumber(kD, 0.0) || + m_F != m_table->GetNumber(kF, 0.0)) { SetPID(m_table->GetNumber(kP, 0.0), m_table->GetNumber(kI, 0.0), m_table->GetNumber(kD, 0.0), m_table->GetNumber(kF, 0.0)); } - } else if (key == kSetpoint && m_setpoint != value.f) { - SetSetpoint(value.f); - } else if (key == kEnabled && m_enabled != value.b) { - if (value.b) { + } else if (key == kSetpoint && value->IsDouble() && + m_setpoint != value->GetDouble()) { + SetSetpoint(value->GetDouble()); + } else if (key == kEnabled && value->IsBoolean() && + m_enabled != value->GetBoolean()) { + if (value->GetBoolean()) { Enable(); } else { Disable(); diff --git a/wpilibc/wpilibC++Devices/src/PWM.cpp b/wpilibc/wpilibC++Devices/src/PWM.cpp index b0c8c8cb31..5a70932424 100644 --- a/wpilibc/wpilibC++Devices/src/PWM.cpp +++ b/wpilibc/wpilibC++Devices/src/PWM.cpp @@ -65,6 +65,8 @@ PWM::~PWM() { freePWMChannel(m_pwm_ports[m_channel], &status); wpi_setErrorWithContext(status, getHALErrorMessage(status)); + + if (m_table != nullptr) m_table->RemoveTableListener(this); } /** @@ -337,9 +339,10 @@ void PWM::SetZeroLatch() { wpi_setErrorWithContext(status, getHALErrorMessage(status)); } -void PWM::ValueChanged(std::shared_ptr source, const std::string& key, EntryValue value, - bool isNew) { - SetSpeed(value.f); +void PWM::ValueChanged(ITable* source, llvm::StringRef key, + std::shared_ptr value, bool isNew) { + if (!value->IsDouble()) return; + SetSpeed(value->GetDouble()); } void PWM::UpdateTable() { diff --git a/wpilibc/wpilibC++Devices/src/Preferences.cpp b/wpilibc/wpilibC++Devices/src/Preferences.cpp index 840aa2ef88..cb6d1001e3 100644 --- a/wpilibc/wpilibC++Devices/src/Preferences.cpp +++ b/wpilibc/wpilibC++Devices/src/Preferences.cpp @@ -15,25 +15,8 @@ /** The Preferences table name */ static const char *kTableName = "Preferences"; -/** The value of the save field */ -static const char *kSaveField = "~S A V E~"; -/** The file to save to */ -static const char *kFileName = "/home/lvuser/wpilib-preferences.ini"; -/** The characters to put between a field and value */ -static const char *kValuePrefix = "=\""; -/** The characters to put after the value */ -static const char *kValueSuffix = "\"\n"; - -Preferences::Preferences() { - std::unique_lock sync(m_fileLock); - m_readTask = Task("PreferencesReadTask", &Preferences::ReadTaskRun, this); - - /* The main thread initially blocks on the semaphore. The read task signals - * the main thread to continue after it has locked the table mutex (so the - * table will be fully populated when the main thread can finally access it). - */ - m_fileOpStarted.take(); +Preferences::Preferences() : m_table(NetworkTable::GetTable(kTableName)) { HALReport(HALUsageReporting::kResourceType_Preferences, 0); } @@ -50,7 +33,7 @@ Preferences *Preferences::GetInstance() { * Returns a vector of all the keys * @return a vector of the keys */ -std::vector Preferences::GetKeys() { return m_keys; } +std::vector Preferences::GetKeys() { return m_table->GetKeys(); } /** * Returns the string at the given key. If this table does not have a value @@ -59,25 +42,9 @@ std::vector Preferences::GetKeys() { return m_keys; } * @param defaultValue the value to return if none exists in the table * @return either the value in the table, or the defaultValue */ -std::string Preferences::GetString(const char *key, const char *defaultValue) { - std::string value = Get(key); - return value.empty() ? defaultValue : value; -} - -/** - * Returns the string at the given key. If this table does not have a value - * for that position, then the given defaultValue will be returned. - * @param key the key - * @param value the buffer to copy the value into - * @param valueSize the size of value - * @param defaultValue the value to return if none exists in the table - * @return The size of the returned string - */ -int Preferences::GetString(const char *key, char *value, int valueSize, - const char *defaultValue) { - std::string stringValue = GetString(key, defaultValue); - stringValue.copy(value, valueSize); - return stringValue.size(); +std::string Preferences::GetString(llvm::StringRef key, + llvm::StringRef defaultValue) { + return m_table->GetString(key, defaultValue); } /** @@ -87,11 +54,8 @@ int Preferences::GetString(const char *key, char *value, int valueSize, * @param defaultValue the value to return if none exists in the table * @return either the value in the table, or the defaultValue */ -int Preferences::GetInt(const char *key, int defaultValue) { - std::string value = Get(key); - if (value.empty()) return defaultValue; - - return strtol(value.c_str(), nullptr, 0); +int Preferences::GetInt(llvm::StringRef key, int defaultValue) { + return static_cast(m_table->GetNumber(key, defaultValue)); } /** @@ -101,11 +65,8 @@ int Preferences::GetInt(const char *key, int defaultValue) { * @param defaultValue the value to return if none exists in the table * @return either the value in the table, or the defaultValue */ -double Preferences::GetDouble(const char *key, double defaultValue) { - std::string value = Get(key); - if (value.empty()) return defaultValue; - - return strtod(value.c_str(), nullptr); +double Preferences::GetDouble(llvm::StringRef key, double defaultValue) { + return m_table->GetNumber(key, defaultValue); } /** @@ -115,11 +76,8 @@ double Preferences::GetDouble(const char *key, double defaultValue) { * @param defaultValue the value to return if none exists in the table * @return either the value in the table, or the defaultValue */ -float Preferences::GetFloat(const char *key, float defaultValue) { - std::string value = Get(key); - if (value.empty()) return defaultValue; - - return strtod(value.c_str(), nullptr); +float Preferences::GetFloat(llvm::StringRef key, float defaultValue) { + return static_cast(m_table->GetNumber(key, defaultValue)); } /** @@ -129,19 +87,8 @@ float Preferences::GetFloat(const char *key, float defaultValue) { * @param defaultValue the value to return if none exists in the table * @return either the value in the table, or the defaultValue */ -bool Preferences::GetBoolean(const char *key, bool defaultValue) { - std::string value = Get(key); - if (value.empty()) return defaultValue; - - if (value.compare("true") == 0) - return true; - else if (value.compare("false") == 0) - return false; - - wpi_setWPIErrorWithContext( - ParameterOutOfRange, - "Boolean value does not contain \"true\" or \"false\""); - return false; +bool Preferences::GetBoolean(llvm::StringRef key, bool defaultValue) { + return m_table->GetBoolean(key, defaultValue); } /** @@ -152,15 +99,8 @@ bool Preferences::GetBoolean(const char *key, bool defaultValue) { * @param defaultValue the value to return if none exists in the table * @return either the value in the table, or the defaultValue */ -int64_t Preferences::GetLong(const char *key, int64_t defaultValue) { - std::string value = Get(key); - if (value.empty()) return defaultValue; - - // Ummm... not available in our VxWorks... - // return strtoll(value.c_str(), nullptr, 0); - int64_t intVal; - sscanf(value.c_str(), "%lld", &intVal); - return intVal; +int64_t Preferences::GetLong(llvm::StringRef key, int64_t defaultValue) { + return static_cast(m_table->GetNumber(key, defaultValue)); } /** @@ -169,24 +109,12 @@ int64_t Preferences::GetLong(const char *key, int64_t defaultValue) { *

The value may not have quotation marks, nor may the key * have any whitespace nor an equals sign

* - *

This will NOT save the value to memory between power cycles, - * to do that you must call {@link Preferences#Save() Save()} (which must be - * used with care). - * at some point after calling this.

* @param key the key * @param value the value */ -void Preferences::PutString(const char *key, const char *value) { - if (value == nullptr) { - wpi_setWPIErrorWithContext(NullParameter, "value"); - return; - } - if (std::string(value).find_first_of("\"") != std::string::npos) { - wpi_setWPIErrorWithContext(ParameterOutOfRange, - "value contains illegal characters"); - return; - } - Put(key, value); +void Preferences::PutString(llvm::StringRef key, llvm::StringRef value) { + m_table->PutString(key, value); + m_table->SetPersistent(key); } /** @@ -194,17 +122,12 @@ void Preferences::PutString(const char *key, const char *value) { * *

The key may not have any whitespace nor an equals sign

* - *

This will NOT save the value to memory between power cycles, - * to do that you must call {@link Preferences#Save() Save()} (which must be - * used with care) - * at some point after calling this.

* @param key the key * @param value the value */ -void Preferences::PutInt(const char *key, int value) { - char buf[32]; - snprintf(buf, 32, "%d", value); - Put(key, buf); +void Preferences::PutInt(llvm::StringRef key, int value) { + m_table->PutNumber(key, value); + m_table->SetPersistent(key); } /** @@ -212,17 +135,12 @@ void Preferences::PutInt(const char *key, int value) { * *

The key may not have any whitespace nor an equals sign

* - *

This will NOT save the value to memory between power cycles, - * to do that you must call {@link Preferences#Save() Save()} (which must be - * used with care) - * at some point after calling this.

* @param key the key * @param value the value */ -void Preferences::PutDouble(const char *key, double value) { - char buf[32]; - snprintf(buf, 32, "%f", value); - Put(key, buf); +void Preferences::PutDouble(llvm::StringRef key, double value) { + m_table->PutNumber(key, value); + m_table->SetPersistent(key); } /** @@ -230,17 +148,12 @@ void Preferences::PutDouble(const char *key, double value) { * *

The key may not have any whitespace nor an equals sign

* - *

This will NOT save the value to memory between power cycles, - * to do that you must call {@link Preferences#Save() Save()} (which must be - * used with care) - * at some point after calling this.

* @param key the key * @param value the value */ -void Preferences::PutFloat(const char *key, float value) { - char buf[32]; - snprintf(buf, 32, "%f", value); - Put(key, buf); +void Preferences::PutFloat(llvm::StringRef key, float value) { + m_table->PutNumber(key, value); + m_table->SetPersistent(key); } /** @@ -248,15 +161,12 @@ void Preferences::PutFloat(const char *key, float value) { * *

The key may not have any whitespace nor an equals sign

* - *

This will NOT save the value to memory between power cycles, - * to do that you must call {@link Preferences#Save() Save()} (which must be - * used with care) - * at some point after calling this.

* @param key the key * @param value the value */ -void Preferences::PutBoolean(const char *key, bool value) { - Put(key, value ? "true" : "false"); +void Preferences::PutBoolean(llvm::StringRef key, bool value) { + m_table->PutBoolean(key, value); + m_table->SetPersistent(key); } /** @@ -264,282 +174,35 @@ void Preferences::PutBoolean(const char *key, bool value) { * *

The key may not have any whitespace nor an equals sign

* - *

This will NOT save the value to memory between power cycles, - * to do that you must call {@link Preferences#Save() Save()} (which must be - * used with care) - * at some point after calling this.

* @param key the key * @param value the value */ -void Preferences::PutLong(const char *key, int64_t value) { - char buf[32]; - snprintf(buf, 32, "%lld", value); - Put(key, buf); +void Preferences::PutLong(llvm::StringRef key, int64_t value) { + m_table->PutNumber(key, value); + m_table->SetPersistent(key); } /** - * Saves the preferences to a file on the RoboRIO. - * - *

This should NOT be called often. - * Too many writes can damage the RoboRIO's flash memory. - * While it is ok to save once or twice a match, this should never - * be called every run of {@link IterativeRobot#TeleopPeriodic()}, etc.

- * - *

The actual writing of the file is done in a separate thread. - * However, any call to a get or put method will wait until the table is fully - * saved before continuing.

+ * This function is no longer required, as NetworkTables automatically + * saves persistent values (which all Preferences values are) periodically + * when running as a server. + * @deprecated backwards compatibility shim */ -void Preferences::Save() { - std::unique_lock sync(m_fileLock); - m_writeTask = Task("PreferencesWriteTask", &Preferences::WriteTaskRun, this); - m_fileOpStarted.take(); -} +void Preferences::Save() {} /** * Returns whether or not there is a key with the given name. * @param key the key * @return if there is a value at the given key */ -bool Preferences::ContainsKey(const char *key) { return !Get(key).empty(); } +bool Preferences::ContainsKey(llvm::StringRef key) { + return m_table->ContainsKey(key); +} /** * Remove a preference * @param key the key */ -void Preferences::Remove(const char *key) { - m_values.erase(std::string(key)); - auto it = m_keys.begin(); - for (; it != m_keys.end(); it++) { - if (it->compare(key) == 0) { - m_keys.erase(it); - break; - } - } -} - -/** - * Returns the value at the given key. - * @param key the key - * @return the value (or empty if none exists) - */ -std::string Preferences::Get(const char *key) { - std::unique_lock sync(m_tableLock); - if (key == nullptr) { - wpi_setWPIErrorWithContext(NullParameter, "key"); - return ""; - } - return m_values[key]; -} - -/** - * Puts the given value into the given key position - * @param key the key - * @param value the value - */ -void Preferences::Put(const char *key, std::string value) { - std::unique_lock sync(m_tableLock); - if (key == nullptr) { - wpi_setWPIErrorWithContext(NullParameter, "key"); - return; - } - - if (std::string(key).find_first_of("=\n\r \t\"") != std::string::npos) { - wpi_setWPIErrorWithContext(ParameterOutOfRange, - "key contains illegal characters"); - return; - } - - std::pair ret = - m_values.insert(StringMap::value_type(key, value)); - if (ret.second) - m_keys.push_back(key); - else - ret.first->second = value; - - NetworkTable* table = NetworkTable::GetTable(kTableName); - table->PutString(key, value); -} - -/** - * The internal method to read from a file. - * This will be called in its own thread when the preferences singleton is - * first created. - */ -void Preferences::ReadTaskRun() { - std::unique_lock sync(m_tableLock); - m_fileOpStarted.give(); - - std::string comment; - - FILE *file = nullptr; - file = fopen(kFileName, "r"); - - if (file != nullptr) { - std::string buffer; - while (true) { - char value; - do { - value = fgetc(file); - } while (value == ' ' || value == '\t'); - - if (value == '\n' || value == ';') { - if (value == '\n') { - comment += "\n"; - } else { - buffer.clear(); - for (; value != '\n' && !feof(file); value = fgetc(file)) - buffer += value; - buffer += '\n'; - comment += buffer; - } - } else if (value == '[') { - // Find the end of the section and the new line after it and throw it - // away - for (; value != ']' && !feof(file); value = fgetc(file)) - ; - for (; value != '\n' && !feof(file); value = fgetc(file)) - ; - } else { - buffer.clear(); - for (; value != '=' && !feof(file);) { - buffer += value; - do { - value = fgetc(file); - } while (value == ' ' || value == '\t'); - } - std::string name = buffer; - buffer.clear(); - - bool shouldBreak = false; - - do { - value = fgetc(file); - } while (value == ' ' || value == '\t'); - - if (value == '"') { - for (value = fgetc(file); value != '"' && !feof(file); - value = fgetc(file)) - buffer += value; - - // Clear the line - while (fgetc(file) != '\n' && !feof(file)) - ; - } else { - for (; value != '\n' && !feof(file);) { - buffer += value; - do { - value = fgetc(file); - } while (value == ' ' || value == '\t'); - } - if (feof(file)) shouldBreak = true; - } - - std::string value = buffer; - - if (!name.empty() && !value.empty()) { - m_keys.push_back(name); - m_values.insert(std::pair(name, value)); - NetworkTable::GetTable(kTableName)->PutString(name, value); - - if (!comment.empty()) { - m_comments.insert( - std::pair(name, comment)); - comment.clear(); - } - } - - if (shouldBreak) break; - } - } - } else { - wpi_setErrnoErrorWithContext("Opening preferences file"); - } - - if (file != nullptr) fclose(file); - - if (!comment.empty()) m_endComment = comment; - - NetworkTable::GetTable(kTableName)->PutBoolean(kSaveField, false); - NetworkTable::GetTable(kTableName)->AddTableListener(this); -} - -/** - * Internal method that actually writes the table to a file. - * This is called in its own thread when {@link Preferences#Save() Save()} is - * called. - */ -void Preferences::WriteTaskRun() { - std::unique_lock sync(m_tableLock); - m_fileOpStarted.give(); - - FILE *file = nullptr; - file = fopen(kFileName, "w"); - - fputs("[Preferences]\n", file); - auto it = m_keys.begin(); - for (; it != m_keys.end(); it++) { - std::string key = *it; - std::string value = m_values[key]; - std::string comment = m_comments[key]; - - if (!comment.empty()) fputs(comment.c_str(), file); - - fputs(key.c_str(), file); - fputs(kValuePrefix, file); - fputs(value.c_str(), file); - fputs(kValueSuffix, file); - } - - if (!m_endComment.empty()) fputs(m_endComment.c_str(), file); - - if (file != nullptr) fclose(file); - - NetworkTable::GetTable(kTableName)->PutBoolean(kSaveField, false); -} - -static bool isKeyAcceptable(const std::string &value) { - for (auto letter : value) { - switch (letter) { - case '=': - case '\n': - case '\r': - case ' ': - case '\t': - case '[': - case ']': - return false; - } - } - return true; -} - -void Preferences::ValueChanged(std::shared_ptr table, const std::string &key, - EntryValue value, bool isNew) { - if (key == kSaveField) { - if (table->GetBoolean(kSaveField, false)) Save(); - } else { - std::unique_lock sync(m_tableLock); - - if (!isKeyAcceptable(key) || - table->GetString(key, "").find('"') != std::string::npos) { - if (m_values.find(key) != m_values.end()) { - m_values.erase(key); - auto it = m_keys.begin(); - for (; it != m_keys.end(); it++) { - if (key == *it) { - m_keys.erase(it); - break; - } - } - table->PutString(key, "\""); - } - } else { - std::pair ret = m_values.insert( - StringMap::value_type(key, table->GetString(key, ""))); - if (ret.second) - m_keys.push_back(key); - else - ret.first->second = table->GetString(key, ""); - } - } +void Preferences::Remove(llvm::StringRef key) { + m_table->Delete(key); } diff --git a/wpilibc/wpilibC++Devices/src/Relay.cpp b/wpilibc/wpilibC++Devices/src/Relay.cpp index 8d48812755..3977dd978f 100644 --- a/wpilibc/wpilibC++Devices/src/Relay.cpp +++ b/wpilibc/wpilibC++Devices/src/Relay.cpp @@ -81,6 +81,7 @@ Relay::~Relay() { if (m_direction == kBothDirections || m_direction == kReverseOnly) { relayChannels->Free(m_channel * 2 + 1); } + if (m_table != nullptr) m_table->RemoveTableListener(this); } /** @@ -189,16 +190,16 @@ Relay::Value Relay::Get() const { wpi_setErrorWithContext(status, getHALErrorMessage(status)); } -void Relay::ValueChanged(std::shared_ptr source, const std::string &key, - EntryValue value, bool isNew) { - std::string *val = (std::string *)value.ptr; - if (*val == "Off") +void Relay::ValueChanged(ITable* source, llvm::StringRef key, + std::shared_ptr value, bool isNew) { + if (!value->IsString()) return; + if (value->GetString() == "Off") Set(kOff); - else if (*val == "On") + else if (value->GetString() == "On") Set(kOn); - else if (*val == "Forward") + else if (value->GetString() == "Forward") Set(kForward); - else if (*val == "Reverse") + else if (value->GetString() == "Reverse") Set(kReverse); } diff --git a/wpilibc/wpilibC++Devices/src/RobotBase.cpp b/wpilibc/wpilibC++Devices/src/RobotBase.cpp index 9adc51f638..07f2c8ce46 100644 --- a/wpilibc/wpilibC++Devices/src/RobotBase.cpp +++ b/wpilibc/wpilibC++Devices/src/RobotBase.cpp @@ -15,6 +15,7 @@ #include "HLUsageReporting.h" #include "Internal/HardwareHLReporting.h" #include "Utility.h" +#include "networktables/NetworkTable.h" #include #include "HAL/HAL.hpp" #include @@ -51,6 +52,8 @@ RobotBase::RobotBase() : m_ds(DriverStation::GetInstance()) { RobotBase::setInstance(this); + NetworkTable::SetNetworkIdentity("Robot"); + FILE *file = nullptr; file = fopen("/tmp/frc_versions/FRC_Lib_Version.ini", "w"); diff --git a/wpilibc/wpilibC++Devices/src/Servo.cpp b/wpilibc/wpilibC++Devices/src/Servo.cpp index e2ff60e854..72a35260ea 100644 --- a/wpilibc/wpilibC++Devices/src/Servo.cpp +++ b/wpilibc/wpilibC++Devices/src/Servo.cpp @@ -30,7 +30,11 @@ Servo::Servo(uint32_t channel) : SafePWM(channel) { // printf("Done initializing servo %d\n", channel); } -Servo::~Servo() {} +Servo::~Servo() { + if (m_table != nullptr) { + m_table->RemoveTableListener(this); + } +} /** * Set the servo position. @@ -95,9 +99,10 @@ float Servo::GetAngle() const { return (float)GetPosition() * GetServoAngleRange() + kMinServoAngle; } -void Servo::ValueChanged(std::shared_ptr source, const std::string& key, - EntryValue value, bool isNew) { - Set(value.f); +void Servo::ValueChanged(ITable* source, llvm::StringRef key, + std::shared_ptr value, bool isNew) { + if (!value->IsDouble()) return; + Set(value->GetDouble()); } void Servo::UpdateTable() { diff --git a/wpilibc/wpilibC++Devices/src/Solenoid.cpp b/wpilibc/wpilibC++Devices/src/Solenoid.cpp index fd9c6450e6..6cf32e12a8 100644 --- a/wpilibc/wpilibC++Devices/src/Solenoid.cpp +++ b/wpilibc/wpilibC++Devices/src/Solenoid.cpp @@ -61,6 +61,7 @@ Solenoid::~Solenoid() { if (CheckSolenoidModule(m_moduleNumber)) { m_allocated->Free(m_moduleNumber * kSolenoidChannels + m_channel); } + if (m_table != nullptr) m_table->RemoveTableListener(this); } /** @@ -99,9 +100,10 @@ bool Solenoid::IsBlackListed() const { return (value != 0); } -void Solenoid::ValueChanged(std::shared_ptr source, const std::string& key, - EntryValue value, bool isNew) { - Set(value.b); +void Solenoid::ValueChanged(ITable* source, llvm::StringRef key, + std::shared_ptr value, bool isNew) { + if (!value->IsBoolean()) return; + Set(value->GetBoolean()); } void Solenoid::UpdateTable() { diff --git a/wpilibc/wpilibC++IntegrationTests/CMakeLists.txt b/wpilibc/wpilibC++IntegrationTests/CMakeLists.txt index 31431fbb8f..88887b318e 100644 --- a/wpilibc/wpilibC++IntegrationTests/CMakeLists.txt +++ b/wpilibc/wpilibC++IntegrationTests/CMakeLists.txt @@ -7,4 +7,4 @@ file(GLOB_RECURSE SRC_FILES src/*.cpp src/gtest/src/gtest-all.cc src/gtest/src/g include_directories(include/ src/gtest/ src/gtest/include/ ../wpilibC++Devices/include/ ${WPILIB_INCLUDES} ${HAL_API_INCLUDES} ${NWT_API_INCLUDES}) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread -Wno-unused-variable") add_executable(FRCUserProgram ${SRC_FILES}) -target_link_libraries(FRCUserProgram wpilib_nonshared HALAthena NetworkTables ${NI_LIBS}) +target_link_libraries(FRCUserProgram wpilib_nonshared HALAthena ntcore ${NI_LIBS}) diff --git a/wpilibc/wpilibC++IntegrationTests/src/PreferencesTest.cpp b/wpilibc/wpilibC++IntegrationTests/src/PreferencesTest.cpp index 925f333d4e..030d373c9b 100644 --- a/wpilibc/wpilibC++IntegrationTests/src/PreferencesTest.cpp +++ b/wpilibc/wpilibC++IntegrationTests/src/PreferencesTest.cpp @@ -11,25 +11,27 @@ #include #include -static const char *kFileName = "/home/lvuser/wpilib-preferences.ini"; -static const double kSaveTime = 0.2; +static const char *kFileName = "networktables.ini"; +static const double kSaveTime = 1.2; /** - * If we write a new wpilib-preference.ini with some sample values, test that + * If we write a new networktables.ini with some sample values, test that * we get those same values back using the Preference class. */ TEST(PreferencesTest, ReadPreferencesFromFile) { + NetworkTable::Shutdown(); std::remove(kFileName); std::ofstream preferencesFile(kFileName); - preferencesFile << "[Preferences]" << std::endl; - preferencesFile << "testFileGetString=\"Hello, preferences file\"" + preferencesFile << "[NetworkTables Storage 3.0]" << std::endl; + preferencesFile << "string \"/Preferences/testFileGetString\"=\"Hello, preferences file\"" << std::endl; - preferencesFile << "testFileGetInt=\"1\"" << std::endl; - preferencesFile << "testFileGetDouble=\"0.5\"" << std::endl; - preferencesFile << "testFileGetFloat=\"0.25\"" << std::endl; - preferencesFile << "testFileGetBoolean=\"true\"" << std::endl; - preferencesFile << "testFileGetLong=\"1000000000000000000\"" << std::endl; + preferencesFile << "double \"/Preferences/testFileGetInt\"=1" << std::endl; + preferencesFile << "double \"/Preferences/testFileGetDouble\"=0.5" << std::endl; + preferencesFile << "double \"/Preferences/testFileGetFloat\"=0.25" << std::endl; + preferencesFile << "boolean \"/Preferences/testFileGetBoolean\"=true" << std::endl; + preferencesFile << "double \"/Preferences/testFileGetLong\"=1000000000000000000" << std::endl; preferencesFile.close(); + NetworkTable::Initialize(); Preferences *preferences = Preferences::GetInstance(); EXPECT_EQ("Hello, preferences file", @@ -43,9 +45,13 @@ TEST(PreferencesTest, ReadPreferencesFromFile) { /** * If we set some values using the Preferences class, test that they show up - * in wpilib-preferences.ini + * in networktables.ini */ TEST(PreferencesTest, WritePreferencesToFile) { + NetworkTable::Shutdown(); + NetworkTable::GlobalDeleteAll(); + std::remove(kFileName); + NetworkTable::Initialize(); Preferences *preferences = Preferences::GetInstance(); preferences->PutString("testFilePutString", "Hello, preferences file"); preferences->PutInt("testFilePutInt", 1); @@ -58,10 +64,13 @@ TEST(PreferencesTest, WritePreferencesToFile) { Wait(kSaveTime); static char const *kExpectedFileContents[] = { - "[Preferences]", "testFileGetString=\"Hello, preferences file\"", - "testFileGetInt=\"1\"", "testFileGetDouble=\"0.5\"", - "testFileGetFloat=\"0.25\"", "testFileGetBoolean=\"true\"", - "testFileGetLong=\"1000000000000000000\""}; + "[NetworkTables Storage 3.0]", + "boolean \"/Preferences/testFilePutBoolean\"=true", + "double \"/Preferences/testFilePutDouble\"=0.5", + "double \"/Preferences/testFilePutFloat\"=0.25", + "double \"/Preferences/testFilePutInt\"=1", + "double \"/Preferences/testFilePutLong\"=1e+18", + "string \"/Preferences/testFilePutString\"=\"Hello, preferences file\""}; std::ifstream preferencesFile(kFileName); for (auto& kExpectedFileContent : kExpectedFileContents) { @@ -72,6 +81,6 @@ TEST(PreferencesTest, WritePreferencesToFile) { std::getline(preferencesFile, line); ASSERT_EQ(kExpectedFileContent, line) - << "A line in wpilib-preferences.ini was not correct"; + << "A line in networktables.ini was not correct"; } } diff --git a/wpilibc/wpilibC++Sim/CMakeLists.txt b/wpilibc/wpilibC++Sim/CMakeLists.txt index 7be2cec34b..1241fd3a64 100644 --- a/wpilibc/wpilibC++Sim/CMakeLists.txt +++ b/wpilibc/wpilibC++Sim/CMakeLists.txt @@ -20,22 +20,12 @@ if (WIN32) add_definitions(-Dsnprintf=sprintf_s) endif() -if (WIN32) - file(GLOB_RECURSE SRC_FILES src/*.cpp - ../../networktables/cpp/lib/share/*.cpp - ../../networktables/cpp/lib/WIN32/*.cpp) -else() - file(GLOB_RECURSE SRC_FILES src/*.cpp - ../../networktables/cpp/lib/share/*.cpp - ../../networktables/cpp/lib/Athena/*.cpp) -endif() - file(GLOB_RECURSE COM_SRC_FILES ../wpilibC++/src/*.cpp) set (INCLUDE_FOLDERS include ../wpilibC++/include - ../../networktables/cpp/include + ../../networktables/ntcore/include ../../hal/include ${GZ_MSGS_INCLUDE_DIR} ${Boost_INCLUDE_DIR} @@ -61,7 +51,7 @@ else() add_library(WPILibSim SHARED ${SRC_FILES} ${COM_SRC_FILES}) endif() -target_link_libraries(WPILibSim gz_msgs ${PTHREAD_LIBRARY} ${Boost_LIBRARIES} ${GAZEBO_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} -fPIC) # NetworkTables +target_link_libraries(WPILibSim gz_msgs ntcore ${PTHREAD_LIBRARY} ${Boost_LIBRARIES} ${GAZEBO_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} -fPIC) # NetworkTables if (WIN32) set_target_properties(${project} PROPERTIES LINK_FLAGS "/DEBUG") diff --git a/wpilibc/wpilibC++Sim/include/DoubleSolenoid.h b/wpilibc/wpilibC++Sim/include/DoubleSolenoid.h index 87858a845a..122a439627 100644 --- a/wpilibc/wpilibC++Sim/include/DoubleSolenoid.h +++ b/wpilibc/wpilibC++Sim/include/DoubleSolenoid.h @@ -30,11 +30,12 @@ public: explicit DoubleSolenoid(uint32_t forwardChannel, uint32_t reverseChannel); DoubleSolenoid(uint8_t moduleNumber, uint32_t forwardChannel, uint32_t reverseChannel); - virtual ~DoubleSolenoid() = default; + virtual ~DoubleSolenoid(); virtual void Set(Value value); virtual Value Get() const; - void ValueChanged(std::shared_ptr source, const std::string& key, EntryValue value, bool isNew) override; + void ValueChanged(ITable* source, llvm::StringRef key, + std::shared_ptr value, bool isNew) override; void UpdateTable() override; void StartLiveWindowMode() override; void StopLiveWindowMode() override; diff --git a/wpilibc/wpilibC++Sim/include/PWM.h b/wpilibc/wpilibC++Sim/include/PWM.h index aec0d77592..dd29a9376d 100644 --- a/wpilibc/wpilibC++Sim/include/PWM.h +++ b/wpilibc/wpilibC++Sim/include/PWM.h @@ -39,7 +39,7 @@ public: }; explicit PWM(uint32_t channel); - virtual ~PWM() = default; + virtual ~PWM(); virtual void SetRaw(unsigned short value); void SetPeriodMultiplier(PeriodMultiplier mult); void EnableDeadbandElimination(bool eliminateDeadband); @@ -87,7 +87,8 @@ protected: bool m_eliminateDeadband; int32_t m_centerPwm; - void ValueChanged(std::shared_ptr source, const std::string& key, EntryValue value, bool isNew) override; + void ValueChanged(ITable* source, llvm::StringRef key, + std::shared_ptr value, bool isNew) override; void UpdateTable() override; void StartLiveWindowMode() override; void StopLiveWindowMode() override; diff --git a/wpilibc/wpilibC++Sim/include/Relay.h b/wpilibc/wpilibC++Sim/include/Relay.h index c8076ab1be..0f5d33c3ee 100644 --- a/wpilibc/wpilibC++Sim/include/Relay.h +++ b/wpilibc/wpilibC++Sim/include/Relay.h @@ -47,7 +47,8 @@ public: void Set(Value value); Value Get() const; - void ValueChanged(std::shared_ptr source, const std::string& key, EntryValue value, bool isNew) override; + void ValueChanged(ITable* source, llvm::StringRef key, + std::shared_ptr value, bool isNew) override; void UpdateTable() override; void StartLiveWindowMode() override; void StopLiveWindowMode() override; diff --git a/wpilibc/wpilibC++Sim/include/Solenoid.h b/wpilibc/wpilibC++Sim/include/Solenoid.h index eac30deb6f..b91da6e570 100644 --- a/wpilibc/wpilibC++Sim/include/Solenoid.h +++ b/wpilibc/wpilibC++Sim/include/Solenoid.h @@ -22,11 +22,12 @@ class Solenoid : public LiveWindowSendable, public ITableListener public: explicit Solenoid(uint32_t channel); Solenoid(uint8_t moduleNumber, uint32_t channel); - virtual ~Solenoid() = default; + virtual ~Solenoid(); virtual void Set(bool on); virtual bool Get() const; - void ValueChanged(std::shared_ptr source, const std::string& key, EntryValue value, bool isNew) override; + void ValueChanged(ITable* source, llvm::StringRef key, + std::shared_ptr value, bool isNew) override; void UpdateTable() override; void StartLiveWindowMode() override; void StopLiveWindowMode() override; diff --git a/wpilibc/wpilibC++Sim/src/DoubleSolenoid.cpp b/wpilibc/wpilibC++Sim/src/DoubleSolenoid.cpp index b6e45278e4..d1d09176ca 100644 --- a/wpilibc/wpilibC++Sim/src/DoubleSolenoid.cpp +++ b/wpilibc/wpilibC++Sim/src/DoubleSolenoid.cpp @@ -43,6 +43,10 @@ DoubleSolenoid::DoubleSolenoid(uint8_t moduleNumber, uint32_t forwardChannel, ui forwardChannel, this); } +DoubleSolenoid::~DoubleSolenoid() { + if (m_table != nullptr) m_table->RemoveTableListener(this); +} + /** * Set the value of a solenoid. * @@ -75,12 +79,14 @@ DoubleSolenoid::Value DoubleSolenoid::Get() const return m_value; } -void DoubleSolenoid::ValueChanged(std::shared_ptr source, const std::string& key, EntryValue value, bool isNew) { - Value lvalue = kOff; - std::string *val = (std::string *)value.ptr; - if (*val == "Forward") +void DoubleSolenoid::ValueChanged(ITable *source, llvm::StringRef key, + std::shared_ptr value, + bool isNew) { + if (!value->IsString()) return; + Value lvalue = kOff; + if (value->GetString() == "Forward") lvalue = kForward; - else if (*val == "Reverse") + else if (value->GetString() == "Reverse") lvalue = kReverse; Set(lvalue); } diff --git a/wpilibc/wpilibC++Sim/src/PIDController.cpp b/wpilibc/wpilibC++Sim/src/PIDController.cpp index c6abdcac60..cd2a5e4073 100644 --- a/wpilibc/wpilibC++Sim/src/PIDController.cpp +++ b/wpilibc/wpilibC++Sim/src/PIDController.cpp @@ -93,6 +93,10 @@ void PIDController::Initialize(float Kp, float Ki, float Kd, float Kf, m_toleranceType = kNoTolerance; } +PIDController::~PIDController() { + if (m_table != nullptr) m_table->RemoveTableListener(this); +} + /** * Call the Calculate method as a non-static method. This avoids having to prepend * all local variables in that method with the class pointer. This way the "this" @@ -579,20 +583,27 @@ std::shared_ptr PIDController::GetTable() const { return m_table; } -void PIDController::ValueChanged(std::shared_ptr source, const std::string& key, EntryValue value, bool isNew){ - if (key==kP || key==kI || key==kD || key==kF) { - if (m_P != m_table->GetNumber(kP) || m_I != m_table->GetNumber(kI) || m_D != m_table->GetNumber(kD) || m_F != m_table->GetNumber(kF) ) { - SetPID(m_table->GetNumber(kP, 0.0), m_table->GetNumber(kI, 0.0), m_table->GetNumber(kD, 0.0), m_table->GetNumber(kF, 0.0)); - } - } else if (key==kSetpoint && m_setpoint != value.f) { - SetSetpoint(value.f); - } else if (key==kEnabled && m_enabled != value.b) { - if (value.b) { - Enable(); - } else { - Disable(); - } - } +void PIDController::ValueChanged(ITable* source, llvm::StringRef key, + std::shared_ptr value, bool isNew) { + if (key == kP || key == kI || key == kD || key == kF) { + if (m_P != m_table->GetNumber(kP, 0.0) || + m_I != m_table->GetNumber(kI, 0.0) || + m_D != m_table->GetNumber(kD, 0.0) || + m_F != m_table->GetNumber(kF, 0.0)) { + SetPID(m_table->GetNumber(kP, 0.0), m_table->GetNumber(kI, 0.0), + m_table->GetNumber(kD, 0.0), m_table->GetNumber(kF, 0.0)); + } + } else if (key == kSetpoint && value->IsDouble() && + m_setpoint != value->GetDouble()) { + SetSetpoint(value->GetDouble()); + } else if (key == kEnabled && value->IsBoolean() && + m_enabled != value->GetBoolean()) { + if (value->GetBoolean()) { + Enable(); + } else { + Disable(); + } + } } void PIDController::UpdateTable() { diff --git a/wpilibc/wpilibC++Sim/src/PWM.cpp b/wpilibc/wpilibC++Sim/src/PWM.cpp index 1b1a6dfc6a..dfb8bd9d2a 100644 --- a/wpilibc/wpilibC++Sim/src/PWM.cpp +++ b/wpilibc/wpilibC++Sim/src/PWM.cpp @@ -43,6 +43,10 @@ PWM::PWM(uint32_t channel) m_centerPwm = kPwmDisabled; // In simulation, the same thing. } +PWM::~PWM() { + if (m_table != nullptr) m_table->RemoveTableListener(this); +} + /** * Optionally eliminate the deadband from a speed controller. * @param eliminateDeadband If true, set the motor curve on the Jaguar to eliminate @@ -217,8 +221,10 @@ void PWM::SetPeriodMultiplier(PeriodMultiplier mult) } -void PWM::ValueChanged(std::shared_ptr source, const std::string& key, EntryValue value, bool isNew) { - SetSpeed(value.f); +void PWM::ValueChanged(ITable* source, llvm::StringRef key, + std::shared_ptr value, bool isNew) { + if (!value->IsDouble()) return; + SetSpeed(value->GetDouble()); } void PWM::UpdateTable() { diff --git a/wpilibc/wpilibC++Sim/src/Relay.cpp b/wpilibc/wpilibC++Sim/src/Relay.cpp index a86320af6d..971fe28698 100644 --- a/wpilibc/wpilibC++Sim/src/Relay.cpp +++ b/wpilibc/wpilibC++Sim/src/Relay.cpp @@ -43,6 +43,7 @@ Relay::Relay(uint32_t channel, Relay::Direction direction) Relay::~Relay() { impl->Set(0); + if (m_table != nullptr) m_table->RemoveTableListener(this); } /** @@ -140,11 +141,12 @@ Relay::Value Relay::Get() const { } } -void Relay::ValueChanged(std::shared_ptr source, const std::string& key, EntryValue value, bool isNew) { - std::string *val = (std::string *) value.ptr; - if (*val == "Off") Set(kOff); - else if (*val == "Forward") Set(kForward); - else if (*val == "Reverse") Set(kReverse); +void Relay::ValueChanged(ITable* source, llvm::StringRef key, + std::shared_ptr value, bool isNew) { + if (!value->IsString()) return; + if (value->GetString() == "Off") Set(kOff); + else if (value->GetString() == "Forward") Set(kForward); + else if (value->GetString() == "Reverse") Set(kReverse); } void Relay::UpdateTable() { diff --git a/wpilibc/wpilibC++Sim/src/Solenoid.cpp b/wpilibc/wpilibC++Sim/src/Solenoid.cpp index 682995b497..387194db2a 100644 --- a/wpilibc/wpilibC++Sim/src/Solenoid.cpp +++ b/wpilibc/wpilibC++Sim/src/Solenoid.cpp @@ -32,6 +32,10 @@ Solenoid::Solenoid(uint8_t moduleNumber, uint32_t channel) this); } +Solenoid::~Solenoid() { + if (m_table != nullptr) m_table->RemoveTableListener(this); +} + /** * Set the value of a solenoid. * @@ -54,8 +58,10 @@ bool Solenoid::Get() const } -void Solenoid::ValueChanged(std::shared_ptr source, const std::string& key, EntryValue value, bool isNew) { - Set(value.b); +void Solenoid::ValueChanged(ITable* source, llvm::StringRef key, + std::shared_ptr value, bool isNew) { + if (!value->IsBoolean()) return; + Set(value->GetBoolean()); } void Solenoid::UpdateTable() { diff --git a/wpilibj/build.gradle b/wpilibj/build.gradle index bb027daca7..b0c78d1c6d 100644 --- a/wpilibj/build.gradle +++ b/wpilibj/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'cpp' apply plugin: 'maven-publish' // We need this so we can get the networktables javadoc for the javadoc task -evaluationDependsOn(':networktables:java') +evaluationDependsOn(':networktables:ntcore') def jdkDownloadSite = 'http://www.oracle.com/technetwork/java/javase/downloads/jdk8-arm-downloads-2187472.html' def jdkFolder = 'jdk-linux-arm-vfp-sflt' @@ -117,10 +117,10 @@ sourceSets { dependencies { compile sourceSets.shared.output - compile project(':networktables:java') + compile project(':networktables:ntcore') testCompile 'junit:junit:4.11' - sharedCompile project(':networktables:java') - integrationTestCompile project(':networktables:java') + sharedCompile project(':networktables:ntcore') + integrationTestCompile project(':networktables:ntcore') integrationTestCompile 'junit:junit:4.11' integrationTestCompile sourceSets.main.output integrationTestCompile sourceSets.shared.output @@ -130,7 +130,7 @@ dependencies { simulationCompile sourceSets.main.output simulationCompile sourceSets.shared.output simulationCompile project(':simulation:JavaGazebo') - simulationCompile project(':networktables:java') + simulationCompile project(':networktables:ntcore') } task wpilibjJar(type: Jar) { @@ -156,7 +156,7 @@ task wpilibjSources(type: Jar, dependsOn: classes) { } task javadoc(type: Javadoc, overwrite: true) { - def netTables = project(':networktables:java') + def netTables = project(':networktables:ntcore') source sourceSets.main.allJava, sourceSets.shared.allJava, netTables.sourceSets.main.allJava classpath = files([sourceSets.main.compileClasspath, sourceSets.shared.compileClasspath, netTables.sourceSets.main.compileClasspath]) } diff --git a/wpilibj/wpilibJava/src/main/java/edu/wpi/first/wpilibj/command/Scheduler.java b/wpilibj/wpilibJava/src/main/java/edu/wpi/first/wpilibj/command/Scheduler.java index e7ad4acb02..72ae524746 100644 --- a/wpilibj/wpilibJava/src/main/java/edu/wpi/first/wpilibj/command/Scheduler.java +++ b/wpilibj/wpilibJava/src/main/java/edu/wpi/first/wpilibj/command/Scheduler.java @@ -13,8 +13,6 @@ import java.util.Vector; import edu.wpi.first.wpilibj.HLUsageReporting; import edu.wpi.first.wpilibj.NamedSendable; import edu.wpi.first.wpilibj.buttons.Trigger.ButtonScheduler; -import edu.wpi.first.wpilibj.networktables2.type.NumberArray; -import edu.wpi.first.wpilibj.networktables2.type.StringArray; import edu.wpi.first.wpilibj.tables.ITable; /** @@ -318,49 +316,48 @@ public class Scheduler implements NamedSendable { return "Scheduler"; } - private StringArray commands; - private NumberArray ids, toCancel; - /** * {@inheritDoc} */ public void initTable(ITable subtable) { m_table = subtable; - commands = new StringArray(); - ids = new NumberArray(); - toCancel = new NumberArray(); - m_table.putValue("Names", commands); - m_table.putValue("Ids", ids); - m_table.putValue("Cancel", toCancel); + m_table.putStringArray("Names", new String[0]); + m_table.putNumberArray("Ids", new double[0]); + m_table.putNumberArray("Cancel", new double[0]); } private void updateTable() { if (m_table != null) { // Get the commands to cancel - m_table.retrieveValue("Cancel", toCancel); - if (toCancel.size() > 0) { + double[] toCancel = m_table.getNumberArray("Cancel", new double[0]); + if (toCancel.length > 0) { for (LinkedListElement e = firstCommand; e != null; e = e.getNext()) { - for (int i = 0; i < toCancel.size(); i++) { - if (e.getData().hashCode() == toCancel.get(i)) { + for (int i = 0; i < toCancel.length; i++) { + if (e.getData().hashCode() == toCancel[i]) { e.getData().cancel(); } } } - toCancel.setSize(0); - m_table.putValue("Cancel", toCancel); + m_table.putNumberArray("Cancel", new double[0]); } if (m_runningCommandsChanged) { - commands.setSize(0); - ids.setSize(0); // Set the the running commands + int n = 0; for (LinkedListElement e = firstCommand; e != null; e = e.getNext()) { - commands.add(e.getData().getName()); - ids.add(e.getData().hashCode()); + n++; } - m_table.putValue("Names", commands); - m_table.putValue("Ids", ids); + String[] commands = new String[n]; + double[] ids = new double[n]; + n = 0; + for (LinkedListElement e = firstCommand; e != null; e = e.getNext()) { + commands[n] = e.getData().getName(); + ids[n] = e.getData().hashCode(); + n++; + } + m_table.putStringArray("Names", commands); + m_table.putNumberArray("Ids", ids); } } } diff --git a/wpilibj/wpilibJava/src/main/java/edu/wpi/first/wpilibj/smartdashboard/SendableChooser.java b/wpilibj/wpilibJava/src/main/java/edu/wpi/first/wpilibj/smartdashboard/SendableChooser.java index 8111bd1fc8..c20a5aaa73 100644 --- a/wpilibj/wpilibJava/src/main/java/edu/wpi/first/wpilibj/smartdashboard/SendableChooser.java +++ b/wpilibj/wpilibJava/src/main/java/edu/wpi/first/wpilibj/smartdashboard/SendableChooser.java @@ -8,10 +8,10 @@ package edu.wpi.first.wpilibj.smartdashboard; import edu.wpi.first.wpilibj.Sendable; import edu.wpi.first.wpilibj.command.Command; -import edu.wpi.first.wpilibj.networktables2.type.StringArray; -import edu.wpi.first.wpilibj.networktables2.util.List; import edu.wpi.first.wpilibj.tables.ITable; +import java.util.ArrayList; + /** * The {@link SendableChooser} class is a useful tool for presenting a selection * of options to the {@link SmartDashboard}. @@ -44,8 +44,8 @@ public class SendableChooser implements Sendable { /** * A table linking strings to the objects the represent */ - private StringArray choices = new StringArray(); - private List values = new List(); + private ArrayList choices = new ArrayList(); + private ArrayList values = new ArrayList(); private String defaultChoice = null; private Object defaultValue = null; @@ -77,8 +77,9 @@ public class SendableChooser implements Sendable { // not found choices.add(name); values.add(object); + if (table != null) { - table.putValue(OPTIONS, choices); + table.putStringArray(OPTIONS, choices.toArray(new String[0])); } } @@ -131,7 +132,7 @@ public class SendableChooser implements Sendable { public void initTable(ITable table) { this.table = table; if (table != null) { - table.putValue(OPTIONS, choices); + table.putStringArray(OPTIONS, choices.toArray(new String[0])); if (defaultChoice != null) { table.putString(DEFAULT, defaultChoice); } diff --git a/wpilibj/wpilibJavaDevices/src/main/java/edu/wpi/first/wpilibj/Preferences.java b/wpilibj/wpilibJavaDevices/src/main/java/edu/wpi/first/wpilibj/Preferences.java index 1984868445..f939c272cf 100644 --- a/wpilibj/wpilibJavaDevices/src/main/java/edu/wpi/first/wpilibj/Preferences.java +++ b/wpilibj/wpilibJavaDevices/src/main/java/edu/wpi/first/wpilibj/Preferences.java @@ -6,20 +6,12 @@ /*----------------------------------------------------------------------------*/ package edu.wpi.first.wpilibj; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.Hashtable; import java.util.Vector; import edu.wpi.first.wpilibj.communication.FRCNetworkCommunicationsLibrary.tResourceType; import edu.wpi.first.wpilibj.communication.UsageReporting; import edu.wpi.first.wpilibj.networktables.NetworkTable; -import edu.wpi.first.wpilibj.tables.ITable; -import edu.wpi.first.wpilibj.tables.ITableListener; +import edu.wpi.first.wpilibj.tables.TableKeyNotDefinedException; /** * The preferences class provides a relatively simple way to save important @@ -28,7 +20,7 @@ import edu.wpi.first.wpilibj.tables.ITableListener; *

* This class loads and saves from a file inside the RoboRIO. The user can not * access the file directly, but may modify values at specific fields which will - * then be saved to the file when {@link Preferences#save() save()} is called. + * then be automatically saved to the file by the NetworkTables server. *

* *

@@ -37,10 +29,7 @@ import edu.wpi.first.wpilibj.tables.ITableListener; * *

* This will also interact with {@link NetworkTable} by creating a table called - * "Preferences" with all the key-value pairs. To save using - * {@link NetworkTable}, simply set the boolean at position ~S A V E~ to true. - * Also, if the value of any variable is " in the {@link NetworkTable}, then - * that represents non-existence in the {@link Preferences} table + * "Preferences" with all the key-value pairs. *

* * @author Joe Grinstead @@ -51,30 +40,14 @@ public class Preferences { * The Preferences table name */ private static final String TABLE_NAME = "Preferences"; - /** - * The value of the save field - */ - private static final String SAVE_FIELD = "~S A V E~"; - /** - * The file to save to - */ - private static final String FILE_NAME = "/home/lvuser/wpilib-preferences.ini"; - /** - * The characters to put between a field and value - */ - private static final byte[] VALUE_PREFIX = {'=', '\"'}; - /** - * The characters to put after the value - */ - private static final byte[] VALUE_SUFFIX = {'\"', '\n'}; - /** - * The newline character - */ - private static final byte[] NEW_LINE = {'\n'}; /** * The singleton instance */ private static Preferences instance; + /** + * The network table + */ + private NetworkTable table; /** * Returns the preferences instance. @@ -89,54 +62,10 @@ public class Preferences { } /** - * The semaphore for beginning reads and writes to the file - */ - private final Object fileLock = new Object(); - /** - * The semaphore for reading from the table - */ - private final Object lock = new Object(); - /** - * The actual values (String->String) - */ - private Hashtable values; - /** - * The keys in the order they were read from the file - */ - private Vector keys; - /** - * The comments that were in the file sorted by which key they appeared over - * (String->Comment) - */ - private Hashtable comments; - /** - * The comment at the end of the file - */ - private Comment endComment; - - /** - * Creates a preference class that will automatically read the file in a - * different thread. Any call to its methods will be blocked until the thread - * is finished reading. + * Creates a preference class. */ private Preferences() { - values = new Hashtable(); - keys = new Vector(); - - // We synchronized on fileLock and then wait - // for it to know that the reading thread has started - synchronized (fileLock) { - new Thread() { - public void run() { - read(); - } - }.start(); - try { - fileLock.wait(); - } catch (InterruptedException ex) { - } - } - + table = NetworkTable.getTable(TABLE_NAME); UsageReporting.report(tResourceType.kResourceType_Preferences, 0); } @@ -144,188 +73,81 @@ public class Preferences { * @return a vector of the keys */ public Vector getKeys() { - synchronized (lock) { - return keys; - } - } - - /** - * Puts the given value into the given key position - * - * @param key the key - * @param value the value - * @throws ImproperPreferenceKeyException if the key contains an illegal - * character - */ - private void put(String key, String value) { - synchronized (lock) { - if (key == null) { - throw new NullPointerException(); - } - ImproperPreferenceKeyException.confirmString(key); - if (values.put(key, value) == null) { - keys.addElement(key); - } - NetworkTable.getTable(TABLE_NAME).putString(key, value); + Vector keys = new Vector(); + for (String key : table.getKeys()) { + keys.add(key); } + return keys; } /** * Puts the given string into the preferences table. * - *

- * The value may not have quotation marks, nor may the key have any whitespace - * nor an equals sign - *

- * - *

- * This will NOT save the value to memory between power cycles, to do - * that you must call {@link Preferences#save() save()} (which must be used - * with care). at some point after calling this. - *

- * * @param key the key * @param value the value * @throws NullPointerException if value is null - * @throws IllegalArgumentException if value contains a quotation mark - * @throws ImproperPreferenceKeyException if the key contains any whitespace - * or an equals sign */ public void putString(String key, String value) { if (value == null) { throw new NullPointerException(); } - if (value.indexOf('"') != -1) { - throw new IllegalArgumentException("Can not put string:" + value - + " because it contains quotation marks"); - } - put(key, value); + table.putString(key, value); + table.setPersistent(key); } /** * Puts the given int into the preferences table. * - *

- * The key may not have any whitespace nor an equals sign - *

- * - *

- * This will NOT save the value to memory between power cycles, to do - * that you must call {@link Preferences#save() save()} (which must be used - * with care) at some point after calling this. - *

- * * @param key the key * @param value the value - * @throws ImproperPreferenceKeyException if the key contains any whitespace - * or an equals sign */ public void putInt(String key, int value) { - put(key, String.valueOf(value)); + table.putNumber(key, value); + table.setPersistent(key); } /** * Puts the given double into the preferences table. * - *

- * The key may not have any whitespace nor an equals sign - *

- * - *

- * This will NOT save the value to memory between power cycles, to do - * that you must call {@link Preferences#save() save()} (which must be used - * with care) at some point after calling this. - *

- * * @param key the key * @param value the value - * @throws ImproperPreferenceKeyException if the key contains any whitespace - * or an equals sign */ public void putDouble(String key, double value) { - put(key, String.valueOf(value)); + table.putNumber(key, value); + table.setPersistent(key); } /** * Puts the given float into the preferences table. * - *

- * The key may not have any whitespace nor an equals sign - *

- * - *

- * This will NOT save the value to memory between power cycles, to do - * that you must call {@link Preferences#save() save()} (which must be used - * with care) at some point after calling this. - *

- * * @param key the key * @param value the value - * @throws ImproperPreferenceKeyException if the key contains any whitespace - * or an equals sign */ public void putFloat(String key, float value) { - put(key, String.valueOf(value)); + table.putNumber(key, value); + table.setPersistent(key); } /** * Puts the given boolean into the preferences table. * - *

- * The key may not have any whitespace nor an equals sign - *

- * - *

- * This will NOT save the value to memory between power cycles, to do - * that you must call {@link Preferences#save() save()} (which must be used - * with care) at some point after calling this. - *

- * * @param key the key * @param value the value - * @throws ImproperPreferenceKeyException if the key contains any whitespace - * or an equals sign */ public void putBoolean(String key, boolean value) { - put(key, String.valueOf(value)); + table.putBoolean(key, value); + table.setPersistent(key); } /** * Puts the given long into the preferences table. * - *

- * The key may not have any whitespace nor an equals sign - *

- * - *

- * This will NOT save the value to memory between power cycles, to do - * that you must call {@link Preferences#save() save()} (which must be used - * with care) at some point after calling this. - *

- * * @param key the key * @param value the value - * @throws ImproperPreferenceKeyException if the key contains any whitespace - * or an equals sign */ public void putLong(String key, long value) { - put(key, String.valueOf(value)); - } - - /** - * Returns the value at the given key. - * - * @param key the key - * @return the value (or null if none exists) - * @throws NullPointerException if the key is null - */ - private String get(String key) { - synchronized (lock) { - if (key == null) { - throw new NullPointerException(); - } - return (String) values.get(key); - } + table.putNumber(key, value); + table.setPersistent(key); } /** @@ -333,26 +155,18 @@ public class Preferences { * * @param key the key * @return if there is a value at the given key - * @throws NullPointerException if key is null */ public boolean containsKey(String key) { - return get(key) != null; + return table.containsKey(key); } /** * Remove a preference * * @param key the key - * @throws NullPointerException if key is null */ public void remove(String key) { - synchronized (lock) { - if (key == null) { - throw new NullPointerException(); - } - values.remove(key); - keys.removeElement(key); - } + table.delete(key); } /** @@ -362,11 +176,9 @@ public class Preferences { * @param key the key * @param backup the value to return if none exists in the table * @return either the value in the table, or the backup - * @throws NullPointerException if the key is null */ public String getString(String key, String backup) { - String value = get(key); - return value == null ? backup : value; + return table.getString(key, backup); } /** @@ -376,19 +188,12 @@ public class Preferences { * @param key the key * @param backup the value to return if none exists in the table * @return either the value in the table, or the backup - * @throws IncompatibleTypeException if the value in the table can not be - * converted to an int */ public int getInt(String key, int backup) { - String value = get(key); - if (value == null) { + try { + return (int)table.getNumber(key); + } catch (TableKeyNotDefinedException e) { return backup; - } else { - try { - return Integer.parseInt(value); - } catch (NumberFormatException e) { - throw new IncompatibleTypeException(value, "int"); - } } } @@ -399,20 +204,9 @@ public class Preferences { * @param key the key * @param backup the value to return if none exists in the table * @return either the value in the table, or the backup - * @throws IncompatibleTypeException if the value in the table can not be - * converted to an double */ public double getDouble(String key, double backup) { - String value = get(key); - if (value == null) { - return backup; - } else { - try { - return Double.parseDouble(value); - } catch (NumberFormatException e) { - throw new IncompatibleTypeException(value, "double"); - } - } + return table.getDouble(key, backup); } /** @@ -422,22 +216,9 @@ public class Preferences { * @param key the key * @param backup the value to return if none exists in the table * @return either the value in the table, or the backup - * @throws IncompatibleTypeException if the value in the table can not be - * converted to a boolean */ public boolean getBoolean(String key, boolean backup) { - String value = get(key); - if (value == null) { - return backup; - } else { - if (value.equalsIgnoreCase("true")) { - return true; - } else if (value.equalsIgnoreCase("false")) { - return false; - } else { - throw new IncompatibleTypeException(value, "boolean"); - } - } + return table.getBoolean(key, backup); } /** @@ -447,19 +228,12 @@ public class Preferences { * @param key the key * @param backup the value to return if none exists in the table * @return either the value in the table, or the backup - * @throws IncompatibleTypeException if the value in the table can not be - * converted to a float */ public float getFloat(String key, float backup) { - String value = get(key); - if (value == null) { + try { + return (float)table.getNumber(key); + } catch (TableKeyNotDefinedException e) { return backup; - } else { - try { - return Float.parseFloat(value); - } catch (NumberFormatException e) { - throw new IncompatibleTypeException(value, "float"); - } } } @@ -470,403 +244,21 @@ public class Preferences { * @param key the key * @param backup the value to return if none exists in the table * @return either the value in the table, or the backup - * @throws IncompatibleTypeException if the value in the table can not be - * converted to a long */ public long getLong(String key, long backup) { - String value = get(key); - if (value == null) { - put(key, String.valueOf(backup)); + try { + return (long)table.getNumber(key); + } catch (TableKeyNotDefinedException e) { return backup; - } else { - try { - return Long.parseLong(value); - } catch (NumberFormatException e) { - throw new IncompatibleTypeException(value, "long"); - } } } /** - * Saves the preferences to a file on the RoboRIO. - * - *

- * This should NOT be called often. Too many writes can damage the - * RoboRIO's flash memory. While it is ok to save once or twice a match, this - * should never be called every run of {@link IterativeRobot#teleopPeriodic()} - * . - *

- * - *

- * The actual writing of the file is done in a separate thread. However, any - * call to a get or put method will wait until the table is fully saved before - * continuing. - *

+ * This function is no longer required, as NetworkTables automatically + * saves persistent values (which all Preferences values are) periodically + * when running as a server. + * @deprecated backwards compatibility shim */ public void save() { - synchronized (fileLock) { - new Thread() { - public void run() { - write(); - } - }.start(); - try { - fileLock.wait(); - } catch (InterruptedException ex) { - } - } - } - - /** - * Internal method that actually writes the table to a file. This is called in - * its own thread when {@link Preferences#save() save()} is called. - */ - private void write() { - synchronized (lock) { - synchronized (fileLock) { - fileLock.notifyAll(); - } - - File file = null; - FileOutputStream output = null; - try { - file = new File(FILE_NAME); - - if (file.exists()) - file.delete(); - - file.createNewFile(); - - output = new FileOutputStream(file); - - output.write("[Preferences]\n".getBytes()); - - for (int i = 0; i < keys.size(); i++) { - String key = (String) keys.elementAt(i); - String value = (String) values.get(key); - - if (comments != null) { - Comment comment = (Comment) comments.get(key); - if (comment != null) { - comment.write(output); - } - } - - output.write(key.getBytes()); - output.write(VALUE_PREFIX); - output.write(value.getBytes()); - output.write(VALUE_SUFFIX); - } - - if (endComment != null) { - endComment.write(output); - } - } catch (IOException ex) { - ex.printStackTrace(); - } finally { - if (output != null) { - try { - output.close(); - } catch (IOException ex) { - } - } - NetworkTable.getTable(TABLE_NAME).putBoolean(SAVE_FIELD, false); - } - } - } - - /** - * The internal method to read from a file. This will be called in its own - * thread when the preferences singleton is first created. - */ - private void read() { - class EndOfStreamException extends Exception { - } - - class Reader { - - InputStream stream; - - Reader(InputStream stream) { - this.stream = stream; - } - - public char read() throws IOException, EndOfStreamException { - int input = stream.read(); - if (input == -1) { - throw new EndOfStreamException(); - } else { - // Check for carriage returns - return input == '\r' ? '\n' : (char) input; - } - } - - char readWithoutWhitespace() throws IOException, EndOfStreamException { - while (true) { - char value = read(); - switch (value) { - case ' ': - case '\t': - continue; - default: - return value; - } - } - } - } - - synchronized (lock) { - synchronized (fileLock) { - fileLock.notifyAll(); - } - - Comment comment = null; - - - - File file = null; - FileInputStream input = null; - try { - file = new File(FILE_NAME); - - if (file.exists()) { - input = new FileInputStream(file); - Reader reader = new Reader(input); - - StringBuffer buffer; - - while (true) { - char value = reader.readWithoutWhitespace(); - - if (value == '\n' || value == ';') { - if (comment == null) { - comment = new Comment(); - } - - if (value == '\n') { - comment.addBytes(NEW_LINE); - } else { - buffer = new StringBuffer(30); - for (; value != '\n'; value = reader.read()) { - buffer.append(value); - } - buffer.append('\n'); - comment.addBytes(buffer.toString().getBytes()); - } - } else if (value == '[') { - // Find the end of the section and the new line after it and throw - // it away - while (reader.read() != ']'); - while (reader.read() != '\n'); - } else { - buffer = new StringBuffer(30); - for (; value != '='; value = reader.readWithoutWhitespace()) { - buffer.append(value); - } - String name = buffer.toString(); - buffer = new StringBuffer(30); - - boolean shouldBreak = false; - - value = reader.readWithoutWhitespace(); - if (value == '"') { - for (value = reader.read(); value != '"'; value = reader.read()) { - buffer.append(value); - } - // Clear the line - while (reader.read() != '\n'); - } else { - try { - for (; value != '\n'; value = reader.readWithoutWhitespace()) { - buffer.append(value); - } - } catch (EndOfStreamException e) { - shouldBreak = true; - } - } - - String result = buffer.toString(); - - keys.addElement(name); - values.put(name, result); - NetworkTable.getTable(TABLE_NAME).putString(name, result); - - if (comment != null) { - if (comments == null) { - comments = new Hashtable(); - } - comments.put(name, comment); - comment = null; - } - - - if (shouldBreak) { - break; - } - } - } - } - } catch (IOException ex) { - ex.printStackTrace(); - } catch (EndOfStreamException ex) { - System.out.println("Done Reading"); - } - - if (input != null) { - try { - input.close(); - } catch (IOException ex) { - } - } - - if (comment != null) { - endComment = comment; - } - } - - NetworkTable.getTable(TABLE_NAME).putBoolean(SAVE_FIELD, false); - // TODO: Verify that this works even though it changes with subtables. - // Should work since preferences shouldn't have subtables. - NetworkTable.getTable(TABLE_NAME).addTableListener(new ITableListener() { - public void valueChanged(ITable source, String key, Object value, boolean isNew) { - if (key.equals(SAVE_FIELD)) { - if (((Boolean) value).booleanValue()) { - save(); - } - } else { - synchronized (lock) { - if (!ImproperPreferenceKeyException.isAcceptable(key) - || value.toString().indexOf('"') != -1) { - if (values.contains(key) || keys.contains(key)) { - values.remove(key); - keys.removeElement(key); - NetworkTable.getTable(TABLE_NAME).putString(key, "\""); - } - } else { - if (values.put(key, value.toString()) == null) { - keys.addElement(key); - } - } - } - } - } - }); - } - - /** - * A class representing some comment lines in the ini file. This is used so - * that if a programmer ever directly modifies the ini file, then his/her - * comments will still be there after {@link Preferences#save() save()} is - * called. - */ - private static class Comment { - - /** - * A vector of byte arrays. Each array represents a line to write - */ - private Vector bytes = new Vector(); - - /** - * Appends the given bytes to the comment. - * - * @param bytes the bytes to add - */ - private void addBytes(byte[] bytes) { - this.bytes.addElement(bytes); - } - - /** - * Writes this comment to the given stream - * - * @param stream the stream to write to - * @throws IOException if the stream has a problem - */ - private void write(OutputStream stream) throws IOException { - for (int i = 0; i < bytes.size(); i++) { - stream.write((byte[]) bytes.elementAt(i)); - } - } - } - - /** - * This exception is thrown if the a value requested cannot be converted to - * the requested type. - */ - public static class IncompatibleTypeException extends RuntimeException { - - /** - * Creates an exception with a description based on the input - * - * @param value the value that can not be converted - * @param type the type that the value can not be converted to - */ - public IncompatibleTypeException(String value, String type) { - super("Cannot convert \"" + value + "\" into " + type); - } - } - - /** - * Should be thrown if a string can not be used as a key in the preferences - * file. This happens if the string contains a new line, a space, a tab, or an - * equals sign. - */ - public static class ImproperPreferenceKeyException extends RuntimeException { - - /** - * Instantiates an exception with a descriptive message based on the input. - * - * @param value the illegal key - * @param letter the specific character that made it illegal - */ - public ImproperPreferenceKeyException(String value, char letter) { - super("Preference key \"" + value + "\" is not allowed to contain letter with ASCII code:" - + (byte) letter); - } - - /** - * Tests if the given string is ok to use as a key in the preference table. - * If not, then a {@link ImproperPreferenceKeyException} will be thrown. - * - * @param value the value to test - */ - public static void confirmString(String value) { - for (int i = 0; i < value.length(); i++) { - char letter = value.charAt(i); - switch (letter) { - case '=': - case '\n': - case '\r': - case ' ': - case '\t': - case '[': - case ']': - throw new ImproperPreferenceKeyException(value, letter); - } - } - } - - /** - * Returns whether or not the given string is ok to use in the preference - * table. - * - * @param value the string to check - * @return true if the given string is ok to use in the preference table - */ - public static boolean isAcceptable(String value) { - for (int i = 0; i < value.length(); i++) { - char letter = value.charAt(i); - switch (letter) { - case '=': - case '\n': - case '\r': - case ' ': - case '\t': - case '[': - case ']': - return false; - } - } - return true; - } } } diff --git a/wpilibj/wpilibJavaDevices/src/main/java/edu/wpi/first/wpilibj/RobotBase.java b/wpilibj/wpilibJavaDevices/src/main/java/edu/wpi/first/wpilibj/RobotBase.java index eba0a7adb6..0802ea6593 100644 --- a/wpilibj/wpilibJavaDevices/src/main/java/edu/wpi/first/wpilibj/RobotBase.java +++ b/wpilibj/wpilibJavaDevices/src/main/java/edu/wpi/first/wpilibj/RobotBase.java @@ -59,6 +59,7 @@ public abstract class RobotBase { // TODO: See if the next line is necessary // Resource.RestartProgram(); + NetworkTable.setNetworkIdentity("Robot"); NetworkTable.setServerMode();// must be before b m_ds = DriverStation.getInstance(); NetworkTable.getTable(""); // forces network tables to initialize diff --git a/wpilibj/wpilibJavaIntegrationTests/src/main/java/edu/wpi/first/wpilibj/PrefrencesTest.java b/wpilibj/wpilibJavaIntegrationTests/src/main/java/edu/wpi/first/wpilibj/PrefrencesTest.java index 623ee94cf5..234012e596 100644 --- a/wpilibj/wpilibJavaIntegrationTests/src/main/java/edu/wpi/first/wpilibj/PrefrencesTest.java +++ b/wpilibj/wpilibJavaIntegrationTests/src/main/java/edu/wpi/first/wpilibj/PrefrencesTest.java @@ -44,8 +44,9 @@ public class PrefrencesTest extends AbstractComsSetup { */ @Before public void setUp() throws Exception { + NetworkTable.shutdown(); try { - File file = new File("/home/lvuser/wpilib-preferences.ini"); + File file = new File("networktables.ini"); file.mkdirs(); if (file.exists()) { file.delete(); @@ -53,12 +54,13 @@ public class PrefrencesTest extends AbstractComsSetup { file.createNewFile(); OutputStream output = new FileOutputStream(file); output - .write("checkedValueInt = 2\ncheckedValueDouble = .2\ncheckedValueFloat = 3.14\ncheckedValueLong = 172\ncheckedValueString =\"hello \nHow are you ?\"\ncheckedValueBoolean = false" + .write("[NetworkTables Storage 3.0]\ndouble \"/Preferences/checkedValueInt\"=2\ndouble \"/Preferences/checkedValueDouble\"=.2\ndouble \"/Preferences/checkedValueFloat\"=3.14\ndouble \"/Preferences/checkedValueLong\"=172\nstring \"/Preferences/checkedValueString\"=\"hello \\nHow are you ?\"\nboolean \"/Preferences/checkedValueBoolean\"=false\n" .getBytes()); } catch (IOException e) { e.printStackTrace(); } + NetworkTable.initialize(); pref = Preferences.getInstance(); prefTable = NetworkTable.getTable("Preferences"); @@ -114,7 +116,7 @@ public class PrefrencesTest extends AbstractComsSetup { String networkedNumber = "networkCheckedValue"; int networkNumberValue = 100; pref.putInt(networkedNumber, networkNumberValue); - assertEquals((new Integer(networkNumberValue).toString()), prefTable.getString(networkedNumber)); + assertEquals(networkNumberValue, (int)(prefTable.getNumber(networkedNumber))); pref.remove(networkedNumber); }