From 81e5eef7ae87bd524dedd1c37344a93371fedc30 Mon Sep 17 00:00:00 2001 From: Xzibit Date: Thu, 27 Aug 2020 14:53:02 -0400 Subject: [PATCH] Status LEDs (#104) * Don't start metrics thread if not on linux * Add statusLED support * [Hardware] Add status LED support * [Hardware] Invalid LED port checks * [Hardware] Check if statusLED exists in config --- .../common/configuration/HardwareConfig.java | 6 +- .../common/hardware/GPIO/CustomGPIO.java | 109 +++++++------ .../common/hardware/GPIO/PiGPIO.java | 147 ++++++++++-------- .../common/hardware/HardwareManager.java | 24 +++ .../hardware/HardwareManagerTest.java | 4 + .../resources/hardware/HardwareConfig.json | 1 + 6 files changed, 182 insertions(+), 109 deletions(-) diff --git a/photon-server/src/main/java/org/photonvision/common/configuration/HardwareConfig.java b/photon-server/src/main/java/org/photonvision/common/configuration/HardwareConfig.java index fc4ebc71f..a20a5215a 100644 --- a/photon-server/src/main/java/org/photonvision/common/configuration/HardwareConfig.java +++ b/photon-server/src/main/java/org/photonvision/common/configuration/HardwareConfig.java @@ -34,6 +34,7 @@ public class HardwareConfig { public final int ledPWMFrequency; public final String ledDimCommand; public final String ledBlinkCommand; + public final ArrayList statusRGBPins; // Metrics public final String cpuTempCommand; @@ -55,6 +56,7 @@ public class HardwareConfig { ledSetCommand = ""; ledsCanDim = false; ledPWMRange = new ArrayList<>(); + statusRGBPins = new ArrayList<>(); ledPWMFrequency = 0; ledPWMSetRange = ""; ledDimCommand = ""; @@ -79,11 +81,12 @@ public class HardwareConfig { ArrayList ledPins, String ledSetCommand, boolean ledsCanDim, - ArrayList ledPWMRange, + ArrayList statusRGBPins, String ledPWMSetRange, int ledPWMFrequency, String ledDimCommand, String ledBlinkCommand, + ArrayList ledPWMRange, String cpuTempCommand, String cpuMemoryCommand, String cpuUtilCommand, @@ -103,6 +106,7 @@ public class HardwareConfig { this.ledPWMFrequency = ledPWMFrequency; this.ledDimCommand = ledDimCommand; this.ledBlinkCommand = ledBlinkCommand; + this.statusRGBPins = statusRGBPins; this.cpuTempCommand = cpuTempCommand; this.cpuMemoryCommand = cpuMemoryCommand; this.cpuUtilCommand = cpuUtilCommand; diff --git a/photon-server/src/main/java/org/photonvision/common/hardware/GPIO/CustomGPIO.java b/photon-server/src/main/java/org/photonvision/common/hardware/GPIO/CustomGPIO.java index e47fdf25b..68ae7392c 100644 --- a/photon-server/src/main/java/org/photonvision/common/hardware/GPIO/CustomGPIO.java +++ b/photon-server/src/main/java/org/photonvision/common/hardware/GPIO/CustomGPIO.java @@ -34,48 +34,59 @@ public class CustomGPIO extends GPIOBase { @Override public void togglePin() { - execute( - commands - .get("setState") - .replace("{s}", String.valueOf(!currentState)) - .replace("{p}", String.valueOf(this.port))); - currentState = !currentState; + if (this.port != -1) { + execute( + commands + .get("setState") + .replace("{s}", String.valueOf(!currentState)) + .replace("{p}", String.valueOf(this.port))); + currentState = !currentState; + } } @Override public void setLow() { - execute( - commands - .get("setState") - .replace("{s}", String.valueOf(false)) - .replace("{p}", String.valueOf(this.port))); - currentState = false; + if (this.port != -1) { + execute( + commands + .get("setState") + .replace("{s}", String.valueOf(false)) + .replace("{p}", String.valueOf(this.port))); + currentState = false; + } } @Override public void setHigh() { - execute( - commands - .get("setState") - .replace("{s}", String.valueOf(true)) - .replace("{p}", String.valueOf(this.port))); - currentState = true; + if (this.port != -1) { + execute( + commands + .get("setState") + .replace("{s}", String.valueOf(true)) + .replace("{p}", String.valueOf(this.port))); + currentState = true; + } } @Override public void setState(boolean state) { - execute( - commands - .get("setState") - .replace("{s}", String.valueOf(state)) - .replace("{p}", String.valueOf(this.port))); - currentState = state; + if (this.port != -1) { + execute( + commands + .get("setState") + .replace("{s}", String.valueOf(state)) + .replace("{p}", String.valueOf(this.port))); + currentState = state; + } } @Override public boolean shutdown() { - execute(commands.get("shutdown")); - return true; + if (this.port != -1) { + execute(commands.get("shutdown")); + return true; + } + return false; } @Override @@ -85,13 +96,15 @@ public class CustomGPIO extends GPIOBase { @Override public void setPwmRange(List range) { - execute( - commands - .get("setRange") - .replace("{lower_range}", String.valueOf(range.get(0))) - .replace("{upper_range}", String.valueOf(range.get(1))) - .replace("{p}", String.valueOf(port))); - pwmRange = range; + if (this.port != -1) { + execute( + commands + .get("setRange") + .replace("{lower_range}", String.valueOf(range.get(0))) + .replace("{upper_range}", String.valueOf(range.get(1))) + .replace("{p}", String.valueOf(port))); + pwmRange = range; + } } @Override @@ -101,23 +114,27 @@ public class CustomGPIO extends GPIOBase { @Override public void blink(int pulseTimeMillis, int blinks) { - execute( - commands - .get("blink") - .replace("{pulseTime}", String.valueOf(pulseTimeMillis)) - .replace("{blinks}", String.valueOf(blinks)) - .replace("{p}", String.valueOf(this.port))); + if (this.port != -1) { + execute( + commands + .get("blink") + .replace("{pulseTime}", String.valueOf(pulseTimeMillis)) + .replace("{blinks}", String.valueOf(blinks)) + .replace("{p}", String.valueOf(this.port))); + } } @Override public void dimLED(int dimValue) { - // Check to see if dimValue is within the range - if (dimValue < pwmRange.get(0) || dimValue > pwmRange.get(1)) return; - execute( - commands - .get("dim") - .replace("{p}", String.valueOf(port)) - .replace("{v}", String.valueOf(dimValue))); + if (this.port != -1) { + // Check to see if dimValue is within the range + if (dimValue < pwmRange.get(0) || dimValue > pwmRange.get(1)) return; + execute( + commands + .get("dim") + .replace("{p}", String.valueOf(port)) + .replace("{v}", String.valueOf(dimValue))); + } } public static void setConfig(HardwareConfig config) { diff --git a/photon-server/src/main/java/org/photonvision/common/hardware/GPIO/PiGPIO.java b/photon-server/src/main/java/org/photonvision/common/hardware/GPIO/PiGPIO.java index a8e2c1732..f3078eba1 100644 --- a/photon-server/src/main/java/org/photonvision/common/hardware/GPIO/PiGPIO.java +++ b/photon-server/src/main/java/org/photonvision/common/hardware/GPIO/PiGPIO.java @@ -29,128 +29,151 @@ import org.photonvision.common.logging.Logger; public class PiGPIO extends GPIOBase { private static final Logger logger = new Logger(PiGPIO.class, LogGroup.General); private final ArrayList pulses = new ArrayList<>(); - private final int pin; + private final int port; public static JPigpio getPigpioDaemon() { return Singleton.INSTANCE; } public PiGPIO(int address, int frequency, int range) { - this.pin = address; + this.port = address; try { - getPigpioDaemon().setPWMFrequency(this.pin, frequency); - getPigpioDaemon().setPWMRange(this.pin, range); + getPigpioDaemon().setPWMFrequency(this.port, frequency); + getPigpioDaemon().setPWMRange(this.port, range); } catch (PigpioException e) { - logger.error("Could not set PWM settings on port " + this.pin); + logger.error("Could not set PWM settings on port " + this.port); e.printStackTrace(); } } @Override public void togglePin() { - try { - getPigpioDaemon().gpioWrite(this.pin, !getPigpioDaemon().gpioRead(this.pin)); - } catch (PigpioException e) { - logger.error("Could not toggle on pin " + this.pin); - e.printStackTrace(); + if (this.port != -1) { + try { + getPigpioDaemon().gpioWrite(this.port, !getPigpioDaemon().gpioRead(this.port)); + } catch (PigpioException e) { + logger.error("Could not toggle on pin " + this.port); + e.printStackTrace(); + } } } @Override public void setLow() { - try { - getPigpioDaemon().gpioWrite(this.pin, false); - } catch (PigpioException e) { - logger.error("Could not set pin low on port " + this.pin); - e.printStackTrace(); + if (this.port != -1) { + try { + getPigpioDaemon().gpioWrite(this.port, false); + } catch (PigpioException e) { + logger.error("Could not set pin low on port " + this.port); + e.printStackTrace(); + } } } @Override public void setHigh() { - try { - getPigpioDaemon().gpioWrite(this.pin, true); - } catch (PigpioException e) { - logger.error("Could not set pin high on port " + this.pin); - e.printStackTrace(); + if (this.port != -1) { + try { + getPigpioDaemon().gpioWrite(this.port, true); + } catch (PigpioException e) { + logger.error("Could not set pin high on port " + this.port); + e.printStackTrace(); + } } } @Override public void setState(boolean state) { - try { - getPigpioDaemon().gpioWrite(this.pin, state); - } catch (PigpioException e) { - logger.error("Could not set pin state on port " + this.pin); - e.printStackTrace(); + if (this.port != -1) { + try { + getPigpioDaemon().gpioWrite(this.port, state); + } catch (PigpioException e) { + logger.error("Could not set pin state on port " + this.port); + e.printStackTrace(); + } } } @Override public boolean shutdown() { - try { - getPigpioDaemon().gpioTerminate(); - } catch (PigpioException e) { - logger.error("Could not terminate GPIO instance"); - e.printStackTrace(); + if (this.port != -1) { + try { + getPigpioDaemon().gpioTerminate(); + } catch (PigpioException e) { + logger.error("Could not terminate GPIO instance"); + e.printStackTrace(); + } + return true; } - return true; + return false; } @Override public boolean getState() { - try { - return getPigpioDaemon().gpioRead(this.pin); - } catch (PigpioException e) { - logger.error("Could not read pin on port " + this.pin); - e.printStackTrace(); - return false; + if (this.port != -1) { + try { + return getPigpioDaemon().gpioRead(this.port); + } catch (PigpioException e) { + logger.error("Could not read pin on port " + this.port); + e.printStackTrace(); + return false; + } } + return false; } @Override public void setPwmRange(List range) { - try { - getPigpioDaemon().setPWMRange(this.pin, range.get(0)); - } catch (PigpioException e) { - logger.error("Could not set PWM range on port " + this.pin); - e.printStackTrace(); + if (this.port != -1) { + try { + getPigpioDaemon().setPWMRange(this.port, range.get(0)); + } catch (PigpioException e) { + logger.error("Could not set PWM range on port " + this.port); + e.printStackTrace(); + } } } @Override public List getPwmRange() { - try { - return List.of(0, getPigpioDaemon().getPWMRange(this.pin)); - } catch (PigpioException e) { - logger.error("Could not get PWM range on port " + this.pin); - e.printStackTrace(); - return null; + if (this.port != -1) { + try { + return List.of(0, getPigpioDaemon().getPWMRange(this.port)); + } catch (PigpioException e) { + logger.error("Could not get PWM range on port " + this.port); + e.printStackTrace(); + return null; + } } + return null; } @Override public void blink(int pulseTimeMillis, int blinks) { - try { - pulses.clear(); - for (int i = 0; i < blinks; i++) { - pulses.add(new Pulse(1 << this.pin, 0, pulseTimeMillis * 100)); - pulses.add(new Pulse(0, 1 << this.pin, pulseTimeMillis * 100)); + if (this.port != -1) { + try { + pulses.clear(); + for (int i = 0; i < blinks; i++) { + pulses.add(new Pulse(1 << this.port, 0, pulseTimeMillis * 100)); + pulses.add(new Pulse(0, 1 << this.port, pulseTimeMillis * 100)); + } + getPigpioDaemon().waveAddGeneric(this.pulses); + getPigpioDaemon().waveSendOnce(getPigpioDaemon().waveCreate()); + } catch (PigpioException e) { + e.printStackTrace(); } - getPigpioDaemon().waveAddGeneric(this.pulses); - getPigpioDaemon().waveSendOnce(getPigpioDaemon().waveCreate()); - } catch (PigpioException e) { - e.printStackTrace(); } } @Override public void dimLED(int dimPercentage) { - try { - getPigpioDaemon().setPWMDutycycle(this.pin, getPwmRange().get(1) * (dimPercentage / 100)); - } catch (PigpioException e) { - logger.error("Could not dim PWM on port " + this.pin); - e.printStackTrace(); + if (this.port != -1) { + try { + getPigpioDaemon().setPWMDutycycle(this.port, getPwmRange().get(1) * (dimPercentage / 100)); + } catch (PigpioException e) { + logger.error("Could not dim PWM on port " + this.port); + e.printStackTrace(); + } } } diff --git a/photon-server/src/main/java/org/photonvision/common/hardware/HardwareManager.java b/photon-server/src/main/java/org/photonvision/common/hardware/HardwareManager.java index 884c6d995..1759fbf7a 100644 --- a/photon-server/src/main/java/org/photonvision/common/hardware/HardwareManager.java +++ b/photon-server/src/main/java/org/photonvision/common/hardware/HardwareManager.java @@ -91,6 +91,30 @@ public class HardwareManager { LEDs.values().forEach(GPIOBase::shutdown); } + public GPIOBase redStatusLED() { + try { + return LEDs.get(hardwareConfig.statusRGBPins.get(0)); + } catch (ArrayIndexOutOfBoundsException e) { + return LEDs.get(-1); + } + } + + public GPIOBase greenStatusLED() { + try { + return LEDs.get(hardwareConfig.statusRGBPins.get(1)); + } catch (ArrayIndexOutOfBoundsException e) { + return LEDs.get(-1); + } + } + + public GPIOBase blueStatusLED() { + try { + return LEDs.get(hardwareConfig.statusRGBPins.get(2)); + } catch (ArrayIndexOutOfBoundsException e) { + return LEDs.get(-1); + } + } + public boolean restartDevice() { try { return shellExec.executeBashCommand(hardwareConfig.restartHardwareCommand) == 0; diff --git a/photon-server/src/test/java/org/photonvision/hardware/HardwareManagerTest.java b/photon-server/src/test/java/org/photonvision/hardware/HardwareManagerTest.java index 8c6b81765..138846f5b 100644 --- a/photon-server/src/test/java/org/photonvision/hardware/HardwareManagerTest.java +++ b/photon-server/src/test/java/org/photonvision/hardware/HardwareManagerTest.java @@ -44,5 +44,9 @@ public class HardwareManagerTest { for (int i = 0; i < 101; i++) { instance.getGPIO(13).dimLED(i); } + + Assertions.assertEquals(config.statusRGBPins.get(0), -1); + Assertions.assertEquals(config.statusRGBPins.get(1), -1); + Assertions.assertEquals(config.statusRGBPins.get(2), -1); } } diff --git a/photon-server/src/test/resources/hardware/HardwareConfig.json b/photon-server/src/test/resources/hardware/HardwareConfig.json index 90dd50739..a97ba2ac5 100644 --- a/photon-server/src/test/resources/hardware/HardwareConfig.json +++ b/photon-server/src/test/resources/hardware/HardwareConfig.json @@ -3,6 +3,7 @@ "deviceLogoPath": "photonvision.png", "supportURL": "https://support.photonvision.com", "ledPins" : [2, 13], + "statusRGBPins" : [-1, -1, -1], "ledSetCommand" : "", "ledsCanDim" : true, "ledPWMRange" : [0, 100],