From 592889d1fddc34072f7f4efc4a8cda3b951d57d2 Mon Sep 17 00:00:00 2001 From: Jesse Kane Date: Tue, 5 May 2026 11:25:32 -0400 Subject: [PATCH 1/2] removed HardwareManager.getInstance()'s reliance on ConfigManager's state --- .../common/hardware/HardwareManager.java | 40 +++++++++++-------- .../src/main/java/org/photonvision/Main.java | 3 +- 2 files changed, 25 insertions(+), 18 deletions(-) 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..458cf12f35 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 @@ -45,11 +45,11 @@ public class HardwareManager { private final ShellExec shellExec = new ShellExec(true, false); private final Logger logger = new Logger(HardwareManager.class, LogGroup.General); - private final HardwareConfig hardwareConfig; - private final HardwareSettings hardwareSettings; + private HardwareConfig hardwareConfig; + private HardwareSettings hardwareSettings; @SuppressWarnings({"FieldCanBeLocal", "unused"}) - private final StatusLED statusLED; + private StatusLED statusLED; @SuppressWarnings("FieldCanBeLocal") private final IntegerSubscriber ledModeRequest; @@ -57,31 +57,21 @@ public class HardwareManager { private final IntegerPublisher ledModeState; @SuppressWarnings({"FieldCanBeLocal", "unused"}) - private final NTDataChangeListener ledModeListener; + private NTDataChangeListener ledModeListener; - public final VisionLED visionLED; // May be null if no LED is specified + public VisionLED visionLED; // May be null if no LED is specified public static HardwareManager getInstance() { if (instance == null) { - var conf = ConfigManager.getInstance().getConfig(); - instance = new HardwareManager(conf.getHardwareConfig(), conf.getHardwareSettings()); + instance = new HardwareManager(); } return instance; } - private HardwareManager(HardwareConfig hardwareConfig, HardwareSettings hardwareSettings) { + public void setConfig(HardwareConfig hardwareConfig, HardwareSettings hardwareSettings) { this.hardwareConfig = hardwareConfig; this.hardwareSettings = hardwareSettings; - ledModeRequest = - NetworkTablesManager.getInstance() - .kRootTable - .getIntegerTopic("ledModeRequest") - .subscribe(-1); - ledModeState = - NetworkTablesManager.getInstance().kRootTable.getIntegerTopic("ledModeState").publish(); - ledModeState.set(VisionLEDMode.kDefault.value); - // Device factory is lazy to prevent creating one if it will go unused. Supplier lazyDeviceFactory = new Supplier() { @@ -141,6 +131,22 @@ public NativeDeviceFactoryInterface get() { // if (Platform.isLinux()) MetricsPublisher.getInstance().startTask(); } + private HardwareManager() { + ledModeRequest = + NetworkTablesManager.getInstance() + .kRootTable + .getIntegerTopic("ledModeRequest") + .subscribe(-1); + ledModeState = + NetworkTablesManager.getInstance().kRootTable.getIntegerTopic("ledModeState").publish(); + ledModeState.set(VisionLEDMode.kDefault.value); + + Runtime.getRuntime().addShutdownHook(new Thread(this::onJvmExit)); + + // Start hardware metrics thread (Disabled until implemented) + // if (Platform.isLinux()) MetricsPublisher.getInstance().startTask(); + } + public static NativeDeviceFactoryInterface configureCustomGPIO(HardwareConfig hardwareConfig) { // Create a new adapter and device factory using the commands from hardwareConfig CustomAdapter adapter = diff --git a/photon-server/src/main/java/org/photonvision/Main.java b/photon-server/src/main/java/org/photonvision/Main.java index d3eacb838b..eac2dc8e14 100644 --- a/photon-server/src/main/java/org/photonvision/Main.java +++ b/photon-server/src/main/java/org/photonvision/Main.java @@ -328,7 +328,8 @@ public static void main(String[] args) { logger.debug("Loading HardwareManager..."); // Force load the hardware manager - HardwareManager.getInstance(); + var conf = ConfigManager.getInstance().getConfig(); + HardwareManager.getInstance().setConfig(conf.getHardwareConfig(), conf.getHardwareSettings()); if (isSmoketest) { logger.info("PhotonVision base functionality loaded -- smoketest complete"); From 4c8500afc03dc87169a2ffe625c474160595d834 Mon Sep 17 00:00:00 2001 From: Jesse Kane Date: Tue, 5 May 2026 12:34:48 -0400 Subject: [PATCH 2/2] minor refactor + added some checks to avoid null dereferences --- .../common/hardware/HardwareManager.java | 19 +++++++++++++------ .../vision/processes/VisionModule.java | 8 ++++---- 2 files changed, 17 insertions(+), 10 deletions(-) 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 458cf12f35..f59fbc0d86 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 @@ -59,7 +59,11 @@ public class HardwareManager { @SuppressWarnings({"FieldCanBeLocal", "unused"}) private NTDataChangeListener ledModeListener; - public VisionLED visionLED; // May be null if no LED is specified + private VisionLED visionLED; // May be null if no LED is specified + + public VisionLED getVisionLED() { + return visionLED; + } public static HardwareManager getInstance() { if (instance == null) { @@ -120,15 +124,10 @@ public NativeDeviceFactoryInterface get() { ledModeRequest, visionLED::onLedModeChange); - Runtime.getRuntime().addShutdownHook(new Thread(this::onJvmExit)); - if (visionLED != null) { visionLED.setBrightness(hardwareSettings.ledBrightnessPercentage); visionLED.blink(85, 4); // bootup blink } - - // Start hardware metrics thread (Disabled until implemented) - // if (Platform.isLinux()) MetricsPublisher.getInstance().startTask(); } private HardwareManager() { @@ -175,6 +174,10 @@ public static NativeDeviceFactoryInterface configureCustomGPIO(HardwareConfig ha } public void setBrightnessPercent(int percent) { + if (hardwareSettings == null) { + logger.error("Could not set led brightness! No hardware settings found"); + return; + } if (percent != hardwareSettings.ledBrightnessPercentage) { hardwareSettings.ledBrightnessPercentage = percent; if (visionLED != null) visionLED.setBrightness(percent); @@ -200,6 +203,10 @@ public boolean restartDevice() { } } try { + if (hardwareConfig == null) { + logger.error("Could not restart device! No hardware configuration found"); + return false; + } return shellExec.executeBashCommand(hardwareConfig.restartHardwareCommand) == 0; } catch (IOException e) { logger.error("Could not restart device!", e); 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..096805fe9d 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 @@ -175,9 +175,9 @@ public VisionModule(PipelineManager pipelineManager, VisionSource visionSource) } // Configure LED's if supported by the underlying hardware - if (HardwareManager.getInstance().visionLED != null && this.camShouldControlLEDs()) { + if (HardwareManager.getInstance().getVisionLED() != null && this.camShouldControlLEDs()) { HardwareManager.getInstance() - .visionLED + .getVisionLED() .setPipelineModeSupplier(() -> pipelineManager.getCurrentPipelineSettings().ledMode); setVisionLEDs(pipelineManager.getCurrentPipelineSettings().ledMode); } @@ -513,8 +513,8 @@ private boolean camShouldControlLEDs() { } private void setVisionLEDs(boolean on) { - if (camShouldControlLEDs() && HardwareManager.getInstance().visionLED != null) - HardwareManager.getInstance().visionLED.setState(on); + if (camShouldControlLEDs() && HardwareManager.getInstance().getVisionLED() != null) + HardwareManager.getInstance().getVisionLED().setState(on); } public void saveModule() {