From 8d215d31c27f4831c49d737c1599dfb270854681 Mon Sep 17 00:00:00 2001 From: Tom Lazar Date: Tue, 22 Feb 2022 08:33:06 -0600 Subject: [PATCH 1/2] feat: wip new nt bind subsystem first draft --- src/main/java/lib2202/nt/NtBind.java | 134 ++++++++++++++++++++++++++ src/main/java/lib2202/nt/NtInput.java | 17 ++++ 2 files changed, 151 insertions(+) create mode 100644 src/main/java/lib2202/nt/NtBind.java create mode 100644 src/main/java/lib2202/nt/NtInput.java diff --git a/src/main/java/lib2202/nt/NtBind.java b/src/main/java/lib2202/nt/NtBind.java new file mode 100644 index 00000000..bd53a0b3 --- /dev/null +++ b/src/main/java/lib2202/nt/NtBind.java @@ -0,0 +1,134 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +package lib2202.nt; + +import java.lang.reflect.Field; +import java.util.LinkedList; +import java.util.function.Consumer; +import java.util.function.Supplier; + +import edu.wpi.first.networktables.NetworkTable; +import edu.wpi.first.networktables.NetworkTableInstance; +import edu.wpi.first.wpilibj2.command.SubsystemBase; + +public class NtBind extends SubsystemBase { + NetworkTable table = NetworkTableInstance.getDefault().getTable("root"); + int count; + + interface apply { + Boolean apply(); + } + + class doubleApply implements apply { + public doubleApply(NtBind ntBind, NetworkTable table, String name, Field f, Object state) { + var nt = table.getEntry(name); + + this.current = () -> { + try { + return f.getDouble(state); + } catch (Exception e) { + ntBind.ReportError(table.getPath(), name, e); + return 0.0; + } + }; + + this.set = (Double val) -> { + try { + f.setDouble(state, val); + } catch (Exception e) { + ntBind.ReportError(table.getPath(), name, e); + } + }; + + this.next = () -> nt.getDouble(this.current.get()); + } + + Supplier current; + Consumer set; + Supplier next; + + public Boolean apply() { + var next = this.next.get(); + var current = this.current.get(); + + if (next != current) { + set.accept(next); + return true; + } + + return false; + } + } + + class boundData implements apply { + LinkedList applys = new LinkedList(); + Runnable onChange; + + public Boolean apply() { + Boolean isChanged = false; + + for (var a : applys) { + isChanged |= a.apply(); + } + + if(isChanged && onChange != null) { + onChange.run(); + } + + return isChanged; + } + } + + LinkedList boundObjects = new LinkedList(); + + public TStateObject bind(TStateObject state, String name, Runnable onChange) { + var classFields = state.getClass().getFields(); + var data = new boundData(); + var sub = table.getSubTable(name); + + for (var field : classFields) { + for (var annotation : field.getAnnotations()) { + + if (annotation instanceof NtInput) { + var ntInput = (NtInput) annotation; + + // figure out we should call it + var entryName = ntInput.name(); + if (entryName == "") { + entryName = field.getName(); + } + + if (field.getType().equals(double.class)) { + data.applys.add(new doubleApply(this, sub, entryName, field, state)); + } + } + } + } + + boundObjects.add(data); + return state; + } + + public void ReportError(String table, String name, Exception e) { + + } + + /** Creates a new NtBind. */ + public NtBind() { + } + + @Override + public void periodic() { + count++; + if (count > 10) { + count = 0; + + for (var data : boundObjects) { + data.apply(); + } + } + // This method will be called once per scheduler run + } +} diff --git a/src/main/java/lib2202/nt/NtInput.java b/src/main/java/lib2202/nt/NtInput.java new file mode 100644 index 00000000..460a06ef --- /dev/null +++ b/src/main/java/lib2202/nt/NtInput.java @@ -0,0 +1,17 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +package lib2202.nt; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.annotation.ElementType; + +/** Add your docs here. */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface NtInput { + String name() default ""; +} From e02a2d01e84a6a7a5b7ba5ed10ae3e50c9b5f987 Mon Sep 17 00:00:00 2001 From: Tom Lazar Date: Thu, 24 Feb 2022 15:27:57 -0600 Subject: [PATCH 2/2] feat: add example and --- src/main/java/lib2202/nt/NtBind.java | 94 ++++++++++++++----- src/main/java/lib2202/nt/NtOutput.java | 17 ++++ .../java/lib2202/nt/examples/DoubleInput.java | 28 ++++++ 3 files changed, 115 insertions(+), 24 deletions(-) create mode 100644 src/main/java/lib2202/nt/NtOutput.java create mode 100644 src/main/java/lib2202/nt/examples/DoubleInput.java diff --git a/src/main/java/lib2202/nt/NtBind.java b/src/main/java/lib2202/nt/NtBind.java index bd53a0b3..ad7920ae 100644 --- a/src/main/java/lib2202/nt/NtBind.java +++ b/src/main/java/lib2202/nt/NtBind.java @@ -21,30 +21,52 @@ interface apply { Boolean apply(); } - class doubleApply implements apply { - public doubleApply(NtBind ntBind, NetworkTable table, String name, Field f, Object state) { - var nt = table.getEntry(name); - - this.current = () -> { - try { - return f.getDouble(state); - } catch (Exception e) { - ntBind.ReportError(table.getPath(), name, e); - return 0.0; - } - }; + public apply buildDoubleInput(NtBind ntBind, NetworkTable table, String name, Field f, Object state) { + var a = new doubleApply(); + var nt = table.getEntry(name); + + a.current = () -> { + try { + return f.getDouble(state); + } catch (Exception e) { + ntBind.ReportError(table.getPath(), name, e); + return 0.0; + } + }; - this.set = (Double val) -> { - try { - f.setDouble(state, val); - } catch (Exception e) { - ntBind.ReportError(table.getPath(), name, e); - } - }; + a.set = (Double val) -> { + try { + f.setDouble(state, val); + } catch (Exception e) { + ntBind.ReportError(table.getPath(), name, e); + } + }; - this.next = () -> nt.getDouble(this.current.get()); - } + a.next = () -> nt.getDouble(a.current.get()); + + return a; + } + + public apply buildDoubleOutput(NtBind ntBind, NetworkTable table, String name, Field f, Object state) { + var a = new doubleApply(); + var nt = table.getEntry(name); + + a.current = () -> nt.getDouble(0.0); + a.set = (Double val) -> nt.setDouble(val); + a.next = () -> { + try { + return f.getDouble(state); + } catch (Exception e) { + ntBind.ReportError(table.getPath(), name, e); + return 0.0; + } + }; + + return a; + } + + class doubleApply implements apply { Supplier current; Consumer set; Supplier next; @@ -73,10 +95,10 @@ public Boolean apply() { isChanged |= a.apply(); } - if(isChanged && onChange != null) { + if (isChanged && onChange != null) { onChange.run(); } - + return isChanged; } } @@ -101,7 +123,21 @@ public TStateObject bind(TStateObject state, String name, Runnabl } if (field.getType().equals(double.class)) { - data.applys.add(new doubleApply(this, sub, entryName, field, state)); + data.applys.add(buildDoubleInput(this, sub, entryName, field, state)); + } + } + + if (annotation instanceof NtOutput) { + var ntOutput = (NtOutput) annotation; + + // figure out we should call it + var entryName = ntOutput.name(); + if (entryName == "") { + entryName = field.getName(); + } + + if (field.getType().equals(double.class)) { + data.applys.add(buildDoubleOutput(this, sub, entryName, field, state)); } } } @@ -112,7 +148,17 @@ public TStateObject bind(TStateObject state, String name, Runnabl } public void ReportError(String table, String name, Exception e) { + // todo: real comments and reporting and something + } + + private static NtBind instance; + + public static NtBind getInstance() { + if (instance == null) { + instance = new NtBind(); + } + return instance; } /** Creates a new NtBind. */ diff --git a/src/main/java/lib2202/nt/NtOutput.java b/src/main/java/lib2202/nt/NtOutput.java new file mode 100644 index 00000000..8e096a43 --- /dev/null +++ b/src/main/java/lib2202/nt/NtOutput.java @@ -0,0 +1,17 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +package lib2202.nt; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.annotation.ElementType; + +/** Add your docs here. */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface NtOutput { + String name() default ""; +} diff --git a/src/main/java/lib2202/nt/examples/DoubleInput.java b/src/main/java/lib2202/nt/examples/DoubleInput.java new file mode 100644 index 00000000..291ad915 --- /dev/null +++ b/src/main/java/lib2202/nt/examples/DoubleInput.java @@ -0,0 +1,28 @@ +package lib2202.nt.examples; + + +import lib2202.nt.NtInput; +import lib2202.nt.NtOutput; +import lib2202.nt.NtBind; + +public class DoubleInput { + class State { + + @NtInput(name = "set") + public double SetPoint = 0; + + @NtOutput(name = "err") + public double Error = 0; + + // @NtInput() + } + + State left = NtBind.getInstance().bind(new State(), "left", this::onChanged); + State right = NtBind.getInstance().bind(new State(), "right", this::onChanged); + + void onChanged() { + System.out.println("SetPoint: " + left.SetPoint + ", err: " + left.Error); + System.out.println("SetPoint: " + right.SetPoint + ", err: " + right.Error); + } + +}