diff --git a/docs/requirements.txt b/docs/requirements.txt index 20bbd59f03..4a80bea4dd 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -36,7 +36,6 @@ sphinx-autobuild==2024.10.3 sphinx-basic-ng==1.0.0b2 sphinx-notfound-page==1.1.0 sphinx-rtd-theme==3.0.2 -sphinx-tabs==3.4.7 sphinx_design==0.6.1 sphinxcontrib-applehelp==2.0.0 sphinxcontrib-devhelp==2.0.0 diff --git a/docs/source/conf.py b/docs/source/conf.py index 3414fc7db5..887e3da799 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -181,4 +181,4 @@ def setup(app): linkcheck_auth = [(R"https://github.com/.+", token)] # MyST configuration (https://myst-parser.readthedocs.io/en/latest/configuration.html) -myst_enable_extensions = ["colon_fence", "substitution"] +myst_enable_extensions = ["colon_fence", "substitution", "attrs_inline"] diff --git a/docs/source/docs/advanced-installation/sw_install/files/Limelight2+/hardwareConfig.json b/docs/source/docs/advanced-installation/sw_install/files/Limelight2+/hardwareConfig.json index e43b1e7940..5b4c12f1a2 100644 --- a/docs/source/docs/advanced-installation/sw_install/files/Limelight2+/hardwareConfig.json +++ b/docs/source/docs/advanced-installation/sw_install/files/Limelight2+/hardwareConfig.json @@ -3,5 +3,8 @@ "ledPins" : [ 13, 18 ], "ledsCanDim" : true, "ledPWMFrequency" : 1000, + "statusLEDType": "GreenYellow", + "statusLEDPins": [ 5, 4 ], + "statusLEDActiveHigh": false, "vendorFOV" : 75.76079874010732 } diff --git a/docs/source/docs/advanced-installation/sw_install/files/Limelight2/hardwareConfig.json b/docs/source/docs/advanced-installation/sw_install/files/Limelight2/hardwareConfig.json index 33afd3cf4f..fd36c6a658 100644 --- a/docs/source/docs/advanced-installation/sw_install/files/Limelight2/hardwareConfig.json +++ b/docs/source/docs/advanced-installation/sw_install/files/Limelight2/hardwareConfig.json @@ -2,5 +2,8 @@ "deviceName" : "Limelight 2", "ledPins" : [ 17, 18 ], "ledsCanDim" : false, + "statusLEDType": "GreenYellow", + "statusLEDPins": [ 5, 4 ], + "statusLEDActiveHigh": false, "vendorFOV" : 75.76079874010732 } diff --git a/docs/source/docs/hardware/customhardware.md b/docs/source/docs/hardware/customhardware.md index b18c54e5ef..7e41ae8235 100644 --- a/docs/source/docs/hardware/customhardware.md +++ b/docs/source/docs/hardware/customhardware.md @@ -19,14 +19,18 @@ When running on Linux, PhotonVision can use [diozero](https://www.diozero.com) t "ledsCanDim" : true, "ledBrightnessRange" : [ 0, 100 ], "ledPWMFrequency" : 0, - "statusRGBPins" : [ ], - "statusRGBActiveHigh" : false, + "statusLEDType": "RGB", + "statusLEDPins" : [ ], + "statusLEDActiveHigh" : false, } ``` -:::{note} -No hardware boards with status RGB LED pins or non-dimming LED's have been tested yet. Please reach out to the development team if these features are desired, they can assist with configuration and testing. -::: +There are currently two types of status LEDs supported: + +* `RGB` (default): A singular LED mixing separate red, green, and blue inputs +* `GreenYellow`: A pair of independent green and yellow LEDs + +For an explanation of the colors used for status LEDs, see {ref}`Status LEDs` ### GPIO Pinout @@ -134,8 +138,9 @@ Here is a complete example `hardwareConfig.json`: "ledsCanDim" : true, "ledBrightnessRange" : [ 0, 100 ], "ledPWMFrequency" : 0, - "statusRGBPins" : [ ], - "statusRGBActiveHigh" : false, + "statusLEDType": "RGB", + "statusLEDPins" : [ ], + "statusLEDActiveHigh" : false, "getGPIOCommand" : "getGPIO {p}", "setGPIOCommand" : "setGPIO {p} {s}", "setPWMCommand" : "setPWM {p} {v}", diff --git a/docs/source/docs/troubleshooting/images/led.svg b/docs/source/docs/troubleshooting/images/led.svg new file mode 100644 index 0000000000..be28767808 --- /dev/null +++ b/docs/source/docs/troubleshooting/images/led.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/docs/source/docs/troubleshooting/index.md b/docs/source/docs/troubleshooting/index.md index 00fe776352..64110cda0d 100644 --- a/docs/source/docs/troubleshooting/index.md +++ b/docs/source/docs/troubleshooting/index.md @@ -5,6 +5,7 @@ common-errors logging +status-leds camera-troubleshooting networking-troubleshooting unix-commands diff --git a/docs/source/docs/troubleshooting/status-leds.md b/docs/source/docs/troubleshooting/status-leds.md new file mode 100644 index 0000000000..c3e1bc23d8 --- /dev/null +++ b/docs/source/docs/troubleshooting/status-leds.md @@ -0,0 +1,101 @@ +--- +myst: + substitutions: + led_loader: | + ```{image} images/led.svg + :height: 0 + ``` + led: | + ```{raw} html + + + + ``` +--- + + + +# Status LEDs + +PhotonVision has support for multiple kinds of status LEDs. Make sure you reference the correct table for the type present on your hardware. + +## RGB LED + + Color | Flashing | Preview | Status +--------|----------|:-------------------------:|----------------------------------------------- + Green | Yes | [{{ led }}]{.green} | Running normally, no targets visible + Blue | No | [{{ led }}]{.solid .blue} | Running normally, targets visible + Yellow | Yes | [{{ led }}]{.yellow} | NT Disconnected, no targets visible + Blue | Yes | [{{ led }}]{.blue} | NT Disconnected, targets visible + Red | Yes | [{{ led }}]{.red} | Initializing or faulted, not running + Off | No | [{{ led }}]{.off} | No power or initialization fault, not running + +## Green and Yellow LEDs + +Used on Limelight 1, 2, 2+, 3, 3G, and 3A + +Green and Yellow LED patterns may be active at the same time + + Color | Pattern | Preview | Status +--------|----------------|:-----------------------------------------------------------:|------------------------------------------------- + Green | Slow Flashing | [{{ led }}]{.green} [{{ led }}]{.off} | No targets visible + Green | Quick Flashing | [{{ led }}]{.fast .green} [{{ led }}]{.off} | Targets visible + Yellow | Flashing | [{{ led }}]{.off} [{{ led }}]{.yellow} | NT Disconnected + Yellow | Solid | [{{ led }}]{.off} [{{ led }}]{.solid .yellow} | NT Connected + Both | Alternating | [{{ led }}]{.green .error} [{{ led }}]{.anti-yellow .error} | Initializing or faulted, not running + Both | Off | [{{ led }}]{.off} [{{ led }}]{.off} | No power or initialization fault, not running + +{{ led_loader }} diff --git a/photon-core/src/main/java/org/photonvision/common/configuration/HardwareConfig.java b/photon-core/src/main/java/org/photonvision/common/configuration/HardwareConfig.java index 387ba6bf3a..23d875bfa3 100644 --- a/photon-core/src/main/java/org/photonvision/common/configuration/HardwareConfig.java +++ b/photon-core/src/main/java/org/photonvision/common/configuration/HardwareConfig.java @@ -17,8 +17,10 @@ package org.photonvision.common.configuration; +import com.fasterxml.jackson.annotation.JsonAlias; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import java.util.ArrayList; +import org.photonvision.common.hardware.statusLED.StatusLEDType; @JsonIgnoreProperties(ignoreUnknown = true) public class HardwareConfig { @@ -29,8 +31,13 @@ public class HardwareConfig { public final boolean ledsCanDim; public final ArrayList ledBrightnessRange; public final int ledPWMFrequency; - public final ArrayList statusRGBPins; - public final boolean statusRGBActiveHigh; + public final StatusLEDType statusLEDType; + + @JsonAlias("statusRGBPins") + public final ArrayList statusLEDPins; + + @JsonAlias("statusRGBActiveHigh") + public final boolean statusLEDActiveHigh; // Custom GPIO public final String getGPIOCommand; @@ -49,8 +56,9 @@ public HardwareConfig( boolean ledsCanDim, ArrayList ledBrightnessRange, int ledPwmFrequency, - ArrayList statusRGBPins, - boolean statusRGBActiveHigh, + StatusLEDType statusLEDType, + ArrayList statusLEDPins, + boolean statusLEDActiveHigh, String getGPIOCommand, String setGPIOCommand, String setPWMCommand, @@ -63,8 +71,9 @@ public HardwareConfig( this.ledsCanDim = ledsCanDim; this.ledBrightnessRange = ledBrightnessRange; this.ledPWMFrequency = ledPwmFrequency; - this.statusRGBPins = statusRGBPins; - this.statusRGBActiveHigh = statusRGBActiveHigh; + this.statusLEDType = statusLEDType; + this.statusLEDPins = statusLEDPins; + this.statusLEDActiveHigh = statusLEDActiveHigh; this.getGPIOCommand = getGPIOCommand; this.setGPIOCommand = setGPIOCommand; this.setPWMCommand = setPWMCommand; @@ -80,8 +89,9 @@ public HardwareConfig() { ledsCanDim = false; ledBrightnessRange = new ArrayList<>(); ledPWMFrequency = 0; - statusRGBPins = new ArrayList<>(); - statusRGBActiveHigh = false; + statusLEDType = StatusLEDType.RGB; + statusLEDPins = new ArrayList<>(); + statusLEDActiveHigh = false; getGPIOCommand = ""; setGPIOCommand = ""; setPWMCommand = ""; @@ -121,10 +131,12 @@ public String toString() { + ledBrightnessRange + ", ledPWMFrequency=" + ledPWMFrequency - + ", statusRGBPins=" - + statusRGBPins - + ", statusRGBActiveHigh" - + statusRGBActiveHigh + + ", statusLEDType=" + + statusLEDType + + ", statusLEDPins=" + + statusLEDPins + + ", statusLEDActiveHigh" + + statusLEDActiveHigh + ", getGPIOCommand=" + getGPIOCommand + ", setGPIOCommand=" diff --git a/photon-core/src/main/java/org/photonvision/common/hardware/HardwareManager.java b/photon-core/src/main/java/org/photonvision/common/hardware/HardwareManager.java index 98e223c124..94be8c4414 100644 --- a/photon-core/src/main/java/org/photonvision/common/hardware/HardwareManager.java +++ b/photon-core/src/main/java/org/photonvision/common/hardware/HardwareManager.java @@ -24,6 +24,7 @@ import java.io.IOException; import java.util.HashSet; import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.function.Supplier; import org.photonvision.common.configuration.ConfigManager; @@ -33,6 +34,7 @@ import org.photonvision.common.dataflow.networktables.NetworkTablesManager; import org.photonvision.common.hardware.gpio.CustomAdapter; import org.photonvision.common.hardware.gpio.CustomDeviceFactory; +import org.photonvision.common.hardware.statusLED.StatusLED; import org.photonvision.common.logging.LogGroup; import org.photonvision.common.logging.Logger; import org.photonvision.common.util.ShellExec; @@ -48,18 +50,15 @@ public class HardwareManager { private final HardwareConfig hardwareConfig; private final HardwareSettings hardwareSettings; - @SuppressWarnings({"FieldCanBeLocal", "unused"}) - private final StatusLED statusLED; + private final Optional statusLED; - @SuppressWarnings("FieldCanBeLocal") private final IntegerSubscriber ledModeRequest; private final IntegerPublisher ledModeState; - @SuppressWarnings({"FieldCanBeLocal", "unused"}) - private final NTDataChangeListener ledModeListener; + private final Optional ledModeListener; - public final VisionLED visionLED; // May be null if no LED is specified + public final Optional visionLED; public static HardwareManager getInstance() { if (instance == null) { @@ -102,40 +101,44 @@ public NativeDeviceFactoryInterface get() { }; statusLED = - hardwareConfig.statusRGBPins.size() == 3 - ? new StatusLED( - lazyDeviceFactory.get(), - hardwareConfig.statusRGBPins, - hardwareConfig.statusRGBActiveHigh) - : null; + hardwareConfig.statusLEDPins.isEmpty() + ? Optional.empty() + : Optional.of( + StatusLED.ofType( + hardwareConfig.statusLEDType, + lazyDeviceFactory, + hardwareConfig.statusLEDPins, + hardwareConfig.statusLEDActiveHigh)); var hasBrightnessRange = hardwareConfig.ledBrightnessRange.size() == 2; visionLED = hardwareConfig.ledPins.isEmpty() - ? null - : new VisionLED( - lazyDeviceFactory.get(), - hardwareConfig.ledPins, - hardwareConfig.ledsCanDim, - hasBrightnessRange ? hardwareConfig.ledBrightnessRange.get(0) : 0, - hasBrightnessRange ? hardwareConfig.ledBrightnessRange.get(1) : 100, - hardwareConfig.ledPWMFrequency, - ledModeState::set); + ? Optional.empty() + : Optional.of( + new VisionLED( + lazyDeviceFactory.get(), + hardwareConfig.ledPins, + hardwareConfig.ledsCanDim, + hasBrightnessRange ? hardwareConfig.ledBrightnessRange.get(0) : 0, + hasBrightnessRange ? hardwareConfig.ledBrightnessRange.get(1) : 100, + hardwareConfig.ledPWMFrequency, + ledModeState::set)); ledModeListener = - visionLED == null - ? null - : new NTDataChangeListener( - NetworkTablesManager.getInstance().kRootTable.getInstance(), - ledModeRequest, - visionLED::onLedModeChange); + visionLED.map( + visionLED -> + new NTDataChangeListener( + NetworkTablesManager.getInstance().kRootTable.getInstance(), + ledModeRequest, + visionLED::onLedModeChange)); Runtime.getRuntime().addShutdownHook(new Thread(this::onJvmExit)); - if (visionLED != null) { - visionLED.setBrightness(hardwareSettings.ledBrightnessPercentage); - visionLED.blink(85, 4); // bootup blink - } + visionLED.ifPresent( + visionLED -> { + visionLED.setBrightness(hardwareSettings.ledBrightnessPercentage); + visionLED.blink(85, 4); // bootup blink + }); // Start hardware metrics thread (Disabled until implemented) // if (Platform.isLinux()) MetricsPublisher.getInstance().startTask(); @@ -161,7 +164,7 @@ public static NativeDeviceFactoryInterface configureCustomGPIO(HardwareConfig ha pinInfo.addGpioPinInfo(pin, pin, List.of(DeviceMode.DIGITAL_OUTPUT)); } } - for (int pin : hardwareConfig.statusRGBPins) { + for (int pin : hardwareConfig.statusLEDPins) { pinInfo.addGpioPinInfo(pin, pin, List.of(DeviceMode.DIGITAL_OUTPUT)); } @@ -171,7 +174,7 @@ public static NativeDeviceFactoryInterface configureCustomGPIO(HardwareConfig ha public void setBrightnessPercent(int percent) { if (percent != hardwareSettings.ledBrightnessPercentage) { hardwareSettings.ledBrightnessPercentage = percent; - if (visionLED != null) visionLED.setBrightness(percent); + visionLED.ifPresent(visionLED -> visionLED.setBrightness(percent)); ConfigManager.getInstance().requestSave(); logger.info("Setting led brightness to " + percent + "%"); } @@ -179,7 +182,7 @@ public void setBrightnessPercent(int percent) { private void onJvmExit() { logger.info("Shutting down LEDs..."); - if (visionLED != null) visionLED.setState(false); + visionLED.ifPresent(visionLED -> visionLED.setState(false)); ConfigManager.getInstance().onJvmExit(); } @@ -220,16 +223,16 @@ public void setNTConnected(boolean isConnected) { updateStatus(); } - public void setError(PhotonStatus status) { - if (status == null || !status.isError()) { + public void setError(Optional status) { + if (status.isEmpty() || !status.get().isError()) { updateStatus(); - } else if (statusLED != null) { - statusLED.setStatus(status); + } else { + statusLED.ifPresent(statusLED -> statusLED.setStatus(status.get())); } } private void updateStatus() { - if (statusLED == null) { + if (statusLED.isEmpty()) { return; } PhotonStatus status; @@ -247,6 +250,6 @@ private void updateStatus() { status = PhotonStatus.NT_DISCONNECTED_TARGETS_MISSING; } } - statusLED.setStatus(status); + statusLED.ifPresent(statusLED -> statusLED.setStatus(status)); } } diff --git a/photon-core/src/main/java/org/photonvision/common/hardware/statusLED/GreenYellowStatusLED.java b/photon-core/src/main/java/org/photonvision/common/hardware/statusLED/GreenYellowStatusLED.java new file mode 100644 index 0000000000..f2ad793d76 --- /dev/null +++ b/photon-core/src/main/java/org/photonvision/common/hardware/statusLED/GreenYellowStatusLED.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) Photon Vision. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.photonvision.common.hardware.statusLED; + +import com.diozero.devices.LED; +import com.diozero.internal.spi.NativeDeviceFactoryInterface; +import java.util.Collections; +import java.util.List; +import org.photonvision.common.hardware.PhotonStatus; +import org.photonvision.common.logging.LogGroup; +import org.photonvision.common.logging.Logger; +import org.photonvision.common.util.TimedTaskManager; + +/** A pair of green and yellow LEDs, as used on the Limelight cameras */ +public class GreenYellowStatusLED implements StatusLED { + private final Logger logger = new Logger(GreenYellowStatusLED.class, LogGroup.General); + + public final LED greenLED; + public final LED yellowLED; + protected int blinkCounter; + + protected PhotonStatus status = PhotonStatus.GENERIC_ERROR; + + public GreenYellowStatusLED( + NativeDeviceFactoryInterface deviceFactory, List statusLedPins, boolean activeHigh) { + if (statusLedPins.size() != 2) { + logger.warn( + pinErrorTemplate.formatted(2, "Green and Yellow status LEDs", statusLedPins.size())); + } + // fill unassigned pins with -1 to disable + if (statusLedPins.size() < 2) { + statusLedPins.addAll(Collections.nCopies(statusLedPins.size() - 2, -1)); + } + + // Outputs are active-low for a common-anode RGB LED + greenLED = new LED(deviceFactory, statusLedPins.get(0), activeHigh, false); + yellowLED = new LED(deviceFactory, statusLedPins.get(1), activeHigh, false); + + TimedTaskManager.getInstance().addTask("StatusLEDUpdate", this::updateLED, 75); + } + + protected void setLEDs(boolean green, boolean yellow) { + greenLED.setOn(green); + yellowLED.setOn(yellow); + } + + @Override + public void setStatus(PhotonStatus status) { + this.status = status; + } + + protected void updateLED() { + boolean slowBlink = (blinkCounter % 6) > 1; + boolean fastBlink = (blinkCounter % 2) > 0; + boolean errorBlink = blinkCounter > 5; + + switch (status) { + case NT_CONNECTED_TARGETS_VISIBLE -> + // Green fast, yellow on + setLEDs(fastBlink, true); + case NT_CONNECTED_TARGETS_MISSING -> + // Green slow, yellow on + setLEDs(slowBlink, true); + case NT_DISCONNECTED_TARGETS_VISIBLE -> + // Green fast, yellow slow + setLEDs(fastBlink, slowBlink); + case NT_DISCONNECTED_TARGETS_MISSING -> + // Green slow, yellow slow + setLEDs(slowBlink, slowBlink); + case GENERIC_ERROR -> + // Extra slow alternating blink + setLEDs(errorBlink, !errorBlink); + } + + blinkCounter++; + blinkCounter %= 12; + } + + @Override + public void close() throws Exception { + greenLED.close(); + yellowLED.close(); + } +} diff --git a/photon-core/src/main/java/org/photonvision/common/hardware/StatusLED.java b/photon-core/src/main/java/org/photonvision/common/hardware/statusLED/RGBStatusLED.java similarity index 80% rename from photon-core/src/main/java/org/photonvision/common/hardware/StatusLED.java rename to photon-core/src/main/java/org/photonvision/common/hardware/statusLED/RGBStatusLED.java index 81a916ae9b..d4103239b4 100644 --- a/photon-core/src/main/java/org/photonvision/common/hardware/StatusLED.java +++ b/photon-core/src/main/java/org/photonvision/common/hardware/statusLED/RGBStatusLED.java @@ -15,14 +15,21 @@ * along with this program. If not, see . */ -package org.photonvision.common.hardware; +package org.photonvision.common.hardware.statusLED; import com.diozero.devices.LED; import com.diozero.internal.spi.NativeDeviceFactoryInterface; +import java.util.Collections; import java.util.List; +import org.photonvision.common.hardware.PhotonStatus; +import org.photonvision.common.logging.LogGroup; +import org.photonvision.common.logging.Logger; import org.photonvision.common.util.TimedTaskManager; -public class StatusLED implements AutoCloseable { +/** Basic RGB LED with individual control over each pin */ +public class RGBStatusLED implements StatusLED { + private final Logger logger = new Logger(RGBStatusLED.class, LogGroup.General); + public final LED redLED; public final LED greenLED; public final LED blueLED; @@ -30,13 +37,14 @@ public class StatusLED implements AutoCloseable { protected PhotonStatus status = PhotonStatus.GENERIC_ERROR; - public StatusLED( + public RGBStatusLED( NativeDeviceFactoryInterface deviceFactory, List statusLedPins, boolean activeHigh) { - // fill unassigned pins with -1 to disable if (statusLedPins.size() != 3) { - for (int i = 0; i < 3 - statusLedPins.size(); i++) { - statusLedPins.add(-1); - } + logger.warn(pinErrorTemplate.formatted(3, "a RGB status LED", statusLedPins.size())); + } + // fill unassigned pins with -1 to disable + if (statusLedPins.size() < 3) { + statusLedPins.addAll(Collections.nCopies(statusLedPins.size() - 3, -1)); } // Outputs are active-low for a common-anode RGB LED @@ -53,6 +61,7 @@ protected void setRGB(boolean r, boolean g, boolean b) { blueLED.setOn(b); } + @Override public void setStatus(PhotonStatus status) { this.status = status; } diff --git a/photon-core/src/main/java/org/photonvision/common/hardware/statusLED/StatusLED.java b/photon-core/src/main/java/org/photonvision/common/hardware/statusLED/StatusLED.java new file mode 100644 index 0000000000..3108452587 --- /dev/null +++ b/photon-core/src/main/java/org/photonvision/common/hardware/statusLED/StatusLED.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) Photon Vision. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.photonvision.common.hardware.statusLED; + +import com.diozero.internal.spi.NativeDeviceFactoryInterface; +import java.util.List; +import java.util.function.Supplier; +import org.photonvision.common.hardware.PhotonStatus; + +public interface StatusLED extends AutoCloseable { + static final String pinErrorTemplate = + "Expected %d pins for %s, but found %n pins; unassigned pins will be skipped, extra pins will be ignored"; + + public void setStatus(PhotonStatus status); + + static StatusLED ofType( + StatusLEDType type, + Supplier lazyDeviceFactory, + List statusLedPins, + boolean activeHigh) { + return switch (type) { + case RGB -> new RGBStatusLED(lazyDeviceFactory.get(), statusLedPins, activeHigh); + case GreenYellow -> new GreenYellowStatusLED(lazyDeviceFactory.get(), statusLedPins, activeHigh); + }; + } +} diff --git a/photon-core/src/main/java/org/photonvision/common/hardware/statusLED/StatusLEDType.java b/photon-core/src/main/java/org/photonvision/common/hardware/statusLED/StatusLEDType.java new file mode 100644 index 0000000000..3142c09bd6 --- /dev/null +++ b/photon-core/src/main/java/org/photonvision/common/hardware/statusLED/StatusLEDType.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) Photon Vision. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.photonvision.common.hardware.statusLED; + +public enum StatusLEDType { + RGB, + GreenYellow; +} diff --git a/photon-core/src/main/java/org/photonvision/vision/processes/VisionModule.java b/photon-core/src/main/java/org/photonvision/vision/processes/VisionModule.java index d9afb714a1..888b659812 100644 --- a/photon-core/src/main/java/org/photonvision/vision/processes/VisionModule.java +++ b/photon-core/src/main/java/org/photonvision/vision/processes/VisionModule.java @@ -178,7 +178,10 @@ public VisionModule(PipelineManager pipelineManager, VisionSource visionSource) if (HardwareManager.getInstance().visionLED != null && this.camShouldControlLEDs()) { HardwareManager.getInstance() .visionLED - .setPipelineModeSupplier(() -> pipelineManager.getCurrentPipelineSettings().ledMode); + .ifPresent( + (visionLED) -> + visionLED.setPipelineModeSupplier( + () -> pipelineManager.getCurrentPipelineSettings().ledMode)); setVisionLEDs(pipelineManager.getCurrentPipelineSettings().ledMode); } @@ -513,8 +516,9 @@ private boolean camShouldControlLEDs() { } private void setVisionLEDs(boolean on) { - if (camShouldControlLEDs() && HardwareManager.getInstance().visionLED != null) - HardwareManager.getInstance().visionLED.setState(on); + if (camShouldControlLEDs()) { + HardwareManager.getInstance().visionLED.ifPresent((visionLED) -> visionLED.setState(on)); + } } public void saveModule() { diff --git a/photon-server/src/main/java/org/photonvision/Main.java b/photon-server/src/main/java/org/photonvision/Main.java index d3eacb838b..13df4b7ddf 100644 --- a/photon-server/src/main/java/org/photonvision/Main.java +++ b/photon-server/src/main/java/org/photonvision/Main.java @@ -21,6 +21,7 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import org.apache.commons.cli.*; import org.opencv.core.Size; import org.photonvision.common.LoadJNI; @@ -355,7 +356,7 @@ public static void main(String[] args) { VisionSourceManager.getInstance().registerTimedTasks(); logger.info("Starting server..."); - HardwareManager.getInstance().setError(null); + HardwareManager.getInstance().setError(Optional.empty()); Server.initialize(DEFAULT_WEBPORT); } }