Skip to content
Draft
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
30 changes: 30 additions & 0 deletions docs/source/docs/hardware/customhardware.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,36 @@ The following diagram shows the GPIO pin numbering of the 40-pin header on Raspb
:alt: Raspberry Pi GPIO Pinout
```

:::

:::{tab-item} Orange Pi

Using numbers to identify Orange Pi pins is cumbersome, so it is best to specify the pins by their names using strings instead (eg. `"GPIO1_B7"`). The mapping between GPIO lines and physical pins varies depending on which Orange Pi model you are using. The below diagrams show the pin names for the Orange Pi 5 series.

Orange Pi 5/5B ([Details](http://www.orangepi.org/orangepiwiki/index.php/26_Pin_Interface_Pin_Description)):

```{image} images/opi5-pinout.png
:alt: Orange Pi 5 Pinout
```

Orange Pi 5 Plus ([User Manual](https://drive.google.com/drive/folders/1Ov3mZqnMOf_8wpNt9rDxoGIR1ray2iiy)):

```{image} images/opi5-plus-pinout.png
:alt: Orange Pi 5 Plus Pinout
```

Orange Pi 5 Pro ([User Manual](https://drive.google.com/drive/folders/1j3gmf31XBuKPBeNIQOqqh9X_7SFCOv0s)):

```{image} images/opi5-pro-pinout.png
:alt: Orange Pi 5 Pro Pinout
```

Orange Pi 5 Max ([User Manual](https://drive.google.com/drive/folders/1kzMRI95yaXLbQuK86fUbs92NJ6QOYIGO)):

```{image} images/opi5-max-pinout.png
:alt: Orange Pi 5 Max Pinout
```

:::
::::

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,18 @@

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import java.util.ArrayList;
import org.photonvision.common.hardware.gpio.PinIdentifier;

@JsonIgnoreProperties(ignoreUnknown = true)
public class HardwareConfig {
public final String deviceName;

// LED control
public final ArrayList<Integer> ledPins;
public final ArrayList<PinIdentifier> ledPins;
public final boolean ledsCanDim;
public final ArrayList<Integer> ledBrightnessRange;
public final int ledPWMFrequency;
public final ArrayList<Integer> statusRGBPins;
public final ArrayList<PinIdentifier> statusRGBPins;
public final boolean statusRGBActiveHigh;

// Custom GPIO
Expand All @@ -45,11 +46,11 @@ public class HardwareConfig {

public HardwareConfig(
String deviceName,
ArrayList<Integer> ledPins,
ArrayList<PinIdentifier> ledPins,
boolean ledsCanDim,
ArrayList<Integer> ledBrightnessRange,
int ledPwmFrequency,
ArrayList<Integer> statusRGBPins,
ArrayList<PinIdentifier> statusRGBPins,
boolean statusRGBActiveHigh,
String getGPIOCommand,
String setGPIOCommand,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@
package org.photonvision.common.hardware;

import com.diozero.api.DeviceMode;
import com.diozero.api.PinInfo;
import com.diozero.internal.spi.NativeDeviceFactoryInterface;
import com.diozero.sbc.BoardPinInfo;
import com.diozero.sbc.DeviceFactoryHelper;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
Expand All @@ -33,6 +35,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.gpio.PinIdentifier;
import org.photonvision.common.logging.LogGroup;
import org.photonvision.common.logging.Logger;
import org.photonvision.common.util.ShellExec;
Expand Down Expand Up @@ -103,7 +106,7 @@ public NativeDeviceFactoryInterface get() {

statusLED =
hardwareConfig.statusRGBPins.size() == 3
? new StatusLED(
? StatusLED.create(
lazyDeviceFactory.get(),
hardwareConfig.statusRGBPins,
hardwareConfig.statusRGBActiveHigh)
Expand Down Expand Up @@ -154,20 +157,42 @@ public static NativeDeviceFactoryInterface configureCustomGPIO(HardwareConfig ha
BoardPinInfo pinInfo = deviceFactory.getBoardPinInfo();

// Populate pin info according to hardware config
for (int pin : hardwareConfig.ledPins) {
for (PinIdentifier pin : hardwareConfig.ledPins) {
if (hardwareConfig.ledsCanDim) {
pinInfo.addGpioPinInfo(pin, pin, List.of(DeviceMode.PWM_OUTPUT, DeviceMode.DIGITAL_OUTPUT));
addCustomGPIOPin(pinInfo, pin, List.of(DeviceMode.PWM_OUTPUT, DeviceMode.DIGITAL_OUTPUT));
} else {
pinInfo.addGpioPinInfo(pin, pin, List.of(DeviceMode.DIGITAL_OUTPUT));
addCustomGPIOPin(pinInfo, pin, List.of(DeviceMode.DIGITAL_OUTPUT));
}
}
for (int pin : hardwareConfig.statusRGBPins) {
pinInfo.addGpioPinInfo(pin, pin, List.of(DeviceMode.DIGITAL_OUTPUT));
for (PinIdentifier pin : hardwareConfig.statusRGBPins) {
addCustomGPIOPin(pinInfo, pin, List.of(DeviceMode.DIGITAL_OUTPUT));
}

return deviceFactory;
}

/*
* This is used to generate integer IDs for custom named pins, deep in the
* unused range for gpio numbers. These IDs will still be recognized as a
* normal gpio number by most of diozero's code, but not by PinIdentifier.
*/
static int namedPinID = Integer.MIN_VALUE;

protected static PinInfo addCustomGPIOPin(
BoardPinInfo pinInfo, PinIdentifier pin, Collection<DeviceMode> modes) {
if (pin instanceof PinIdentifier.NumberedPin) {
int number = pin.getDeviceNumber();
return pinInfo.addGpioPinInfo(number, number, modes);
} else if (pin instanceof PinIdentifier.NamedPin) {
int number = namedPinID++;
String name = ((PinIdentifier.NamedPin) pin).name;
return pinInfo.addGpioPinInfo(number, name, number, modes);
} else {
throw new UnsupportedOperationException(
"Only numbered or named pins can be used with custom GPIO");
}
}

public void setBrightnessPercent(int percent) {
if (percent != hardwareSettings.ledBrightnessPercentage) {
hardwareSettings.ledBrightnessPercentage = percent;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@

package org.photonvision.common.hardware;

import com.diozero.api.NoSuchDeviceException;
import com.diozero.devices.LED;
import com.diozero.internal.spi.NativeDeviceFactoryInterface;
import java.util.List;
import org.jetbrains.annotations.Nullable;
import org.photonvision.common.hardware.gpio.PinIdentifier;
import org.photonvision.common.util.TimedTaskManager;

public class StatusLED implements AutoCloseable {
Expand All @@ -31,22 +34,52 @@ public class StatusLED implements AutoCloseable {
protected PhotonStatus status = PhotonStatus.GENERIC_ERROR;

public StatusLED(
NativeDeviceFactoryInterface deviceFactory, List<Integer> statusLedPins, boolean activeHigh) {
NativeDeviceFactoryInterface deviceFactory,
List<PinIdentifier> statusLedPins,
boolean activeHigh)
throws NoSuchDeviceException {
// fill unassigned pins with -1 to disable
if (statusLedPins.size() != 3) {
for (int i = 0; i < 3 - statusLedPins.size(); i++) {
statusLedPins.add(-1);
statusLedPins.add(PinIdentifier.numbered(-1));
}
}

// Outputs are active-low for a common-anode RGB LED
redLED = new LED(deviceFactory, statusLedPins.get(0), activeHigh, false);
greenLED = new LED(deviceFactory, statusLedPins.get(1), activeHigh, false);
blueLED = new LED(deviceFactory, statusLedPins.get(2), activeHigh, false);
redLED =
new LED(
deviceFactory,
statusLedPins.get(0).info(deviceFactory).getDeviceNumber(),
activeHigh,
false);
greenLED =
new LED(
deviceFactory,
statusLedPins.get(1).info(deviceFactory).getDeviceNumber(),
activeHigh,
false);
blueLED =
new LED(
deviceFactory,
statusLedPins.get(2).info(deviceFactory).getDeviceNumber(),
activeHigh,
false);

TimedTaskManager.getInstance().addTask("StatusLEDUpdate", this::updateLED, 150);
}

@Nullable
static StatusLED create(
NativeDeviceFactoryInterface deviceFactory,
List<PinIdentifier> statusLedPins,
boolean activeHigh) {
try {
return new StatusLED(deviceFactory, statusLedPins, activeHigh);
} catch (NoSuchDeviceException e) {
return null;
}
}

protected void setRGB(boolean r, boolean g, boolean b) {
redLED.setOn(r);
greenLED.setOn(g);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,17 @@

package org.photonvision.common.hardware;

import com.diozero.api.NoSuchDeviceException;
import com.diozero.api.PinInfo;
import com.diozero.devices.LED;
import com.diozero.devices.PwmLed;
import com.diozero.internal.spi.NativeDeviceFactoryInterface;
import com.diozero.sbc.BoardPinInfo;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import org.photonvision.common.hardware.gpio.PinIdentifier;
import org.photonvision.common.logging.LogGroup;
import org.photonvision.common.logging.Logger;
import org.photonvision.common.util.TimedTaskManager;
Expand All @@ -51,7 +53,7 @@ public class VisionLED implements AutoCloseable {

public VisionLED(
NativeDeviceFactoryInterface deviceFactory,
List<Integer> ledPins,
List<PinIdentifier> ledPins,
boolean ledsCanDim,
int brightnessMin,
int brightnessMax,
Expand All @@ -63,17 +65,23 @@ public VisionLED(
if (pwmFrequency > 0) {
deviceFactory.setBoardPwmFrequency(pwmFrequency);
}
BoardPinInfo boardPinInfo = deviceFactory.getBoardPinInfo();
ledPins.forEach(
pin -> {
if (ledsCanDim && boardPinInfo.getByPwmOrGpioNumberOrThrow(pin).isPwmOutputSupported()) {
PwmLed led = new PwmLed(deviceFactory, pin);
if (pwmFrequency > 0) {
led.setPwmFrequency(pwmFrequency);
PinInfo pinInfo = pin.info(deviceFactory);
if (ledsCanDim && pinInfo.isPwmOutputSupported()) {
try {
PwmLed led = new PwmLed(deviceFactory, pinInfo.getPwmNum());
if (pwmFrequency > 0) {
led.setPwmFrequency(pwmFrequency);
}
dimmableVisionLEDs.add(led);
} catch (NoSuchDeviceException e) {
}
dimmableVisionLEDs.add(led);
} else {
visionLEDs.add(new LED(deviceFactory, pin));
try {
visionLEDs.add(new LED(deviceFactory, pinInfo.getDeviceNumber(), true, false));
} catch (NoSuchDeviceException e) {
}
}
});
pipelineModeSupplier = () -> false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,33 +55,26 @@ protected static String execute(String command) {
return runCommand.get().getOutput();
}

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

public void setGPIO(int gpio, boolean state) {
execute(
setGPIOCommand
.replace("{p}", Integer.toString(gpio))
.replace("{s}", Boolean.toString(state)));
public void setGPIO(PinIdentifier gpio, boolean state) {
execute(setGPIOCommand.replace("{p}", gpio.toString()).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 setPWM(PinIdentifier gpio, double value) {
execute(setPWMCommand.replace("{p}", gpio.toString()).replace("{v}", Double.toString(value)));
}

public void setPwmFrequency(int gpio, int frequency) {
public void setPwmFrequency(PinIdentifier gpio, int frequency) {
execute(
setPWMFrequencyCommand
.replace("{p}", Integer.toString(gpio))
.replace("{p}", gpio.toString())
.replace("{f}", Integer.toString(frequency)));
}

public void releaseGPIO(int gpio) {
execute(releaseGPIOCommand.replace("{p}", Integer.toString(gpio)));
public void releaseGPIO(PinIdentifier gpio) {
execute(releaseGPIOCommand.replace("{p}", gpio.toString()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public String getName() {

@Override
public int getGpioValue(int gpio) {
return adapter.getGPIO(gpio) ? 1 : 0;
return adapter.getGPIO(PinIdentifier.numbered(gpio)) ? 1 : 0;
}

@Override
Expand Down Expand Up @@ -118,26 +118,26 @@ public void setBoardServoFrequency(int servoFrequency) {
@Override
public GpioDigitalInputDeviceInterface createDigitalInputDevice(
String key, PinInfo pinInfo, GpioPullUpDown pud, GpioEventTrigger trigger) {
return new CustomDigitalInputDevice(this, key, pinInfo.getDeviceNumber(), pud, trigger);
return new CustomDigitalInputDevice(this, key, PinIdentifier.fromInfo(pinInfo), pud, trigger);
}

@Override
public GpioDigitalOutputDeviceInterface createDigitalOutputDevice(
String key, PinInfo pinInfo, boolean initialValue) {
return new CustomDigitalOutputDevice(this, key, pinInfo.getDeviceNumber(), initialValue);
return new CustomDigitalOutputDevice(this, key, PinIdentifier.fromInfo(pinInfo), initialValue);
}

@Override
public GpioDigitalInputOutputDeviceInterface createDigitalInputOutputDevice(
String key, PinInfo pinInfo, DeviceMode mode) {
return new CustomDigitalInputOutputDevice(this, key, pinInfo.getDeviceNumber(), mode);
return new CustomDigitalInputOutputDevice(this, key, PinIdentifier.fromInfo(pinInfo), mode);
}

@Override
public InternalPwmOutputDeviceInterface createPwmOutputDevice(
String key, PinInfo pinInfo, int pwmFrequency, float initialValue) {
return new CustomPwmOutputDevice(
this, key, pinInfo.getDeviceNumber(), pwmFrequency, initialValue);
this, key, PinIdentifier.fromInfo(pinInfo), pwmFrequency, initialValue);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@
public class CustomDigitalInputDevice extends AbstractInputDevice<DigitalInputEvent>
implements GpioDigitalInputDeviceInterface {
protected final CustomAdapter adapter;
protected final int gpio;
protected final PinIdentifier gpio;

public CustomDigitalInputDevice(
CustomDeviceFactory deviceFactory,
String key,
int gpio,
PinIdentifier gpio,
GpioPullUpDown pud,
GpioEventTrigger trigger) {
super(key, deviceFactory);
Expand All @@ -48,7 +48,7 @@ public boolean getValue() throws RuntimeIOException {

@Override
public int getGpio() {
return gpio;
return gpio.getDeviceNumber();
}

@Override
Expand Down
Loading
Loading