Skip to content

Commit

Permalink
Dependency version bump. Property to indicate if this is a recognised
Browse files Browse the repository at this point in the history
board. Improved handling of unknown boards, ability to provision via
GPIO chip and line offset (#202).
  • Loading branch information
mattjlewis committed May 28, 2024
1 parent cdb582d commit 129bcba
Show file tree
Hide file tree
Showing 20 changed files with 288 additions and 205 deletions.
26 changes: 13 additions & 13 deletions diozero-bom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -65,32 +65,32 @@
<maven-compiler-plugin.version>3.13.0</maven-compiler-plugin.version>
<maven-assembly-plugin.version>3.7.1</maven-assembly-plugin.version>
<maven-javadoc-plugin.version>3.6.3</maven-javadoc-plugin.version>
<maven-jar-plugin.version>3.3.0</maven-jar-plugin.version>
<maven-shade-plugin.version>3.5.2</maven-shade-plugin.version>
<maven-jar-plugin.version>3.4.1</maven-jar-plugin.version>
<maven-shade-plugin.version>3.5.3</maven-shade-plugin.version>
<maven-source-plugin.version>3.3.1</maven-source-plugin.version>
<maven-install-plugin.version>3.1.1</maven-install-plugin.version>
<maven-deploy-plugin.version>3.1.1</maven-deploy-plugin.version>
<maven-gpg-plugin.version>3.2.2</maven-gpg-plugin.version>
<maven-install-plugin.version>3.1.2</maven-install-plugin.version>
<maven-deploy-plugin.version>3.1.2</maven-deploy-plugin.version>
<maven-gpg-plugin.version>3.2.4</maven-gpg-plugin.version>
<maven-release-plugin.version>3.0.1</maven-release-plugin.version>
<maven-surefire-plugin.version>3.2.5</maven-surefire-plugin.version>

<!-- Other plugins -->
<nexus-staging-maven-plugin.version>1.6.13</nexus-staging-maven-plugin.version>
<nexus-staging-maven-plugin.version>1.7.0</nexus-staging-maven-plugin.version>
<license-maven-plugin.version>2.4.0</license-maven-plugin.version>
<versions-maven-plugin.version>2.16.2</versions-maven-plugin.version>
<exec-maven-plugin.version>3.2.0</exec-maven-plugin.version>
<exec-maven-plugin.version>3.3.0</exec-maven-plugin.version>
<eclipse.m2e.lifecycle-mapping.version>1.0.0</eclipse.m2e.lifecycle-mapping.version>

<!-- Libraries -->
<tinylog.version>2.7.0</tinylog.version>
<hipparchus.version>3.0</hipparchus.version>
<hipparchus.version>3.1</hipparchus.version>
<eclipse-paho-client-mqttv3.version>1.2.5</eclipse-paho-client-mqttv3.version>
<google-gson.version>2.10.1</google-gson.version>
<google-protobuf-java.version>3.25.2</google-protobuf-java.version>
<netty.version>4.1.108.Final</netty.version>
<grpc.version>1.63.0</grpc.version>
<google-gson.version>2.11.0</google-gson.version>
<google-protobuf-java.version>4.27.0</google-protobuf-java.version>
<netty.version>4.1.110.Final</netty.version>
<grpc.version>1.64.0</grpc.version>
<junit.version>5.10.2</junit.version>
<mockito.version>5.11.0</mockito.version>
<mockito.version>5.12.0</mockito.version>
</properties>

<!-- Prepare common library versions -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ public class GenericLinuxArmBoardInfo extends BoardInfo {
private List<String> compatibility;
private Properties mmapGpioClasses;
private Optional<Map<String, Integer>> chipMapping;
private boolean boardDefLoaded = false;

public GenericLinuxArmBoardInfo(LocalSystemInfo systemInfo) {
this(systemInfo, systemInfo.getMake());
Expand Down Expand Up @@ -102,17 +103,21 @@ public void populateBoardPinInfo() {
* ["hardkernel,odroid-c2", "amlogic,meson-gxbb"]
*/
for (String compat : compatibility) {
boolean loaded = loadBoardPinInfoDefinition(compat.split(","));

if (loaded) {
boardDefLoaded = loadBoardPinInfoDefinition(compat.split(","));
if (boardDefLoaded) {
break;
}
}

// Note that if this fails the GPIO character implementation in the device
// Note that if this fails the GPIO chardev implementation in the device
// factory will attempt to auto-populate (if enabled)
}

@Override
public boolean isRecognised() {
return boardDefLoaded;
}

protected boolean loadBoardPinInfoDefinition(String... compatibilityParts) {
for (int i = 0; i < compatibilityParts.length; i++) {
compatibilityParts[i] = compatibilityParts[i].trim();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ public void start() {

Logger.debug("Found {} GPIO chips", Integer.valueOf(chips.size()));

final boolean unknown_board = !board_info.isRecognised();

// Validate the data in BoardPinInfo
if (board_info instanceof GenericLinuxArmBoardInfo) {
board_info.getChipMapping()
Expand All @@ -123,7 +125,7 @@ public void start() {
// Validate the board pin info matches the GPIO chip and line offsets
Logger.debug("Validating BoardPinInfo against detected GPIO chip and line offsets...");
board_info.getGpioPins().forEach(pin_info -> {
GpioChip chip = chips.get(Integer.valueOf(pin_info.getChip()));
final GpioChip chip = chips.get(Integer.valueOf(pin_info.getChip()));
if (chip == null) {
if (pin_info.getChip() != -1) {
Logger.warn("No such chip for id {}", Integer.valueOf(pin_info.getChip()));
Expand All @@ -138,75 +140,7 @@ public void start() {

// Validate the GPIO chip and line offsets match those detected
Logger.debug("Validating detected GPIO chip and line offsets against BoardPinInfo...");
chips.values().forEach(chip -> {
for (GpioLine gpio_line : chip.getLines()) {
PinInfo pin_info = null;
final String line_name = gpio_line.getName().trim();

// Try to find this GPIO in the board pin info by the assumed system name
if (!line_name.isEmpty()) {
pin_info = board_info.getByName(line_name);
}

// If the pin couldn't be found for the assigned name try to find the pin info
// by chip and line offset number
if (pin_info == null) {
// Note that getByChipAndLineOffset doesn't create missing entries
pin_info = board_info.getByChipAndLineOffset(chip.getChipId(), gpio_line.getOffset())
.orElse(null);
}

// Finally, if still not found see if the name is in the format GPIOnn and
// lookup by GPIO number
if (pin_info == null && line_name.matches(GPIO_LINE_NUMBER_PATTERN)) {
// Note that this isn't reliable - GPIO names are often missing or not in this
// format
// Note that the unknown / generic board info classes will create missing pin
// info objects if you call getByGpioNumber - we don't want that to happen here
pin_info = board_info.getGpios()
.get(Integer.valueOf(line_name.replaceAll(GPIO_LINE_NUMBER_PATTERN, "$1")));
}

// XXX This includes a bit of a hack to ignore pins with the name "NC" - the BBB
// does this for quite a few pins which triggers the warning message
if (pin_info == null && !line_name.isEmpty() && !line_name.equals("NC")
&& !line_name.equals("-")) {
Logger.debug("Detected GPIO line ({} {}-{}) that isn't configured in BoardPinInfo",
line_name, Integer.valueOf(chip.getChipId()),
Integer.valueOf(gpio_line.getOffset()));
if (addUnconfiguredGpios) {
// Add a new pin info to the board pin info
int gpio_num;
if (line_name.matches(GPIO_LINE_NUMBER_PATTERN)) {
gpio_num = Integer.parseInt(line_name.replaceAll(GPIO_LINE_NUMBER_PATTERN, "$1"));
} else {
// Calculate the GPIO number
gpio_num = chip.getLineOffset() + gpio_line.getOffset();
}
pin_info = board_info.addGpioPinInfo(gpio_num, line_name, PinInfo.NOT_DEFINED,
PinInfo.DIGITAL_IN_OUT, chip.getChipId(), gpio_line.getOffset());
Logger.debug("Added pin info {}", pin_info);
}
} else if (pin_info != null) {
if (pin_info.getChip() != chip.getChipId()
|| pin_info.getLineOffset() != gpio_line.getOffset()) {
Logger.warn(
"Configured pin chip and line offset ({}-{}) doesn't match that detected ({}-{}), line name '{}' - updating",
Integer.valueOf(pin_info.getChip()), Integer.valueOf(pin_info.getLineOffset()),
Integer.valueOf(chip.getChipId()), Integer.valueOf(gpio_line.getOffset()),
gpio_line.getName());
pin_info.setChip(chip.getChipId());
pin_info.setLineOffset(gpio_line.getOffset());
}

if (!line_name.isEmpty() && !pin_info.getName().equals(line_name)) {
Logger.info("Configured pin name ({}) doesn't match that detected ({})",
pin_info.getName(), line_name);
// XXX What to do about it - update the board pin info? Just ignore for now.
}
}
}
});
chips.values().forEach(chip -> loadChip(board_info, unknown_board, chip));
} catch (IOException e) {
throw new RuntimeIOException("Error initialising GPIO chips: " + e.getMessage(), e);
}
Expand Down Expand Up @@ -235,6 +169,76 @@ public void start() {
}
}

private void loadChip(BoardInfo boardInfo, boolean unknownBoard, GpioChip chip) {
for (GpioLine gpio_line : chip.getLines()) {
PinInfo pin_info = null;
final String line_name = gpio_line.getName().trim();

// Try to find this GPIO in the board pin info by the assumed system name
if (!line_name.isEmpty()) {
pin_info = boardInfo.getByName(line_name);
}

// If the pin couldn't be found for the assigned name try to find the pin info
// by chip and line offset number
if (pin_info == null) {
// Note that getByChipAndLineOffset doesn't create missing entries
pin_info = boardInfo.getByChipAndLineOffset(chip.getChipId(), gpio_line.getOffset()).orElse(null);
}

// Finally, if still not found see if the name is in the format GPIOnn and
// lookup by GPIO number
if (pin_info == null && line_name.matches(GPIO_LINE_NUMBER_PATTERN)) {
// Note that this isn't reliable - GPIO names are often missing or not in this
// format
// Note that the unknown / generic board info classes will create missing pin
// info objects if you call getByGpioNumber - we don't want that to happen here
pin_info = boardInfo.getGpios()
.get(Integer.valueOf(line_name.replaceAll(GPIO_LINE_NUMBER_PATTERN, "$1")));
}

// XXX This includes a bit of a hack to ignore pins with the name "NC" - the BBB
// does this for quite a few pins which triggers the warning message
if (pin_info == null && !line_name.isEmpty() && !line_name.equals("NC") && !line_name.equals("-")) {
Logger.debug("Detected GPIO line ({} {}-{}) that isn't configured in BoardPinInfo", line_name,
Integer.valueOf(chip.getChipId()), Integer.valueOf(gpio_line.getOffset()));
if (addUnconfiguredGpios || unknownBoard) {
// Add a new pin info to the board pin info
int gpio_num;
if (line_name.matches(GPIO_LINE_NUMBER_PATTERN)) {
gpio_num = Integer.parseInt(line_name.replaceAll(GPIO_LINE_NUMBER_PATTERN, "$1"));
} else {
// Calculate the GPIO number
gpio_num = chip.getLineOffset() + gpio_line.getOffset();
}
int physical_pin = PinInfo.NOT_DEFINED;
if (line_name.startsWith("PIN_")) {
physical_pin = Integer.parseInt(line_name.substring("PIN_".length()));
}
pin_info = boardInfo.addGpioPinInfo(gpio_num, line_name, physical_pin, PinInfo.DIGITAL_IN_OUT,
chip.getChipId(), gpio_line.getOffset());
Logger.debug("Added {}", pin_info);
}
} else if (pin_info != null) {
if (pin_info.getChip() != chip.getChipId() || pin_info.getLineOffset() != gpio_line.getOffset()) {
Logger.warn(
"Configured pin chip and line offset ({}-{}) doesn't match that detected ({}-{}), line name '{}' - updating",
Integer.valueOf(pin_info.getChip()), Integer.valueOf(pin_info.getLineOffset()),
Integer.valueOf(chip.getChipId()), Integer.valueOf(gpio_line.getOffset()),
gpio_line.getName());
pin_info.setChip(chip.getChipId());
pin_info.setLineOffset(gpio_line.getOffset());
}

if (!line_name.isEmpty() && !pin_info.getName().equals(line_name)) {
Logger.info("Configured pin name ({}) doesn't match that detected ({})", pin_info.getName(),
line_name);
// XXX What to do about it - update the board pin info? Just ignore for now.
}
}
}
}

private static void updateChipIds(Map<Integer, GpioChip> chips, Map<String, Integer> chipMapping,
BoardInfo boardInfo) {
if (chips == null || chips.isEmpty()) {
Expand All @@ -261,7 +265,7 @@ public void shutdown() {
Logger.trace("shutdown()");

if (chips != null) {
chips.values().forEach(chip -> chip.close());
chips.values().forEach(GpioChip::close);
chips.clear();
}

Expand Down Expand Up @@ -312,6 +316,9 @@ public int getGpioValue(int gpio) {
if (mmapGpio != null) {
return mmapGpio.gpioRead(gpio) ? 1 : 0;
}
// TODO Use GpioChip to read the device and clean up afterwards - check how gpioget works
// (sets top input)
// https://github.com/brgl/libgpiod/blob/master/tools/gpioget.c
return Diozero.UNKNOWN_VALUE;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public class GpioChip extends GpioChipInfo implements AutoCloseable, GpioLineEve
public static Map<Integer, GpioChip> openAllChips() throws IOException {
LibraryLoader.loadSystemUtils();

Map<Integer, GpioChip> chips = Files.list(Paths.get("/dev"))
final Map<Integer, GpioChip> chips = Files.list(Paths.get("/dev"))
.filter(p -> p.getFileName().toString().startsWith("gpiochip"))
.map(p -> NativeGpioDevice.openChip(p.toString())) //
.filter(p -> p != null) // openChip will return null if it is unable to open the chip
Expand All @@ -74,10 +74,9 @@ public static Map<Integer, GpioChip> openAllChips() throws IOException {
// Calculate the line offset for the chips
// This allows GPIOs to be auto-detected as the GPIO number is chip offset +
// line offset
AtomicInteger offset = new AtomicInteger(0);
chips.entrySet().stream().sorted(Map.Entry.comparingByKey()).forEach(entry -> {
entry.getValue().setLineOffset(offset.getAndAdd(entry.getValue().getNumLines()));
});
final AtomicInteger offset = new AtomicInteger(0);
chips.entrySet().stream().sorted(Map.Entry.comparingByKey()).map(Map.Entry::getValue)
.forEach(chip -> chip.setLineOffset(offset.getAndAdd(chip.getNumLines())));

return chips;
}
Expand All @@ -91,7 +90,7 @@ public static List<GpioChipInfo> getChips() {
public static GpioChip openChip(int chipNum) {
LibraryLoader.loadSystemUtils();

return openChip("/dev/" + GPIO_CHIP_FILENAME_PREFIX + "/" + chipNum);
return openChip("/dev/" + GPIO_CHIP_FILENAME_PREFIX + chipNum);
}

public static GpioChip openChip(String chipDeviceFile) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,18 +47,17 @@ public interface SerialDeviceFactoryInterface extends DeviceFactoryInterface {
* @param parity Parity option
* @param readBlocking Do read operations block?
* @param minReadChars The minimum number of characters to read
* @param readTimeoutMillis How long a read operation waits for data before
* timing out. 0 == no timeout
* @param readTimeoutMillis How long a read operation waits for data before timing out. 0
* == no timeout
* @return Serial device instance
* @throws RuntimeIOException if an error occurs
*/
default InternalSerialDeviceInterface provisionSerialDevice(String deviceFilename, int baud,
SerialDevice.DataBits dataBits, SerialDevice.StopBits stopBits, SerialDevice.Parity parity,
boolean readBlocking, int minReadChars, int readTimeoutMillis) throws RuntimeIOException {

return registerDevice(()->createSerialKey(deviceFilename),
(k)-> createSerialDevice(k, deviceFilename, baud, dataBits, stopBits, parity,
readBlocking, minReadChars, readTimeoutMillis));
return registerDevice(() -> createSerialKey(deviceFilename), key -> createSerialDevice(key, deviceFilename,
baud, dataBits, stopBits, parity, readBlocking, minReadChars, readTimeoutMillis));
}

InternalSerialDeviceInterface createSerialDevice(String key, String deviceFilename, int baud,
Expand Down
31 changes: 15 additions & 16 deletions diozero-core/src/main/java/com/diozero/sbc/BoardInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,11 @@
import com.diozero.internal.spi.MmapGpioInterface;

/**
* Information about the connected SBC. Note that the connected board instance
* might be a remote device, e.g. connected via serial, Bluetooth or TCP/IP. The
* BoardInfo instance for the connected device must be obtained by calling
* Information about the connected SBC. Note that the connected board instance might be a
* remote device, e.g. connected via serial, Bluetooth or TCP/IP. The BoardInfo instance
* for the connected device must be obtained by calling
* {@link com.diozero.internal.spi.NativeDeviceFactoryInterface#getBoardInfo()
* getBoardInfo()} the on the
* {@link com.diozero.internal.spi.NativeDeviceFactoryInterface
* getBoardInfo()} the on the {@link com.diozero.internal.spi.NativeDeviceFactoryInterface
* NativeDeviceFactoryInterface} instance returned from
* {@link DeviceFactoryHelper#getNativeDeviceFactory()}.
*/
Expand All @@ -63,11 +62,17 @@ public BoardInfo(String make, String model, int memoryKb, String osId, String os
}

/**
* Pin initialisation is done separately to the constructor since all known
* BoardInfo instances get instantiated on startup by the Java ServiceLoader.
* Pin initialisation is done separately to the constructor since all known BoardInfo
* instances get instantiated on startup by the Java ServiceLoader.
*/
public abstract void populateBoardPinInfo();

public boolean isBiasControlSupported() {
return false;
}

public abstract boolean isRecognised();

/**
* The make of the connected board, e.g. "Raspberry Pi"
*
Expand Down Expand Up @@ -128,12 +133,10 @@ public boolean compareMakeAndModel(String make2, String model2) {
}

/**
* Instantiate the memory mapped GPIO interface for this board. Not that the
* caller needs to call {@link MmapGpioInterface#initialise initialise} prior to
* use.
* Instantiate the memory mapped GPIO interface for this board. Not that the caller needs
* to call {@link MmapGpioInterface#initialise initialise} prior to use.
*
* @return the MMAP GPIO interface implementation for this board, null if there
* isn't one
* @return the MMAP GPIO interface implementation for this board, null if there isn't one
*/
public MmapGpioInterface createMmapGpio() {
return null;
Expand All @@ -143,8 +146,4 @@ public MmapGpioInterface createMmapGpio() {
public String toString() {
return "BoardInfo [make=" + make + ", model=" + model + ", memory=" + memoryKb + "]";
}

public boolean isBiasControlSupported() {
return false;
}
}
Loading

0 comments on commit 129bcba

Please sign in to comment.