Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add LimelightHelpers; make Limelight an interface #11

Merged
merged 4 commits into from
Jan 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.team2813.lib2813.limelight;

import java.util.Optional;
import java.util.OptionalDouble;
import java.util.OptionalLong;
import java.util.function.Function;

Expand Down Expand Up @@ -39,10 +40,6 @@ static Function<JSONObject, Optional<JSONObject>> getRoot() {
return getJSONObject("Results");
}

static OptionalLong unboxLong(Optional<Long> val) {
return val.map(OptionalLong::of).orElseGet(OptionalLong::empty);
}

static Function<JSONObject, Optional<Long>> getLong(String key) {
return (j) -> {
if (!j.has(key)) {
Expand All @@ -55,6 +52,20 @@ static Function<JSONObject, Optional<Long>> getLong(String key) {
}
};
}

static Function<JSONObject, Optional<Double>> getDouble(String key) {
return (j) -> {
if (!j.has(key)) {
return Optional.empty();
}
try {
return Optional.of(j.getDouble(key));
} catch (JSONException e) {
return Optional.empty();
}
};
}

static Function<JSONObject, Optional<JSONArray>> getArr(String key) {
return (obj) -> {
if (!obj.has(key)) {
Expand Down
131 changes: 14 additions & 117 deletions limelight/src/main/java/com/team2813/lib2813/limelight/Limelight.java
Original file line number Diff line number Diff line change
@@ -1,135 +1,32 @@
package com.team2813.lib2813.limelight;

import static com.team2813.lib2813.limelight.JSONHelper.getArr;
import static com.team2813.lib2813.limelight.JSONHelper.getLong;
import static com.team2813.lib2813.limelight.JSONHelper.getRoot;
import static com.team2813.lib2813.limelight.JSONHelper.unboxLong;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.OptionalLong;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

import org.json.JSONArray;
import org.json.JSONObject;

import edu.wpi.first.wpilibj.DriverStation;

public class Limelight {
private static Map<String, Limelight> limelights = new HashMap<>();
private final String name;
private final DataCollection collectionThread;
private static final ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);

static final String DEFAULT_ADDRESS = "limelight.local";

private ScheduledFuture<?> thread;

boolean started = false;

// specific types of data;
private final LocationalData data;

Limelight(String address) {
data = new LocationalData(this);
this.name = address;
collectionThread = new DataCollection(address);
}

void start() {
if (!started) {
thread = executor.scheduleAtFixedRate(collectionThread, 20, 40, TimeUnit.MILLISECONDS);
started = true;
}
}

void runThread() {
collectionThread.run();
}

String getName() {
return name;
}

public Optional<JSONObject> getJsonDump() {
return collectionThread.getMostRecent();
}
import java.util.Optional;
import java.util.OptionalDouble;

public interface Limelight {

/**
* Gets the targeting latency from the limelight
* @return The targeting latency
* Gets the limelight with the default name.
* @return the {@link Limelight} object for interfacing with the limelight
*/
public OptionalLong getTargetingLatency() {
return unboxLong(getJsonDump().flatMap(getRoot()).flatMap(getLong("tl")));
public static Limelight getDefaultLimelight() {
return RestLimelight.getDefaultLimelight();
}

public OptionalLong getCaptureLatency() {
return unboxLong(getJsonDump().flatMap(getRoot()).flatMap(getLong("cl")));
}
OptionalDouble getTimestamp();

public OptionalLong getTimestamp() {
return unboxLong(getJsonDump().flatMap(getRoot()).flatMap(getLong("ts")));
}
boolean hasTarget();

private static <T> Function<T, Boolean> not(Function<? super T, Boolean> fnc) {
return (t) -> !fnc.apply(t);
}

public boolean hasTarget() {
return getJsonDump().flatMap(getRoot()).flatMap(getArr("Fiducial")).map(not(JSONArray::isEmpty)).orElse(false);
}
/**
* Gets an object for getting locational data
* @return an object for getting locational data
*/
public LocationalData getLocationalData() {
return data;
}

private void clean() {
try {
thread.cancel(true);
executor.awaitTermination(2, TimeUnit.SECONDS);
} catch (InterruptedException e) {
DriverStation.reportError(e.getMessage(), false);
}
}

/**
* Gets the limelight with the default name.
* @return the {@link Limelight} object for interfacing with the limelight
*/
public static Limelight getDefaultLimelight() {
return getLimelight("");
}
LocationalData getLocationalData();

/**
* Gets the limelight with the specified name. Calling with a blank {@code limelightName}
* is equivalent to calling {@link #getDefaultLimelight()}
* @param limelightName The hostname or ip address of the limelight
* @return the {@link Limelight} object for interfacing with the limelight
* @throws NullPointerException if {@code limelightName} is null
*/
public static Limelight getLimelight(String limelightName) {
String table = Objects.requireNonNull(limelightName,"limelightName shouldn't be null");
if (table.isBlank()) {
table = DEFAULT_ADDRESS;
}
Limelight result = limelights.computeIfAbsent(table, Limelight::new);
result.start();
return result;
}
OptionalDouble getCaptureLatency();

static void eraseInstances() {
for (Limelight limelight : limelights.values()) {
limelight.clean();
}
limelights.clear();
}
@Deprecated
Optional<JSONObject> getJsonDump();
}
Loading
Loading