Skip to content
Open
Show file tree
Hide file tree
Changes from 11 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
40 changes: 31 additions & 9 deletions docs/source/docs/hardware/customhardware.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,17 @@ By default, PhotonVision attempts to make minimal assumptions of the hardware it

## LED Support

For Raspberry-Pi based hardware, PhotonVision can use [PiGPIO](https://abyz.me.uk/rpi/pigpio/) to control IO pins. The mapping of which pins control which LED's is part of the hardware config. The pins are active-high: set high when LED's are commanded on, and set low when commanded off.
When running on Linux, PhotonVision can use [diozero](https://www.diozero.com) to control IO pins. The mapping of which pins control which LED's is part of the hardware config. The pins are active-high: set high when LED's are commanded on, and set low when commanded off.

```{eval-rst}
.. tab-set-code::
.. code-block:: json

{
"ledPins" : [ 13 ],
"ledSetCommand" : "",
"ledsCanDim" : true,
"ledPWMRange" : [ 0, 100 ],
"ledPWMSetRange" : "",
"ledPWMFrequency" : 0,
"ledDimCommand" : "",
"ledBlinkCommand" : "",
"statusRGBPins" : [ ],
}
```
Expand All @@ -31,6 +27,32 @@ For Raspberry-Pi based hardware, PhotonVision can use [PiGPIO](https://abyz.me.u
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.
:::

### Custom GPIO

If your hardware does not support diozero's default provider, custom commands can be provided to interact with the GPIO lines.

```{eval-rst}
.. tab-set-code::
.. code-block:: json

{
"getGPIOCommand" : ""
"setGPIOCommand" : ""
"setPWMCommand" : ""
"releaseGPIOCommand" : ""
}
```

The following template strings are used to input parameters to the commands:

| Template | Parameter | Values |
| -------- | ---------- | ---------- |
| `{p}` | pin number | integers |
| `{s}` | state | true/false |
| `{v}` | value | 0.0-1.0 |

If you were using custom LED commands from 2025 or earlier and still need custom GPIO commands, they can likely be copied over. `ledSetCommand` can be reused as `setGPIOCommand`. `ledDimCommand` can be reused with edits as `setPWMCommand`, replacing any occurrences of `{v}` with `$(awk 'BEGIN{ print int({v}*100) }')` if your command requires integer percentages.

## Hardware Interaction Commands

For Non-Raspberry-Pi hardware, users must provide valid hardware-specific commands for some parts of the UI interaction (including performance metrics, and executing system restarts).
Expand Down Expand Up @@ -101,14 +123,14 @@ Here is a complete example `hardwareConfig.json`:
"deviceLogoPath" : "",
"supportURL" : "https://www.youtube.com/watch?v=b-CvLWbfZhU",
"ledPins" : [2, 13],
"ledSetCommand" : "",
"ledsCanDim" : true,
"ledPWMRange" : [ 0, 100 ],
"ledPWMSetRange" : "",
"ledPWMFrequency" : 0,
"ledDimCommand" : "",
"ledBlinkCommand" : "",
"statusRGBPins" : [ ],
"getGPIOCommand" : ""
"setGPIOCommand" : ""
"setPWMCommand" : ""
"releaseGPIOCommand" : ""
"cpuTempCommand" : "",
"cpuMemoryCommand" : "",
"cpuUtilCommand" : "",
Expand Down
1 change: 1 addition & 0 deletions photon-core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ dependencies {
implementation 'org.zeroturnaround:zt-zip:1.14'

implementation "org.xerial:sqlite-jdbc:3.41.0.0"
implementation 'com.diozero:diozero-core:1.4.1'
implementation("org.photonvision:rknn_jni-jni:$rknnVersion:linuxarm64") {
transitive = false
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,16 @@ public class HardwareConfig {

// LED control
public final ArrayList<Integer> ledPins;
public final String ledSetCommand;
public final boolean ledsCanDim;
public final ArrayList<Integer> ledBrightnessRange;
public final String ledDimCommand;
public final String ledBlinkCommand;
public final ArrayList<Integer> statusRGBPins;

// Custom GPIO
public final String getGPIOCommand;
public final String setGPIOCommand;
public final String setPWMCommand;
public final String releaseGPIOCommand;

// Metrics
public final String cpuTempCommand;
public final String cpuMemoryCommand;
Expand All @@ -55,12 +58,13 @@ public HardwareConfig(
String deviceLogoPath,
String supportURL,
ArrayList<Integer> ledPins,
String ledSetCommand,
boolean ledsCanDim,
ArrayList<Integer> ledBrightnessRange,
String ledDimCommand,
String ledBlinkCommand,
ArrayList<Integer> statusRGBPins,
String getGPIOCommand,
String setGPIOCommand,
String setPWMCommand,
String releaseGPIOCommand,
String cpuTempCommand,
String cpuMemoryCommand,
String cpuUtilCommand,
Expand All @@ -76,12 +80,13 @@ public HardwareConfig(
this.deviceLogoPath = deviceLogoPath;
this.supportURL = supportURL;
this.ledPins = ledPins;
this.ledSetCommand = ledSetCommand;
this.ledsCanDim = ledsCanDim;
this.ledBrightnessRange = ledBrightnessRange;
this.ledDimCommand = ledDimCommand;
this.ledBlinkCommand = ledBlinkCommand;
this.statusRGBPins = statusRGBPins;
this.getGPIOCommand = getGPIOCommand;
this.setGPIOCommand = setGPIOCommand;
this.setPWMCommand = setPWMCommand;
this.releaseGPIOCommand = releaseGPIOCommand;
this.cpuTempCommand = cpuTempCommand;
this.cpuMemoryCommand = cpuMemoryCommand;
this.cpuUtilCommand = cpuUtilCommand;
Expand All @@ -100,12 +105,13 @@ public HardwareConfig() {
deviceLogoPath = "";
supportURL = "";
ledPins = new ArrayList<>();
ledSetCommand = "";
ledsCanDim = false;
ledBrightnessRange = new ArrayList<>();
ledDimCommand = "";
ledBlinkCommand = "";
statusRGBPins = new ArrayList<>();
getGPIOCommand = "";
setGPIOCommand = "";
setPWMCommand = "";
releaseGPIOCommand = "";
cpuTempCommand = "";
cpuMemoryCommand = "";
cpuUtilCommand = "";
Expand All @@ -127,7 +133,7 @@ public final boolean hasPresetFOV() {
}

/**
* @return True if any command has been configured to a non-default empty, false otherwise
* @return True if any info command has been configured to be non-empty, false otherwise
*/
public final boolean hasCommandsConfigured() {
return cpuTempCommand != ""
Expand All @@ -137,11 +143,20 @@ public final boolean hasCommandsConfigured() {
|| cpuUptimeCommand != ""
|| gpuMemoryCommand != ""
|| ramUtilCommand != ""
|| ledBlinkCommand != ""
|| gpuMemUsageCommand != ""
|| diskUsageCommand != "";
}

/**
* @return True if any gpio command has been configured to be non-empty, false otherwise
*/
public final boolean hasGPIOCommandsConfigured() {
return getGPIOCommand != ""
|| setGPIOCommand != ""
|| setPWMCommand != ""
|| releaseGPIOCommand != "";
}

@Override
public String toString() {
return "HardwareConfig[deviceName="
Expand All @@ -152,16 +167,10 @@ public String toString() {
+ supportURL
+ ", ledPins="
+ ledPins
+ ", ledSetCommand="
+ ledSetCommand
+ ", ledsCanDim="
+ ledsCanDim
+ ", ledBrightnessRange="
+ ledBrightnessRange
+ ", ledDimCommand="
+ ledDimCommand
+ ", ledBlinkCommand="
+ ledBlinkCommand
+ ", statusRGBPins="
+ statusRGBPins
+ ", cpuTempCommand="
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/

package org.photonvision.common.hardware.GPIO;

import java.util.Arrays;
import org.photonvision.common.logging.LogGroup;
import org.photonvision.common.logging.Logger;
import org.photonvision.common.util.ShellExec;

public class CustomAdapter {
private static final Logger logger = new Logger(CustomAdapter.class, LogGroup.General);
private static final ShellExec runCommand = new ShellExec(true, true);

public final String deviceName;
protected final String getGPIOCommand;
protected final String setGPIOCommand;
protected final String setPWMCommand;
protected final String releaseGPIOCommand;

public CustomAdapter(
String deviceName,
String getGPIOCommand,
String setGPIOCommand,
String setPWMCommand,
String releaseGPIOCommand) {
this.deviceName = deviceName;
this.getGPIOCommand = getGPIOCommand;
this.setGPIOCommand = setGPIOCommand;
this.setPWMCommand = setPWMCommand;
this.releaseGPIOCommand = releaseGPIOCommand;
}

protected static String execute(String command) {
try {
runCommand.executeBashCommand(command);
} catch (Exception e) {
logger.error(Arrays.toString(e.getStackTrace()));
return "";
}
return runCommand.getOutput();
}

public boolean getGPIO(int gpio) {
return Boolean.parseBoolean(
execute(getGPIOCommand.replace("{p}", Integer.toString(gpio))).trim());
}

public void setGPIO(int gpio, boolean state) {
execute(
setGPIOCommand
.replace("{p}", Integer.toString(gpio))
.replace("{s}", Boolean.toString(state)));
}

public void setPWM(int gpio, double value) {
execute(
setPWMCommand
.replace("{p}", Integer.toString(gpio))
.replace("{v}", Double.toString(value)));
}

public void releaseGPIO(int gpio) {
execute(releaseGPIOCommand.replace("{p}", Integer.toString(gpio)));
}
}
Loading
Loading